Skip to content

Commit f252675

Browse files
authored
Merge pull request #96 from eclipse-thingweb/client-capabilities
feat!: add supportsOperation method
2 parents 8e012d7 + 6f3ffa7 commit f252675

File tree

12 files changed

+265
-14
lines changed

12 files changed

+265
-14
lines changed

example/complex_example.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const thingDescriptionJson = {
3434
{
3535
"href": "coap://californium.eclipseprojects.io/obs",
3636
"op": ["observeproperty", "unobserveproperty"],
37+
"subprotocol": "cov:observe",
3738
}
3839
],
3940
},

lib/src/binding_coap/coap_client_factory.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import "../../core.dart";
88

99
import "coap_client.dart";
1010
import "coap_config.dart";
11+
import "coap_definitions.dart";
1112

1213
/// A [ProtocolClientFactory] that produces CoAP clients.
1314
final class CoapClientFactory implements ProtocolClientFactory {
@@ -45,4 +46,21 @@ final class CoapClientFactory implements ProtocolClientFactory {
4546
bool init() {
4647
return true;
4748
}
49+
50+
@override
51+
bool supportsOperation(OperationType operationType, String? subprotocol) {
52+
const observeOperations = [
53+
OperationType.observeproperty,
54+
OperationType.unobserveproperty,
55+
OperationType.subscribeevent,
56+
OperationType.unsubscribeevent,
57+
];
58+
59+
if (observeOperations.contains(operationType)) {
60+
return CoapSubprotocol.tryParse(subprotocol ?? "") ==
61+
CoapSubprotocol.observe;
62+
}
63+
64+
return subprotocol == null;
65+
}
4866
}

lib/src/binding_http/http_client_factory.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,24 @@ final class HttpClientFactory implements ProtocolClientFactory {
4242
bool init() {
4343
return true;
4444
}
45+
46+
@override
47+
bool supportsOperation(OperationType operationType, String? subprotocol) {
48+
const unsupportedOperations = [
49+
OperationType.observeproperty,
50+
OperationType.unobserveproperty,
51+
OperationType.subscribeevent,
52+
OperationType.unsubscribeevent,
53+
];
54+
55+
if (unsupportedOperations.contains(operationType)) {
56+
return false;
57+
}
58+
59+
if (subprotocol != null) {
60+
return false;
61+
}
62+
63+
return true;
64+
}
4565
}

lib/src/binding_mqtt/mqtt_client_factory.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,10 @@ final class MqttClientFactory implements ProtocolClientFactory {
4242

4343
@override
4444
Set<String> get schemes => {mqttUriScheme, mqttSecureUriScheme};
45+
46+
@override
47+
bool supportsOperation(OperationType operationType, String? subprotocol) {
48+
// MQTT client does not support any subprotocols
49+
return subprotocol == null;
50+
}
4551
}

lib/src/core/implementation/consumed_thing.dart

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,19 @@ class ConsumedThing implements scripting_api.ConsumedThing {
9797
}
9898
} else {
9999
foundForm = augmentedForms.firstWhere(
100-
(form) =>
101-
hasClientFor(form.href.scheme) &&
102-
_supportsOperationType(form, interactionAffordance, operationType),
100+
(form) {
101+
final opValues = form.op;
102+
103+
if (!opValues.contains(operationType)) {
104+
return false;
105+
}
106+
107+
return servient.supportsOperation(
108+
form.resolvedHref.scheme,
109+
operationType,
110+
form.subprotocol,
111+
);
112+
},
103113
// TODO(JKRhb): Add custom Exception
104114
orElse: () => throw Exception("No matching form found!"),
105115
);
@@ -429,17 +439,6 @@ class ConsumedThing implements scripting_api.ConsumedThing {
429439
}
430440
}
431441

