From 94d6a9ba6684699630082e50f65f72f6c854cbbd Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Wed, 29 Nov 2023 01:54:25 +0100 Subject: [PATCH] feat: improve DataSchemaValue handling --- lib/scripting_api.dart | 1 + lib/src/core/content_serdes.dart | 35 ++++++++----------- lib/src/core/interaction_output.dart | 23 ++++++++++-- lib/src/scripting_api/data_schema_value.dart | 12 +++++++ lib/src/scripting_api/interaction_output.dart | 4 +-- 5 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 lib/src/scripting_api/data_schema_value.dart diff --git a/lib/scripting_api.dart b/lib/scripting_api.dart index b07aa50a..8cc6ecd5 100644 --- a/lib/scripting_api.dart +++ b/lib/scripting_api.dart @@ -11,6 +11,7 @@ library scripting_api; export 'src/scripting_api/consumed_thing.dart'; +export 'src/scripting_api/data_schema_value.dart'; export 'src/scripting_api/discovery/discovery_method.dart'; export 'src/scripting_api/discovery/thing_discovery.dart'; export 'src/scripting_api/discovery/thing_filter.dart'; diff --git a/lib/src/core/content_serdes.dart b/lib/src/core/content_serdes.dart index 3eaf7565..a1219d87 100644 --- a/lib/src/core/content_serdes.dart +++ b/lib/src/core/content_serdes.dart @@ -10,7 +10,9 @@ import 'dart:io'; import 'package:http_parser/http_parser.dart'; import 'package:json_schema/json_schema.dart'; +import '../../scripting_api.dart' as scripting_api; import '../definitions/data_schema.dart'; +import '../scripting_api/data_schema_value.dart'; import 'codecs/cbor_codec.dart'; import 'codecs/codec_media_type.dart'; import 'codecs/content_codec.dart'; @@ -175,18 +177,14 @@ class ContentSerdes { final mimeType = parsedMediaType.mimeType; final parameters = parsedMediaType.parameters; - List bytes; final codec = _getCodecFromMediaType(mimeType); - if (codec != null) { - bytes = codec.valueToBytes(value, dataSchema, parameters); - } else { - // Media Type is unsupported. Convert the String representation to bytes - // instead. - // TODO(JKRhb): Could be moved to a dedicated Value class method. - bytes = utf8.encoder.convert(value.toString()); + if (codec == null) { + // TODO: Throw UnsupportedError + throw Exception(); } + final bytes = codec.valueToBytes(value, dataSchema, parameters); return Content(resolvedMediaType, Stream.value(bytes)); } @@ -195,7 +193,7 @@ class ContentSerdes { /// A [dataSchema] can be passed for validating the result. If the media type /// specified in the [content] is not supported, its body is converted to an /// UTF-8 string. - Future contentToValue( + Future contentToValue( Content content, DataSchema? dataSchema, ) async { @@ -204,20 +202,15 @@ class ContentSerdes { final parameters = parsedMediaType.parameters; final bytes = await content.toByteList(); + final codec = _getCodecFromMediaType(mimeType); - // TODO: Should null be returned in this case? - if (bytes.isEmpty) { - return null; + if (codec == null) { + // TODO: Throw NotSupportedError + throw Exception(); } - final codec = _getCodecFromMediaType(mimeType); - if (codec != null) { - final value = codec.bytesToValue(bytes, dataSchema, parameters); - _validateValue(value, dataSchema); - return value; - } else { - // TODO(JKRhb): Should unsupported data be returned as a String? - return utf8.decode(bytes.toList()); - } + final value = codec.bytesToValue(bytes, dataSchema, parameters); + _validateValue(value, dataSchema); + return value; } } diff --git a/lib/src/core/interaction_output.dart b/lib/src/core/interaction_output.dart index 30d74202..8bfdb496 100644 --- a/lib/src/core/interaction_output.dart +++ b/lib/src/core/interaction_output.dart @@ -34,6 +34,9 @@ class InteractionOutput implements scripting_api.InteractionOutput { bool _dataUsed = false; + // TODO: Name these fields + (bool, scripting_api.DataSchemaValue) _value = (false, null); + @override Future arrayBuffer() async { _dataUsed = true; @@ -44,9 +47,25 @@ class InteractionOutput implements scripting_api.InteractionOutput { bool get dataUsed => _dataUsed; @override - Future value() async { + Future value() async { + if (_value.$1) { + return _value.$2; + } + + final schema = this.schema; + if (schema == null) { + // TODO: Throw NotReadableError + throw Exception(); + } + + final value = await _contentSerdes.contentToValue( + _content, + schema, + ); _dataUsed = true; - return _contentSerdes.contentToValue(_content, schema); + + _value = (true, value); + return value; } @override diff --git a/lib/src/scripting_api/data_schema_value.dart b/lib/src/scripting_api/data_schema_value.dart new file mode 100644 index 00000000..fcb24c87 --- /dev/null +++ b/lib/src/scripting_api/data_schema_value.dart @@ -0,0 +1,12 @@ +// 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 + +/// Value corresponding to a WoT DataSchema as specified in [section 7.1] +/// of the [WoT Scripting API] specification. +/// +/// [section 7.1]: https://www.w3.org/TR/wot-scripting-api/#the-interactioninput-type +/// [WoT Scripting API]: https://www.w3.org/TR/wot-scripting-api +typedef DataSchemaValue = Object?; diff --git a/lib/src/scripting_api/interaction_output.dart b/lib/src/scripting_api/interaction_output.dart index db8521c3..2ee33fd7 100644 --- a/lib/src/scripting_api/interaction_output.dart +++ b/lib/src/scripting_api/interaction_output.dart @@ -8,6 +8,7 @@ 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. /// @@ -33,7 +34,6 @@ abstract interface class InteractionOutput { /// of the [InteractionOutput]. Future arrayBuffer(); - // TODO(JKRhb): Replace with some kind of DataSchemaValue /// The parsed value of the [InteractionOutput]. - Future value(); + Future value(); }