From bd740469f15532a01f907cca541f211a8d3bd3c1 Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Fri, 7 Jun 2024 10:39:48 +0200 Subject: [PATCH 1/2] refactor(scripting_api): move DirectoryPayloadFormat to its own file --- lib/src/core/scripting_api.dart | 1 + .../discovery/directory_payload_format.dart | 34 +++++++++++++++++++ lib/src/core/scripting_api/wot.dart | 30 +--------------- 3 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 lib/src/core/scripting_api/discovery/directory_payload_format.dart diff --git a/lib/src/core/scripting_api.dart b/lib/src/core/scripting_api.dart index 2092af3b..954de639 100644 --- a/lib/src/core/scripting_api.dart +++ b/lib/src/core/scripting_api.dart @@ -12,6 +12,7 @@ library scripting_api; export "scripting_api/consumed_thing.dart"; export "scripting_api/data_schema_value.dart"; +export "scripting_api/discovery/directory_payload_format.dart"; export "scripting_api/discovery/thing_discovery.dart"; export "scripting_api/discovery/thing_filter.dart"; export "scripting_api/exposed_thing.dart"; diff --git a/lib/src/core/scripting_api/discovery/directory_payload_format.dart b/lib/src/core/scripting_api/discovery/directory_payload_format.dart new file mode 100644 index 00000000..db892c1b --- /dev/null +++ b/lib/src/core/scripting_api/discovery/directory_payload_format.dart @@ -0,0 +1,34 @@ +// Copyright 2024 Contributors to the Eclipse Foundation. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// SPDX-License-Identifier: BSD-3-Clause + +/// Enumeration for specifying the value of the `format` query parameter when +/// using the `exploreDirectory` discovery method. +/// +/// See [section 7.3.2.1.5] of the [WoT Discovery] specification for more +/// information. +/// +/// [WoT Discovery]: https://www.w3.org/TR/2023/REC-wot-discovery-20231205 +/// [section 7.3.2.1.5]: https://www.w3.org/TR/2023/REC-wot-discovery-20231205/#exploration-directory-api-things-listing +enum DirectoryPayloadFormat { + /// Indicates that an array of Thing Descriptions should be returned. + /// + /// This is the default value. + array, + + /// Indicates that an collection of Thing Descriptions should be returned. + collection, + ; + + @override + String toString() { + switch (this) { + case array: + return "array"; + case collection: + return "collection"; + } + } +} diff --git a/lib/src/core/scripting_api/wot.dart b/lib/src/core/scripting_api/wot.dart index d586bc45..4d23d896 100644 --- a/lib/src/core/scripting_api/wot.dart +++ b/lib/src/core/scripting_api/wot.dart @@ -7,40 +7,12 @@ import "../definitions.dart"; import "consumed_thing.dart"; +import "discovery/directory_payload_format.dart"; import "discovery/thing_discovery.dart"; import "discovery/thing_filter.dart"; import "exposed_thing.dart"; import "types.dart"; -/// Enumeration for specifying the value of the `format` query parameter when -/// using the `exploreDirectory` discovery method. -/// -/// See [section 7.3.2.1.5] of the [WoT Discovery] specification for more -/// information. -/// -/// [WoT Discovery]: https://www.w3.org/TR/2023/REC-wot-discovery-20231205 -/// [section 7.3.2.1.5]: https://www.w3.org/TR/2023/REC-wot-discovery-20231205/#exploration-directory-api-things-listing -enum DirectoryPayloadFormat { - /// Indicates that an array of Thing Descriptions should be returned. - /// - /// This is the default value. - array, - - /// Indicates that an collection of Thing Descriptions should be returned. - collection, - ; - - @override - String toString() { - switch (this) { - case array: - return "array"; - case collection: - return "collection"; - } - } -} - /// Interface for a [WoT] runtime. /// /// See WoT Scripting API specification, From bcac81fb673048dc006cdf50b456b82ea349d22f Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Fri, 7 Jun 2024 10:42:40 +0200 Subject: [PATCH 2/2] feat!: move discovery configurations to scripting_api package --- example/coap_discovery.dart | 15 ++++---- example/coap_dns_sd_discovery.dart | 12 +++--- example/core_link_format_discovery.dart | 12 +++--- lib/src/core/implementation.dart | 1 - lib/src/core/implementation/servient.dart | 27 +++---------- .../core/implementation/thing_discovery.dart | 38 +++++++++++-------- lib/src/core/implementation/wot.dart | 11 +++++- lib/src/core/scripting_api.dart | 1 + .../discovery/discovery_configuration.dart | 7 +++- lib/src/core/scripting_api/wot.dart | 12 +++++- 10 files changed, 75 insertions(+), 61 deletions(-) rename lib/src/core/{implementation => scripting_api}/discovery/discovery_configuration.dart (99%) diff --git a/example/coap_discovery.dart b/example/coap_discovery.dart index c72c7e72..aa86efe5 100644 --- a/example/coap_discovery.dart +++ b/example/coap_discovery.dart @@ -39,18 +39,19 @@ Future handleThingDescription( Future main(List args) async { final servient = Servient.create( clientFactories: [CoapClientFactory()], - discoveryConfigurations: [ - DirectConfiguration( - Uri.parse("coap://plugfest.thingweb.io:5683/testthing"), - ), - ], ); final wot = await servient.start(); + final discoveryConfigurations = [ + DirectConfiguration( + Uri.parse("coap://plugfest.thingweb.io:5683/testthing"), + ), + ]; // Example using for-await-loop try { - await for (final thingDescription in wot.discover()) { + await for (final thingDescription + in wot.discover(discoveryConfigurations)) { await handleThingDescription(wot, thingDescription); } print('Discovery with "await for" has finished.'); @@ -62,7 +63,7 @@ Future main(List args) async { // // Notice how the "onDone" callback is called before the result is passed // to the handleThingDescription function. - wot.discover().listen( + wot.discover(discoveryConfigurations).listen( (thingDescription) async { await handleThingDescription(wot, thingDescription); }, diff --git a/example/coap_dns_sd_discovery.dart b/example/coap_dns_sd_discovery.dart index 0e2944a6..432305f2 100644 --- a/example/coap_dns_sd_discovery.dart +++ b/example/coap_dns_sd_discovery.dart @@ -19,16 +19,18 @@ Future main(List args) async { CoapClientFactory(), HttpClientFactory(), ], - discoveryConfigurations: [ - const DnsSdDConfiguration(protocolType: ProtocolType.udp), - ], ); final wot = await servient.start(); + final discoveryConfigurations = [ + const DnsSdDConfiguration(protocolType: ProtocolType.udp), + ]; + // Example using for-await-loop try { - await for (final thingDescription in wot.discover()) { + await for (final thingDescription + in wot.discover(discoveryConfigurations)) { handleThingDescription(thingDescription); } print('Discovery with "await for" has finished.'); @@ -40,7 +42,7 @@ Future main(List args) async { // // Notice how the "onDone" callback is called before the result is passed // to the handleThingDescription function. - wot.discover().listen( + wot.discover(discoveryConfigurations).listen( handleThingDescription, onError: (error) => print("Encountered an error: $error"), onDone: () => print('Discovery with "listen" has finished.'), diff --git a/example/core_link_format_discovery.dart b/example/core_link_format_discovery.dart index 93a6bc43..4be758d3 100644 --- a/example/core_link_format_discovery.dart +++ b/example/core_link_format_discovery.dart @@ -12,16 +12,16 @@ import "package:dart_wot/core.dart"; Future main(List args) async { final servient = Servient.create( clientFactories: [CoapClientFactory()], - discoveryConfigurations: [ - CoreLinkFormatConfiguration( - Uri.parse("coap://plugfest.thingweb.io"), - ), - ], ); final wot = await servient.start(); + final discoveryConfigurations = [ + CoreLinkFormatConfiguration( + Uri.parse("coap://plugfest.thingweb.io"), + ), + ]; - await for (final thingDescription in wot.discover()) { + await for (final thingDescription in wot.discover(discoveryConfigurations)) { print(thingDescription.title); if (thingDescription.title != "Smart-Coffee-Machine") { diff --git a/lib/src/core/implementation.dart b/lib/src/core/implementation.dart index 42421741..ea010869 100644 --- a/lib/src/core/implementation.dart +++ b/lib/src/core/implementation.dart @@ -11,5 +11,4 @@ export "implementation/augmented_form.dart"; export "implementation/codecs/content_codec.dart"; export "implementation/content.dart"; export "implementation/content_serdes.dart"; -export "implementation/discovery/discovery_configuration.dart"; export "implementation/servient.dart" show Servient; diff --git a/lib/src/core/implementation/servient.dart b/lib/src/core/implementation/servient.dart index aca0a449..b63d4028 100644 --- a/lib/src/core/implementation/servient.dart +++ b/lib/src/core/implementation/servient.dart @@ -15,7 +15,6 @@ import "../scripting_api.dart" as scripting_api; import "consumed_thing.dart"; import "content_serdes.dart"; -import "discovery/discovery_configuration.dart"; import "exposed_thing.dart"; import "thing_discovery.dart"; import "wot.dart"; @@ -28,8 +27,7 @@ import "wot.dart"; abstract class Servient { /// Creates a new [Servient]. /// - /// The [Servient] can be pre-configured with [List]s of - /// [clientFactories] and [discoveryConfigurations]. + /// The [Servient] can be pre-configured with a [List] of [clientFactories]. /// However, it is also possible to dynamically [addClientFactory]s and /// [removeClientFactory]s at runtime. /// @@ -40,24 +38,14 @@ abstract class Servient { List? clientFactories, ServerSecurityCallback? serverSecurityCallback, ContentSerdes? contentSerdes, - List? discoveryConfigurations, }) { return InternalServient( clientFactories: clientFactories, serverSecurityCallback: serverSecurityCallback, contentSerdes: contentSerdes, - discoveryConfigurations: discoveryConfigurations, ); } - /// [List] of [DiscoveryConfiguration]s that are used when calling the - /// [scripting_api.WoT.discover] method. - List get discoveryConfigurations; - - set discoveryConfigurations( - List discoveryConfigurations, - ); - /// Starts this [Servient] and returns a [scripting_api.WoT] runtime object. /// /// The [scripting_api.WoT] runtime can be used for consuming, producing, and @@ -85,9 +73,7 @@ class InternalServient implements Servient { List? clientFactories, ServerSecurityCallback? serverSecurityCallback, ContentSerdes? contentSerdes, - List? discoveryConfigurations, }) : contentSerdes = contentSerdes ?? ContentSerdes(), - discoveryConfigurations = discoveryConfigurations ?? [], _serverSecurityCallback = serverSecurityCallback { for (final clientFactory in clientFactories ?? []) { addClientFactory(clientFactory); @@ -100,9 +86,6 @@ class InternalServient implements Servient { final ServerSecurityCallback? _serverSecurityCallback; - @override - List discoveryConfigurations; - /// The [ContentSerdes] object that is used for serializing/deserializing. final ContentSerdes contentSerdes; @@ -343,15 +326,15 @@ class InternalServient implements Servient { return thingDescription; } - /// Perform automatic discovery using this [InternalServient]'s - /// [discoveryConfigurations]. + /// Perform discovery using the passed-in [discoveryConfigurations]. /// /// A [thingFilter] can be provided to filter the discovered Thing /// Descriptions; however, doing so currently does not have any effect yet. - ThingDiscovery discover({ + ThingDiscovery discover( + List discoveryConfigurations, { scripting_api.ThingFilter? thingFilter, }) { - return ThingDiscovery(thingFilter, this); + return ThingDiscovery(thingFilter, this, discoveryConfigurations); } /// Requests a [ThingDescription] from a [url]. diff --git a/lib/src/core/implementation/thing_discovery.dart b/lib/src/core/implementation/thing_discovery.dart index 28e40776..dbf6e780 100644 --- a/lib/src/core/implementation/thing_discovery.dart +++ b/lib/src/core/implementation/thing_discovery.dart @@ -17,14 +17,17 @@ import "../protocol_interfaces.dart"; import "../scripting_api.dart" as scripting_api; import "content.dart"; -import "discovery/discovery_configuration.dart"; import "servient.dart"; /// Implementation of the [scripting_api.ThingDiscovery] interface. class ThingDiscovery extends Stream implements scripting_api.ThingDiscovery { /// Creates a new [ThingDiscovery] object with a given [thingFilter]. - ThingDiscovery(this.thingFilter, this._servient) { + ThingDiscovery( + this.thingFilter, + this._servient, + this._discoveryConfigurations, + ) { _stream = _start(); } @@ -42,40 +45,45 @@ class ThingDiscovery extends Stream @override final scripting_api.ThingFilter? thingFilter; + final List _discoveryConfigurations; + late final Stream _stream; Stream _start() async* { - for (final discoveryParameter in _servient.discoveryConfigurations) { + for (final discoveryParameter in _discoveryConfigurations) { switch (discoveryParameter) { - case DnsSdDConfiguration( + case scripting_api.DnsSdDConfiguration( :final discoveryType, domainName: final domain, :final protocolType, ): yield* _discoverUsingDnsSd(discoveryType, domain, protocolType); - case CoreLinkFormatConfiguration( + case scripting_api.CoreLinkFormatConfiguration( :final uri, :final discoveryType, ): yield* _discoverWithCoreLinkFormat(uri, discoveryType); - case CoreResourceDirectoryConfiguration( + case scripting_api.CoreResourceDirectoryConfiguration( :final uri, :final discoveryType, ): yield* _discoverFromCoreResourceDirectory(uri, discoveryType); - case DirectConfiguration(:final uri): + case scripting_api.DirectConfiguration(:final uri): if (!uri.hasMulticastAddress) { yield* Stream.fromFuture(_servient.requestThingDescription(uri)); } else { yield* _performMulticastDiscovery(uri); } - case ExploreDirectoryConfiguration(:final uri, :final thingFilter): + case scripting_api.ExploreDirectoryConfiguration( + :final uri, + :final thingFilter + ): final thingDiscoveryProcess = await _servient.exploreDirectory( uri, thingFilter: thingFilter, ); yield* thingDiscoveryProcess; - case MqttDiscoveryConfiguration( + case scripting_api.MqttDiscoveryConfiguration( :final brokerUri, :final discoveryTopic, :final expectedContentType, @@ -122,9 +130,9 @@ class ThingDiscovery extends Stream } Stream _discoverUsingDnsSd( - DiscoveryType discoveryType, + scripting_api.DiscoveryType discoveryType, String domainName, - ProtocolType protocolType, + scripting_api.ProtocolType protocolType, ) async* { if (domainName != ".local") { throw UnimplementedError( @@ -134,7 +142,7 @@ class ThingDiscovery extends Stream final serviceNameSegments = []; - if (discoveryType == DiscoveryType.directory) { + if (discoveryType == scripting_api.DiscoveryType.directory) { serviceNameSegments.addAll(const ["_directory", "_sub"]); } @@ -155,7 +163,7 @@ class ThingDiscovery extends Stream Stream _performMdnsDiscovery( String domainName, String defaultUriScheme, - DiscoveryType expectedType, + scripting_api.DiscoveryType expectedType, ) async* { final MDnsClient client = MDnsClient(); await client.start(); @@ -233,7 +241,7 @@ class ThingDiscovery extends Stream Stream _discoverWithCoreLinkFormat( Uri uri, - DiscoveryType discoveryType, + scripting_api.DiscoveryType discoveryType, ) async* { await for (final coreWebLinks in _performCoreLinkFormatDiscovery( uri, @@ -246,7 +254,7 @@ class ThingDiscovery extends Stream Stream _discoverFromCoreResourceDirectory( Uri uri, - DiscoveryType discoveryType, + scripting_api.DiscoveryType discoveryType, ) async* { yield* _performCoreLinkFormatDiscovery( uri, diff --git a/lib/src/core/implementation/wot.dart b/lib/src/core/implementation/wot.dart index f906810d..0b395a8e 100644 --- a/lib/src/core/implementation/wot.dart +++ b/lib/src/core/implementation/wot.dart @@ -6,6 +6,8 @@ import "dart:async"; +import "package:meta/meta.dart"; + import "../definitions.dart"; import "../scripting_api.dart" as scripting_api; import "consumed_thing.dart"; @@ -39,10 +41,15 @@ class WoT implements scripting_api.WoT { _servient.produce(init); @override - ThingDiscovery discover({ + ThingDiscovery discover( + @experimental + List discoveryConfigurations, { scripting_api.ThingFilter? thingFilter, }) => - _servient.discover(thingFilter: thingFilter); + _servient.discover( + discoveryConfigurations, + thingFilter: thingFilter, + ); @override Future requestThingDescription(Uri url) => diff --git a/lib/src/core/scripting_api.dart b/lib/src/core/scripting_api.dart index 954de639..5910fdb9 100644 --- a/lib/src/core/scripting_api.dart +++ b/lib/src/core/scripting_api.dart @@ -13,6 +13,7 @@ library scripting_api; export "scripting_api/consumed_thing.dart"; export "scripting_api/data_schema_value.dart"; export "scripting_api/discovery/directory_payload_format.dart"; +export "scripting_api/discovery/discovery_configuration.dart"; export "scripting_api/discovery/thing_discovery.dart"; export "scripting_api/discovery/thing_filter.dart"; export "scripting_api/exposed_thing.dart"; diff --git a/lib/src/core/implementation/discovery/discovery_configuration.dart b/lib/src/core/scripting_api/discovery/discovery_configuration.dart similarity index 99% rename from lib/src/core/implementation/discovery/discovery_configuration.dart rename to lib/src/core/scripting_api/discovery/discovery_configuration.dart index e706326d..41a06437 100644 --- a/lib/src/core/implementation/discovery/discovery_configuration.dart +++ b/lib/src/core/scripting_api/discovery/discovery_configuration.dart @@ -6,7 +6,7 @@ import "package:meta/meta.dart"; -import "../../scripting_api/discovery/thing_filter.dart"; +import "thing_filter.dart"; /// Used to indicate whether the discovery mechanism will be used to discover /// Thing Descriptions of Things or Thing Description Directories. @@ -92,6 +92,7 @@ enum ProtocolType { /// A configuration that is used by the `WoT.discover()` method when registered /// with the underlying `Servient`. @immutable +@experimental sealed class DiscoveryConfiguration { const DiscoveryConfiguration(); } @@ -108,6 +109,7 @@ final class DirectConfiguration extends DiscoveryConfiguration { /// A configuration that is used for retrieving Thing Descriptions from a Thing /// Description Directory (TDD). +@experimental final class ExploreDirectoryConfiguration extends DiscoveryConfiguration { /// Instantiates a new [ExploreDirectoryConfiguration]. /// @@ -183,6 +185,7 @@ final class MqttDiscoveryConfiguration extends DiscoveryConfiguration { /// These mechanisms first discover URLs pointing to Thing Descriptions /// (introduction phase) before retrieving the Thing Descriptions themselves /// (exploration phase). +@experimental sealed class TwoStepConfiguration extends DiscoveryConfiguration { /// Creates a new [TwoStepConfiguration] object from a [discoveryType]. const TwoStepConfiguration({required this.discoveryType}); @@ -229,6 +232,7 @@ final class DnsSdDConfiguration extends TwoStepConfiguration { /// Configures discovery using the CoRE link format ([RFC 6690]). /// /// [RFC 6690]: https://datatracker.ietf.org/doc/html/rfc6690 +@experimental final class CoreLinkFormatConfiguration extends TwoStepConfiguration { /// Instantiates a new [CoreLinkFormatConfiguration] object. /// @@ -273,6 +277,7 @@ final class CoreLinkFormatConfiguration extends TwoStepConfiguration { /// Descriptions themselves. /// /// [RFC 9176]: https://datatracker.ietf.org/doc/html/rfc9176 +@experimental final class CoreResourceDirectoryConfiguration extends TwoStepConfiguration { /// Instantiates a new [CoreResourceDirectoryConfiguration] object. /// diff --git a/lib/src/core/scripting_api/wot.dart b/lib/src/core/scripting_api/wot.dart index 4d23d896..a011ba79 100644 --- a/lib/src/core/scripting_api/wot.dart +++ b/lib/src/core/scripting_api/wot.dart @@ -4,10 +4,13 @@ // // SPDX-License-Identifier: BSD-3-Clause +import "package:meta/meta.dart"; + import "../definitions.dart"; import "consumed_thing.dart"; import "discovery/directory_payload_format.dart"; +import "discovery/discovery_configuration.dart"; import "discovery/thing_discovery.dart"; import "discovery/thing_filter.dart"; import "exposed_thing.dart"; @@ -46,7 +49,8 @@ abstract interface class WoT { DirectoryPayloadFormat? format, }); - /// Discovers [ThingDescription]s using the underlying platform configuration. + /// Discovers [ThingDescription]s based on the provided + /// [discoveryConfigurations]. /// /// A [thingFilter] may be passed for filtering out TDs before they /// are processed. @@ -60,7 +64,11 @@ abstract interface class WoT { /// It also allows for stopping the Discovery process prematurely and /// for retrieving information about its current state (i.e., whether it is /// still [ThingDiscovery.active]). - ThingDiscovery discover({ + /// + /// The shape of the `discover` API is still experimental and will most likely + /// change in the future. + ThingDiscovery discover( + @experimental List discoveryConfigurations, { ThingFilter? thingFilter, }); }