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

refactor: add possibility to support different URI schemes #69

Closed
wants to merge 3 commits into from
Closed
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
31 changes: 27 additions & 4 deletions lib/src/channel/coap_network_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,40 @@

part of coap;

/// This [Exception] is thrown when an unsupported URI scheme is encountered.
class UnsupportedProtocolException implements Exception {
/// The error message of this [Exception].
String get message => 'Unsupported URI scheme $uriScheme encountered.';

/// The unsupported Uri Scheme that was encountered.
final String uriScheme;

/// Constructor.
UnsupportedProtocolException(this.uriScheme);
}

/// A network management/caching class, allows already
/// bound endpoints to be reused without instantiating them again.
class CoapNetworkManagement {
static final List<CoapINetwork> _networks = <CoapINetwork>[];

/// Gets a new network, otherwise tries to find a cached network
/// and returns that.
static CoapINetwork getNetwork(CoapInternetAddress address, int port,
{required String namespace}) {
final CoapINetwork network =
CoapNetworkUDP(address, port, namespace: namespace);
static CoapINetwork getNetwork(
CoapInternetAddress address, int port, String scheme,
{required String namespace, required DefaultCoapConfig config}) {
final CoapINetwork network;

switch (scheme) {
case CoapConstants.uriScheme:
{
network = CoapNetworkUDP(address, port, namespace: namespace);
break;
}
default:
throw UnsupportedProtocolException(scheme);
}

if (_networks.contains(network)) {
return _networks.where((CoapINetwork e) => e == network).toList()[0];
} else {
Expand Down
24 changes: 13 additions & 11 deletions lib/src/channel/coap_udp_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,30 @@ part of coap;
/// Channel via UDP protocol.
class CoapUDPChannel extends CoapIChannel {
/// Initialise with a specific address and port
CoapUDPChannel(this._address, this._port, {required String namespace}) {
_eventBus = CoapEventBus(namespace: namespace);
final socket =
CoapNetworkManagement.getNetwork(address!, _port, namespace: namespace);
_socket = socket as CoapNetworkUDP;
}
CoapUDPChannel(this._address, this._port, this.uriScheme,
{required String namespace, required this.config})
: _eventBus = CoapEventBus(namespace: namespace),
_socket = CoapNetworkManagement.getNetwork(
_address!, _port, CoapConstants.uriScheme,
namespace: namespace, config: config);

final String uriScheme;

final int _port;

final DefaultCoapConfig config;

@override
int get port => _port;
final CoapInternetAddress? _address;

@override
CoapInternetAddress? get address => _address;
late CoapNetworkUDP _socket;
final CoapINetwork _socket;

final typed.Uint8Buffer _buff = typed.Uint8Buffer();

late final CoapEventBus _eventBus;
final CoapEventBus _eventBus;

@override
Future<void> start() async {
Expand All @@ -47,9 +51,7 @@ class CoapUDPChannel extends CoapIChannel {
@override
Future<void> send(typed.Uint8Buffer data,
[CoapInternetAddress? address]) async {
if (_socket.socket != null) {
_socket.send(data, address);
}
_socket.send(data, address);
}

@override
Expand Down
9 changes: 6 additions & 3 deletions lib/src/coap_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,8 @@ class CoapClient {
if (endpoint != null) {
return endpoint;
} else {
return CoapEndpointManager.getDefaultEndpoint(request.endpoint!,
return CoapEndpointManager.getDefaultEndpoint(
request.uri.scheme, request.endpoint!,
namespace: _namespace);
}
}
Expand All @@ -331,8 +332,10 @@ class CoapClient {
await request.resolveDestination(addressType);
// Endpoint and channel
CoapEndpointManager.getDefaultSpec();
final CoapIChannel channel =
CoapUDPChannel(request.destination, uri.port, namespace: _namespace);

final channel = CoapEndpointManager.determineCoapChannel(
uri.scheme, request.destination, uri.port,
namespace: _namespace, config: _config);
if (endpoint != null) {
request.endpoint = endpoint;
} else {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/coap_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ abstract class DefaultCoapConfig {
int defaultPort = CoapConstants.defaultPort;

/// The default CoAP port for secure CoAP communication (coaps).
int get defaultSecurePort => CoapConstants.defaultSecurePort;
int defaultSecurePort = CoapConstants.defaultSecurePort;

/// The port which HTTP proxy is on.
int get httpPort => 8080;
Expand Down
34 changes: 14 additions & 20 deletions lib/src/net/coap_endpoint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ part of coap;
class CoapEndPoint implements CoapIEndPoint, CoapIOutbox {
/// Instantiates a new endpoint with the
/// specified channel and configuration.
CoapEndPoint(CoapIChannel channel, DefaultCoapConfig config,
CoapEndPoint(CoapIChannel channel, this._config,
{required String namespace}) {
_config = config;
_channel = channel;
_eventBus = CoapEventBus(namespace: namespace);
_matcher = CoapMatcher(config, namespace: namespace);
Expand All @@ -22,19 +21,22 @@ class CoapEndPoint implements CoapIEndPoint, CoapIOutbox {
}

/// Instantiates a new endpoint with internet address, port and configuration
CoapEndPoint.address(
CoapInternetAddress localEndpoint, int port, DefaultCoapConfig config,
{required String namespace})
: this(newUDPChannel(localEndpoint, port, namespace: namespace), config,
CoapEndPoint.address(String scheme, CoapInternetAddress localEndpoint,
int port, DefaultCoapConfig config, {required String namespace})
: this(
CoapEndpointManager.determineCoapChannel(
scheme, localEndpoint, port,
namespace: namespace, config: config),
config,
namespace: namespace);

final CoapILogger? _log = CoapLogManager().logger;
late final CoapEventBus _eventBus;

DefaultCoapConfig? _config;
DefaultCoapConfig _config;

@override
DefaultCoapConfig? get config => _config;
DefaultCoapConfig get config => _config;
late CoapIChannel _channel;
late CoapStack _coapStack;
StreamSubscription? subscr;
Expand Down Expand Up @@ -104,7 +106,7 @@ class CoapEndPoint implements CoapIEndPoint, CoapIOutbox {
final data = typed.Uint8Buffer();
data.addAll(event.data);
// Return if we have no data, should not happen but be defensive
final decoder = config!.spec!.newMessageDecoder(data);
final decoder = config.spec!.newMessageDecoder(data);
if (decoder.isRequest) {
CoapRequest? request;
try {
Expand Down Expand Up @@ -218,7 +220,7 @@ class CoapEndPoint implements CoapIEndPoint, CoapIOutbox {
typed.Uint8Buffer _serializeEmpty(CoapEmptyMessage message) {
var bytes = message.bytes;
if (bytes == null) {
bytes = _config!.spec!.newMessageEncoder().encodeMessage(message);
bytes = _config.spec!.newMessageEncoder().encodeMessage(message);
message.bytes = bytes;
}
return bytes!;
Expand All @@ -227,7 +229,7 @@ class CoapEndPoint implements CoapIEndPoint, CoapIOutbox {
typed.Uint8Buffer _serializeRequest(CoapMessage message) {
var bytes = message.bytes;
if (bytes == null) {
bytes = _config!.spec!.newMessageEncoder().encodeMessage(message);
bytes = _config.spec!.newMessageEncoder().encodeMessage(message);
message.bytes = bytes;
}
return bytes!;
Expand All @@ -236,17 +238,9 @@ class CoapEndPoint implements CoapIEndPoint, CoapIOutbox {
typed.Uint8Buffer _serializeResponse(CoapMessage message) {
var bytes = message.bytes;
if (bytes == null) {
bytes = _config!.spec!.newMessageEncoder().encodeMessage(message);
bytes = _config.spec!.newMessageEncoder().encodeMessage(message);
message.bytes = bytes;
}
return bytes!;
}

/// New UDP channel
static CoapIChannel newUDPChannel(CoapInternetAddress localEndpoint, int port,
{required String namespace}) {
final CoapIChannel channel =
CoapUDPChannel(localEndpoint, port, namespace: namespace);
return channel;
}
}
33 changes: 29 additions & 4 deletions lib/src/net/coap_endpoint_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,40 @@ class CoapEndpointManager {
config.spec ??= CoapRfc7252();
}

static CoapIChannel determineCoapChannel(
String uriScheme, CoapInternetAddress? endpoint, int port,
{required String namespace, required DefaultCoapConfig config}) {
switch (uriScheme) {
case CoapConstants.uriScheme:
return CoapUDPChannel(endpoint, port, uriScheme,
namespace: namespace, config: config);
default:
throw UnsupportedProtocolException(uriScheme);
}
}

static int _getPortForUriScheme(String scheme, CoapISpec spec) {
switch (scheme) {
case CoapConstants.uriScheme:
return spec.defaultPort;
case CoapConstants.secureUriScheme:
return spec.defaultSecurePort;
default:
throw UnsupportedProtocolException(scheme);
}
}

/// Default endpoint
static CoapIEndPoint getDefaultEndpoint(CoapIEndPoint endpoint,
static CoapIEndPoint getDefaultEndpoint(String scheme, CoapIEndPoint endpoint,
{required String namespace}) {
final config = DefaultCoapConfig.inst!;
config.spec ??= CoapRfc7252();
config.defaultPort = config.spec!.defaultPort;
final CoapIChannel channel = CoapUDPChannel(
endpoint.localEndpoint, config.defaultPort,
namespace: namespace);
config.defaultSecurePort = config.spec!.defaultSecurePort;

final port = _getPortForUriScheme(scheme, config.spec!);
final channel = determineCoapChannel(scheme, endpoint.localEndpoint, port,
namespace: namespace, config: config);
final ep = CoapEndPoint(channel, config, namespace: namespace);
ep.start();
return ep;
Expand Down
3 changes: 3 additions & 0 deletions lib/src/specification/coap_ispec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ abstract class CoapISpec {
/// Gets the default CoAP port in this draft.
int get defaultPort;

/// Gets the default CoAPS port in this draft.
int get defaultSecurePort;

/// Encodes a CoAP message into a bytes array.
/// Returns the encoded bytes, or null if the message can not be encoded,
/// i.e. the message is not a Request, a Response or an EmptyMessage.
Expand Down
3 changes: 3 additions & 0 deletions lib/src/specification/rfcs/coap_rfc7252.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class CoapRfc7252 implements CoapISpec {
@override
int get defaultPort => 5683;

@override
int get defaultSecurePort => 5684;

@override
CoapIMessageEncoder newMessageEncoder() => CoapMessageEncoderRfc7252();

Expand Down