add example for integrate with jsonrpsee (#632)
* add example for integrate with jsonrpsee * Update CI
This commit is contained in:
parent
983a16fc41
commit
290d2c5172
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@ -293,7 +293,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
path: [basic, actix_example, actix4_example, axum_example, axum-graphql_example, rocket_example, poem_example]
|
path: [basic, actix_example, actix4_example, axum_example, axum-graphql_example, rocket_example, poem_example, jsonrpsee_example]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
4
examples/jsonrpsee_example/.env
Normal file
4
examples/jsonrpsee_example/.env
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
HOST=127.0.0.1
|
||||||
|
PORT=8000
|
||||||
|
#DATABASE_URL="mysql://root:@localhost/poem_example"
|
||||||
|
DATABASE_URL="sqlite::memory:"
|
21
examples/jsonrpsee_example/Cargo.toml
Normal file
21
examples/jsonrpsee_example/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "sea-orm-jsonrpsee-example"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[workspace]
|
||||||
|
members = [".", "entity", "migration"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
jsonrpsee = { version = "^0.8.0", features = ["full"] }
|
||||||
|
jsonrpsee-core = "0.9.0"
|
||||||
|
tokio = { version = "1.8.0", features = ["full"] }
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
dotenv = "0.15"
|
||||||
|
entity = { path = "entity" }
|
||||||
|
migration = { path = "migration" }
|
||||||
|
anyhow = "1.0.52"
|
||||||
|
async-trait = "0.1.52"
|
||||||
|
log = { version = "0.4", features = ["std"] }
|
||||||
|
simplelog = "*"
|
64
examples/jsonrpsee_example/README.md
Normal file
64
examples/jsonrpsee_example/README.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Poem with SeaORM example app
|
||||||
|
|
||||||
|
1. Modify the `DATABASE_URL` var in `.env` to point to your chosen database
|
||||||
|
|
||||||
|
1. Turn on the appropriate database feature for your chosen db in `entity/Cargo.toml` (the `"sqlx-sqlite",` line)
|
||||||
|
|
||||||
|
1. Execute `cargo run` to start the server
|
||||||
|
|
||||||
|
2. Send jsonrpc request to server
|
||||||
|
|
||||||
|
```shell
|
||||||
|
#insert
|
||||||
|
curl --location --request POST 'http://127.0.0.1:8000' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{"jsonrpc": "2.0", "method": "Post.Insert", "params": [
|
||||||
|
{
|
||||||
|
"id":0,
|
||||||
|
"title":"aaaaaaa",
|
||||||
|
"text":"aaaaaaa"
|
||||||
|
}
|
||||||
|
], "id": 2}'
|
||||||
|
|
||||||
|
#list
|
||||||
|
curl --location --request POST 'http://127.0.0.1:8000' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "Post.List",
|
||||||
|
"params": [
|
||||||
|
1,
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"id": 2
|
||||||
|
}'
|
||||||
|
|
||||||
|
#delete
|
||||||
|
curl --location --request POST 'http://127.0.0.1:8000' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "Post.Delete",
|
||||||
|
"params": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"id": 2
|
||||||
|
}'
|
||||||
|
|
||||||
|
#update
|
||||||
|
curl --location --request POST 'http://127.0.0.1:8000' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "Post.Update",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "1111",
|
||||||
|
"text": "11111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 2
|
||||||
|
}'
|
||||||
|
|
||||||
|
```
|
25
examples/jsonrpsee_example/entity/Cargo.toml
Normal file
25
examples/jsonrpsee_example/entity/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "entity"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "entity"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
|
||||||
|
[dependencies.sea-orm]
|
||||||
|
# path = "../../../" # remove this line in your own project
|
||||||
|
version = "^0.6.0"
|
||||||
|
features = [
|
||||||
|
"macros",
|
||||||
|
"debug-print",
|
||||||
|
"runtime-tokio-native-tls",
|
||||||
|
"sqlx-sqlite",
|
||||||
|
# "sqlx-postgres",
|
||||||
|
# "sqlx-mysql",
|
||||||
|
]
|
||||||
|
default-features = false
|
3
examples/jsonrpsee_example/entity/src/lib.rs
Normal file
3
examples/jsonrpsee_example/entity/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod post;
|
||||||
|
|
||||||
|
pub use sea_orm;
|
17
examples/jsonrpsee_example/entity/src/post.rs
Normal file
17
examples/jsonrpsee_example/entity/src/post.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
||||||
|
#[sea_orm(table_name = "posts")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: i32,
|
||||||
|
pub title: String,
|
||||||
|
#[sea_orm(column_type = "Text")]
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
13
examples/jsonrpsee_example/migration/Cargo.toml
Normal file
13
examples/jsonrpsee_example/migration/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "migration"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "migration"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sea-schema = { version = "^0.5.0", default-features = false, features = [ "migration", "debug-print" ] }
|
||||||
|
entity = { path = "../entity" }
|
37
examples/jsonrpsee_example/migration/README.md
Normal file
37
examples/jsonrpsee_example/migration/README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Running Migrator CLI
|
||||||
|
|
||||||
|
- Apply all pending migrations
|
||||||
|
```sh
|
||||||
|
cargo run
|
||||||
|
```
|
||||||
|
```sh
|
||||||
|
cargo run -- up
|
||||||
|
```
|
||||||
|
- Apply first 10 pending migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- up -n 10
|
||||||
|
```
|
||||||
|
- Rollback last applied migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- down
|
||||||
|
```
|
||||||
|
- Rollback last 10 applied migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- down -n 10
|
||||||
|
```
|
||||||
|
- Drop all tables from the database, then reapply all migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- fresh
|
||||||
|
```
|
||||||
|
- Rollback all applied migrations, then reapply all migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- refresh
|
||||||
|
```
|
||||||
|
- Rollback all applied migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- reset
|
||||||
|
```
|
||||||
|
- Check the status of all migrations
|
||||||
|
```sh
|
||||||
|
cargo run -- status
|
||||||
|
```
|
12
examples/jsonrpsee_example/migration/src/lib.rs
Normal file
12
examples/jsonrpsee_example/migration/src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
pub use sea_schema::migration::prelude::*;
|
||||||
|
|
||||||
|
mod m20220120_000001_create_post_table;
|
||||||
|
|
||||||
|
pub struct Migrator;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigratorTrait for Migrator {
|
||||||
|
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||||
|
vec![Box::new(m20220120_000001_create_post_table::Migration)]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
use entity::post::*;
|
||||||
|
use sea_schema::migration::prelude::*;
|
||||||
|
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
impl MigrationName for Migration {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"m20220120_000001_create_post_table"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(Entity)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Column::Id)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(Column::Title).string().not_null())
|
||||||
|
.col(ColumnDef::new(Column::Text).string().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Entity).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
7
examples/jsonrpsee_example/migration/src/main.rs
Normal file
7
examples/jsonrpsee_example/migration/src/main.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use migration::Migrator;
|
||||||
|
use sea_schema::migration::*;
|
||||||
|
|
||||||
|
#[async_std::main]
|
||||||
|
async fn main() {
|
||||||
|
cli::run_cli(Migrator).await;
|
||||||
|
}
|
149
examples/jsonrpsee_example/src/main.rs
Normal file
149
examples/jsonrpsee_example/src/main.rs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
use std::env;
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use entity::post;
|
||||||
|
use entity::sea_orm;
|
||||||
|
use jsonrpsee::core::{async_trait, RpcResult};
|
||||||
|
use jsonrpsee::http_server::HttpServerBuilder;
|
||||||
|
use jsonrpsee::proc_macros::rpc;
|
||||||
|
use jsonrpsee::types::error::CallError;
|
||||||
|
use log::info;
|
||||||
|
use migration::{Migrator, MigratorTrait};
|
||||||
|
use sea_orm::NotSet;
|
||||||
|
use sea_orm::{entity::*, query::*, DatabaseConnection};
|
||||||
|
use simplelog::*;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use tokio::signal::ctrl_c;
|
||||||
|
use tokio::signal::unix::{signal, SignalKind};
|
||||||
|
|
||||||
|
const DEFAULT_POSTS_PER_PAGE: usize = 5;
|
||||||
|
|
||||||
|
#[rpc(server, client)]
|
||||||
|
pub trait PostRpc {
|
||||||
|
#[method(name = "Post.List")]
|
||||||
|
async fn list(
|
||||||
|
&self,
|
||||||
|
page: Option<usize>,
|
||||||
|
posts_per_page: Option<usize>,
|
||||||
|
) -> RpcResult<Vec<post::Model>>;
|
||||||
|
|
||||||
|
#[method(name = "Post.Insert")]
|
||||||
|
async fn insert(&self, p: post::Model) -> RpcResult<i32>;
|
||||||
|
|
||||||
|
#[method(name = "Post.Update")]
|
||||||
|
async fn update(&self, p: post::Model) -> RpcResult<bool>;
|
||||||
|
|
||||||
|
#[method(name = "Post.Delete")]
|
||||||
|
async fn delete(&self, id: i32) -> RpcResult<bool>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PpcImpl {
|
||||||
|
conn: DatabaseConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl PostRpcServer for PpcImpl {
|
||||||
|
async fn list(
|
||||||
|
&self,
|
||||||
|
page: Option<usize>,
|
||||||
|
posts_per_page: Option<usize>,
|
||||||
|
) -> RpcResult<Vec<post::Model>> {
|
||||||
|
let page = page.unwrap_or(1);
|
||||||
|
let posts_per_page = posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE);
|
||||||
|
let paginator = post::Entity::find()
|
||||||
|
.order_by_asc(post::Column::Id)
|
||||||
|
.paginate(&self.conn, posts_per_page);
|
||||||
|
paginator.fetch_page(page - 1).await.internal_call_error()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn insert(&self, p: post::Model) -> RpcResult<i32> {
|
||||||
|
let active_post = post::ActiveModel {
|
||||||
|
id: NotSet,
|
||||||
|
title: Set(p.title),
|
||||||
|
text: Set(p.text),
|
||||||
|
};
|
||||||
|
let new_post = active_post.insert(&self.conn).await.internal_call_error()?;
|
||||||
|
Ok(new_post.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update(&self, p: post::Model) -> RpcResult<bool> {
|
||||||
|
let update_post = post::ActiveModel {
|
||||||
|
id: Set(p.id),
|
||||||
|
title: Set(p.title),
|
||||||
|
text: Set(p.text),
|
||||||
|
};
|
||||||
|
update_post
|
||||||
|
.update(&self.conn)
|
||||||
|
.await
|
||||||
|
.map(|_| true)
|
||||||
|
.internal_call_error()
|
||||||
|
}
|
||||||
|
async fn delete(&self, id: i32) -> RpcResult<bool> {
|
||||||
|
let post = post::Entity::find_by_id(id)
|
||||||
|
.one(&self.conn)
|
||||||
|
.await
|
||||||
|
.internal_call_error()?;
|
||||||
|
|
||||||
|
post.unwrap()
|
||||||
|
.delete(&self.conn)
|
||||||
|
.await
|
||||||
|
.map(|res| res.rows_affected == 1)
|
||||||
|
.internal_call_error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoJsonRpcResult<T> {
|
||||||
|
fn internal_call_error(self) -> RpcResult<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> IntoJsonRpcResult<T> for Result<T, E>
|
||||||
|
where
|
||||||
|
E: Display,
|
||||||
|
{
|
||||||
|
fn internal_call_error(self) -> RpcResult<T> {
|
||||||
|
self.map_err(|e| jsonrpsee::core::Error::Call(CallError::Failed(anyhow!("{}", e))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> std::io::Result<()> {
|
||||||
|
let _ = TermLogger::init(
|
||||||
|
LevelFilter::Trace,
|
||||||
|
Config::default(),
|
||||||
|
TerminalMode::Mixed,
|
||||||
|
ColorChoice::Auto,
|
||||||
|
);
|
||||||
|
|
||||||
|
// get env vars
|
||||||
|
dotenv::dotenv().ok();
|
||||||
|
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set in .env file");
|
||||||
|
let host = env::var("HOST").expect("HOST is not set in .env file");
|
||||||
|
let port = env::var("PORT").expect("PORT is not set in .env file");
|
||||||
|
let server_url = format!("{}:{}", host, port);
|
||||||
|
|
||||||
|
// create post table if not exists
|
||||||
|
let conn = sea_orm::Database::connect(&db_url).await.unwrap();
|
||||||
|
Migrator::up(&conn, None).await.unwrap();
|
||||||
|
|
||||||
|
let server = HttpServerBuilder::default()
|
||||||
|
.build(server_url.parse::<SocketAddr>().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let rpc_impl = PpcImpl { conn };
|
||||||
|
let server_addr = server.local_addr().unwrap();
|
||||||
|
let handle = server.start(rpc_impl.into_rpc()).unwrap();
|
||||||
|
|
||||||
|
info!("starting listening {}", server_addr);
|
||||||
|
let mut sig_int = signal(SignalKind::interrupt()).unwrap();
|
||||||
|
let mut sig_term = signal(SignalKind::terminate()).unwrap();
|
||||||
|
|
||||||
|
tokio::select! {
|
||||||
|
_ = sig_int.recv() => info!("receive SIGINT"),
|
||||||
|
_ = sig_term.recv() => info!("receive SIGTERM"),
|
||||||
|
_ = ctrl_c() => info!("receive Ctrl C"),
|
||||||
|
}
|
||||||
|
handle.stop().unwrap();
|
||||||
|
info!("Shutdown program");
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user