432-
static bool _supportsOperationType(
433-
Form form,
434-
InteractionAffordance interactionAffordance,
435-
OperationType operationType,
436-
) {
437-
final opValues =
438-
form.op ?? OperationType.defaultOpValues(interactionAffordance);
439-
440-
return opValues.contains(operationType);
441-
}
442-
443442
/// Cleans up the resources used by this [ConsumedThing].
444443
void destroy() {
445444
for (final observedProperty in _observedProperties.values) {

lib/src/core/implementation/protocol_interfaces/protocol_client_factory.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
//
55
// SPDX-License-Identifier: BSD-3-Clause
66

7+
import "package:meta/meta.dart";
8+
9+
import "../../definitions.dart";
710
import "protocol_client.dart";
811

912
/// Base class for a factory that produces [ProtocolClient]s.
@@ -24,4 +27,9 @@ abstract interface class ProtocolClientFactory {
2427
/// Creates a new [ProtocolClient] with that supports one or more of the given
2528
/// [schemes].
2629
ProtocolClient createClient();
30+
31+
/// Indicates whether this [ProtocolClientFactory] supports a given
32+
/// [operationType] and subprotocol.
33+
@experimental
34+
bool supportsOperation(OperationType operationType, String? subprotocol);
2735
}

lib/src/core/implementation/servient.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//
55
// SPDX-License-Identifier: BSD-3-Clause
66

7+
import "package:meta/meta.dart";
8+
79
import "../definitions.dart";
810
import "../scripting_api.dart" as scripting_api;
911
import "consumed_thing.dart";
@@ -222,6 +224,26 @@ class Servient {
222224
return clientFactory.createClient();
223225
}
224226

227+
/// Indicates whether there is a registered [ProtocolClientFactory] supporting
228+
/// the given [operationType] and [subprotocol].
229+
///
230+
/// Also returns `false` if there is no [ProtocolClientFactory] registered for
231+
/// the given [scheme].
232+
@experimental
233+
bool supportsOperation(
234+
String scheme,
235+
OperationType operationType,
236+
String? subprotocol,
237+
) {
238+
final protocolClient = _clientFactories[scheme];
239+
240+
if (protocolClient == null) {
241+
return false;
242+
}
243+
244+
return protocolClient.supportsOperation(operationType, subprotocol);
245+
}
246+
225247
/// Requests a [ThingDescription] from a [url].
226248
Future<ThingDescription> requestThingDescription(Uri url) async {
227249
final client = clientFor(url.scheme);
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2024 Contributors to the Eclipse Foundation. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
//
5+
// SPDX-License-Identifier: BSD-3-Clause
6+
7+
import "package:dart_wot/binding_coap.dart";
8+
import "package:dart_wot/core.dart";
9+
import "package:test/test.dart";
10+
11+
void main() {
12+
group("CoapClientFactory should", () {
13+
test("indicate correctly whether an operation is supported", () {
14+
final coapClientFactory = CoapClientFactory();
15+
16+
const observeOperations = [
17+
OperationType.observeproperty,
18+
OperationType.unobserveproperty,
19+
OperationType.subscribeevent,
20+
OperationType.unsubscribeevent,
21+
];
22+
final otherOperations = OperationType.values
23+
.where((operationType) => !observeOperations.contains(operationType));
24+
25+
final testVector = [
26+
(
27+
expectedResult: true,
28+
operationTypes: observeOperations,
29+
subprotocol: "cov:observe",
30+
),
31+
(
32+
expectedResult: false,
33+
operationTypes: observeOperations,
34+
subprotocol: null,
35+
),
36+
(
37+
expectedResult: true,
38+
operationTypes: otherOperations,
39+
subprotocol: null,
40+
),
41+
(
42+
expectedResult: false,
43+
operationTypes: otherOperations,
44+
subprotocol: "cov:observe",
45+
),
46+
(
47+
expectedResult: false,
48+
operationTypes: OperationType.values,
49+
subprotocol: "foobar",
50+
),
51+
];
52+
53+
for (final testCase in testVector) {
54+
for (final operationType in testCase.operationTypes) {
55+
expect(
56+
coapClientFactory.supportsOperation(
57+
operationType,
58+
testCase.subprotocol,
59+
),
60+
testCase.expectedResult,
61+
);
62+
}
63+
}
64+
});
65+
});
66+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2024 Contributors to the Eclipse Foundation. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
//
5+
// SPDX-License-Identifier: BSD-3-Clause
6+
7+
import "package:dart_wot/binding_http.dart";
8+
import "package:dart_wot/core.dart";
9+
import "package:test/test.dart";
10+
11+
void main() {
12+
group("HttpClientFactory should", () {
13+
test("indicate correctly whether an operation is supported", () {
14+
final httpClientFactory = HttpClientFactory();
15+
16+
const observeOperations = [
17+
OperationType.observeproperty,
18+
OperationType.unobserveproperty,
19+
OperationType.subscribeevent,
20+
OperationType.unsubscribeevent,
21+
];
22+
final otherOperations = OperationType.values
23+
.where((operationType) => !observeOperations.contains(operationType));
24+
25+
final testVector = [
26+
(
27+
expectedResult: false,
28+
operationTypes: observeOperations,
29+
subprotocol: null,
30+
),
31+
(
32+
expectedResult: false,
33+
operationTypes: observeOperations,
34+
subprotocol: "foobar",
35+
),
36+
(
37+
expectedResult: true,
38+
operationTypes: otherOperations,
39+
subprotocol: null,
40+
),
41+
(
42+
expectedResult: false,
43+
operationTypes: otherOperations,
44+
subprotocol: "foobar",
45+
),
46+
];
47+
48+
for (final testCase in testVector) {
49+
for (final operationType in testCase.operationTypes) {
50+
expect(
51+
httpClientFactory.supportsOperation(
52+
operationType,
53+
testCase.subprotocol,
54+
),
55+
testCase.expectedResult,
56+
);
57+
}
58+
}
59+
});
60+
});
61+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2024 Contributors to the Eclipse Foundation. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
//
5+
// SPDX-License-Identifier: BSD-3-Clause
6+
7+
import "package:dart_wot/binding_mqtt.dart";
8+
import "package:dart_wot/core.dart";
9+
import "package:test/test.dart";
10+
11+
void main() {
12+
group("MqttClientFactory should", () {
13+
test("indicate correctly whether an operation is supported", () {
14+
final coapClientFactory = MqttClientFactory();
15+
16+
final testVector = [
17+
(
18+
expectedResult: false,
19+
operationTypes: OperationType.values,
20+
subprotocol: "foobar",
21+
),
22+
(
23+
expectedResult: true,
24+
operationTypes: OperationType.values,
25+
subprotocol: null,
26+
),
27+
];
28+
29+
for (final testCase in testVector) {
30+
for (final operationType in testCase.operationTypes) {
31+
expect(
32+
coapClientFactory.supportsOperation(
33+
operationType,
34+
testCase.subprotocol,
35+
),
36+
testCase.expectedResult,
37+
);
38+
}
39+
}
40+
});
41+
});
42+
}

0 commit comments

Comments
 (0)