Add readme instructions, run proxy command.

This commit is contained in:
jeff 2021-01-03 21:24:52 +00:00
parent 06954caaaf
commit f479da9001
5 changed files with 98 additions and 52 deletions

View File

@ -6,6 +6,9 @@ edition = "2018"
build = "build.rs" build = "build.rs"
default-run = "tenebrous" default-run = "tenebrous"
[package.metadata.scripts]
grpc-proxy = 'docker run -d --rm -v "$(pwd)"/envoy.yaml:/etc/envoy/envoy.yaml:ro --network=host envoyproxy/envoy:v1.16.1'
[[bin]] [[bin]]
name = "tenebrous-migrate" name = "tenebrous-migrate"
path = "src/migrate.rs" path = "src/migrate.rs"

View File

@ -4,41 +4,66 @@ An open source character sheet service for tabletop roleplaying games.
Currently under heavy development. Currently under heavy development.
## The Stack
This project makes use of these technologies:
- Rust
- Rocket Web Framework
- Tonic gRPC Framework
- Typescript
Building is backed by: cargo, npm, and webpack.
## Build Instructions ## Build Instructions
These are very basic build instructions. They assume you already have These are very basic build instructions. They assume you already have
cargo set up and installed. cargo set up and installed.
### Install Dependencies
Install dependencies. The exact method depends on your OS.
* sqlite3 and development headers (Void Linux: `xbps-install
sqlite sqlite-devel`, Ubuntu: `apt install sqlite3 libsqlite3-dev`).
* protoc: protocol buffers compiler. There is one baked into the
build, so you should not need this unless you are not using
Linux/Mac/Windows.
### Initial Setup ### Initial Setup
Follow these instructions from the root of the repository. Quick initial setup instructions that will set up a development
environment.
Set up database: First, install dependencies by either using the command below (Void
Linux), or reading the "Dependencies Required" section:
``` ```
xbps-install sqlite sqlite-devel protobuf nodejs docker
```
Then run the required `cargo` commands to install management tools and
create a development database:
```
cargo install --version=0.2.0 sqlx-cli cargo install --version=0.2.0 sqlx-cli
cargo install cargo-run-script
cargo run --bin tenebrous-migrate cargo run --bin tenebrous-migrate
``` ```
### Run Application ### Dependencies Required
If you are using `rustup`, then it should automatically switch to the Dependencies required to build the project. The exact installation
stable version of Rust in this repository. This is because of the method depends on your OS.
`rust-toolchain` file.
* sqlite3 and development headers (Void Linux: `xbps-install
sqlite sqlite-devel`, Ubuntu: `apt install sqlite3 libsqlite3-dev`).
* protoc: protocol buffers compiler. Needed to compile protobuf files
for both the server and web frontends (Void Linux: `xbps-install
protobuf`).
* Node and npm: Needed to run webpack for compiling and injecting
Typescript into various web pages (Void Linux: `xbps-install
nodejs`).
* Docker: Needed to run the grpc proxy (Void Linux `xbps-install
docker`).
### Run Application
Command line "instructions" to build and run the application: Command line "instructions" to build and run the application:
``` ```
cargo run-script grpc-proxy # only required if proxy not already running
cargo run cargo run
``` ```
@ -65,4 +90,15 @@ to update the SQLx data JSON file:
cargo sqlx prepare -- --bin tenebrous cargo sqlx prepare -- --bin tenebrous
``` ```
### gRPC-Web Proxy
The frontend web application makes use of the gRPC-Web protocol to
call gPRC endpoints from the browser. This requires a proxy to
translate the calls from the browser to HTTP2 calls gRPC understands.
For development, executing the `cargo run-script grpc-proxy` command
will start the envoy proxy recommended by Google's gRPC-Web project.
The envoy configuration assumes you are on Linux. If you are using Mac
OS or Windows, see the note in the envoy configuration.
[rustup]: https://rust-lang.github.io/rustup/index.html [rustup]: https://rust-lang.github.io/rustup/index.html

24
src/grpc.rs Normal file
View File

