parent
660e69b3a4
commit
4d93975d9f
@ -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
|
||||||
|
}
|
||||||
|
@ -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 handlebars::Handlebars;
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
use crate::FormData;
|
|
||||||
use crate::WotLog;
|
use crate::WotLog;
|
||||||
|
|
||||||
#[post("/submit")]
|
#[post("/submit")]
|
||||||
pub async fn post(form: web::Form<FormData>, hb: web::Data<Handlebars<'_>>) -> HttpResponse {
|
pub async fn post(
|
||||||
let form_data = form.into_inner();
|
payload: Multipart,
|
||||||
let wot_log = WotLog::from(&form_data);
|
hb: web::Data<Handlebars<'_>>,
|
||||||
wot_log.parse();
|
) -> Result<HttpResponse, Error> {
|
||||||
|
let mut wotlog = WotLog::from_payload(payload).await?;
|
||||||
let data = json!({
|
wotlog.parse_log()?;
|
||||||
"name": "rewot"
|
|
||||||
});
|
|
||||||
|
|
||||||
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 actix_multipart::Multipart;
|
||||||
use log::{debug, error, info};
|
use actix_web::Error;
|
||||||
use regex::Regex;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use crate::default_false;
|
use chrono::Utc;
|
||||||
use crate::Action;
|
use futures_util::StreamExt;
|
||||||
use crate::Client;
|
use harsh::Harsh;
|
||||||
use crate::FormData;
|
use serde_json::Value;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
use crate::{client, Client};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct WotLog {
|
pub struct WotLog {
|
||||||
/// ID of the log
|
/// ID of the log
|
||||||
#[serde(default = "String::new")]
|
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
||||||
/// Title of the log
|
/// Title of the log
|
||||||
#[serde(default = "String::new")]
|
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
|
||||||
/// Name of the player
|
/// Name of the player
|
||||||
#[serde(default = "String::new")]
|
|
||||||
pub player: String,
|
pub player: String,
|
||||||
|
|
||||||
/// Is the log public
|
/// Is the log public
|
||||||
#[serde(default = "default_false")]
|
|
||||||
pub public: bool,
|
pub public: bool,
|
||||||
|
|
||||||
/// Log
|
/// Raw bytes of file as received
|
||||||
#[serde(default = "String::new")]
|
pub raw: Vec<u8>,
|
||||||
pub log: String,
|
|
||||||
|
|
||||||
/// Client type
|
/// Client type
|
||||||
#[serde(default = "Client::default")]
|
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
|
|
||||||
|
/// Parsed JSON
|
||||||
|
pub json: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&FormData> for WotLog {
|
impl WotLog {
|
||||||
fn from(form_data: &FormData) -> Self {
|
pub fn new() -> Self {
|
||||||
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,
|
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 {
|
pub async fn from_payload(payload: Multipart) -> Result<Self, Error> {
|
||||||
/// Read and parse the log
|
let mut payload = payload;
|
||||||
pub fn parse(self: &Self) {
|
let mut wotlog = WotLog::new();
|
||||||
let mut lineno: u128 = 1;
|
|
||||||
for line in self.log.lines() {
|
while let Some(item) = payload.next().await {
|
||||||
let line = line.trim_end_matches('\r');
|
let mut field = item?;
|
||||||
|
let mut data: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
let action = Action::from(line);
|
while let Some(Ok(chunk)) = field.next().await {
|
||||||
lineno += 1;
|
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…
Reference in new issue