use juniper::{ graphql_object, EmptyMutation, EmptySubscription, FieldError, FieldResult, GraphQLInputObject, GraphQLObject, RootNode, }; use once_cell::sync::OnceCell; use rocket::{response::content, Rocket, State}; 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; //grpc stuff async fn create_client( shared_secret: &str, ) -> Result, Box> { let channel = TonicChannel::from_static("http://0.0.0.0:9090") .connect() .await?; let bearer = MetadataValue::from_str(&format!("Bearer {}", shared_secret))?; let client = DicebotClient::with_interceptor(channel, move |mut req: TonicRequest<()>| { req.metadata_mut().insert("authorization", bearer.clone()); Ok(req) }); Ok(client) } //api stuff #[derive(GraphQLInputObject)] struct UserVariableArgument { room_id: String, user_id: String, variable_name: String, } #[derive(GraphQLObject)] #[graphql(description = "User variable in a room.")] struct UserVariable { room_id: String, user_id: String, variable_name: String, value: i32, } //graphql shit #[derive(Clone)] struct Context { dicebot_client: DicebotClient, } // 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 { 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 { user_id: user_id.clone(), room_id: room_id.clone(), variable_name: variable.clone(), value: response.value, }) } } type Schema = RootNode<'static, Query, EmptyMutation, EmptySubscription>; fn schema() -> Schema { Schema::new( Query, EmptyMutation::::new(), EmptySubscription::::new(), ) } //rocket stuff #[rocket::get("/")] fn graphiql() -> content::Html { juniper_rocket_async::graphiql_source("/graphql", None) } #[rocket::get("/graphql?")] async fn get_graphql_handler( context: &State, request: juniper_rocket_async::GraphQLRequest, schema: &State, ) -> juniper_rocket_async::GraphQLResponse { request.execute(&*schema, &*context).await } #[rocket::post("/graphql", data = "")] async fn post_graphql_handler( context: &State, request: juniper_rocket_async::GraphQLRequest, schema: &State, ) -> juniper_rocket_async::GraphQLResponse { request.execute(&*schema, &*context).await } #[rocket::main] pub async fn main() -> Result<(), Box> { println!("hi"); let filter = if env::var("RUST_LOG").is_ok() { EnvFilter::from_default_env() } else { EnvFilter::new("tenebrous_api=info,tonic=info,rocket=info") }; tracing_subscriber::fmt().with_env_filter(filter).init(); log::info!("Setting up gRPC connection"); let client = create_client("abc123").await?; log::info!("Listening on 127.0.0.1:8080"); let context = Context { dicebot_client: client, }; Rocket::build() .manage(context) .manage(schema()) .mount( "/", rocket::routes![graphiql, get_graphql_handler, post_graphql_handler], ) .launch() .await .expect("server to launch"); Ok(()) }