Skip to content

Commit

Permalink
Add Website as a device
Browse files Browse the repository at this point in the history
  • Loading branch information
xelahalo committed Mar 11, 2024
1 parent e058fc8 commit 0a54351
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
@file:Suppress("NON_EXPORTABLE_TYPE")

package dk.cachet.carp.common.application.devices

import dk.cachet.carp.common.application.Trilean
import dk.cachet.carp.common.application.data.DataType
import dk.cachet.carp.common.application.sampling.DataTypeSamplingSchemeMap
import dk.cachet.carp.common.application.sampling.SamplingConfiguration
import dk.cachet.carp.common.application.tasks.TaskConfigurationList
import dk.cachet.carp.common.application.toTrilean
import dk.cachet.carp.common.infrastructure.serialization.NotSerializable
import kotlinx.serialization.Required
import kotlinx.serialization.Serializable
import kotlin.js.JsExport
import kotlin.reflect.KClass


/**
* A device representing a website.
*
* @param unsupportedBrowsers A set of web [Browser]s which do not yield a valid [WebsiteDeviceRegistration].
* Empty by default.
*/
@Serializable
@JsExport
data class Website(
val unsupportedBrowsers: Set<Browser> = emptySet(),
override val roleName: String,
override val isOptional: Boolean = false
) : PrimaryDeviceConfiguration<WebsiteDeviceRegistration, WebsiteDeviceRegistrationBuilder>()
{
object Sensors : DataTypeSamplingSchemeMap()
object Tasks : TaskConfigurationList()

override fun getSupportedDataTypes(): Set<DataType> = Sensors.keys

override val defaultSamplingConfiguration: Map<DataType, SamplingConfiguration> = emptyMap()

override fun getDataTypeSamplingSchemes(): DataTypeSamplingSchemeMap = Sensors

override fun createDeviceRegistrationBuilder(): WebsiteDeviceRegistrationBuilder =
WebsiteDeviceRegistrationBuilder()

override fun getRegistrationClass(): KClass<WebsiteDeviceRegistration> = WebsiteDeviceRegistration::class

override fun isValidRegistration( registration: WebsiteDeviceRegistration ): Trilean =
unsupportedBrowsers.contains( registration.browser ).not().toTrilean()
}

/**
* Describes a browser type which can be used to make [WebsiteDeviceRegistration]s.
*/
@Serializable
@JsExport
enum class Browser
{
Chrome,
Firefox,
Safari,
Edge,
Opera,
Other;
companion object
{
fun fromStringIgnoreCase( value: String ): Browser =
entries.firstOrNull { it.name.equals( value, ignoreCase = true ) } ?: Other
}
}

/**
* A [DeviceRegistration] for a website, specifying the [Browser] to be used and URL at which it is hosted.
*/
@Serializable
@JsExport
data class WebsiteDeviceRegistration(
val browser: Browser,
val url: String,
@Required
override val deviceDisplayName: String? = null
) : DeviceRegistration()
{
@Required
override val deviceId: String = "${browser.name}:$url"
}


