Web API, Web UI #86
File diff suppressed because it is too large
Load Diff
|
@ -4,15 +4,19 @@ version = "0.1.0"
|
||||||
authors = ["projectmoon <projectmoon@agnos.is>"]
|
authors = ["projectmoon <projectmoon@agnos.is>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tonic = { git = "https://github.com/hyperium/tonic", branch = "master" }
|
log = "0.4"
|
||||||
tonic-web = { git = "https://github.com/hyperium/tonic", branch = "master" }
|
tracing-subscriber = "0.2"
|
||||||
|
tonic = { version = "0.4" }
|
||||||
prost = "0.7"
|
prost = "0.7"
|
||||||
|
once_cell = "1.7"
|
||||||
tenebrous-rpc = { path = "../rpc" }
|
tenebrous-rpc = { path = "../rpc" }
|
||||||
tokio-stream = { version = "0.1", features = ["net"] }
|
juniper = { git = "https://github.com/graphql-rust/juniper", branch = "master" }
|
||||||
|
juniper_rocket_async = { git = "https://github.com/graphql-rust/juniper", branch = "master" }
|
||||||
|
rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master" }
|
||||||
|
warp = "0.2"
|
||||||
|
#tokio-stream = { version = "0.1", features = ["net"] } # needed for grpc-web?
|
||||||
|
|
||||||
[dependencies.tokio]
|
# [dependencies.tokio]
|
||||||
version = "1"
|
# version = "1"
|
||||||
features = [ "full" ]
|
# features = [ "full" ]
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// use std::net::SocketAddr;
|
||||||
|
// use tenebrous_rpc::protos::web_api::{
|
||||||
|
// web_api_server::{WebApi, WebApiServer},
|
||||||
|
// RoomsListReply, UserIdRequest,
|
||||||
|
// };
|
||||||
|
// use tokio::net::TcpListener;
|
||||||
|
// use tokio_stream::wrappers::TcpListenerStream;
|
||||||
|
// use tonic::{transport::Server, Request, Response, Status};
|
||||||
|
|
||||||
|
//grpc-web stuff
|
||||||
|
// struct WebApiService;
|
||||||
|
|
||||||
|
// #[tonic::async_trait]
|
||||||
|
// impl WebApi for WebApiService {
|
||||||
|
// async fn list_room(
|
||||||
|
// &self,
|
||||||
|
// request: Request<UserIdRequest>,
|
||||||
|
// ) -> Result<Response<RoomsListReply>, Status> {
|
||||||
|
// println!("Hello hopefully from a web browser");
|
||||||
|
// Ok(Response::new(RoomsListReply { rooms: vec![] }))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[tokio::main]
|
||||||
|
// pub async fn grpc_web() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// let addr = SocketAddr::from(([127, 0, 0, 1], 10000));
|
||||||
|
// let listener = TcpListener::bind(addr).await.expect("listener");
|
||||||
|
// let url = format!("http://{}", listener.local_addr().unwrap());
|
||||||
|
// println!("Listening at {}", url);
|
||||||
|
|
||||||
|
// let svc = tonic_web::config()
|
||||||
|
// .allow_origins(vec!["http://localhost:8000"])
|
||||||
|
// .enable(WebApiServer::new(WebApiService));
|
||||||
|
|
||||||
|
// let fut = Server::builder()
|
||||||
|
// .accept_http1(true)
|
||||||
|
// .add_service(svc)
|
||||||
|
// .serve_with_incoming(TcpListenerStream::new(listener));
|
||||||
|
|
||||||
|
// fut.await?;
|
||||||
|
// Ok(())
|
||||||
|
// }
|
172
api/src/main.rs
172
api/src/main.rs
|
@ -1,41 +1,155 @@
|
||||||
use std::net::SocketAddr;
|
use juniper::{
|
||||||
use tenebrous_rpc::protos::web_api::{
|
graphql_object, EmptyMutation, EmptySubscription, FieldError, FieldResult, GraphQLObject,
|
||||||
web_api_server::{WebApi, WebApiServer},
|
RootNode,
|
||||||
RoomsListReply, UserIdRequest,
|
|
||||||
};
|
};
|
||||||
use tokio::net::TcpListener;
|
use once_cell::sync::OnceCell;
|
||||||
use tokio_stream::wrappers::TcpListenerStream;
|
use rocket::{response::content, Rocket, State};
|
||||||
use tonic::{transport::Server, Request, Response, Status};
|
use std::cell::RefCell;
|
||||||
|
use std::env;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use tenebrous_rpc::protos::dicebot::dicebot_client::DicebotClient;
|
||||||
|
use tenebrous_rpc::protos::dicebot::GetVariableRequest;
|
||||||
|
use tonic::{metadata::MetadataValue, transport::Channel as TonicChannel, Request as TonicRequest};
|
||||||
|
use tracing_subscriber::filter::EnvFilter;
|
||||||
|
|
||||||
struct WebApiService;
|
//grpc stuff
|
||||||
|
async fn create_client(
|
||||||
|
shared_secret: &str,
|
||||||
|
) -> Result<DicebotClient<TonicChannel>, Box<dyn std::error::Error>> {
|
||||||
|
let channel = TonicChannel::from_static("http://0.0.0.0:9090")
|
||||||
|
.connect()
|
||||||
|
.await?;
|
||||||
|
|
||||||
#[tonic::async_trait]
|
let bearer = MetadataValue::from_str(&format!("Bearer {}", shared_secret))?;
|
||||||
impl WebApi for WebApiService {
|
let client = DicebotClient::with_interceptor(channel, move |mut req: TonicRequest<()>| {
|
||||||
async fn list_room(
|
req.metadata_mut().insert("authorization", bearer.clone());
|
||||||
&self,
|
Ok(req)
|
||||||
request: Request<UserIdRequest>,
|
});
|
||||||
) -> Result<Response<RoomsListReply>, Status> {
|
|
||||||
println!("Hello hopefully from a web browser");
|
Ok(client)
|
||||||
Ok(Response::new(RoomsListReply { rooms: vec![] }))
|
}
|
||||||
|
|
||||||
|
//api stuff
|
||||||
|
#[derive(GraphQLObject)]
|
||||||
|
#[graphql(description = "User variable in a room.")]
|
||||||
|
struct UserVariable {
|
||||||
|
room_id: String,
|
||||||
|
variable_name: String,
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
//graphql shit
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Context {
|
||||||
|
dicebot_client: DicebotClient<TonicChannel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// To make our context usable by Juniper, we have to implement a marker trait.
|
||||||
|
impl juniper::Context for Context {}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct Query;
|
||||||
|
|
||||||
|
#[graphql_object(
|
||||||
|
// Here we specify the context type for the object.
|
||||||
|
// We need to do this in every type that
|
||||||
|
// needs access to the context.
|
||||||
|
context = Context,
|
||||||
|
)]
|
||||||
|
impl Query {
|
||||||
|
fn apiVersion() -> &str {
|
||||||
|
"1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn variable(
|
||||||
|
context: &mut Context,
|
||||||
|
room_id: String,
|
||||||
|
user_id: String,
|
||||||
|
variable: String,
|
||||||
|
) -> FieldResult<UserVariable> {
|
||||||
|
let request = TonicRequest::new(GetVariableRequest {
|
||||||
|
room_id: room_id.clone(),
|
||||||
|
user_id: user_id.clone(),
|
||||||
|
variable_name: variable.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = context
|
||||||
|
.dicebot_client
|
||||||
|
.clone()
|
||||||
|
.get_variable(request)
|
||||||
|
.await?
|
||||||
|
.into_inner();
|
||||||
|
|
||||||
|
Ok(UserVariable {
|
||||||
|
room_id: room_id.clone(),
|
||||||
|
variable_name: variable.clone(),
|
||||||
|
value: response.value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
type Schema = RootNode<'static, Query, EmptyMutation<Context>, EmptySubscription<Context>>;
|
||||||
|
|
||||||
|
fn schema() -> Schema {
|
||||||
|
Schema::new(
|
||||||
|
Query,
|
||||||
|
EmptyMutation::<Context>::new(),
|
||||||
|
EmptySubscription::<Context>::new(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//rocket stuff
|
||||||
|
|
||||||
|
#[rocket::get("/")]
|
||||||
|
fn graphiql() -> content::Html<String> {
|
||||||
|
juniper_rocket_async::graphiql_source("/graphql", None)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::get("/graphql?<request>")]
|
||||||
|
fn get_graphql_handler(
|
||||||
|
context: &State<Context>,
|
||||||
|
request: juniper_rocket_async::GraphQLRequest,
|
||||||
|
schema: &State<Schema>,
|
||||||
|
) -> juniper_rocket_async::GraphQLResponse {
|
||||||
|
request.execute_sync(&*schema, &*context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::post("/graphql", data = "<request>")]
|
||||||
|
fn post_graphql_handler(
|
||||||
|
context: &State<Context>,
|
||||||
|
request: juniper_rocket_async::GraphQLRequest,
|
||||||
|
schema: &State<Schema>,
|
||||||
|
) -> juniper_rocket_async::GraphQLResponse {
|
||||||
|
request.execute_sync(&*schema, &*context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::main]
|
||||||
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 10000));
|
let filter = if env::var("RUST_LOG").is_ok() {
|
||||||
let listener = TcpListener::bind(addr).await.expect("listener");
|
EnvFilter::from_default_env()
|
||||||
let url = format!("http://{}", listener.local_addr().unwrap());
|
} else {
|
||||||
println!("Listening at {}", url);
|
EnvFilter::new("warp_async")
|
||||||
|
};
|
||||||
|
|
||||||
let svc = tonic_web::config()
|
tracing_subscriber::fmt().with_env_filter(filter).init();
|
||||||
.allow_origins(vec!["http://localhost:8000"])
|
|
||||||
.enable(WebApiServer::new(WebApiService));
|
|
||||||
|
|
||||||
let fut = Server::builder()
|
let log = warp::log("warp_server");
|
||||||
.accept_http1(true)
|
let client = create_client("abc123").await?;
|
||||||
.add_service(svc)
|
|
||||||
.serve_with_incoming(TcpListenerStream::new(listener));
|
|
||||||
|
|
||||||
fut.await?;
|
log::info!("Listening on 127.0.0.1:8080");
|
||||||
|
let context = Context {
|
||||||
|
dicebot_client: client,
|
||||||
|
};
|
||||||
|
|
||||||
|
Rocket::build()
|
||||||
|
.manage(client)
|
||||||
|
.manage(schema())
|
||||||
|
.mount(
|
||||||
|
"/",
|
||||||
|
rocket::routes![graphiql, get_graphql_handler, post_graphql_handler],
|
||||||
|
)
|
||||||
|
.launch()
|
||||||
|
.await
|
||||||
|
.expect("server to launch");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ barrel = { version = "0.6", features = ["sqlite3"] }
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
substring = "1.4"
|
substring = "1.4"
|
||||||
fuse-rust = "0.2"
|
fuse-rust = "0.2"
|
||||||
tonic = { git = "https://github.com/hyperium/tonic", branch = "master" }
|
tonic = { version = "0.4" }
|
||||||
prost = "0.7"
|
prost = "0.7"
|
||||||
tenebrous-rpc = { path = "../rpc" }
|
tenebrous-rpc = { path = "../rpc" }
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,10 @@ async fn create_client(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let bearer = MetadataValue::from_str(&format!("Bearer {}", shared_secret))?;
|
let bearer = MetadataValue::from_str(&format!("Bearer {}", shared_secret))?;
|
||||||
let client = DicebotClient::new(channel);
|
let client = DicebotClient::with_interceptor(channel, move |mut req: Request<()>| {
|
||||||
|
req.metadata_mut().insert("authorization", bearer.clone());
|
||||||
// let client = DicebotClient::with_interceptor(channel, move |mut req: Request<()>| {
|
Ok(req)
|
||||||
// req.metadata_mut().insert("authorization", bearer.clone());
|
});
|
||||||
// Ok(req)
|
|
||||||
// });
|
|
||||||
|
|
||||||
Ok(client)
|
Ok(client)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ default = ["tonic/default", "tonic-build/default"]
|
||||||
wasm = [ "tonic/codegen", "tonic/prost", "tonic-build/prost"]
|
wasm = [ "tonic/codegen", "tonic/prost", "tonic-build/prost"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = { git = "https://github.com/hyperium/tonic", branch = "master", default_features = false }
|
tonic-build = { version = "0.4", default_features = false }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tonic = { git = "https://github.com/hyperium/tonic", branch = "master", default_features = false }
|
tonic = { version = "0.4", default_features = false }
|
||||||
prost = "0.7"
|
prost = "0.7"
|
|
@ -9,21 +9,18 @@ edition = "2018"
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
tonic-build = { version = "0.4", default-features = false, features = ["prost"] }
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
yew = { version = "0.17", default_features = false }#features = [ "agent", "web-sys" ] }
|
yew = { version = "0.17" }
|
||||||
yewtil = {version = "0.3" }
|
yewtil = {version = "0.3" }
|
||||||
yew-router = {version = "0.14", default_features = false }
|
yew-router = {version = "0.14" }
|
||||||
yewdux = {version = "^0.6", default_features = false }
|
yewdux = {version = "^0.6" }
|
||||||
wasm-bindgen = { version = "0.2", default-features = false, features = ["serde-serialize"] }
|
wasm-bindgen = { version = "0.2" }
|
||||||
grpc-web-client = "0.1"
|
grpc-web-client = "0.1"
|
||||||
prost = { version = "0.7.0", default-features = false }
|
|
||||||
tonic = { git = "https://github.com/hyperium/tonic", branch = "master", default-features = false, features = ["codegen", "prost"] }
|
|
||||||
tenebrous-rpc = { path = "../../rpc", default_features = false, features = ["wasm"] }
|
|
||||||
|
|
||||||
# [dependencies.tokio]
|
# hopefully we can add grpc-web later instead of graphql.
|
||||||
# version = "1"
|
# prost = { version = "0.7.0", default-features = false }
|
||||||
# features = [ "rt", "sync" ]
|
# tonic = { git = "https://github.com/hyperium/tonic", branch = "master", default-features = false, features = ["codegen", "prost"] }
|
||||||
|
# tenebrous-rpc = { path = "../../rpc", default_features = false, features = ["wasm"] }
|
||||||
|
|
||||||
|
# [build-dependencies]
|
||||||
|
# tonic-build = { version = "0.4", default-features = false, features = ["prost"] }
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
async fn test_grpc_web() {
|
// async fn test_grpc_web() {
|
||||||
use grpc_web_client::Client as GrpcWebClient;
|
// use grpc_web_client::Client as GrpcWebClient;
|
||||||
use tenebrous_rpc::protos::web_api::web_api_client::WebApiClient as TheCloud;
|
// use tenebrous_rpc::protos::web_api::web_api_client::WebApiClient as TheCloud;
|
||||||
use tenebrous_rpc::protos::web_api::{RoomsListReply, UserIdRequest};
|
// use tenebrous_rpc::protos::web_api::{RoomsListReply, UserIdRequest};
|
||||||
|
|
||||||
let client = GrpcWebClient::new("http://localhost:10000".to_string());
|
// let client = GrpcWebClient::new("http://localhost:10000".to_string());
|
||||||
let mut client = TheCloud::new(client);
|
// let mut client = TheCloud::new(client);
|
||||||
|
|
||||||
let request = tonic::Request::new(UserIdRequest {
|
// let request = tonic::Request::new(UserIdRequest {
|
||||||
user_id: "WebTonic".into(),
|
// user_id: "WebTonic".into(),
|
||||||
});
|
// });
|
||||||
|
|
||||||
let response = client.list_room(request).await.unwrap().into_inner();
|
// let response = client.list_room(request).await.unwrap().into_inner();
|
||||||
println!("Room reply: {:?}", response);
|
// println!("Room reply: {:?}", response);
|
||||||
}
|
// }
|
||||||
|
|
Loading…
Reference in New Issue