lots of additions and modifications but now maybe mudlet replays can be parsed

master
rascul 2 years ago
parent 660e69b3a4
commit 4d93975d9f

58
Cargo.lock generated

@ -89,6 +89,24 @@ dependencies = [
"syn",
]
[[package]]
name = "actix-multipart"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9edfb0e7663d7fe18c8d5b668c9c1bcf79176b1dcc9d4da9592503209a6bfb0"
dependencies = [
"actix-utils",
"actix-web",
"bytes",
"derive_more",
"futures-core",
"httparse",
"local-waker",
"log",
"mime",
"twoway",
]
[[package]]
name = "actix-router"
version = "0.5.0"
@ -382,6 +400,7 @@ dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"time 0.1.44",
"winapi",
]
@ -568,6 +587,17 @@ version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
[[package]]
name = "futures-macro"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.21"
@ -587,9 +617,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
dependencies = [
"futures-core",
"futures-macro",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
@ -656,6 +688,12 @@ dependencies = [
"walkdir",
]
[[package]]
name = "harsh"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6fce2283849822530a18d7d8eeb1719ac65a27cfb6649c0dc8dfd2d2cc5edfb"
[[package]]
name = "hashbrown"
version = "0.11.2"
@ -1123,9 +1161,13 @@ name = "rewot"
version = "0.1.0"
dependencies = [
"actix-files",
"actix-multipart",
"actix-web",
"chrono",
"clap",
"futures-util",
"handlebars",
"harsh",
"lazy_static",
"log",
"rag",
@ -1408,6 +1450,16 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "twoway"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47"
dependencies = [
"memchr",
"unchecked-index",
]
[[package]]
name = "typenum"
version = "1.15.0"
@ -1420,6 +1472,12 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unchecked-index"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
[[package]]
name = "unicase"
version = "2.6.0"

@ -7,9 +7,13 @@ edition = "2021"
[dependencies]
actix-files = "0.6.0"
actix-multipart = "0.4.0"
actix-web = "4.0.1"
chrono = { version = "0.4.19", features = ["serde"] }
clap = { version = "3.1.18", features = ["derive"] }
futures-util = "0.3.21"
handlebars = { version = "4.2.2", features = ["dir_source"] }
harsh = "0.2.2"
lazy_static = "1.4.0"
log = { version = "0.4.17", features = ["std"] }
rag = { git = "https://gitlab.com/rascul/rag", tag = "v0.2.0" }

18062
run.txt

File diff suppressed because it is too large Load Diff

@ -1,10 +1,9 @@
/// mud client type
use std::default::Default;
use serde::Deserialize;
use std::fmt;
/// client type to know log format
#[derive(Debug, Deserialize, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum Client {
/// mudlet
Mudlet,
@ -25,6 +24,17 @@ impl Default for Client {
}
}
impl fmt::Display for Client {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Self::Mudlet => write!(f, "Mudlet"),
Self::TinTin => write!(f, "TinTin++"),
Self::ZMud => write!(f, "ZMud"),
Self::None => write!(f, "None"),
}
}
}
impl From<&String> for Client {
fn from(s: &String) -> Self {
match s.to_lowercase().as_str() {

@ -1,5 +1,4 @@
mod client;
mod tintin;
pub mod mudlet;
pub use client::Client;
pub use tintin::TinTin;

@ -0,0 +1,87 @@
use std::ops::Range;
use serde_json::{Map, Value};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn chunk32(chunk: &Vec<u8>) -> Result<(i32, i32)> {
let (delta_chunk, size_chunk) = {
let (mut delta_chunk, mut size_chunk): ([u8; 4], [u8; 4]) = ([0; 4], [0; 4]);
for i in 0..4 {
delta_chunk[i] = chunk[i];
size_chunk[i] = chunk[i + 4];
}
(delta_chunk, size_chunk)
};
let delta = i32::from_be_bytes(delta_chunk);
let size = i32::from_be_bytes(size_chunk);
if size < 0 {
return Err("size is too small".into());
}
Ok((delta, size))
}
fn chunk64(delta_chunk: &Vec<u8>, size_chunk: &Vec<u8>) -> Result<(i32, i32)> {
let delta = i64::from_be_bytes(delta_chunk.as_slice().try_into()?);
let size = i32::from_be_bytes(size_chunk.as_slice().try_into()?);
if delta > i32::MAX.into() {
return Err("delta out of range".into());
}
if size < 1 {
return Err("size should not be zero".into());
}
let delta: i32 = delta.try_into()?;
Ok((delta, size))
}
pub fn parse_log(raw: &Vec<u8>) -> Result<Value> {
let mut raw = raw.to_owned();
let mut chunks: Vec<Map<String, Value>> = Vec::new();
while raw.len() > 0 {
let chunk: Vec<u8> = raw.drain(0..7).collect();
if chunk.len() != 8 {
return Err("chunk size too small".into());
}
let (delta, size) = {
if let Ok((delta, size)) = chunk32(&chunk) {
(delta, size)
} else {
let next_chunk: Vec<u8> = raw.drain(0..3).collect();
if next_chunk.len() != 4 {
return Err("next_chunk size too small".into());
}
if let Ok((delta, size)) = chunk64(&chunk, &next_chunk) {
(delta, size)
} else {
return Err("broken".into());
}
}
};
let r = Range { start: 0 as usize, end: (size - 1) as usize };
let text_chunk: Vec<u8> = raw.drain(r).collect();
if text_chunk.len() != size as usize {
return Err("text_chunk size too small".into());
}
let text: String = String::from_utf8_lossy(&text_chunk).into();
let mut bm: Map<String, Value> = Map::new();
bm.insert("delta".into(), delta.into());
bm.insert("text".into(), text.into());
chunks.push(bm);
}
Ok(chunks.into())
}

@ -1 +1,5 @@
pub struct TinTin {}
use serde_json::Value;
pub fn parse_log(raw: &Vec<u8>) -> Value {
Value::Null
}

@ -2,35 +2,43 @@
use std::default::Default;
use actix_extract_multipart::{File, FileData};
use serde::Deserialize;
use crate::Client;
#[derive(Debug, Deserialize)]
#[serde(default = "FormData::default")]
pub struct FormData {
/// Client
#[serde(rename = "submit_client")]
pub client: Option<Client>,
/// Title
#[serde(rename = "submit_title")]
pub title: String,
pub title: Option<String>,
/// Player
#[serde(rename = "submit_player")]
pub player: String,
pub player: Option<String>,
/// Public
#[serde(rename = "submit_public")]
pub public: String,
pub public: Option<String>,
/// Log
#[serde(rename = "submit_log")]
pub log: String,
/// Replay
#[serde(rename = "submit_file")]
pub replay: Option<File>,
}
impl Default for FormData {
fn default() -> Self {
Self {
title: String::new(),
player: String::new(),
public: String::new(),
log: String::new(),
client: None,
title: None,
player: None,
public: None,
replay: None,
}
}
}

@ -1,6 +1,6 @@
mod action;
mod client;
mod form_data;
//mod form_data;
mod line;
mod options;
mod routes;
@ -14,7 +14,7 @@ use log::info;
use action::Action;
use client::Client;
use form_data::FormData;
//use form_data::FormData;
use options::Options;
use wot_log::WotLog;
@ -29,6 +29,7 @@ async fn main() -> std::io::Result<()> {
// start logger
rag::init().unwrap();
rag::set_level_debug();
// load templates
let mut handlebars = Handlebars::new();
@ -46,6 +47,7 @@ async fn main() -> std::io::Result<()> {
.service(routes::help::get)
.service(routes::index::get)
.service(routes::submit::get)
//.route("/submit", web::post().to(routes::submit::post))
.service(routes::submit::post)
.service(Files::new("/static", "static").show_files_listing())
})

@ -1,21 +1,20 @@
use actix_web::{post, web, HttpResponse};
use actix_multipart::Multipart;
use actix_web::{post, web, Error, HttpResponse};
use handlebars::Handlebars;
use serde_json::json;
use crate::FormData;
use crate::WotLog;
#[post("/submit")]
pub async fn post(form: web::Form<FormData>, hb: web::Data<Handlebars<'_>>) -> HttpResponse {
let form_data = form.into_inner();
let wot_log = WotLog::from(&form_data);
wot_log.parse();
let data = json!({
"name": "rewot"
});
pub async fn post(
payload: Multipart,
hb: web::Data<Handlebars<'_>>,
) -> Result<HttpResponse, Error> {
let mut wotlog = WotLog::from_payload(payload).await?;
wotlog.parse_log()?;
let body = hb.render("submit", &data).unwrap();
//let body = hb.render("submit", &json!({})).unwrap();
let body = format!("{:#?}", wotlog);
HttpResponse::Ok().body(body)
Ok(HttpResponse::Ok().body(body))
}

@ -1,62 +1,97 @@
use lazy_static::lazy_static;
use log::{debug, error, info};
use regex::Regex;
use serde::Deserialize;
use actix_multipart::Multipart;
use actix_web::Error;
use crate::default_false;
use crate::Action;
use crate::Client;
use crate::FormData;
use chrono::Utc;
use futures_util::StreamExt;
use harsh::Harsh;
use serde_json::Value;
#[derive(Debug, Deserialize)]
use crate::{client, Client};
#[derive(Debug)]
pub struct WotLog {
/// ID of the log
#[serde(default = "String::new")]
pub id: String,
/// Title of the log
#[serde(default = "String::new")]
pub title: String,
/// Name of the player
#[serde(default = "String::new")]
pub player: String,
/// Is the log public
#[serde(default = "default_false")]
pub public: bool,
/// Log
#[serde(default = "String::new")]
pub log: String,
/// Raw bytes of file as received
pub raw: Vec<u8>,
/// Client type
#[serde(default = "Client::default")]
pub client: Client,
/// Parsed JSON
pub json: Value,
}
impl From<&FormData> for WotLog {
fn from(form_data: &FormData) -> Self {
impl WotLog {
pub fn new() -> Self {
Self {
id: "".into(),
title: form_data.title.clone(),
player: form_data.player.clone(),
public: if form_data.public == "public" { true } else { false },
log: form_data.log.clone(),
client: Client::None,
id: {
let harsh = Harsh::default();
let ts = Utc::now();
harsh.encode(&[ts.timestamp_nanos() as u64])
},
player: String::new(),
public: false,
title: String::new(),
raw: Vec::new(),
json: Value::Null,
}
}
}
impl WotLog {
/// Read and parse the log
pub fn parse(self: &Self) {
let mut lineno: u128 = 1;
for line in self.log.lines() {
let line = line.trim_end_matches('\r');
pub async fn from_payload(payload: Multipart) -> Result<Self, Error> {
let mut payload = payload;
let mut wotlog = WotLog::new();
while let Some(item) = payload.next().await {
let mut field = item?;
let mut data: Vec<u8> = Vec::new();
let action = Action::from(line);
lineno += 1;
while let Some(Ok(chunk)) = field.next().await {
for byte in chunk {
data.push(byte);
}
}
match field.name() {
"submit_client" => {
//let b: Vec<u8> = data.iter().map(|b| *b).collect();
wotlog.client = Client::from(&String::from_utf8_lossy(&data).to_string())
}
"submit_player" => wotlog.player = String::from_utf8_lossy(&data).into(),
"submit_public" => {
if &data == "public".as_bytes() {
wotlog.public = true;
}
}
"submit_title" => wotlog.title = String::from_utf8_lossy(&data).into(),
"submit_file" => wotlog.raw = data.into(),
_ => {}
}
}
Ok(wotlog)
}
/// Read and parse the log
pub fn parse_log(self: &mut Self) -> Result<(), Error> {
self.json = match self.client {
Client::Mudlet => client::mudlet::parse_log(&self.raw)?,
Client::TinTin => Value::Null,
Client::ZMud => Value::Null,
Client::None => Value::Null,
};
Ok(())
}
}

Loading…
Cancel
Save