use crate::{util::rand_u64, Error, Result};
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Service {
pub r#type: String,
pub ip: String,
pub port: u16,
}
impl Service {
pub fn new(r#type: String, ip: String, port: u16) -> Self {
Self { r#type, ip, port }
}
}
impl Default for Service {
fn default() -> Self {
Self::new("_SSH".into(), "127.0.0.1".into(), 22)
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Header {
pub frame_type: FrameType,
#[serde(skip_serializing_if = "Option::is_none")]
pub frame_id: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub service_type: Option<String>,
}
#[derive(Serialize_repr, Deserialize_repr, Debug, Copy, Clone, PartialEq)]
#[repr(u16)]
pub enum FrameType {
Response = 1,
NewSession = 2,
ReleaseSession = 3,
RawData = 4,
}
#[derive(Serialize_repr, Deserialize_repr, Debug, Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum ResponseCode {
Success = 0,
SessionLimit = 1,
DeviceRefused = 2,
}
#[derive(Serialize_repr, Deserialize_repr, Debug, Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum ReleaseCode {
ClientClose = 0,
DeviceClose = 1,
CloudClientDisconnect = 2,
CloudDeviceDisconnect = 3,
CloudUpdate = 4,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ResponseBody<T> {
pub code: T,
pub msg: String,
}
#[derive(Debug)]
pub struct Frame {
pub header: Header,
pub body: Vec<u8>,
}
impl Frame {
pub fn session_id(&self) -> String {
self.header.session_id.clone().unwrap_or("".to_string())
}
pub fn service_type(&self) -> String {
self.header.service_type.clone().unwrap_or("".to_string())
}
pub fn frame_id(&self) -> u64 {
self.header.frame_id.clone().unwrap_or(rand_u64())
}
pub fn new(header: Header, body: Vec<u8>) -> Frame {
Frame { header, body }
}
pub fn new_session(frame_id: u64, service_type: String) -> Frame {
Frame::new(
Header {
frame_type: FrameType::NewSession,
frame_id: Some(frame_id),
session_id: None,
service_type: Some(service_type),
},
Vec::new(),
)
}
pub fn raw(session_id: String, frame_id: u64, service_type: Option<String>, body: Vec<u8>) -> Frame {
Frame::new(
Header {
frame_type: FrameType::RawData,
frame_id: Some(frame_id),
session_id: Some(session_id),
service_type,
},
body,
)
}
pub fn response(
session_id: String,
frame_id: u64,
service_type: String,
code: ResponseCode,
msg: String,
) -> Frame {
Frame::new(
Header {
frame_type: FrameType::Response,
frame_id: Some(frame_id),
session_id: Some(session_id),
service_type: Some(service_type),
},
serde_json::to_vec(&ResponseBody { code, msg }).unwrap(),
)
}
pub fn release(session_id: String, frame_id: u64, code: ReleaseCode, msg: String) -> Frame {
Frame::new(
Header {
frame_type: FrameType::ReleaseSession,
frame_id: Some(frame_id),
session_id: Some(session_id),
service_type: None,
},
serde_json::to_vec(&ResponseBody { code, msg }).unwrap(),
)
}
pub fn to_vec(&self) -> Result<Vec<u8>> {
let mut buf = Vec::new();
let header = serde_json::to_vec(&self.header).map_err(Error::SerdeError)?;
buf.extend_from_slice(&(header.len() as u16).to_be_bytes());
buf.extend_from_slice(&header);
buf.extend_from_slice(&self.body);
log::debug!("{}{}", header.len(), String::from_utf8_lossy(&header));
Ok(buf)
}
pub fn from_slice(bytes: &[u8]) -> Result<Self> {
if bytes.len() < 2 {
return Err(Error::HeaderFormatError("长度不够".into()));
}
let len = u16::from_be_bytes(bytes[..2].try_into().unwrap()) as usize;
if bytes.len() < 2 + len {
return Err(Error::HeaderFormatError(format!("头部长度 {} + 2 不够 {} [{:02x}][{:02x}]", bytes.len(), len, bytes[0], bytes[1])));
}
let header = bytes[2..(2 + len)].try_into().unwrap();
let header: Header = serde_json::from_slice(header)?;
Ok(Self {
header,
body: bytes[(2 + len)..].to_vec(),
})
}
}
#[test]
fn test_frame_build() {
let header = Header {
frame_type: FrameType::Response,
frame_id: Some(1),
session_id: Some("session_id".to_string()),
service_type: Some("service_type".to_string()),
};
let body = vec![1, 2, 3];
let frame = Frame::new(header, body.clone());
let bytes = frame.to_vec().unwrap();
println!("{}", String::from_utf8_lossy(&bytes));
let frame = Frame::from_slice(&bytes).unwrap();
println!("{:?}", frame);
assert_eq!(frame.header.frame_type, FrameType::Response);
assert_eq!(frame.header.frame_id, Some(1));
assert_eq!(frame.header.session_id, Some("session_id".to_string()));
assert_eq!(frame.header.service_type, Some("service_type".to_string()));
assert_eq!(frame.body, body);
}