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
|
||||
matrix:
|
||||
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:
|
||||
- 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