Browse Source

Merge pull request #10 from joshsulin/sulin-12

上传昨天晚上公开课内容
pull/11/head
joshsulin 3 years ago
committed by GitHub
parent
commit
bd5d1a4222
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. BIN
      .DS_Store
  2. BIN
      12-初探Rust微服务架构(gRPC+Tonic)/.DS_Store
  3. BIN
      12-初探Rust微服务架构(gRPC+Tonic)/12-初探Rust微服务架构(gRPC+Tonic).pdf
  4. BIN
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/.DS_Store
  5. 26
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/Cargo.toml
  6. 5
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/build.rs
  7. 14
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/proto/shortlink.proto
  8. 1
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/controllers/mod.rs
  9. 87
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/controllers/shortlink_controller.rs
  10. 2
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/mod.rs
  11. 27
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/models/dto.rs
  12. 2
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/models/mod.rs
  13. 41
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/models/shortlink.rs
  14. 16
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/database.rs
  15. 26
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/env.rs
  16. 3
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/mod.rs
  17. 29
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/routes.rs
  18. 16
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/main.rs
  19. 42
      12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/server.rs
  20. BIN
      12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/.DS_Store
  21. 22
      12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/Cargo.toml
  22. 4
      12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/build.rs
  23. 14
      12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/proto/helloworld.proto
  24. 20
      12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/src/client.rs
  25. 9
      12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/src/main.rs
  26. 40
      12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/src/server.rs

BIN
.DS_Store

Binary file not shown.

BIN
12-初探Rust微服务架构(gRPC+Tonic)/.DS_Store

Binary file not shown.

BIN
12-初探Rust微服务架构(gRPC+Tonic)/12-初探Rust微服务架构(gRPC+Tonic).pdf

Binary file not shown.

BIN
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/.DS_Store

Binary file not shown.

26
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/Cargo.toml

@ -0,0 +1,26 @@
[package]
name = "api-service-demo"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]] # 用来运行 HelloWorld gRPC 服务器的可执行文件
name = "shortlink-server"
path = "src/server.rs"
[dependencies]
tonic = "0.5"
prost = "0.8"
axum = { version = "0.2.3" }
sqlx = { version = "0.5.6", features = ["mysql", "runtime-tokio-rustls"] }
tokio = { version = "1.11.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
tower = { version = "0.4", features = ["util", "timeout"] }
tower-http = { version = "0.1", features = ["add-extension", "trace"] }
uuid = { version = "0.8.2", features = ["serde", "v4"] }
anyhow = "1.0.44"
redis = { version = "0.21", features = ["tokio-comp", "aio"] }
[build-dependencies]
tonic-build = "0.5"

5
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/build.rs

@ -0,0 +1,5 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("======");
tonic_build::compile_protos("proto/shortlink.proto")?;
Ok(())
}

14
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/proto/shortlink.proto

@ -0,0 +1,14 @@
syntax = "proto3";
package shortlink;
service ShortLink {
rpc GetInfo(ShortLinkRequest) returns (ShortLinkReply);
}
message ShortLinkRequest {
int32 id = 1;
}
message ShortLinkReply {
string url = 1;
}

1
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/controllers/mod.rs

@ -0,0 +1 @@
pub mod shortlink_controller;

87
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/controllers/shortlink_controller.rs

