Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(servient): improve handling of client factories #83

Merged
merged 7 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ import 'package:dart_wot/dart_wot.dart';

Future<void> main(List<String> args) async {
final CoapClientFactory coapClientFactory = CoapClientFactory();
final servient = Servient()..addClientFactory(coapClientFactory);
final servient = Servient(
protocolClients: [coapClientFactory]
);
final wot = await servient.start();

final thingDescriptionJson = '''
Expand Down
2 changes: 1 addition & 1 deletion example/coap_discovery.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Future<void> handleThingDescription(
}

Future<void> main(List<String> args) async {
final servient = Servient()..addClientFactory(CoapClientFactory());
final servient = Servient(clientFactories: [CoapClientFactory()]);

final wot = await servient.start();
final uri = Uri.parse('coap://plugfest.thingweb.io:5683/testthing');
Expand Down
6 changes: 5 additions & 1 deletion example/coap_dns_sd_discovery.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ void handleThingDescription(ThingDescription thingDescription) =>
print('Discovered TD with title "${thingDescription.title}".');

Future<void> main(List<String> args) async {
final servient = Servient()..addClientFactory(CoapClientFactory());
final servient = Servient(
clientFactories: [
CoapClientFactory(),
],
);

final wot = await servient.start();
final uri = Uri.parse('_wot._udp.local');
Expand Down
7 changes: 6 additions & 1 deletion example/coaps_readproperty.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ Future<void> main(List<String> args) async {
),
pskCredentialsCallback: _pskCredentialsCallback,
);
final servient = Servient()..addClientFactory(coapClientFactory);

final servient = Servient(
clientFactories: [
coapClientFactory,
],
);

final wot = await servient.start();

Expand Down
18 changes: 11 additions & 7 deletions example/complex_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,19 @@ Future<BasicCredentials?> basicCredentialsCallback(
}

Future<void> main() async {
const coapConfig = CoapConfig(blocksize: 64);
final CoapClientFactory coapClientFactory = CoapClientFactory(
coapConfig: coapConfig,
final coapClientFactory = CoapClientFactory(
coapConfig: const CoapConfig(blocksize: 64),
);
final HttpClientFactory httpClientFactory =

final httpClientFactory =
HttpClientFactory(basicCredentialsCallback: basicCredentialsCallback);
final servient = Servient()
..addClientFactory(coapClientFactory)
..addClientFactory(httpClientFactory);

final servient = Servient(
clientFactories: [
coapClientFactory,
httpClientFactory,
],
);
final wot = await servient.start();

final thingDescription = ThingDescription(thingDescriptionJson);
Expand Down
2 changes: 1 addition & 1 deletion example/core_link_format_discovery.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const propertyName = 'status';
const actionName = 'toggle';

Future<void> main(List<String> args) async {
final servient = Servient()..addClientFactory(CoapClientFactory());
final servient = Servient(clientFactories: [CoapClientFactory()]);

final wot = await servient.start();

Expand Down
19 changes: 12 additions & 7 deletions example/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,19 @@ Future<BasicCredentials?> basicCredentialsCallback(
}

Future<void> main(List<String> args) async {
final CoapClientFactory coapClientFactory = CoapClientFactory();
final HttpClientFactory httpClientFactory =
final coapClientFactory = CoapClientFactory();
final httpClientFactory =
HttpClientFactory(basicCredentialsCallback: basicCredentialsCallback);
final MqttClientFactory mqttClientFactory = MqttClientFactory();
final servient = Servient()
..addClientFactory(coapClientFactory)
..addClientFactory(httpClientFactory)
..addClientFactory(mqttClientFactory);
final mqttClientFactory = MqttClientFactory();

final servient = Servient(
clientFactories: [
coapClientFactory,
httpClientFactory,
mqttClientFactory,
],
);

final wot = await servient.start();

const thingDescriptionJson = '''
Expand Down
11 changes: 8 additions & 3 deletions example/http_basic_authentication.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,14 @@ Future<BasicCredentials?> basicCredentialsCallback(
/// Illustrates the usage of both the basic and the automatic security scheme,
/// with a server supporting basic authentication.
Future<void> main(List<String> args) async {
final HttpClientFactory httpClientFactory =
HttpClientFactory(basicCredentialsCallback: basicCredentialsCallback);
final servient = Servient()..addClientFactory(httpClientFactory);
final httpClientFactory = HttpClientFactory(
basicCredentialsCallback: basicCredentialsCallback,
);
final servient = Servient(
clientFactories: [
httpClientFactory,
],
);
final wot = await servient.start();

final thingDescription = ThingDescription(thingDescriptionJson);
Expand Down
27 changes: 23 additions & 4 deletions lib/src/core/servient.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,24 @@ class ServientException implements Exception {
class Servient {
/// Creates a new [Servient].
///
/// A custom [contentSerdes] can be passed that supports other media types
/// than the default ones.
/// The [Servient] can be preconfigured with a [List] of
/// [ProtocolClientFactory]s.
/// However, it is also possible to dynamically [addClientFactory]s and
/// [removeClientFactory]s at runtime.
///
/// If you want to support a custom media type not already included in the
/// [ContentSerdes] class, a custom [contentSerdes] object can be passed as an
/// argument.
Servient({
List<ProtocolClientFactory>? clientFactories,
ServerSecurityCallback? serverSecurityCallback,
ContentSerdes? contentSerdes,
}) : contentSerdes = contentSerdes ?? ContentSerdes(),
_serverSecurityCallback = serverSecurityCallback;
_serverSecurityCallback = serverSecurityCallback {
for (final clientFactory in clientFactories ?? <ProtocolClientFactory>[]) {
addClientFactory(clientFactory);
}
}

final List<ProtocolServer> _servers = [];
final Map<String, ProtocolClientFactory> _clientFactories = {};
Expand Down Expand Up @@ -184,13 +195,21 @@ class Servient {
List<String> get clientSchemes =>
_clientFactories.keys.toList(growable: false);

/// Adds a new [clientFactory] to this [Servient.]
/// Adds a new [clientFactory] to this [Servient].
void addClientFactory(ProtocolClientFactory clientFactory) {
for (final scheme in clientFactory.schemes) {
_clientFactories[scheme] = clientFactory;
}
}

/// Removes a [ProtocolClientFactory] matching the given [scheme] from this
/// [Servient], if present.
///
/// If a [ProtocolClientFactory] was removed, the method returns it, otherwise
/// the return value is `null`.
ProtocolClientFactory? removeClientFactory(String scheme) =>
_clientFactories.remove(scheme);

/// Checks whether a [ProtocolClient] is avaiable for a given [scheme].
bool hasClientFor(String scheme) => _clientFactories.containsKey(scheme);

Expand Down
7 changes: 4 additions & 3 deletions test/binding_http/http_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,14 @@ void main() {
]) async =>
bearerCredentialsStore[uri.host];

final servient = Servient()
..addClientFactory(
final servient = Servient(
clientFactories: [
HttpClientFactory(
basicCredentialsCallback: basicCredentialsCallback,
bearerCredentialsCallback: bearerCredentialsCallback,
),
);
],
);
final wot = await servient.start();

final consumedThing = await wot.consume(parsedTd);
Expand Down
2 changes: 1 addition & 1 deletion test/core/consumed_thing_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ void main() {

final parsedTd = ThingDescription(thingDescriptionJson);

final servient = Servient()..addClientFactory(HttpClientFactory());
final servient = Servient(clientFactories: [HttpClientFactory()]);
final wot = await servient.start();

final uriVariables = {'value': 'SFRUUEJJTiBpcyBhd2Vzb21l'};
Expand Down
61 changes: 61 additions & 0 deletions test/core/servient_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2023 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:dart_wot/dart_wot.dart';
import 'package:test/test.dart';

const testUriScheme = 'test';

class MockedProtocolClientFactory implements ProtocolClientFactory {
@override
ProtocolClient createClient() {
throw UnimplementedError('Instantiating a client is not supported yet.');
}

@override
bool destroy() {
return true;
}

@override
bool init() {
return true;
}

@override
Set<String> get schemes => {testUriScheme};
}

void main() {
group('Servient Tests', () {
test('Should accept a ProtocolClientFactory list as constructor argument',
() {
final servient = Servient(
clientFactories: [
MockedProtocolClientFactory(),
],
);

expect(servient.clientSchemes, [testUriScheme]);
expect(servient.hasClientFor(testUriScheme), true);
});

test(
'Should allow for adding and removing a ProtocolClientFactory at runtime',
() {
final servient = Servient()
..addClientFactory(MockedProtocolClientFactory());

expect(servient.hasClientFor(testUriScheme), true);

servient.removeClientFactory(testUriScheme);

expect(servient.hasClientFor(testUriScheme), false);
expect(servient.clientSchemes.length, 0);
},
);
});
}