blob: 51ec51fe6c9661a448766241eedb87a9a4ac513d [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.
use crate::auth_provider::{self, GoogleAuthProvider};
use crate::http::UrlLoaderHttpClient;
use crate::web::DefaultStandaloneWebFrame;
use failure::Error;
use fidl::endpoints::{create_proxy, ClientEnd};
use fidl_fuchsia_auth::{
AuthProviderFactoryRequest, AuthProviderFactoryRequestStream, AuthProviderStatus,
};
use fidl_fuchsia_net_oldhttp::{HttpServiceMarker, UrlLoaderMarker};
use fidl_fuchsia_web::{ContextMarker, ContextProviderMarker, CreateContextParams, FrameMarker};
use fuchsia_async as fasync;
use fuchsia_component::client::connect_to_service;
use fuchsia_zircon as zx;
use futures::prelude::*;
use log::error;
use std::sync::Arc;
/// Implementation of the `AuthProviderFactory` FIDL protocol capable of
/// returning `AuthProvider` channels for a `GoogleAuthProvider`.
pub struct GoogleAuthProviderFactory {
/// The GoogleAuthProvider vended through `GetAuthProvider` requests.
google_auth_provider: Arc<GoogleAuthProvider<WebFrameSupplier, UrlLoaderHttpClient>>,
}
impl GoogleAuthProviderFactory {
/// Create a new `GoogleAuthProviderFactory`
pub fn new() -> Result<Self, Error> {
let http_service = connect_to_service::<HttpServiceMarker>()?;
let (url_loader, url_loader_service) = create_proxy::<UrlLoaderMarker>()?;
http_service.create_url_loader(url_loader_service)?;
let frame_supplier = WebFrameSupplier::new();
let http_client = UrlLoaderHttpClient::new(url_loader);
Ok(GoogleAuthProviderFactory {
google_auth_provider: Arc::new(GoogleAuthProvider::new(frame_supplier, http_client)),
})
}
/// Handle requests passed to the supplied stream.
pub async fn handle_requests_from_stream(
&self,
mut stream: AuthProviderFactoryRequestStream,
) -> Result<(), Error> {
while let Some(request) = stream.try_next().await? {
self.handle_request(request).await?;
}
Ok(())
}
/// Handle `AuthProviderFactoryRequest`.
/// Spawn a new `AuthProvider` on every `GetAuthProvider` request
/// to the `AuthProviderFactory` interface.
async fn handle_request(&self, req: AuthProviderFactoryRequest) -> Result<(), Error> {
let AuthProviderFactoryRequest::GetAuthProvider { auth_provider: server_end, responder } =
req;
let request_stream = server_end.into_stream()?;
let auth_provider = Arc::clone(&self.google_auth_provider);
fasync::spawn(async move {
auth_provider
.handle_requests_from_stream(request_stream)
.await
.unwrap_or_else(|e| error!("Error handling AuthProvider channel {:?}", e));
});
responder.send(AuthProviderStatus::Ok)?;
Ok(())
}
}
/// Struct that provides new web frames by connecting to a ContextProvider service.
struct WebFrameSupplier;
impl WebFrameSupplier {
/// Create a new `WebFrameSupplier`
fn new() -> Self {
WebFrameSupplier {}
}
}
impl auth_provider::WebFrameSupplier for WebFrameSupplier {
type Frame = DefaultStandaloneWebFrame;
fn new_standalone_frame(&self) -> Result<DefaultStandaloneWebFrame, failure::Error> {
let context_provider = connect_to_service::<ContextProviderMarker>()?;
let (context_proxy, context_server_end) = create_proxy::<ContextMarker>()?;
// Get a handle to the incoming service directory to pass to the web browser.
// TODO(satsukiu): create a method in fidl::endpoints to connect to ServiceFs instead.
let (client, server) = zx::Channel::create()?;
fdio::service_connect("/svc", server)?;
let service_directory = ClientEnd::new(client);
context_provider.create(
CreateContextParams {
service_directory: Some(service_directory),
..CreateContextParams::empty()
},
context_server_end,
)?;
let (frame_proxy, frame_server_end) = create_proxy::<FrameMarker>()?;
context_proxy.create_frame(frame_server_end)?;
Ok(DefaultStandaloneWebFrame::new(context_proxy, frame_proxy))
}
}