@Suppress( "SERIALIZER_TYPE_INCOMPATIBLE" )
@Serializable( NotSerializable::class )
@JsExport
class WebsiteDeviceRegistrationBuilder : DeviceRegistrationBuilder<WebsiteDeviceRegistration>()
{
/**
* The web [Browser] to register. The built [WebsiteDeviceRegistration] defaults to [Browser.Other] if not set.
*/
var browser: String = ""

/**
* The URL to register.
*/
var url: String = ""

override fun build(): WebsiteDeviceRegistration =
WebsiteDeviceRegistration( Browser.fromStringIgnoreCase( browser ), url )
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ val COMMON_SERIAL_MODULE = SerializersModule {
{
subclass( CustomProtocolDevice::class )
subclass( Smartphone::class )
subclass( Website::class )

subclass( CustomPrimaryDeviceConfiguration::class )
}
Expand All @@ -87,6 +88,7 @@ val COMMON_SERIAL_MODULE = SerializersModule {
subclass( BLESerialNumberDeviceRegistration::class )
subclass( DefaultDeviceRegistration::class )
subclass( MACAddressDeviceRegistration::class )
subclass( WebsiteDeviceRegistration::class )

subclass( CustomDeviceRegistration::class )
defaultDeserializer { DeviceRegistrationSerializer }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ val commonInstances = listOf(
BLESerialNumberDeviceRegistration( "123456789" ),
CustomProtocolDevice( "User's phone" ),
Smartphone( "User's phone" ),
Website( setOf( Browser.Safari ), "Example browser" ),
WebsiteDeviceRegistration( Browser.Chrome, "https://example.com", "User's browser"),

// Shared device registrations in `devices` namespace.
DefaultDeviceRegistration(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dk.cachet.carp.common.application.devices

import dk.cachet.carp.common.application.Trilean
import kotlin.test.Test
import kotlin.test.assertEquals

class WebsiteTest
{
@Test
// Browser.entries() is not supported in JS.
@Suppress( "EnumValuesSoftDeprecate")
fun browser_enum_contains_all_supported_browsers()
{
val browsers =
setOf( Browser.Chrome, Browser.Firefox, Browser.Safari, Browser.Edge, Browser.Opera, Browser.Other )
assertEquals( browsers, Browser.values().toSet() )
}

@Test
fun browser_fromStringIgnoreCase_should_ignore_case()
{
assertEquals( Browser.Chrome, Browser.fromStringIgnoreCase( "chrome" ) )
assertEquals( Browser.Chrome, Browser.fromStringIgnoreCase( "CHROME" ) )
}

@Test
fun browser_fromStringIgnoreCase_returns_Other_for_unknown_browsers()
{
assertEquals( Browser.Other, Browser.fromStringIgnoreCase( "unknown" ) )
}

@Test
fun registration_builder_sets_properties()
{
val registration = WebsiteDeviceRegistrationBuilder().apply {
browser = "CHROME"
url = "https://www.example.com"
}.build()

assertEquals( Browser.Chrome, registration.browser )
assertEquals( "https://www.example.com", registration.url )
}

@Test
fun registration_valid_if_browser_is_supported()
{
val configuration = Website( setOf( Browser.Firefox ), "Web browser" )
val registration = WebsiteDeviceRegistration( Browser.Chrome, "https://www.example.com" )
assertEquals( Trilean.TRUE, configuration.isValidRegistration( registration ) )
}

@Test
fun registration_invalid_if_browser_is_not_supported()
{
val configuration = Website( setOf( Browser.Firefox ), "Web browser" )
val registration = WebsiteDeviceRegistration( Browser.Firefox, "https://www.example.com" )
assertEquals( Trilean.FALSE, configuration.isValidRegistration( registration ) )
}
}
2 changes: 1 addition & 1 deletion docs/carp-common.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ act as a hub to aggregate, synchronize, and upload incoming data received from o
| [AltBeacon](../carp.common/src/commonMain/kotlin/dk/cachet/carp/common/application/devices/AltBeacon.kt) | | A beacon meeting the open AltBeacon standard. |
| [BLEHeartRateDevice](../carp.common/src/commonMain/kotlin/dk/cachet/carp/common/application/devices/BLEHeartRateDevice.kt) | | A Bluetooth device which implements a Heart Rate service. |
| [CustomProtocolDevice](../carp.common/src/commonMain/kotlin/dk/cachet/carp/common/application/devices/CustomProtocolDevice.kt) | Yes | A primary device which uses a single `CustomProtocolTask` to determine how to run a study on the device. |

| [Website](../carp.common/src/commonMain/kotlin/dk/cachet/carp/common/application/devices/Website.kt) | Yes | A primary device which can declare unsupported `Browser`s and can be registered via a URL. |
## Sampling schemes and configurations

Supports specifying the sampling scheme for a [`DataType`](#data-types), including possible options, defaults, and constraints.
Expand Down
10 changes: 10 additions & 0 deletions rpc/schemas/common/devices/Browser.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"properties": {
"__type": { "const": "dk.cachet.carp.common.application.devices.browser" },
"value": { "enum": [ "Chrome", "Firefox", "Safari", "Edge", "Opera", "Other" ] }
},
"required": [ "__type", "value" ],
"additionalProperties": false
}
4 changes: 4 additions & 0 deletions rpc/schemas/common/devices/DeviceRegistration.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
{
"if": { "properties": { "__type": { "const": "dk.cachet.carp.common.application.devices.MACAddressDeviceRegistration" } } },
"then": { "$ref": "MACAddressDeviceRegistration.json" }
},
{
"if": { "properties": { "__type": { "const": "dk.cachet.carp.common.application.devices.WebsiteDeviceRegistration" } } },
"then": { "$ref": "WebsiteDeviceRegistration.json"}
}
],
"$defs": {
Expand Down
4 changes: 4 additions & 0 deletions rpc/schemas/common/devices/PrimaryDeviceConfiguration.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
{
"if": { "properties": { "__type": { "const": "dk.cachet.carp.common.application.devices.Smartphone" } } },
"then": { "$ref": "Smartphone.json" }
},
{
"if": { "properties": { "__type": { "const": "dk.cachet.carp.common.application.devices.Website" } } },
"then": { "$ref": "Website.json"}
}
],
"$defs": {
Expand Down
19 changes: 19 additions & 0 deletions rpc/schemas/common/devices/Website.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"allOf": [ { "$ref": "PrimaryDeviceConfiguration.json#PrimaryDeviceConfiguration" } ],
"properties": {
"__type": { "const": "dk.cachet.carp.common.application.devices.Website" },
"unsupportedBrowsers": {
"type": "array",
"items": { "$ref": "Browser.json" }
}
},
"unevaluatedProperties": false,
"$defs": {
"DeviceRegistration": {
"$anchor": "DeviceRegistration",
"$ref": "WebsiteDeviceRegistration.json"
}
}
}
11 changes: 11 additions & 0 deletions rpc/schemas/common/devices/WebsiteDeviceRegistration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"allOf": [ { "$ref": "DeviceRegistration.json#DeviceRegistration" } ],
"properties": {
"url": { "type": "string", "format": "uri" },
"browser": { "$ref": "Browser.json" }
},
"required": [ "url", "browser" ],
"unevaluatedProperties": false
}

0 comments on commit 0a54351

Please sign in to comment.