Server code
This commit is contained in:
1 parent
4c2cd7130b
commit
ec73c54276
6 files changed
+213
-47
No files matched your search
Generated
+7
@@ -170,6 +170,12 @@ dependencies = [
|
|||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "litemap"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.34"
|
version = "0.4.34"
|
||||||
@@ -261,6 +267,7 @@ name = "remote_marks"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"litemap",
|
||||||
"log",
|
"log",
|
||||||
"minicbor",
|
"minicbor",
|
||||||
]
|
]
|
||||||
|
|||||||
+2
-1
@@ -6,4 +6,5 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.11.11"
|
env_logger = "0.11.11"
|
||||||
log = "0.4.34"
|
log = "0.4.34"
|
||||||
minicbor = "2.3.0"
|
minicbor = "2.3.0"
|
||||||
|
litemap = "0.8.3"
|
||||||
+39
-7
@@ -1,15 +1,47 @@
|
|||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
use std::any::Any;
|
use crate::server::{Command, NoteContext};
|
||||||
use std::collections::HashMap;
|
use std::io;
|
||||||
|
use std::io::Read;
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
|
use std::sync::mpsc::*;
|
||||||
|
|
||||||
const LISTEN: &str = "127.0.0.1:8080";
|
const LISTEN: &str = "127.0.0.1:8080";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let listener = UdpSocket::bind(LISTEN).unwrap();
|
let (cw, cr) = channel::<Command>();
|
||||||
let mut buffer = [0; 1024];
|
|
||||||
while let Ok((inbound, outbound)) = listener.recv_from(&mut buffer) {}
|
std::thread::spawn(move || {
|
||||||
|
let mut context = NoteContext::default();
|
||||||
|
while let Ok(message) = cr.recv() {
|
||||||
|
context.execute_command(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let network_cw = cw.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let listener = UdpSocket::bind(LISTEN).unwrap();
|
||||||
|
let mut buffer = [0; 1024];
|
||||||
|
while let Ok((inbound, _outbound)) = listener.recv_from(&mut buffer) {
|
||||||
|
let command= Command::from(&buffer[..inbound]);
|
||||||
|
network_cw.send(command).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
handle_console_input(cw);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_console_input(command_channel: Sender<Command>) {
|
||||||
|
let mut key = String::new();
|
||||||
|
loop {
|
||||||
|
io::stdin().read_to_string(&mut key).unwrap();
|
||||||
|
if key == "exit" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if key.is_empty(){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_channel.send(Command::Display(key.clone())).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
use crate::server::StoredData::*;
|
||||||
|
use crate::server::{Command, NoteContext, StoredData};
|
||||||
|
use litemap::LiteMap;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::string::String;
|
||||||
|
|
||||||
|
impl NoteContext {
|
||||||
|
pub fn execute_command(&mut self, command: Command) {
|
||||||
|
match command {
|
||||||
|
Command::Unknown => {}
|
||||||
|
Command::Set(key, value) => self.set(key, value),
|
||||||
|
Command::Define(key, schema) => self.define(key, schema),
|
||||||
|
Command::Push(key, value) => self.push(key, value),
|
||||||
|
Command::Display(key) => self.display(key),
|
||||||
|
Command::SetOutput(generator) => self.output = generator(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, key: String, value: StoredData) {
|
||||||
|
if key.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.entries.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, key: String, value: StoredData) {
|
||||||
|
let mut vectorize: Option<StoredData> = None;
|
||||||
|
let current = self.entries.get_mut(&key);
|
||||||
|
if let Some(current) = current {
|
||||||
|
if let Vec(vec) = current {
|
||||||
|
vec.push(value);
|
||||||
|
} else {
|
||||||
|
vectorize = Some(Vec(vec![current.clone()]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.set(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(vec) = vectorize {
|
||||||
|
self.set(key, vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn define(&mut self, _key: String, _value: LiteMap<String, StoredData>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(&mut self, key: String) {
|
||||||
|
if let Some(data) = self.entries.get(&key) {
|
||||||
|
writeln!(self.output, "{}", key).unwrap();
|
||||||
|
_ = self.output.write_all(data.to_string().as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+105
-39
@@ -1,29 +1,73 @@
|
|||||||
use minicbor::decode::Error;
|
mod handling;
|
||||||
|
mod testing;
|
||||||
|
|
||||||
|
use litemap::LiteMap;
|
||||||
use minicbor::Decoder;
|
use minicbor::Decoder;
|
||||||
use std::any::Any;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
|
||||||
use minicbor::data::Type;
|
use minicbor::data::Type;
|
||||||
|
use minicbor::decode::Error;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::{Display, Formatter };
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
enum Command {
|
pub enum Command {
|
||||||
Unknown,
|
Unknown,
|
||||||
Set(String, Box<dyn Display>),
|
Set(String, StoredData),
|
||||||
Push(String, Box<dyn Display>),
|
Define(String, LiteMap<String, StoredData>),
|
||||||
|
Push(String, StoredData),
|
||||||
|
Display(String),
|
||||||
|
SetOutput(fn() -> Box<dyn Write>),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Line{
|
#[derive(Clone)]
|
||||||
data: Vec<Box<dyn Display>>,
|
pub enum StoredData {
|
||||||
|
Integer(isize),
|
||||||
|
Float(f64),
|
||||||
|
String(String),
|
||||||
|
Bool(bool),
|
||||||
|
Line(Line),
|
||||||
|
Vec(Vec<StoredData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<Box<dyn Display>>> for Line {
|
impl Display for StoredData {
|
||||||
fn from(value: Vec<Box<dyn Display>>) -> Self {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
Self{data: value}
|
match self {
|
||||||
|
StoredData::Integer(v) => v.fmt(f),
|
||||||
|
StoredData::Float(v) => v.fmt(f),
|
||||||
|
StoredData::String(v) => v.fmt(f),
|
||||||
|
StoredData::Bool(v) => v.fmt(f),
|
||||||
|
StoredData::Line(v) => v.fmt(f),
|
||||||
|
StoredData::Vec(vec) => {
|
||||||
|
vec.iter().for_each(|d| {
|
||||||
|
_ = write!(f, "{}\n", d);
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Line {
|
||||||
|
data: Vec<StoredData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<StoredData>> for Line {
|
||||||
|
fn from(value: Vec<StoredData>) -> Self {
|
||||||
|
Self { data: value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Line {
|
impl Display for Line {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "[{}]", self.data.iter().map(|i| i.to_string()).collect::<Vec<String>>().join(", "))
|
write!(
|
||||||
|
f,
|
||||||
|
"[{}]",
|
||||||
|
self.data
|
||||||
|
.iter()
|
||||||
|
.map(|i| i.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +84,7 @@ fn parse_command(data: &[u8]) -> Result<Command, Error> {
|
|||||||
decoder.array()?;
|
decoder.array()?;
|
||||||
let id = decoder.str()?.to_string();
|
let id = decoder.str()?.to_string();
|
||||||
let value = decode_value(&mut decoder)?;
|
let value = decode_value(&mut decoder)?;
|
||||||
return Ok(Command::Set(id, value))
|
return Ok(Command::Set(id, value));
|
||||||
}
|
}
|
||||||
if data.starts_with(b"PUSH:") {
|
if data.starts_with(b"PUSH:") {
|
||||||
let payload = &data[b"PUSH:".len()..];
|
let payload = &data[b"PUSH:".len()..];
|
||||||
@@ -48,32 +92,41 @@ fn parse_command(data: &[u8]) -> Result<Command, Error> {
|
|||||||
decoder.array()?;
|
decoder.array()?;
|
||||||
let id = decoder.str()?.to_string();
|
let id = decoder.str()?.to_string();
|
||||||
let value = decode_value(&mut decoder)?;
|
let value = decode_value(&mut decoder)?;
|
||||||
return Ok(Command::Push(id, value))
|
return Ok(Command::Push(id, value));
|
||||||
|
}
|
||||||
|
if data.starts_with(b"DISPLAY:") {
|
||||||
|
let payload = &data[b"DISPLAY:".len()..];
|
||||||
|
let mut decoder = Decoder::new(&payload);
|
||||||
|
decoder.array()?;
|
||||||
|
let id = decoder.str()?.to_string();
|
||||||
|
return Ok(Command::Display(id));
|
||||||
}
|
}
|
||||||
Ok(Command::Unknown)
|
Ok(Command::Unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_value(decoder: &mut Decoder) -> Result<Box<dyn Display>, Error> {
|
fn decode_value(decoder: &mut Decoder) -> Result<StoredData, Error> {
|
||||||
Ok(match decoder.datatype()? {
|
Ok(match decoder.datatype()? {
|
||||||
Type::Bool => Box::new(decoder.bool()?),
|
Type::Bool => StoredData::Bool(decoder.bool()?),
|
||||||
Type::U8 => Box::new(decoder.u8()? as isize),
|
Type::U8 => StoredData::Integer(decoder.u8()? as isize),
|
||||||
Type::U16 => Box::new(decoder.u16()? as isize),
|
Type::U16 => StoredData::Integer(decoder.u16()? as isize),
|
||||||
Type::U32 => Box::new(decoder.u32()? as isize),
|
Type::U32 => StoredData::Integer(decoder.u32()? as isize),
|
||||||
Type::U64 => Box::new(decoder.u64()? as isize),
|
Type::U64 => StoredData::Integer(decoder.u64()? as isize),
|
||||||
Type::I8 => Box::new(decoder.i8()? as isize),
|
Type::I8 => StoredData::Integer(decoder.i8()? as isize),
|
||||||
Type::I16 => Box::new(decoder.i16()? as isize),
|
Type::I16 => StoredData::Integer(decoder.i16()? as isize),
|
||||||
Type::I32 => Box::new(decoder.i32()? as isize),
|
Type::I32 => StoredData::Integer(decoder.i32()? as isize),
|
||||||
Type::I64 => Box::new(decoder.i64()? as isize),
|
Type::I64 => StoredData::Integer(decoder.i64()? as isize),
|
||||||
Type::Int => Box::new(decoder.i32()? as isize),
|
Type::Int => StoredData::Integer(decoder.i32()? as isize),
|
||||||
Type::F16 => Box::new(decoder.f32()? as f64),
|
Type::F16 => StoredData::Float(decoder.f32()? as f64),
|
||||||
Type::F32 => Box::new(decoder.f32()? as f64),
|
Type::F32 => StoredData::Float(decoder.f32()? as f64),
|
||||||
Type::F64 => Box::new(decoder.f64()?),
|
Type::F64 => StoredData::Float(decoder.f64()?),
|
||||||
Type::String |
|
Type::String | Type::StringIndef => StoredData::String(decoder.str()?.to_string()),
|
||||||
Type::StringIndef => Box::new(decoder.str()?.to_string()),
|
Type::Array | Type::ArrayIndef => {
|
||||||
Type::Array |
|
|
||||||
Type::ArrayIndef => {
|
|
||||||
let len = decoder.array()?;
|
let len = decoder.array()?;
|
||||||
let mut array = if let Some(len) = len { Vec::with_capacity(len as usize) } else { vec![] };
|
let mut array = if let Some(len) = len {
|
||||||
|
Vec::with_capacity(len as usize)
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
if array.is_empty() {
|
if array.is_empty() {
|
||||||
loop {
|
loop {
|
||||||
let dt = decoder.datatype()?;
|
let dt = decoder.datatype()?;
|
||||||
@@ -83,12 +136,25 @@ fn decode_value(decoder: &mut Decoder) -> Result<Box<dyn Display>, Error> {
|
|||||||
array.push(decode_value(decoder)?);
|
array.push(decode_value(decoder)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box::new(Line::from(array))
|
StoredData::Line(Line::from(array))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
decoder.skip()?;
|
||||||
|
StoredData::Bool(false)
|
||||||
}
|
}
|
||||||
_ => { decoder.skip()?; Box::new(false)}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NoteContext {
|
pub struct NoteContext {
|
||||||
entries: HashMap<String, Box<dyn Any>>,
|
entries: HashMap<String, StoredData>,
|
||||||
}
|
output: Box<dyn Write>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoteContext {
|
||||||
|
pub fn default() -> Self {
|
||||||
|
Self{
|
||||||
|
entries: Default::default(),
|
||||||
|
output: Box::new(std::io::stdout()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#[test]
|
||||||
|
fn x() {}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user