diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 6ca23448e5d859157fc070faf496c0e270652581..52f3796d5dc69aa7cffe1ef49572efafd9884bc2 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 30 + compileSdkVersion 31 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -39,6 +39,9 @@ android { targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + + manifestPlaceholders = [appAuthRedirectScheme: 'com.redirectScheme.comm'] + } buildTypes { diff --git a/example/android/build.gradle b/example/android/build.gradle index 9b6ed06eb38acc554df2b8a38e5a794cb05fb354..cd4a213ba40c3838ff9a7e4d402b895969932a86 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.6.0' repositories { google() jcenter() diff --git a/example/lib/main.dart b/example/lib/main.dart index 1ff9b46d017d91ef859cdeb0b8ef441491bcf75b..90bba601c5afc94c9b0f0c3bb995f50404bef20c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -8,9 +8,9 @@ import 'package:flutter/foundation.dart' show kIsWeb; //TODO: replace with your own client data // the client used here has no permissions in the s3i unless your personal // account grants some -final clientIdentity = ClientIdentity("s3i:flutter-example-client", - secret: "86c0025d-3cb4-4db8-a8d3-4bf30e2e0930"); -final String ownEndpoint = 's3ib://s3i:cb420dbc-0d0f-4c57-8cf6-12bdf96b8578'; +final clientIdentity = ClientIdentity("s3i:b5152a47-fb1c-415c-a340-69e176e15da7", + secret: "AP9JrkbpCK6IWBT5x4RJ10h847RQTjl5"); +final String ownEndpoint = 's3ibs://s3i:b5152a47-fb1c-415c-a340-69e176e15da7'; void main() { runApp(MyApp()); @@ -38,7 +38,7 @@ class MyHomePage extends StatefulWidget { static final authManager = OAuthProxyFlow(clientIdentity, maxRetryPickup: 500, retryWaitingTimeMilliSec: 100, - openUrlCallback: openUrl, onAuthSuccess: () { + openUrlCallback: openUrl, onAuthSuccess: (AccessToken accessToken) { debugPrint("Auth succeeded"); }, scopes: ["group", "offline_access"]); static final s3i = S3ICore(authManager); diff --git a/example/pubspec.lock b/example/pubspec.lock index 4219823f0b96ba4c428200fdf260f4ca3ef477b6..c31289032067dbd560a7eb8ea499a7d86def669b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -21,7 +21,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: @@ -35,7 +35,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -127,28 +127,28 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" plugin_platform_interface: dependency: transitive description: @@ -174,7 +174,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -195,21 +195,21 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" typed_data: dependency: transitive description: diff --git a/lib/s3i_flutter.dart b/lib/s3i_flutter.dart index 512df9b304ca23b7e9f391ce6a0af7417e175bf1..18bdaae5077171e425f9dfe762056fdbc59db9e7 100644 --- a/lib/s3i_flutter.dart +++ b/lib/s3i_flutter.dart @@ -8,7 +8,6 @@ export 'src/auth/client_identity.dart'; export 'src/auth/keycloak_client_representation.dart'; export 'src/auth/oauth_proxy_flow.dart'; export 'src/auth/tokens.dart'; - //broker export 'src/broker/broker_amqp_connector.dart' if (dart.library.js) 'src/broker/broker_rest_connector.dart'; @@ -18,15 +17,15 @@ export 'src/broker/messages/attribute_value_messages.dart'; export 'src/broker/messages/event_system_messages.dart'; export 'src/broker/messages/service_messages.dart'; export 'src/broker/messages/user_message.dart'; - //directory export 'src/directory/dir_object.dart'; export 'src/directory/endpoint.dart'; +export 'src/directory/event.dart'; export 'src/directory/link.dart'; export 'src/directory/location.dart'; +export 'src/directory/service.dart'; export 'src/directory/thing.dart'; export 'src/directory/value.dart'; - //exception export 'src/exceptions/invalid_json_schema_exception.dart'; export 'src/exceptions/json_missing_key_exception.dart'; @@ -36,19 +35,16 @@ export 'src/exceptions/network_response_exception.dart'; export 'src/exceptions/parse_exception.dart'; export 'src/exceptions/response_parsing_exception.dart'; export 'src/exceptions/s3i_exception.dart'; - //policy export 'src/policy/policy_entry.dart'; export 'src/policy/policy_group.dart'; export 'src/policy/policy_resource.dart'; export 'src/policy/policy_subject.dart'; - //query export 'src/query/field_query.dart'; export 'src/query/namespace_query.dart'; export 'src/query/option_query.dart'; export 'src/query/query_assembler.dart'; export 'src/query/rql_query.dart'; - //core export 'src/s3i_core.dart'; diff --git a/lib/src/auth/oauth_proxy_flow.dart b/lib/src/auth/oauth_proxy_flow.dart index c2ce0f7d97bb8682324bd59a7c194e19b73e4d8a..f56c7415bec07bf9c4efb9fa6a740be1b6d22add 100644 --- a/lib/src/auth/oauth_proxy_flow.dart +++ b/lib/src/auth/oauth_proxy_flow.dart @@ -24,7 +24,7 @@ class OAuthProxyFlow extends AuthenticationManager { {required this.openUrlCallback, this.onAuthSuccess, this.onNewRefreshToken, - this.maxRetryPickup = 100, + this.maxRetryPickup = 200, this.retryWaitingTimeMilliSec = 200, List<String> scopes = const <String>[], String discoveryEndpoint = ''}) @@ -41,7 +41,7 @@ class OAuthProxyFlow extends AuthenticationManager { /// [scopes]. RefreshToken? _refreshToken; - /// Number of retries (default: 100) to pickup the token bundle from + /// Number of retries (default: 200) to pickup the token bundle from /// the OAuthProxy endpoint. final int maxRetryPickup; diff --git a/lib/src/broker/messages/message.dart b/lib/src/broker/messages/message.dart index aa46fabed80e9786711faec772abe9d33771d64e..1dc6d66a6436c572d802330824cf3384479b78fc 100644 --- a/lib/src/broker/messages/message.dart +++ b/lib/src/broker/messages/message.dart @@ -22,22 +22,22 @@ abstract class Message extends JsonSerializableObject { this.sender = '', this.replyingToMessage, this.replyToEndpoint}) { - _identifier = messageId ?? const Uuid().v4(); + _identifier = messageId ?? 's3i:${const Uuid().v4()}'; } /// Should be not editable from the outside, see [identifier] for the getter. late String _identifier; - /// The unique identifier of this message (UUIDv4). + /// The unique identifier of this message (s3i:UUIDv4). /// /// Is generated in the constructor if not other specified. String get identifier => _identifier; - /// All receivers of this message (should be a `s3I:UUIDv4` of the + /// All receivers of this message (should be a `s3i:UUIDv4` of the /// receiving thing). Set<String> receivers; - /// The sender of this message (should be a `s3I:UUIDv4` of the publishing + /// The sender of this message (should be a `s3i:UUIDv4` of the publishing /// thing). String sender; diff --git a/lib/src/broker/messages/user_message.dart b/lib/src/broker/messages/user_message.dart index 3042a24a967867cecf3c98133845b8dc52c6d738..28cde9588de21ee1f7c9cae45f5f6ab9aa4fd117 100644 --- a/lib/src/broker/messages/user_message.dart +++ b/lib/src/broker/messages/user_message.dart @@ -1,3 +1,4 @@ +import 'package:s3i_flutter/s3i_flutter.dart'; import 'package:s3i_flutter/src/broker/messages/message.dart'; import 'package:s3i_flutter/src/exceptions/invalid_json_schema_exception.dart'; import 'package:s3i_flutter/src/exceptions/json_missing_key_exception.dart'; @@ -17,7 +18,7 @@ class UserMessage extends Message { String sender = '', String? replyingToMessage, String? replyToEndpoint, - this.attachment, + this.attachments, this.subject, this.text}) : super( @@ -38,9 +39,9 @@ class UserMessage extends Message { try { final UserMessage msg = UserMessage() ..generateFromJson(json) - ..attachment = json.containsKey(BrokerKeys.attachments) - ? Attachment.fromJson( - json[BrokerKeys.attachments] as Map<String, dynamic>) + ..attachments = json.containsKey(BrokerKeys.attachments) + ? _createAttachmentList( + json[BrokerKeys.attachments] as List<dynamic>) : null ..subject = json[BrokerKeys.subject] as String? ..text = json[BrokerKeys.text] as String?; @@ -51,8 +52,8 @@ class UserMessage extends Message { } } - /// The optional attachment of an user message. - Attachment? attachment; + /// The optional attachments of an user message. + List<Attachment>? attachments; /// The subject of a user message - should be a short topic (optional). String? subject; @@ -60,12 +61,23 @@ class UserMessage extends Message { /// The content of the user message (optional). String? text; + /// Maps the [jsonList] to a [List<Attachment>]. + /// + /// Throws a [TypeError] if a element in the list could not be parsed to + /// a Map<String, dynamic> or [Attachment.fromJson] throws this error. Throws a + /// [JsonMissingKeyException] if a needed key is missing. + static List<Attachment> _createAttachmentList(List<dynamic> jsonList) { + return jsonList + .map((dynamic linkE) => Attachment.fromJson(linkE as Map<String, dynamic>)) + .toList(); + } + @override Map<String, dynamic> toJson() { final Map<String, dynamic> newJson = super.toJson(); newJson[BrokerKeys.messageType] = BrokerKeys.userMessage; - if (attachment != null) { - newJson[BrokerKeys.attachments] = attachment!.toJson(); + if (attachments != null) { + newJson[BrokerKeys.attachments] = attachments; } if (subject != null) newJson[BrokerKeys.subject] = subject; if (text != null) newJson[BrokerKeys.text] = text; diff --git a/lib/src/directory/link.dart b/lib/src/directory/link.dart index 4d5c966e1410d55bf71ddaa62a1154b224fc3c71..49656b0be71b230e2f882c1365555570ab0ae515 100644 --- a/lib/src/directory/link.dart +++ b/lib/src/directory/link.dart @@ -25,10 +25,12 @@ class Link implements JsonSerializableObject { ? json[DirectoryKeys.association] as String : null; //if both are non-existing throw an exception + /* if(association == null) { throw JsonMissingKeyException( DirectoryKeys.association, json.toString()); } + */ final Link l = Link(association) ..target = json.containsKey(DirectoryKeys.target) diff --git a/lib/src/directory/property.dart b/lib/src/directory/property.dart index 5a6158c84a825e466946a32aa07f187665b5dd17..b62ddfe3e8c050d25e83fe25c39ccf040bed0e15 100644 --- a/lib/src/directory/property.dart +++ b/lib/src/directory/property.dart @@ -20,7 +20,10 @@ class Property implements JsonSerializableObject { ? json[DirectoryKeys.thingType] as String : throw JsonMissingKeyException( DirectoryKeys.thingType, json.toString()); - final Property p = Property(name, type); + final Property p = Property(name, type) + ..unit = json.containsKey(DirectoryKeys.unit) + ? json[DirectoryKeys.unit] as String + : null; return p; } @@ -30,6 +33,9 @@ class Property implements JsonSerializableObject { /// The stored values associated with the attribute. final String type; + /// The associated unit with the attribute + String? unit; + /// Maps the [jsonList] to a [List<String>]. /// /// Throws a [TypeError] if a element in the list could not be parsed to @@ -40,7 +46,7 @@ class Property implements JsonSerializableObject { @override String toString() { - return 'Value($name, $type)'; + return 'Value($name, $type, $unit)'; } /// TODO(Bek): name should be parent attribute of type diff --git a/lib/src/directory/service.dart b/lib/src/directory/service.dart index efdcb243c98d40fc5dd5a0f76c339cc59871da0f..652e6f1c4dc1fe108e72105a3e2970e468443bfc 100644 --- a/lib/src/directory/service.dart +++ b/lib/src/directory/service.dart @@ -113,9 +113,3 @@ class ResultProperty extends IoParameterType{ ResultProperty(String name, String type): super(name, type); } -class IoType{ - static const String string = "string"; - static const String number = "number"; - static const String file = "file"; -} - diff --git a/lib/src/directory/thing.dart b/lib/src/directory/thing.dart index ce25c32a236778efe5317f2ff2a89789346877ce..59c229b45ff2a72135788e12bca7784f90263cb0 100644 --- a/lib/src/directory/thing.dart +++ b/lib/src/directory/thing.dart @@ -44,7 +44,7 @@ import 'package:s3i_flutter/src/utils/json_keys.dart'; /// ``` class Thing extends Entry { /// Creates a new [Thing] with the given [id]. - Thing(String id/*, {this.name, this.events}*/) : super(id); + Thing(String id /*, {this.name, this.events}*/) : super(id); /// Creates a [Thing] from a decoded [json] entry. /// @@ -67,7 +67,7 @@ class Thing extends Entry { ? _createThingType( attributesMap[DirectoryKeys.thingType] as String) : null; - } on FallThroughError { + } on UnknownThingTypeException { throw InvalidJsonSchemaException( 'unknown thing type', map.toString()); } on TypeError { @@ -90,8 +90,10 @@ class Thing extends Entry { ? Location.fromJson( attributesMap[DirectoryKeys.location] as Map<String, dynamic>) : null - ..events = attributesMap.containsKey(DirectoryKeys.events) //TODO(Bek): Added - ? _createEventList(attributesMap[DirectoryKeys.events] as Map<String,dynamic>) + ..events = attributesMap + .containsKey(DirectoryKeys.events) //TODO(Bek): Added + ? _createEventList( + attributesMap[DirectoryKeys.events] as Map<String, dynamic>) : null ..ownedBy = attributesMap[DirectoryKeys.ownedBy] as String? ..administratedBy = @@ -204,7 +206,7 @@ class Thing extends Entry { case 'hmi': return ThingType.hmi; default: - throw FallThroughError(); + throw UnknownThingTypeException('Unknown thing type: $jsonField'); } } @@ -223,9 +225,12 @@ class Thing extends Entry { return jsonList.map((dynamic endP) => Endpoint(endP as String)).toList(); } - static List<EventObj> _createEventList(Map<String, dynamic> jsonMap) //TODO(Bek): added + static List<EventObj> _createEventList( + Map<String, dynamic> jsonMap) //TODO(Bek): added { - return jsonMap.entries.map((e) => EventObj.fromJson(e.key, e.value as Map<String,dynamic>)).toList(); + return jsonMap.entries + .map((e) => EventObj.fromJson(e.key, e.value as Map<String, dynamic>)) + .toList(); } } @@ -242,3 +247,17 @@ enum ThingType { /// HumanMachineInterface. hmi, } + +/// Represents an error that occurs when an unrecognized thing type is +/// encountered. +class UnknownThingTypeException implements Exception { + /// Creates an instance of [UnknownThingTypeException] with a detailed + /// message. + UnknownThingTypeException(this.message); + + /// The detailed message describing the exception. + final String message; + + @override + String toString() => message; +} diff --git a/lib/src/s3i_core.dart b/lib/src/s3i_core.dart index 14e0b3640fea007c0a641e4206d653c1597f6288..90354471456afb9de2ca595974b2d943d3de06d6 100644 --- a/lib/src/s3i_core.dart +++ b/lib/src/s3i_core.dart @@ -219,10 +219,11 @@ class S3ICore { /// a [ResponseParsingException] if something went wrong during the parsing /// to an [Endpoint]. Future<Endpoint> createEventQueueBinding(String thingId, List<String> topic, - {int queueLength = 0}) async { + {int queueLength = 5, int ttl = 10000}) async { final Map<String, dynamic> requestBody = <String, dynamic>{'topic': topic}; if (queueLength > 0) { requestBody['queue_length'] = queueLength; + requestBody['ttl'] = ttl; } final Response response = await postConfig('/things/$thingId/broker/event', jsonBody: requestBody); diff --git a/lib/src/utils/json_keys.dart b/lib/src/utils/json_keys.dart index 40015844812dc3e209fd9650bc8c4bc3db567261..16283e4f62ab123c9e206dc53f7d4955b0b7630f 100644 --- a/lib/src/utils/json_keys.dart +++ b/lib/src/utils/json_keys.dart @@ -158,6 +158,9 @@ class DirectoryKeys { ///services static const String services = 'services'; //TODO(Bek): added + + ///units + static const String unit = 'unit'; //TODO(Bek): added } /// Stores universal string keys constants for the S3I-B protocol.