| // 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. |
| |
| use failure::Error; |
| use fidl::endpoints::{RequestStream, ServerEnd}; |
| use fidl_fuchsia_amber::ControlProxy as AmberProxy; |
| use fidl_fuchsia_io::{self, DirectoryMarker, DirectoryProxy}; |
| use fidl_fuchsia_pkg::{PackageResolverRequest, PackageResolverRequestStream, UpdatePolicy}; |
| use fuchsia_async as fasync; |
| use fuchsia_pkg_uri::PackageUri; |
| use fuchsia_syslog::{fx_log_err, fx_log_info, fx_log_warn}; |
| use fuchsia_zircon::{Channel, MessageBuf, Signals, Status}; |
| use futures::prelude::*; |
| |
| pub async fn run_resolver_service( |
| amber: AmberProxy, pkgfs: DirectoryProxy, chan: fasync::Channel, |
| ) -> Result<(), Error> { |
| let mut stream = PackageResolverRequestStream::from_channel(chan); |
| |
| while let Some(event) = await!(stream.try_next())? { |
| let PackageResolverRequest::Resolve { |
| package_uri, |
| selectors, |
| update_policy, |
| dir, |
| responder, |
| } = event; |
| |
| let status = await!(resolve( |
| &amber, |
| &pkgfs, |
| package_uri, |
| selectors, |
| update_policy, |
| dir |
| )); |
| responder.send(Status::from(status).into_raw())?; |
| } |
| |
| Ok(()) |
| } |
| |
| /// Resolve the package. |
| /// |
| /// FIXME: at the moment, we are proxying to Amber to resolve a package name and variant to a |
| /// merkleroot. Because of this, we cant' implement the update policy, so we just ignore it. |
| async fn resolve<'a>( |
| amber: &'a AmberProxy, pkgfs: &'a DirectoryProxy, pkg_uri: String, selectors: Vec<String>, |
| _update_policy: UpdatePolicy, dir_request: ServerEnd<DirectoryMarker>, |
| ) -> Result<(), Status> { |
| fx_log_info!("resolving {:?} with the selectors {:?}", pkg_uri, selectors); |
| |
| let uri = PackageUri::parse(&pkg_uri).map_err(|err| { |
| fx_log_err!("failed to parse package uri: {}", err); |
| Err(Status::INVALID_ARGS) |
| })?; |
| |
| // FIXME: at the moment only the fuchsia.com host is supported. |
| if uri.host() != "fuchsia.com" { |
| fx_log_warn!("package uri's host is currently unsupported: {}", uri); |
| } |
| |
| // FIXME: need to implement selectors. |
| if !selectors.is_empty() { |
| fx_log_warn!("resolve does not support selectors yet"); |
| } |
| |
| // While the fuchsia-pkg:// spec doesn't require a package name, we do. |
| let name = uri.name().ok_or_else(|| { |
| fx_log_err!("package uri is missing a package name: {}", uri); |
| Err(Status::INVALID_ARGS) |
| })?; |
| |
| // Ask amber to cache the package. |
| let chan = |
| await!(amber.get_update_complete(&name, uri.variant(), uri.hash())).map_err(|err| { |
| fx_log_err!("error communicating with amber: {:?}", err); |
| Status::INTERNAL |
| })?; |
| |
| let merkle = await!(wait_for_update_to_complete(chan)).map_err(|err| { |
| fx_log_err!("error when waiting for amber to complete: {:?}", err); |
| Status::INTERNAL |
| })?; |
| |
| fx_log_info!("success: {} has a merkle of {}", name, merkle); |
| |
| // FIXME: this is a bit of a hack but there isn't a formal way to convert a Directory request |
| // into a Node request. |
| let node_request = ServerEnd::new(dir_request.into_channel()); |
| |
| let flags = fidl_fuchsia_io::OPEN_RIGHT_READABLE | fidl_fuchsia_io::OPEN_FLAG_DIRECTORY; |
| pkgfs.open(flags, 0, &merkle, node_request).map_err(|err| { |
| fx_log_err!("error opening {}: {:?}", merkle, err); |
| Status::INTERNAL |
| })?; |
| |
| Ok(()) |
| } |
| |
| async fn wait_for_update_to_complete(chan: Channel) -> Result<String, Status> { |
| let mut buf = MessageBuf::new(); |
| |
| let sigs = await!(fasync::OnSignals::new( |
| &chan, |
| Signals::CHANNEL_PEER_CLOSED | Signals::CHANNEL_READABLE |
| ))?; |
| |
| if sigs.contains(Signals::CHANNEL_READABLE) { |
| chan.read(&mut buf)?; |
| let buf = buf.split().0; |
| |
| if sigs.contains(Signals::USER_0) { |
| let msg = String::from_utf8_lossy(&buf); |
| fx_log_err!("error installing package: {}", msg); |
| return Err(Status::INTERNAL); |
| } |
| |
| let merkle = match String::from_utf8(buf) { |
| Ok(merkle) => merkle, |
| Err(err) => { |
| let merkle = String::from_utf8_lossy(err.as_bytes()); |
| fx_log_err!("{:?} is not a valid merkleroot: {:?}", merkle, err); |
| |
| return Err(Status::INTERNAL); |
| } |
| }; |
| |
| Ok(merkle) |
| } else { |
| fx_log_err!("response channel closed unexpectedly"); |
| Err(Status::INTERNAL) |
| } |
| } |