blob: d90f6e9a02b25c29ab0844fbada4e118a1e2b26c [file] [log] [blame]
// Copyright 2019 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_fuchsia_io/fidl_async.dart';
import 'package:fidl_fuchsia_services_examples/fidl_async.dart';
import 'package:fidl_fuchsia_sys/fidl_async.dart';
import 'package:fuchsia/fuchsia.dart' show exit;
import 'package:fuchsia_logger/logger.dart';
import 'package:fuchsia_services/services.dart';
import 'src/_thought_leaker_impl.dart';
/// The URL which will be used to launch the mind reader server component.
const _mindReaderServerUrl =
'fuchsia-pkg://fuchsia.com/mind_reader_dart#meta/mind_reader_server.cmx';
/// The main entry point for the mind reader client
///
/// Optional args:
/// --thought [string]: Exposes the string to the mind_reader server.
void main(List<String> args) {
setupLogger(name: 'mind_reader_client');
final thoughtToExpose = _parseArgs(args);
_run(thoughtToExpose).then((_) => _shutdown());
}
Future<void> _run(String thoughtToExpose) async {
final context = StartupContext.fromStartupInfo();
ServiceList serviceList;
if (thoughtToExpose == null) {
log
..info(
'No thought provided. Mind reader will not be able to read your mind.')
..info(
'To expose a thought add `--thought "Fuchsia is cool"` when launching the component');
} else {
final thoughtLeaker = ThoughtLeakerImpl(thoughtToExpose);
serviceList = _makeServiceList(thoughtLeaker);
log.info('Exposing ThoughtLeakerImpl with the thought "$thoughtToExpose"');
}
/// A [DirectoryProxy] who's channels will facilitate the connection between
/// this client component and the launched server component we're about to
/// launch. This client component is looking for service under /in/svc/
/// directory to connect to while the server exposes services others can
/// connect to under /out/public directory.
final dirProxy = DirectoryProxy();
/// The [LaunchInfo] struct is used to construct the component we want to
/// launch.
final launchInfo = LaunchInfo(
url: _mindReaderServerUrl,
// The directoryRequest is the handle to the /out directory of the launched
// component.
directoryRequest: dirProxy.ctrl.request().passChannel(),
// The service list is a list of services which are exposed to the child.
// If a service is not included in this list the child will fail to connect.
additionalServices: serviceList,
);
// Launch the component and wait for it to start. We pass a
// [ComponentControllerProxy] here to tie the lifecycle of our component to
// the one we are launching. If we were to pass null the launched process
// would live on after this process dies. Note: you can keep a reference to
// the proxy and close it when you want if your process was longer lived.
await context.launcher
.createComponent(launchInfo, ComponentControllerProxy().ctrl.request());
// Now that the component has launched we attempt to connect to the mind
// reader service which is exposed to us by the child.
final mindReader = MindReaderProxy();
Incoming(dirProxy).connectToService(mindReader);
// We ask the service to read our mind and wait for the response.
final response = await mindReader.readMind();
log.info('Got response: $response');
}
/// Creates a [ServiceList] object which will be used by the launcher to expose
/// the thoughtLeaker service to the launched component.
ServiceList _makeServiceList(ThoughtLeakerImpl thoughtLeaker) {
// Create a [ServiceProvider] and expose the service to the child. This service
// will be exposed to the child in the in/svc directory. When the child attempts
// to connect to the service the [bind] method will be called with the
// given request.
final provider = ServiceProviderImpl()
..addServiceForName(thoughtLeaker.bind, ThoughtLeakerImpl.serviceName);
// The binding will forward the messages sent to the channel to the provided
// thoughtLeaker implementation. The [wrap] method on the binding will create
// a bound channel which will forward messages.
final serviceProviderBinding = ServiceProviderBinding();
final serviceList = ServiceList(
names: [ThoughtLeaker.$serviceName],
provider: serviceProviderBinding.wrap(provider),
);
return serviceList;
}
/// Attempts to parse the args for a supplied thought. If no thought is provided
/// null will be returned.
String _parseArgs(List<String> args) {
if (args.length >= 2 && args[0] == '--thought') {
// temporary workaround for not being able to group args with quotes
return args[1];
}
return null;
}
void _shutdown() {
// we want to allow the log messages to get piped through to the syslogger
// before we kill our process.
Future(() => exit(0));
}