diff --git a/example/complex_example.dart b/example/complex_example.dart index b9b1e766..82018fca 100644 --- a/example/complex_example.dart +++ b/example/complex_example.dart @@ -139,7 +139,7 @@ Future main() async { final status3 = await consumedThing.readProperty( 'anotherStatus', - const InteractionOptions(uriVariables: {'test': 'hi'}), + uriVariables: {'test': 'hi'}, ); final value3 = await status3.value(); print(value3); diff --git a/example/mqtt_example.dart b/example/mqtt_example.dart index 15358070..4b299495 100644 --- a/example/mqtt_example.dart +++ b/example/mqtt_example.dart @@ -85,13 +85,13 @@ Future main(List args) async { }, ); - await consumedThing.invokeAction('toggle', 'Hello World!'); - await consumedThing.invokeAction('toggle', 'Hello World!'); - await consumedThing.invokeAction('toggle', 'Hello World!'); - await consumedThing.invokeAction('toggle', 'Hello World!'); + await consumedThing.invokeAction('toggle', input: 'Hello World!'); + await consumedThing.invokeAction('toggle', input: 'Hello World!'); + await consumedThing.invokeAction('toggle', input: 'Hello World!'); + await consumedThing.invokeAction('toggle', input: 'Hello World!'); await subscription.stop(); - await consumedThing.invokeAction('toggle', 'Bye World!'); + await consumedThing.invokeAction('toggle', input: 'Bye World!'); await consumedThing.readAndPrintProperty('status'); print('Done!'); } diff --git a/lib/scripting_api.dart b/lib/scripting_api.dart index 6f7d573e..b07aa50a 100644 --- a/lib/scripting_api.dart +++ b/lib/scripting_api.dart @@ -15,7 +15,6 @@ export 'src/scripting_api/discovery/discovery_method.dart'; export 'src/scripting_api/discovery/thing_discovery.dart'; export 'src/scripting_api/discovery/thing_filter.dart'; export 'src/scripting_api/exposed_thing.dart'; -export 'src/scripting_api/interaction_options.dart'; export 'src/scripting_api/interaction_output.dart'; export 'src/scripting_api/subscription.dart'; export 'src/scripting_api/types.dart'; diff --git a/lib/src/binding_coap/coap_subscription.dart b/lib/src/binding_coap/coap_subscription.dart index 80ad0be8..4cf94dea 100644 --- a/lib/src/binding_coap/coap_subscription.dart +++ b/lib/src/binding_coap/coap_subscription.dart @@ -6,7 +6,6 @@ import 'package:coap/coap.dart'; -import '../scripting_api/interaction_options.dart'; import '../scripting_api/subscription.dart'; /// [Subscription] to a CoAP resource, based on the observe option ([RFC 7641]). @@ -34,7 +33,11 @@ class CoapSubscription implements Subscription { final void Function() _complete; @override - Future stop([InteractionOptions? options]) async { + Future stop({ + int? formIndex, + Map? uriVariables, + Object? data, + }) async { if (!_active) { return; } diff --git a/lib/src/binding_mqtt/mqtt_subscription.dart b/lib/src/binding_mqtt/mqtt_subscription.dart index d01a3ee1..a89e3e53 100644 --- a/lib/src/binding_mqtt/mqtt_subscription.dart +++ b/lib/src/binding_mqtt/mqtt_subscription.dart @@ -9,7 +9,6 @@ import 'package:mqtt_client/mqtt_server_client.dart'; import '../core/content.dart'; import '../definitions/form.dart'; -import '../scripting_api/interaction_options.dart'; import '../scripting_api/subscription.dart' as scripting_api; /// [scripting_api.Subscription] for the MQTT protocol. @@ -61,7 +60,11 @@ class MqttSubscription implements scripting_api.Subscription { bool get active => _active; @override - Future stop([InteractionOptions? options]) async { + Future stop({ + int? formIndex, + Map? uriVariables, + Object? data, + }) async { _client.disconnect(); _active = false; _complete(); diff --git a/lib/src/core/consumed_thing.dart b/lib/src/core/consumed_thing.dart index 14a1ebf3..a6bff5f6 100644 --- a/lib/src/core/consumed_thing.dart +++ b/lib/src/core/consumed_thing.dart @@ -76,9 +76,10 @@ class ConsumedThing implements scripting_api.ConsumedThing { List
forms, OperationType operationType, _AffordanceType affordanceType, - InteractionOptions? options, - InteractionAffordance interactionAffordance, - ) { + InteractionAffordance interactionAffordance, { + required int? formIndex, + required Map? uriVariables, + }) { if (forms.isEmpty) { throw StateError( 'ConsumedThing "$title" has no links for this interaction', @@ -88,8 +89,6 @@ class ConsumedThing implements scripting_api.ConsumedThing { final ProtocolClient client; final Form foundForm; - final formIndex = options?.formIndex; - if (formIndex != null) { if (formIndex >= 0 && formIndex < forms.length) { foundForm = forms[formIndex]; @@ -114,17 +113,18 @@ class ConsumedThing implements scripting_api.ConsumedThing { client = servient.clientFor(scheme); } - final form = - foundForm.resolveUriVariables(options?.uriVariables) ?? foundForm; + final form = foundForm.resolveUriVariables(uriVariables) ?? foundForm; return (client: client, form: form); } @override Future readProperty( - String propertyName, [ - InteractionOptions? options, - ]) async { + String propertyName, { + int? formIndex, + Map? uriVariables, + Object? data, + }) async { final property = thingDescription.properties[propertyName]; if (property == null) { @@ -138,8 +138,9 @@ class ConsumedThing implements scripting_api.ConsumedThing { property.forms, OperationType.readproperty, _AffordanceType.property, - options, property, + formIndex: formIndex, + uriVariables: uriVariables, ); final form = clientAndForm.form; @@ -152,9 +153,11 @@ class ConsumedThing implements scripting_api.ConsumedThing { @override Future writeProperty( String propertyName, - Object? interactionInput, [ - InteractionOptions? options, - ]) async { + InteractionInput input, { + int? formIndex, + Map? uriVariables, + Object? data, + }) async { // TODO(JKRhb): Refactor final property = thingDescription.properties[propertyName]; @@ -169,23 +172,26 @@ class ConsumedThing implements scripting_api.ConsumedThing { property.forms, OperationType.writeproperty, _AffordanceType.property, - options, property, + formIndex: formIndex, + uriVariables: uriVariables, ); final form = clientAndForm.form; final client = clientAndForm.client; final content = servient.contentSerdes - .valueToContent(interactionInput, property, form.contentType); + .valueToContent(input, property, form.contentType); await client.writeResource(form, content); } @override Future invokeAction( - String actionName, [ - Object? interactionInput, - InteractionOptions? options, - ]) async { + String actionName, { + InteractionInput input, + Object? data, + int? formIndex, + Map? uriVariables, + }) async { // TODO(JKRhb): Refactor final action = thingDescription.actions[actionName]; @@ -200,26 +206,27 @@ class ConsumedThing implements scripting_api.ConsumedThing { action.forms, OperationType.invokeaction, _AffordanceType.action, - options, action, + uriVariables: uriVariables, + formIndex: formIndex, ); final form = clientAndForm.form; final client = clientAndForm.client; - final input = servient.contentSerdes - .valueToContent(interactionInput, action.input, form.contentType); + final content = servient.contentSerdes + .valueToContent(input, action.input, form.contentType); - final content = await client.invokeResource(form, input); + final output = await client.invokeResource(form, content); final response = form.response; if (response != null) { - if (content.type != response.contentType) { + if (output.type != response.contentType) { throw UnexpectedReponseException('Unexpected type in response'); } } return InteractionOutput( - content, + output, servient.contentSerdes, form, action.output, @@ -229,10 +236,12 @@ class ConsumedThing implements scripting_api.ConsumedThing { @override Future observeProperty( String propertyName, - scripting_api.InteractionListener listener, [ + scripting_api.InteractionListener listener, { scripting_api.ErrorListener? onError, - InteractionOptions? options, - ]) async { + Object? data, + int? formIndex, + Map? uriVariables, + }) async { final property = thingDescription.properties[propertyName]; if (property == null) { @@ -251,24 +260,26 @@ class ConsumedThing implements scripting_api.ConsumedThing { return _createSubscription( property, - options, listener, onError, propertyName, property, SubscriptionType.property, + formIndex: formIndex, + uriVariables: uriVariables, ); } Future _createSubscription( InteractionAffordance affordance, - scripting_api.InteractionOptions? options, scripting_api.InteractionListener listener, scripting_api.ErrorListener? onError, String affordanceName, DataSchema? dataSchema, - SubscriptionType subscriptionType, - ) async { + SubscriptionType subscriptionType, { + required int? formIndex, + required Map? uriVariables, + }) async { final OperationType operationType; final _AffordanceType affordanceType; final Map subscriptions; @@ -287,8 +298,9 @@ class ConsumedThing implements scripting_api.ConsumedThing { affordance.forms, operationType, affordanceType, - options, affordance, + uriVariables: uriVariables, + formIndex: formIndex, ); final form = clientAndForm.form; @@ -318,13 +330,20 @@ class ConsumedThing implements scripting_api.ConsumedThing { } Future _readProperties( - List propertyNames, - InteractionOptions? options, - ) async { + List propertyNames, { + Object? data, + int? formIndex, + Map? uriVariables, + }) async { final Map> outputs = {}; for (final propertyName in propertyNames) { - outputs[propertyName] = readProperty(propertyName, options); + outputs[propertyName] = readProperty( + propertyName, + data: data, + formIndex: formIndex, + uriVariables: uriVariables, + ); } final outputList = await Future.wait(outputs.values); @@ -333,28 +352,46 @@ class ConsumedThing implements scripting_api.ConsumedThing { } @override - Future readAllProperties([InteractionOptions? options]) { + Future readAllProperties({ + Object? data, + int? formIndex, + Map? uriVariables, + }) { final propertyNames = thingDescription.properties.keys.toList(growable: false); - return _readProperties(propertyNames, options); + return _readProperties( + propertyNames, + data: data, + formIndex: formIndex, + uriVariables: uriVariables, + ); } @override Future readMultipleProperties( - List propertyNames, [ - InteractionOptions? options, - ]) { - return _readProperties(propertyNames, options); + List propertyNames, { + Object? data, + int? formIndex, + Map? uriVariables, + }) { + return _readProperties( + propertyNames, + data: data, + formIndex: formIndex, + uriVariables: uriVariables, + ); } @override Future subscribeEvent( String eventName, - scripting_api.InteractionListener listener, [ + scripting_api.InteractionListener listener, { scripting_api.ErrorListener? onError, - InteractionOptions? options, - ]) { + Object? data, + int? formIndex, + Map? uriVariables, + }) { // TODO(JKRhb): Handle subscription and cancellation data. final event = thingDescription.events[eventName]; @@ -374,20 +411,23 @@ class ConsumedThing implements scripting_api.ConsumedThing { return _createSubscription( event, - options, listener, onError, eventName, event.data, SubscriptionType.event, + formIndex: formIndex, + uriVariables: uriVariables, ); } @override Future writeMultipleProperties( - PropertyWriteMap valueMap, [ - InteractionOptions? options, - ]) async { + PropertyWriteMap valueMap, { + Object? data, + int? formIndex, + Map? uriVariables, + }) async { await Future.wait( valueMap.keys.map((key) => writeProperty(key, valueMap[key])), ); diff --git a/lib/src/scripting_api/consumed_thing.dart b/lib/src/scripting_api/consumed_thing.dart index b6711a04..534c0369 100644 --- a/lib/src/scripting_api/consumed_thing.dart +++ b/lib/src/scripting_api/consumed_thing.dart @@ -5,7 +5,6 @@ // SPDX-License-Identifier: BSD-3-Clause import '../definitions/thing_description.dart'; -import 'interaction_options.dart'; import 'interaction_output.dart'; import 'subscription.dart'; import 'types.dart'; @@ -31,56 +30,75 @@ abstract interface class ConsumedThing { /// Reads a property with the given [propertyName]. Future readProperty( - String propertyName, [ - InteractionOptions? options, - ]); + String propertyName, { + int? formIndex, + Map? uriVariables, + Object? data, + }); /// Reads all properties. - Future readAllProperties([InteractionOptions? options]); + Future readAllProperties({ + int? formIndex, + Map? uriVariables, + Object? data, + }); /// Reads a number of properties with the given [propertyNames]. Future readMultipleProperties( - List propertyNames, [ - InteractionOptions? options, - ]); + List propertyNames, { + int? formIndex, + Map? uriVariables, + Object? data, + }); - /// Writes a [value] to a property with the given [propertyName]. + /// Writes an [input] value to a property with the given + /// [propertyName]. Future writeProperty( String propertyName, - InteractionInput value, [ - InteractionOptions? options, - ]); + InteractionInput input, { + int? formIndex, + Map? uriVariables, + Object? data, + }); /// Writes multiple values to multiple properties, as described in a /// [valueMap]. Future writeMultipleProperties( - PropertyWriteMap valueMap, [ - InteractionOptions? options, - ]); + PropertyWriteMap valueMap, { + int? formIndex, + Map? uriVariables, + Object? data, + }); /// Invokes an action with the given [actionName]. Accepts an optional /// [input]. /// /// After (asynchronous )completion, it might return an [InteractionOutput]. Future invokeAction( - String actionName, [ - InteractionInput input, - InteractionOptions? options, - ]); + String actionName, { + InteractionInput? input, + int? formIndex, + Map? uriVariables, + Object? data, + }); /// Observes a property with the given [propertyName]. Future observeProperty( String propertyName, - InteractionListener listener, [ + InteractionListener listener, { ErrorListener? onError, - InteractionOptions? options, - ]); + int? formIndex, + Map? uriVariables, + Object? data, + }); /// Subscribes to an event with the given [eventName]. Future subscribeEvent( String eventName, - InteractionListener listener, [ + InteractionListener listener, { ErrorListener? onError, - InteractionOptions? options, - ]); + int? formIndex, + Map? uriVariables, + Object? data, + }); } diff --git a/lib/src/scripting_api/exposed_thing.dart b/lib/src/scripting_api/exposed_thing.dart index 2406f694..46e3f0c9 100644 --- a/lib/src/scripting_api/exposed_thing.dart +++ b/lib/src/scripting_api/exposed_thing.dart @@ -5,35 +5,42 @@ // SPDX-License-Identifier: BSD-3-Clause import '../definitions/thing_description.dart'; -import 'interaction_options.dart'; import 'interaction_output.dart'; import 'types.dart'; /// A function that is called when an external request for reading a Property is /// received and defines what to do with such requests. -typedef PropertyReadHandler = Future Function( - InteractionOptions? options, -); +typedef PropertyReadHandler = Future Function({ + int? formIndex, + Map? uriVariables, + Object? data, +}); /// A function that is called when an external request for writing a Property is /// received and defines what to do with such requests. typedef PropertyWriteHandler = Future Function( - InteractionOutput value, - InteractionOptions? options, -); + InteractionOutput value, { + int? formIndex, + Map? uriVariables, + Object? data, +}); /// A function that is called when an external request for invoking an Action /// is received and defines what to do with such requests. typedef ActionHandler = Future Function( - InteractionOutput params, - InteractionOptions? options, -); + InteractionOutput params, { + int? formIndex, + Map? uriVariables, + Object? data, +}); /// A function that is called when an external request for subscribing to an /// Event is received and defines what to do with such requests. -typedef EventSubscriptionHandler = Future Function( - InteractionOptions? options, -); +typedef EventSubscriptionHandler = Future Function({ + int? formIndex, + Map? uriVariables, + Object? data, +}); /// A function that is called when an associated Event is triggered and provides /// the data to be sent with the Event to subscribers. diff --git a/lib/src/scripting_api/interaction_options.dart b/lib/src/scripting_api/interaction_options.dart deleted file mode 100644 index 445f298f..00000000 --- a/lib/src/scripting_api/interaction_options.dart +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2021 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 - -import 'package:meta/meta.dart'; - -/// Holds the interaction options that need to be exposed for application -/// scripts according to the Thing Description. -/// -/// See [WoT Scripting API Specification, Section 8.12][spec link]. -/// -/// [spec link]: https://w3c.github.io/wot-scripting-api/#the-interactionoptions-dictionary -@immutable -final class InteractionOptions { - /// Constructor - const InteractionOptions({this.formIndex, this.uriVariables, this.data}); - - /// Represents an application hint for which Form definition should be used - /// for the given interaction. - final int? formIndex; - - /// Represents the URI template variables to be used with the interaction. - final Map? uriVariables; - - /// Represents additional opaque data that needs to be passed to the - /// interaction. - final Object? data; -} diff --git a/lib/src/scripting_api/subscription.dart b/lib/src/scripting_api/subscription.dart index e2b82d39..3b112a08 100644 --- a/lib/src/scripting_api/subscription.dart +++ b/lib/src/scripting_api/subscription.dart @@ -7,7 +7,6 @@ import '../definitions/form.dart'; import '../definitions/interaction_affordances/interaction_affordance.dart'; import '../definitions/operation_type.dart'; -import 'interaction_options.dart'; /// [Exception] that is thrown when error during the unsubscribe process occurs. class UnsubscribeException implements Exception { @@ -46,8 +45,16 @@ abstract interface class Subscription { bool get active; /// Stops delivering notifications for the subscription. - /// It takes an optional parameter [options] and returns a [Future]. - Future stop([InteractionOptions? options]); + /// + /// This method accepts optional arguments as [interaction options] + /// ([formIndex], [uriVariables], and [data]) and returns a [Future]. + /// + /// [interaction options]: https://www.w3.org/TR/wot-scripting-api/#the-interactionoptions-dictionary + Future stop({ + int? formIndex, + Map? uriVariables, + Object? data, + }); } /// Finds a matching unsubscribe [Form] for a subscription [form]. diff --git a/test/core/consumed_thing_test.dart b/test/core/consumed_thing_test.dart index 66b38962..b2884d89 100644 --- a/test/core/consumed_thing_test.dart +++ b/test/core/consumed_thing_test.dart @@ -288,18 +288,22 @@ void main() { final wot = await servient.start(); final uriVariables = {'value': 'SFRUUEJJTiBpcyBhd2Vzb21l'}; - final interactionOptions = InteractionOptions(uriVariables: uriVariables); final consumedThing = await wot.consume(parsedTd); - final result = - await consumedThing.readProperty('status', interactionOptions); + final result = await consumedThing.readProperty( + 'status', + uriVariables: uriVariables, + ); final value = await result.value(); expect(value, 'HTTPBIN is awesome'); // status2 expects an integer instead of a String and throws an error if // the same value is provided as an input expect( - consumedThing.readProperty('status2', interactionOptions), + consumedThing.readProperty( + 'status2', + uriVariables: uriVariables, + ), throwsA(const TypeMatcher()), );