Add Target: Rust

This commit is contained in:
Fabian Stamm
2022-07-16 21:22:16 +00:00
parent 71a6e3f2e0
commit 96d2d9ee76
13 changed files with 1118 additions and 4 deletions

2
templates/Rust/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
target
Cargo.lock

15
templates/Rust/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "__name__"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
int-enum = "0.4.0"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
threadpool = "1.8.1"
nanoid = "0.4.0"

286
templates/Rust/src/lib.rs Normal file
View File

@ -0,0 +1,286 @@
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::boxed::Box;
use std::collections::HashMap;
use std::error::Error;
use std::marker::PhantomData;
use std::marker::Send;
use std::sync::mpsc::{Receiver, Sender};
use std::sync::{Arc, Mutex};
use threadpool::ThreadPool;
pub type Result<T> = std::result::Result<T, Box<dyn Error>>;
// TODO: Check what happens when error code is not included
// #[repr(i64)]
// #[derive(Clone, Copy, Debug, Eq, PartialEq, IntEnum, Deserialize, Serialize)]
// pub enum ErrorCodes {
// ParseError = -32700,
// InvalidRequest = -32600,
// MethodNotFound = -32601,
// InvalidParams = -32602,
// InternalError = -32603,
// }
#[derive(Serialize, Deserialize)]
pub struct JRPCRequest {
pub jsonrpc: String,
pub id: Option<String>,
pub method: String,
pub params: Value,
}
#[derive(Serialize, Deserialize)]
pub struct JRPCError {
pub code: i64,
pub message: String,
pub data: Value,
}
#[derive(Serialize, Deserialize)]
pub struct JRPCResult {
pub jsonrpc: String,
pub id: String,
pub result: Value,
pub error: Option<JRPCError>,
}
// ******************************************************************************
// * SERVER
// ******************************************************************************
pub trait JRPCServiceHandler<C: Sync>: Send {
fn get_name(&self) -> String;
fn on_message(&self, msg: JRPCRequest, function: String, ctx: &C) -> Result<(bool, Value)>;
}
type Shared<T> = Arc<Mutex<T>>;
type SharedHM<K, V> = Shared<HashMap<K, V>>;
type ServiceSharedHM<C> = SharedHM<String, Box<dyn JRPCServiceHandler<C>>>;
type SharedThreadPool = Shared<ThreadPool>;
pub struct JRPCServer<CTX: 'static + Sync + Send + Copy> {
services: ServiceSharedHM<CTX>,
pool: SharedThreadPool,
}
impl<CTX: 'static + Sync + Send + Copy> JRPCServer<CTX> {
pub fn new() -> Self {
return Self {
services: Arc::new(Mutex::new(HashMap::new())),
pool: Arc::new(Mutex::new(ThreadPool::new(32))),
};
}
pub fn add_service(&mut self, service: Box<dyn JRPCServiceHandler<CTX>>) {
let mut services = self.services.lock().unwrap();
services.insert(service.get_name(), service);
}
pub fn start_session(
&mut self,
read_ch: Receiver<String>,
write_ch: Sender<String>,
context: CTX,
) {
let services = self.services.clone();
let p = self.pool.lock().unwrap();
let pool = self.pool.clone();
p.execute(move || {
JRPCSession::start(read_ch, write_ch, context, services, pool);
});
}
}
pub struct JRPCSession<CTX: 'static + Sync + Send + Copy> {
_ctx: PhantomData<CTX>,
}
unsafe impl<CTX: 'static + Sync + Send + Copy> Sync for JRPCSession<CTX> {}
impl<CTX: 'static + Sync + Send + Copy> JRPCSession<CTX> {
fn start(
read_ch: Receiver<String>,
write_ch: Sender<String>,
context: CTX,
services: ServiceSharedHM<CTX>,
pool: SharedThreadPool,
) {
loop {
let pkg = read_ch.recv();
let data = match pkg {
Err(_) => return,
Ok(res) => res,
};
if data.len() == 0 {
//TODO: This can be done better
return;
}
let ctx = context.clone();
let svs = services.clone();
let wc = write_ch.clone();
pool.lock().unwrap().execute(move || {
JRPCSession::handle_packet(data, wc, ctx, svs);
})
}
}
fn handle_packet(
data: String,
write_ch: Sender<String>,
context: CTX,
services: ServiceSharedHM<CTX>,
) {
let req: Result<JRPCRequest> =
serde_json::from_str(data.as_str()).map_err(|err| Box::from(err));
let req = match req {
Err(_) => {
return;
}
Ok(parsed) => parsed,
};
let req_id = req.id.clone();
let mut parts: Vec<String> = req.method.splitn(2, '.').map(|e| e.to_owned()).collect();
if parts.len() != 2 {
return Self::send_err_res(req_id, write_ch, Box::from("Error".to_owned()));
}
let service = parts.remove(0);
let function = parts.remove(0);
let svs = services.lock().unwrap();
let srv = svs.get(&service);
if let Some(srv) = srv {
match srv.on_message(req, function, &context) {
Ok((is_send, value)) => {
if is_send {
if let Some(id) = req_id {
let r = JRPCResult {
jsonrpc: "2.0".to_owned(),
id,
result: value,
error: None,
};
let s = serde_json::to_string(&r);
if s.is_ok() {
write_ch
.send(s.unwrap())
.expect("Sending data into channel failed!");
}
}
}
}
Err(err) => return Self::send_err_res(req_id, write_ch, err),
}
}
}
fn send_err_res(id: Option<String>, write_ch: Sender<String>, err: Box<dyn Error>) {
if let Some(id) = id {
let error = JRPCError {
code: 0, //TODO: Make this better?
message: err.to_string(),
data: Value::Null,
};
let r = JRPCResult {
jsonrpc: "2.0".to_owned(),
id: id.clone(),
result: Value::Null,
error: Option::from(error),
};
let s = serde_json::to_string(&r);
if s.is_ok() {
write_ch
.send(s.unwrap())
.expect("Sending data into channel failed!");
}
}
return ();
}
}
// ******************************************************************************
// * CLIENT
// ******************************************************************************
#[derive(Clone)]
pub struct JRPCClient {
write_ch: Sender<String>,
requests: SharedHM<String, Sender<Result<Value>>>,
}
unsafe impl Send for JRPCClient {} //TODO: Is this a problem
impl JRPCClient {
pub fn new(write_ch: Sender<String>, read_ch: Receiver<String>) -> Self {
let n = Self {
write_ch,
requests: Arc::new(Mutex::new(HashMap::new())),
};
n.start(read_ch);
return n;
}
pub fn start(&self, read_ch: Receiver<String>) {
let s = self.clone();
std::thread::spawn(move || {
s.start_reader(read_ch);
});
}
fn start_reader(&self, read_ch: Receiver<String>) {
loop {
let data = read_ch.recv().expect("Error receiving packet!");
let response: JRPCResult =
serde_json::from_str(data.as_str()).expect("Error decoding response!");
let id = response.id;
let reqs = self.requests.lock().expect("Error locking requests map!");
let req = reqs.get(&id);
if let Some(req) = req {
let res = if let Some(err) = response.error {
Err(Box::from(err.message))
} else {
Ok(response.result)
};
req.send(res).expect("Error sending reponse!");
}
}
}
pub fn send_request(&self, mut req: JRPCRequest) -> Result<Value> {
let mut reqs = self.requests.lock().expect("Error locking requests map!");
let id = nanoid!();
req.id = Some(id.clone());
let (tx, rx) = std::sync::mpsc::channel();
reqs.insert(id, tx);
self
.write_ch
.send(serde_json::to_string(&req).expect("Error converting Request to JSON!"))
.expect("Error Sending to Channel!");
return rx.recv().expect("Error getting response!");
}
pub fn send_notification(&self, mut req: JRPCRequest) {
req.id = None;
self
.write_ch
.send(serde_json::to_string(&req).expect("Error converting Request to JSON!"))
.expect("Error Sending to Channel!");
}
}