Add Target: Rust
This commit is contained in:
2
templates/Rust/.gitignore
vendored
Normal file
2
templates/Rust/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
15
templates/Rust/Cargo.toml
Normal file
15
templates/Rust/Cargo.toml
Normal 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
286
templates/Rust/src/lib.rs
Normal 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!");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user