forked from SeaQL/sea-orm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib.rs
145 lines (122 loc) · 4.11 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::env;
use entity::post;
use jsonrpsee::core::{async_trait, RpcResult};
use jsonrpsee::proc_macros::rpc;
use jsonrpsee::server::ServerBuilder;
use jsonrpsee::types::error::ErrorObjectOwned;
use jsonrpsee_example_service::sea_orm::{Database, DatabaseConnection};
use jsonrpsee_example_service::{Mutation, Query};
use log::info;
use migration::{Migrator, MigratorTrait};
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: u64 = 5;
#[rpc(server, client)]
trait PostRpc {
#[method(name = "Post.List")]
async fn list(
&self,
page: Option<u64>,
posts_per_page: Option<u64>,
) -> 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>;
}
struct PpcImpl {
conn: DatabaseConnection,
}
#[async_trait]
impl PostRpcServer for PpcImpl {
async fn list(
&self,
page: Option<u64>,
posts_per_page: Option<u64>,
) -> RpcResult<Vec<post::Model>> {
let page = page.unwrap_or(1);
let posts_per_page = posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE);
Query::find_posts_in_page(&self.conn, page, posts_per_page)
.await
.map(|(p, _)| p)
.internal_call_error()
}
async fn insert(&self, p: post::Model) -> RpcResult<i32> {
let new_post = Mutation::create_post(&self.conn, p)
.await
.internal_call_error()?;
Ok(new_post.id.unwrap())
}
async fn update(&self, p: post::Model) -> RpcResult<bool> {
Mutation::update_post_by_id(&self.conn, p.id, p)
.await
.map(|_| true)
.internal_call_error()
}
async fn delete(&self, id: i32) -> RpcResult<bool> {
Mutation::delete_post(&self.conn, id)
.await
.map(|res| res.rows_affected == 1)
.internal_call_error()
}
}
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> {
// Err(ErrorObjectOwned::owned(1, "c", None::<()>))
// self.map_err(|e| jsonrpsee::core::Error::Call(CallError::Failed(anyhow!("{}", e))))
self.map_err(|e| ErrorObjectOwned::owned(1, format!("{}", e), None::<()>))
}
}
#[tokio::main]
async fn start() -> std::io::Result<()> {
let _ = TermLogger::init(
LevelFilter::Trace,
Config::default(),
TerminalMode::Mixed,
ColorChoice::Auto,
);
// get env vars
dotenvy::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 = Database::connect(&db_url).await.unwrap();
Migrator::up(&conn, None).await.unwrap();
let server = ServerBuilder::default()
.build(server_url.parse::<SocketAddr>().unwrap())
.await
.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(())
}
pub fn main() {
let result = start();
if let Some(err) = result.err() {
println!("Error: {err}");
}
}