@ -0,0 +1,87 @@
use axum::{Json, extract};
use crate::app::models::dto;
use axum::extract::Extension;
use axum::response::IntoResponse;
use axum::http::{StatusCode, HeaderMap, Request};
use crate::app::models::shortlink;
use sqlx::{Pool, MySql};
use axum::http::header::LOCATION;
use axum::body::Body;
use redis::{Client, AsyncCommands, RedisResult};
use redis::aio::Connection;
use std::sync::Arc;
use tokio::sync::{RwLock, Mutex};
use std::ops::Deref;
pub async fn create_shortlink(
Json(req): Json<dto::CreateShortLinkReq>,
Extension(pool): Extension<Pool<MySql>>
) -> impl IntoResponse {
println!("{:#?}", req);
match shortlink::create_shortlink(&pool, &req.url).await {
Ok(_) => {
(StatusCode::OK, Json(dto::CreateUserResp {
ok: true
}))
}
Err(_) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(dto::CreateUserResp {
ok: false
}))
}
}
}
pub async fn delete_shortlink(
Json(req): Json<dto::DeleteShortLinkReq>,
Extension(pool): Extension<Pool<MySql>>,
) -> impl IntoResponse {
println!("{:#?}", req);
match shortlink::delete_shortlink(&pool, req.id).await {
Ok(_) => {
(StatusCode::OK, Json(dto::DeleteShortLinkResp {
ok: true
}))
}
Err(_) => {
(StatusCode::INTERNAL_SERVER_ERROR, Json(dto::DeleteShortLinkResp {
ok: false
}))
}
}
}
pub async fn get_shortlink(
extract::Path(id): extract::Path<i32>,
req: Request<Body>
) -> impl IntoResponse {
let mut url = String::from("/api/not_found");
//let pool = req.extensions().get::<Pool<MySql>>().unwrap();
let mut con = req.extensions().get::<Arc<Mutex<Connection>>>().unwrap().lock().await;
let mut redis_key = String::from("url_");
redis_key.push_str(&*id.to_string());
let res: RedisResult<String> = con.get(redis_key).await;
match res {
Ok(v) => {
url = v;
}
Err(err) => {
println!("err = {:#?}", err);
}
}
// match shortlink::get_shortlink(pool, id).await {
// Ok(record) => {
// url = Box::leak(record.url.into_boxed_str());
// }
// Err(err) => {
// println!("err = {:#?}", err);
// }
// }
let mut headers = HeaderMap::new();
headers.insert(LOCATION, url.parse().unwrap());
(StatusCode::FOUND, headers, ())
}
pub async fn not_found() -> impl IntoResponse {
(StatusCode::OK, "404 Not Found")
}

2
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/mod.rs

@ -0,0 +1,2 @@
pub mod controllers;
pub mod models;

27
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/models/dto.rs

@ -0,0 +1,27 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CreateShortLinkReq {
pub url: String
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CreateUserResp {
pub ok: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct DeleteShortLinkReq {
pub id: u64,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct DeleteShortLinkResp {
pub ok: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ShortLinkInfoResp {
pub id: u32,
pub url: String
}

2
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/models/mod.rs

@ -0,0 +1,2 @@
pub mod shortlink;
pub mod dto;

41
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/app/models/shortlink.rs

@ -0,0 +1,41 @@
use sqlx::{Error, MySql, Pool, FromRow};
use sqlx::mysql::MySqlQueryResult;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, FromRow, Clone)]
pub struct ShortLink {
pub id: u32,
pub url: String,
}
pub async fn create_shortlink(pool: &Pool<MySql>, url: &str) -> Result<MySqlQueryResult, Error> {
sqlx::query(
r#"
INSERT INTO short_links (`url`)
VALUES(?)"#,
)
.bind(url)
.execute(pool).await
}
pub async fn delete_shortlink(pool: &Pool<MySql>, id: u64) -> Result<MySqlQueryResult, Error> {
sqlx::query(
r#"
DELETE FROM short_links
WHERE id = ?
"#,
)
.bind(id)
.execute(pool).await
}
// pub async fn get_shortlink(pool: &Pool<MySql>, id: i32) -> Result<ShortLink, Error> {
// sqlx::query_as::<_, ShortLink>(
// r#"
// SELECT * FROM short_links
// WHERE id = ?
// "#,
// )
// .bind(id)
// .fetch_one(pool).await
// }

16
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/database.rs

@ -0,0 +1,16 @@
use sqlx::mysql::MySqlPoolOptions;
use sqlx::{MySql, Pool};
use redis::Client;
use redis::aio::Connection;
pub async fn do_connect() -> Pool<MySql> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:jkxsl12369@127.0.0.1/shorten_db").await;
pool.unwrap()
}
pub async fn do_redis_connect() -> Connection {
let client = redis::Client::open("redis://127.0.0.1/").unwrap();
client.get_async_connection().await.unwrap()
}

26
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/env.rs

@ -0,0 +1,26 @@
// use sqlx::{Pool, MySql};
// use redis::aio::Connection;
// use std::sync::Arc;
//
// #[derive(Clone, Debug)]
// pub struct Environment {
// mysql_conn: Pool<MySql>,
// redis_conn: Arc::new<Connection>
// }
//
// impl Environment {
// pub async fn new(mysql_conn: Pool<MySql>, redis_conn: Arc::new<Connection>) -> anyhow::Result<Self> {
// Ok(Self {
// mysql_conn,
// redis_conn
// })
// }
//
// pub fn db(self) -> Pool<MySql> {
// self.mysql_conn
// }
//
// pub fn clients(self) -> Arc::new<Connection> {
// self.redis_conn
// }
// }

3
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/mod.rs

@ -0,0 +1,3 @@
pub mod routes;
pub mod database;
pub mod env;

29
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/config/routes.rs

@ -0,0 +1,29 @@
use axum::handler::{post, get};
use axum::{Router, AddExtensionLayer};
use axum::routing::BoxRoute;
use redis::Client;
use crate::app::controllers::shortlink_controller;
use sqlx::{Pool, MySql};
use redis::aio::Connection;
use std::sync::Arc;
use tokio::sync::{RwLock, Mutex};
pub fn app(pool: Pool<MySql>, redis_client: Connection) -> Router<BoxRoute> {
Router::new()
.route("/", get(|| async { "welcome to use axum!" }))
.nest("/api", short_links())
.layer(AddExtensionLayer::new(pool))
.layer(AddExtensionLayer::new(Arc::new(Mutex::new(redis_client))))
.layer(tower_http::trace::TraceLayer::new_for_http())
.boxed()
}
pub fn short_links() -> Router<BoxRoute> {
Router::new()
.route("/create_shortlink", post(shortlink_controller::create_shortlink))
.route("/delete_shortlink", post(shortlink_controller::delete_shortlink))
.route("/:id", get(shortlink_controller::get_shortlink))
.route("/not_found", get(shortlink_controller::not_found))
.boxed()
}

16
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/main.rs

@ -0,0 +1,16 @@
use std::error::Error;
use std::net::SocketAddr;
mod config;
mod app;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
let pool = config::database::do_connect().await;
let redis_client = config::database::do_redis_connect().await;
axum::Server::bind(&addr)
.serve(config::routes::app(pool, redis_client).into_make_service())
.await?;
Ok(())
}