@ -0,0 +1,24 @@
use crate::models::proto::cofd::api::cofd_api_server::{CofdApi, CofdApiServer};
use crate::models::proto::cofd::api::UpdateSkillValueRequest;
use crate::models::proto::cofd::cofd_sheet::Skill;
use tonic::{transport::Server, Request, Response, Status};
#[derive(Debug)]
pub struct CofdApiService {
pub db: sqlx::SqlitePool,
}
#[tonic::async_trait]
impl CofdApi for CofdApiService {
async fn update_skill_value(
&self,
request: Request<UpdateSkillValueRequest>, // Accept request of type HelloRequest
) -> Result<Response<Skill>, Status> {
// Return an instance of type HelloReply
println!("Got a request: {:?}", request);
let reply = Skill::default();
Ok(Response::new(reply)) // Send back our formatted greeting
}
}

View File

@ -9,56 +9,36 @@ extern crate rocket_contrib;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
use log::{error, info};
use rocket_contrib::serve::StaticFiles; use rocket_contrib::serve::StaticFiles;
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
use std::env; use std::env;
use tonic::transport::Server;
pub mod catchers; pub mod catchers;
pub mod db; pub mod db;
pub mod errors; pub mod errors;
pub mod grpc;
pub mod migrator; pub mod migrator;
pub mod models; pub mod models;
pub mod routes; pub mod routes;
async fn gin_and_tonic() -> Result<(), Box<dyn std::error::Error>> { async fn make_tonic(db: sqlx::SqlitePool) -> Result<(), Box<dyn std::error::Error>> {
use crate::models::proto::cofd::api::cofd_api_server::{CofdApi, CofdApiServer}; use crate::models::proto::cofd::api::cofd_api_server::CofdApiServer;
use crate::models::proto::cofd::api::UpdateSkillValueRequest;
use crate::models::proto::cofd::cofd_sheet::Skill;
use tonic::{transport::Server, Request, Response, Status};
#[derive(Debug, Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl CofdApi for MyGreeter {
async fn update_skill_value(
&self,
request: Request<UpdateSkillValueRequest>, // Accept request of type HelloRequest
) -> Result<Response<Skill>, Status> {
// Return an instance of type HelloReply
println!("Got a request: {:?}", request);
let reply = Skill::default();
Ok(Response::new(reply)) // Send back our formatted greeting
}
}
let addr = "[::1]:9090".parse()?; let addr = "[::1]:9090".parse()?;
let greeter = MyGreeter::default(); let service = grpc::CofdApiService { db };
println!("Running tonic"); info!("Running Tonic");
Server::builder() Server::builder()
.add_service(CofdApiServer::new(greeter)) .add_service(CofdApiServer::new(service))
.serve(addr) .serve(addr)
.await?; .await?;
println!("ending tonic");
Ok(()) Ok(())
} }
async fn make_rocket(database: sqlx::SqlitePool) -> Result<(), Box<dyn std::error::Error>> { async fn make_rocket(database: sqlx::SqlitePool) -> Result<(), Box<dyn std::error::Error>> {
println!("Running rocket"); info!("Running Rocket");
let root_routes: Vec<rocket::Route> = { let root_routes: Vec<rocket::Route> = {
routes::root::routes() routes::root::routes()
.into_iter() .into_iter()
@ -72,7 +52,6 @@ async fn make_rocket(database: sqlx::SqlitePool) -> Result<(), Box<dyn std::erro
rocket::ignite() rocket::ignite()
.attach(Template::fairing()) .attach(Template::fairing())
//.attach(db::TenebrousDbConn::fairing())
.manage(database) .manage(database)
.mount("/", root_routes) .mount("/", root_routes)
.mount("/characters", character_routes) .mount("/characters", character_routes)
@ -106,15 +85,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
migrator::migrate(db_path).await?; migrator::migrate(db_path).await?;
let db = crate::db::create_pool(db_path).await?; let db = crate::db::create_pool(db_path).await?;
// let tonic = gin_and_tonic();
// let rocket = make_rocket(db);
tokio::select! { tokio::select! {
result = make_rocket(db) => { result = make_rocket(db.clone()) => {
println!("done with rocket: {:?}", result); match result {
Ok(_) => info!("Shutting down Rocket."),
Err(e) => error!("Rocket error: {}", e)
}
}
result = make_tonic(db) => {
match result {
Ok(_) => info!("Shutting down Tonic."),
Err(e) => error!("Tonic error: {}", e)
} }
result = gin_and_tonic() => {
println!("done with tonic: {:?}", result);
} }
} }