Skip to content

Commit

Permalink
fixup! feat: improve DataSchemaValue handling
Browse files Browse the repository at this point in the history
  • Loading branch information
JKRhb committed Dec 28, 2023
1 parent bae87fb commit 5f9ebbe
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 86 deletions.
4 changes: 2 additions & 2 deletions lib/src/core/codecs/content_codec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import '../../scripting_api/data_schema_value.dart';
abstract class ContentCodec {
/// Converts an [Object] to its byte representation in the given media type.
List<int> valueToBytes(
DataSchemaValue? value,
DataSchemaValue<Object?>? value,
DataSchema? dataSchema,
Map<String, String>? parameters,
);

/// Converts a payload of the given media type to an [Object].
DataSchemaValue? bytesToValue(
DataSchemaValue<Object?>? bytesToValue(
List<int> bytes,
DataSchema? dataSchema,
Map<String, String>? parameters,
Expand Down
44 changes: 0 additions & 44 deletions lib/src/core/codecs/link_format_codec.dart

This file was deleted.

32 changes: 22 additions & 10 deletions lib/src/core/codecs/text_codec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import '../../definitions/data_schema.dart';
import '../../scripting_api/data_schema_value.dart';
import 'content_codec.dart';

const _utf8Coding = 'utf-8';

/// A [ContentCodec] that encodes and decodes plain text data.
class TextCodec extends ContentCodec {
@override
Expand All @@ -23,14 +25,16 @@ class TextCodec extends ContentCodec {
return [];
}

final rawValue = value.value;
final rawValue = value.value.toString();

if (rawValue is! String) {
throw ArgumentError.value(value);
}
final coding = parameters.coding;

// TODO: Support other codings
return utf8.encode(rawValue);
switch (coding) {
case _utf8Coding:
return utf8.encode(rawValue);
default:
throw FormatException('Encountered unsupported text coding $coding');
}
}

@override
Expand All @@ -39,13 +43,21 @@ class TextCodec extends ContentCodec {
DataSchema? dataSchema,
Map<String, String>? parameters,
) {
// TODO(JKRhb): Use dataSchema for validation

if (bytes.isEmpty) {
return null;
}

// TODO: Support other codings
return DataSchemaValue.fromString(utf8.decoder.convert(bytes));
final coding = parameters.coding;

switch (coding) {
case _utf8Coding:
return DataSchemaValue.fromString(utf8.decoder.convert(bytes));
default:
throw FormatException('Encountered unsupported text coding $coding');
}
}
}

extension _ParametersExtension on Map<String, String>? {
String get coding => this?['charset']?.toLowerCase() ?? _utf8Coding;
}
12 changes: 5 additions & 7 deletions lib/src/core/content_serdes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import 'codecs/cbor_codec.dart';
import 'codecs/codec_media_type.dart';
import 'codecs/content_codec.dart';
import 'codecs/json_codec.dart';
import 'codecs/link_format_codec.dart';
import 'codecs/text_codec.dart';
import 'content.dart';

Expand All @@ -25,7 +24,6 @@ const defaultMediaType = 'application/json';

/// Custom [Exception] that is thrown when Serialization or Deserialization
/// fails.
// TODO(JKRhb): Add codecs for text-based media types
// TODO(JKRhb): Add codecs for XML based media types
// TODO(JKRhb): Add codecs for Base64 media types
// TODO(JKRhb): Add codec for OctetStream media type
Expand Down Expand Up @@ -54,11 +52,11 @@ class ContentSerdes {
/// The supported codecs by this [ContentSerdes] object.
///
/// Is initialized with support for JSON, CBOR, and the CoRE Link-Format.
final _codecs = {
CodecMediaType('application', 'json'): JsonCodec(),
CodecMediaType('application', 'cbor'): CborCodec(),
CodecMediaType('application', 'link-format'): LinkFormatCodec(),
CodecMediaType('text', 'plain'): TextCodec(),
final _codecs = <MediaType, ContentCodec>{
(type: 'application', subtype: 'json'): JsonCodec(),
(type: 'application', subtype: 'cbor'): CborCodec(),
(type: 'application', subtype: 'link-format'): TextCodec(),
(type: 'text', subtype: 'plain'): TextCodec(),
};

final Set<String> _offeredMediaTypes = {
Expand Down
5 changes: 2 additions & 3 deletions lib/src/core/interaction_output.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ class InteractionOutput implements scripting_api.InteractionOutput {
bool _dataUsed = false;

// TODO: Name these fields
(bool, scripting_api.DataSchemaValue?) _value =
(false, scripting_api.DataSchemaValue.fromNull());
(bool, Object?) _value = (false, null);

@override
Future<ByteBuffer> arrayBuffer() async {
Expand All @@ -48,7 +47,7 @@ class InteractionOutput implements scripting_api.InteractionOutput {
bool get dataUsed => _dataUsed;

@override
Future<scripting_api.DataSchemaValue?> value() async {
Future<Object?> value() async {
if (_value.$1) {
return _value.$2;
}
Expand Down
5 changes: 2 additions & 3 deletions lib/src/core/servient.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:uuid/uuid.dart';

import '../definitions/interaction_affordances/interaction_affordance.dart';
import '../definitions/thing_description.dart';
import '../scripting_api/data_schema_value.dart';
import 'consumed_thing.dart';
import 'content_serdes.dart';
import 'credentials/callbacks.dart';
Expand Down Expand Up @@ -235,12 +234,12 @@ class Servient {

final value = await contentSerdes.contentToValue(content, null);

if (value is! ObjectValue) {
if (value is! Map<String, Object?>) {
throw DiscoveryException(
'Could not parse Thing Description obtained from $url',
);
}

return ThingDescription.fromJson(value.value);
return ThingDescription.fromJson(value);
}
}
18 changes: 7 additions & 11 deletions lib/src/core/thing_discovery.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import 'package:multicast_dns/multicast_dns.dart';
import '../../core.dart';
import '../../scripting_api.dart' as scripting_api;
import '../definitions/thing_description.dart';
import '../scripting_api/data_schema_value.dart';
import '../scripting_api/discovery/discovery_method.dart';
import 'content.dart';

Expand Down Expand Up @@ -107,13 +106,13 @@ class ThingDiscovery extends Stream<ThingDescription>
DiscoveryContent content,
) async {
final value = await _servient.contentSerdes.contentToValue(content, null);
if (value is! ObjectValue) {
if (value is! Map<String, Object?>) {
throw DiscoveryException(
'Could not parse Thing Description obtained from ${content.sourceUri}',
);
}

return ThingDescription.fromJson(value.value);
return ThingDescription.fromJson(value);
}

Stream<ThingDescription> _discoverDirectly(Uri uri) async* {
Expand All @@ -125,16 +124,13 @@ class ThingDiscovery extends Stream<ThingDescription>
}

Future<List<CoapWebLink>?> _getCoreWebLinks(Content content) async {
throw UnimplementedError();
final value = await _servient.contentSerdes.contentToValue(content, null);

// final value = await _servient.contentSerdes.contentToValue(content, null);
// if (value is CoapWebLink) {
// return [value];
// } else if (value is List<CoapWebLink>) {
// return value;
// }
if (value is String) {
return CoapLinkFormat.parse(value).toList();
}

// return null;
return null;
}

Future<Iterable<Uri>> _filterCoreWebLinks(
Expand Down
5 changes: 2 additions & 3 deletions lib/src/core/wot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'dart:async';

import '../../scripting_api.dart' as scripting_api;
import '../definitions/thing_description.dart';
import '../scripting_api/data_schema_value.dart';
import '../scripting_api/discovery/discovery_method.dart';
import 'consumed_thing.dart';
import 'exposed_thing.dart';
Expand Down Expand Up @@ -119,15 +118,15 @@ class WoT implements scripting_api.WoT {
await consumedDirectoryThing.readProperty('things');
final rawThingDescriptions = await interactionOutput.value();

if (rawThingDescriptions is! ArrayValue) {
if (rawThingDescriptions is! List<Object?>) {
throw DiscoveryException(
'Expected an array of Thing Descriptions but received an '
'invalid output instead.',
);
}

final thingDescriptionStream = Stream.fromIterable(
rawThingDescriptions.value.whereType<Map<String, Object?>>(),
rawThingDescriptions.whereType<Map<String, Object?>>(),
).toThingDescriptionStream();

return ThingDiscoveryProcess(thingDescriptionStream, filter);
Expand Down
24 changes: 24 additions & 0 deletions lib/src/scripting_api/data_schema_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,27 @@ final class ObjectValue extends DataSchemaValue<Map<String, Object?>> {
return ObjectValue._fromValue(result);
}
}

extension NullDataSchemaValueExtension on Null {
DataSchemaValue asDataSchemaValue() => DataSchemaValue.fromNull();
}

extension StringDataSchemaValueExtension on String {
DataSchemaValue asDataSchemaValue() => DataSchemaValue.fromString(this);
}

extension IntegerDataSchemaValueExtension on int {
DataSchemaValue asDataSchemaValue() => DataSchemaValue.fromInteger(this);
}

extension NumberDataSchemaValueExtension on double {
DataSchemaValue asDataSchemaValue() => DataSchemaValue.fromNumber(this);
}

extension ArrayDataSchemaValueExtension on List<Object?> {
DataSchemaValue asDataSchemaValue() => DataSchemaValue.fromArray(this);
}

extension ObjectDataSchemaValueExtension on Map<String, Object?> {
DataSchemaValue asDataSchemaValue() => DataSchemaValue.fromObject(this);
}
4 changes: 4 additions & 0 deletions lib/src/scripting_api/interaction_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ final class StreamInput extends InteractionInput {
final Stream<List<int>> byteStream;
}

extension NullInteractionInputExtension on Null {
InteractionInput asInteractionInput() => InteractionInput.fromNull();
}

extension StringInteractionInputExtension on String {
InteractionInput asInteractionInput() => InteractionInput.fromString(this);
}
Expand Down
3 changes: 1 addition & 2 deletions lib/src/scripting_api/interaction_output.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'dart:typed_data';

import '../definitions/data_schema.dart';
import '../definitions/form.dart';
import 'data_schema_value.dart';

/// Exposes the data obtained by Thing interactions.
///
Expand All @@ -35,5 +34,5 @@ abstract interface class InteractionOutput {
Future<ByteBuffer> arrayBuffer();

/// The parsed value of the [InteractionOutput].
Future<DataSchemaValue?> value();
Future<Object?> value();
}
2 changes: 1 addition & 1 deletion test/core/content_serdes_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ void main() {

expect(
await contentSerdes.contentToValue(testContent1, successfulSchema),
DataSchemaValue.tryParse(42),
42,
);

final testContent2 = _getTestContent('42');
Expand Down

0 comments on commit 5f9ebbe

Please sign in to comment.