42
12-初探Rust微服务架构(gRPC+Tonic)/api-service-demo/src/server.rs

@ -0,0 +1,42 @@
use tonic::{transport::Server, Request, Response, Status};
use short_link::short_link_server::{ShortLink, ShortLinkServer};
use short_link::{ShortLinkReply, ShortLinkRequest};
pub mod short_link {
tonic::include_proto!("shortlink");
}
#[derive(Debug, Default)]
pub struct MyShortLink {}
#[tonic::async_trait]
impl ShortLink for MyShortLink {
async fn get_info(
&self,
request: Request<ShortLinkRequest>,
) -> Result<Response<ShortLinkReply>, Status> {
println!("Got a request: {:?}", request);
// todo: 需要实现根据request.id来查询数据库和读redis, 这些都是上次公开课说过的, 所以就不写了
let reply = short_link::ShortLinkReply {
url: String::from("http://www.baidu.com"),
};
Ok(Response::new(reply))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50052".parse()?;
let shortlink = MyShortLink::default();
Server::builder()
.add_service(ShortLinkServer::new(shortlink))
.serve(addr)
.await?;
Ok(())
}

BIN
12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/.DS_Store

Binary file not shown.

22
12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/Cargo.toml

@ -0,0 +1,22 @@
[package]
name = "helloworld-tonic"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]] # 用来运行 HelloWorld gRPC 服务器的可执行文件
name = "helloworld-server"
path = "src/server.rs"
[[bin]] # 用来运行 HelloWorld gRPC 客户端的可执行文件
name = "helloworld-client"
path = "src/client.rs"
[dependencies]
tonic = "0.5"
prost = "0.8"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
[build-dependencies]
tonic-build = "0.5"

4
12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/build.rs

@ -0,0 +1,4 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::compile_protos("proto/helloworld.proto")?;
Ok(())
}

14
12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/proto/helloworld.proto

@ -0,0 +1,14 @@
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello(HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}

20
12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/src/client.rs

@ -0,0 +1,20 @@
use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
pub mod hello_world {
tonic::include_proto!("helloworld");
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
let request = tonic::Request::new(HelloRequest {
name: "Tonic".into(),
});
let response = client.say_hello(request).await?;
println!("RESPONSE={:?}", response);
Ok(())
}

9
12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/src/main.rs

@ -0,0 +1,9 @@
// fn main() -> Result<(), Box<dyn std::error::Error>> {
// tonic_build::configure()
// .build_server(false)
// .compile(
// &["proto/helloworld/helloworld.proto"],
// &["proto/helloworld"],
// )?;
// Ok(())
// }

40
12-初探Rust微服务架构(gRPC+Tonic)/helloworld-tonic/src/server.rs

@ -0,0 +1,40 @@
use tonic::{transport::Server, Request, Response, Status};
use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};
pub mod hello_world {
tonic::include_proto!("helloworld");
}
#[derive(Debug, Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
println!("Got a request: {:?}", request);
let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name).into(),
};
Ok(Response::new(reply))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse()?;
let greeter = MyGreeter::default();
Server::builder()
.add_service(GreeterServer::new(greeter))
.serve(addr)
.await?;
Ok(())
}
Loading…
Cancel
Save