blob: 48367f78fa9b21f89239b92993fac7a1ac020da5 [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 'package:fidl/fidl.dart';
import 'package:fuchsia_services/services.dart';
import 'package:fidl_fuchsia_modular/fidl_async.dart' as fidl;
import 'package:fidl_fuchsia_sys/fidl_async.dart' as fidl_sys;
import 'package:fuchsia_modular/lifecycle.dart';
import '../agent.dart';
/// A concrete implementation of the [Agent] interface.
///
/// This class is not intended to be used directly by authors but instead
/// should be used by the [Agent] factory constructor.
class AgentImpl implements Agent, fidl.Agent {
/// Holds the framework binding connection to this agent.
final fidl.AgentBinding _agentBinding = fidl.AgentBinding();
/// The service provider which can be used to expose outgoing services
final ServiceProviderImpl _serviceProvider;
/// Holds the connection of other components to this agent's service provider
final List<fidl_sys.ServiceProviderBinding> _serviceProviderBindings =
<fidl_sys.ServiceProviderBinding>[];
/// Holds the outgoing connection of other components to the services provided
/// by this agent.
final List<AsyncBinding<Object>> _outgoingServicesBindings =
<AsyncBinding<Object>>[];
/// The default constructor for this instance.
AgentImpl(
{Lifecycle lifecycle,
StartupContext startupContext,
ServiceProviderImpl serviceProviderImpl})
: _serviceProvider = serviceProviderImpl ?? ServiceProviderImpl() {
(lifecycle ??= Lifecycle()).addTerminateListener(_terminate);
startupContext ??= StartupContext.fromStartupInfo();
_exposeAgent(startupContext);
}
@override
Future<void> connect(
String requestorUrl,
InterfaceRequest<fidl_sys.ServiceProvider> services,
) {
// Bind this agent's serviceProvider to the client request.
//
// Note: currently we're ignoring the [requestorUrl] and providing the same
// set of services to all clients.
_serviceProviderBindings.add(
fidl_sys.ServiceProviderBinding()..bind(_serviceProvider, services));
return null;
}
@override
void exposeService<T>(FutureOr<T> serviceImpl, ServiceData<T> serviceData) {
if (serviceImpl == null) {
throw ArgumentError.notNull('serviceImpl');
}
exposeServiceProvider(
Future.value(serviceImpl).then((T service) => () => service),
serviceData);
}
@override
void exposeServiceProvider<T>(FutureOr<ServiceProvider<T>> serviceProvider,
ServiceData<T> serviceData) {
if (serviceProvider == null) {
throw ArgumentError.notNull('serviceProvider');
}
if (serviceData == null) {
throw ArgumentError.notNull('serviceData');
}
// Add this [serviceImpl] to this agent's serviceProvider so that it can
// be accessed the `connected clients of this agent.
_serviceProvider.addServiceForName(
(InterfaceRequest<T> request) {
Future.value(serviceProvider)
.then((ServiceProvider<T> providerFunc) => providerFunc())
.then((T service) => _outgoingServicesBindings
.add(serviceData.getBinding()..bind(service, request)));
},
serviceData.getName(),
);
}
@override
Future<void> runTask(String taskId) {
if (taskId == null) {
throw ArgumentError.notNull('taskId');
}
// TODO impl this method.
throw UnimplementedError('runTask method is not yet implemented');
}
/// Exposes this [fidl.Agent] instance to the
/// [StartupContext#outgoingServices]. In other words, advertises this as an
/// [fidl.Agent] to the rest of the system via the [StartupContext].
///
/// This class be must called before the first iteration of the event loop.
void _exposeAgent(StartupContext startupContext) {
startupContext.outgoingServices.addServiceForName(
(InterfaceRequest<fidl.Agent> request) {
assert(!_agentBinding.isBound);
_agentBinding.bind(this, request);
},
fidl.Agent.$serviceName,
);
}
// Any necessary cleanup should be done here.
Future<void> _terminate() async {
_agentBinding.close();
for (fidl_sys.ServiceProviderBinding binding in _serviceProviderBindings) {
binding.close();
}
for (AsyncBinding<Object> binding in _outgoingServicesBindings) {
binding.close();
}
}
}