blob: 89c6e6f7cf417c7397207ae06f0935d319632084 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:typed_data';
import 'package:fidl_fuchsia_mem/fidl_async.dart' as fuchsia_mem;
import 'package:fidl_fuchsia_modular/fidl_async.dart' as fidl_modular;
import 'package:meta/meta.dart';
import 'package:zircon/zircon.dart';
import '../internal/_component_context.dart';
import '../module/internal/_module_context.dart';
import 'entity_exceptions.dart';
import 'internal/_entity_impl.dart';
/// An [Entity] provides a mechanism for communicating
/// data between components.
///
/// Note: this is a preliminary API that is likely to change.
@experimental
abstract class Entity {
/// Creates an Entity instance.
///
/// This method will lazily connect to the entity proxy for data transmission.
/// This object should be treated like it has a valid connection until
/// otherwise informed via a failed future.
///
/// ```
/// final entity = Entity(entityReference: 'foo', type: 'com.foo.bar');
/// // fetch the data assuming that the entity resolved correctly. If it
/// // did not the call to getData() will fail.
/// final data = await entity.getData();
/// ```
factory Entity({
@required String entityReference,
@required String type,
}) {
ArgumentError.checkNotNull(entityReference, 'entityReference');
ArgumentError.checkNotNull(type, 'type');
return EntityImpl(
proxyFactory: () async {
final resolver = fidl_modular.EntityResolverProxy();
await getComponentContext().getEntityResolver(resolver.ctrl.request());
final proxy = fidl_modular.EntityProxy();
await resolver.resolveEntity(entityReference, proxy.ctrl.request());
final types = await proxy.getTypes();
if (!types.contains(type)) {
throw EntityTypeException(type);
}
return proxy;
},
type: type,
);
}
/// The type of data that this object represents.
String get type;
/// Returns the data stored in the entity.
Future<Uint8List> getData();
/// Returns the reference for this entity. Entity references will never change
/// for a given entity so this value can be cached and used to access the
/// entity from a different process or at a later time.
Future<String> getEntityReference();
/// Watches the entity for updates.
///
/// An new value will be added to the stream whenever
/// the entity is updated.
///
/// The returned stream is a single subscription stream
/// which, when closed, will close the underlying fidl
/// connection.
Stream<Uint8List> watch();
/// Writes the object stored in value
Future<void> write(Uint8List object);
/// Creates an entity that will live for the scope of this story.
/// The entity that is created will be backed by the framework and
/// can be treated as if it was received from any other entity provider.
static Future<Entity> createStoryScoped({
@required String type,
@required Uint8List initialData,
}) async {
ArgumentError.checkNotNull(type, 'type');
ArgumentError.checkNotNull(initialData, 'initialData');
if (type.isEmpty) {
throw ArgumentError.value(type, 'type cannot be an empty string');
}
final context = getModuleContext();
// need to create the proxy and write data immediately so other modules
// can extract values
final proxy = fidl_modular.EntityProxy();
final vmo = SizedVmo.fromUint8List(initialData);
final buffer = fuchsia_mem.Buffer(vmo: vmo, size: initialData.length);
final ref = await context.createEntity(type, buffer, proxy.ctrl.request());
// use the ref value to determine if creation was successful
if (ref == null || ref.isEmpty) {
throw Exception('Entity.createStoryScopedentity creation failed because'
' the framework was unable to create the entity.');
}
return EntityImpl(type: type, proxyFactory: () => proxy);
}
}