diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 91a2959..915138e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,7 +2,7 @@ name: Rust on: push: - branches: [master] + branches: ['*'] pull_request: branches: [master] diff --git a/Cargo.toml b/Cargo.toml index 747394b..b91a608 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,35 +1,5 @@ -[package] -name = "loco" -version = "0.1.0" -authors = [ - "Seungjae Park ", - "JellyBrick ", - "kiwiyou ", - "Sangwon Ryu ", - "nnnlog " +[workspace] +members = [ + "loco", + "loco-client", ] -edition = "2018" -description = "Loco Protocol Wrapper for Rust" -documentation = "https://docs.rs/loco" -readme = "README.md" -repository = "https://github.com/organization/loco.rs" -license = "Apache-2.0" - -[dependencies] -bson = "1.0" -hex-literal = "0.3.0" -reqwest = { version = "0.11", features = ["blocking"] } -sha2 = "0.9.0" -hex = "0.4.2" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_repr = "0.1" -data-encoding = "2.2.0" -tokio = { version = "1.0.1", features = ["macros"] } -tokio-util = { version = "0.6.0", features = ["codec"], default-features = false } -bytes = "1.0.0" -futures = "0.3.5" -log = "0.4.8" -loco-derive = { path = "loco-derive" } -webpki = "0.22" -bincode = "1.3" \ No newline at end of file diff --git a/loco-client/Cargo.toml b/loco-client/Cargo.toml new file mode 100644 index 0000000..a76f576 --- /dev/null +++ b/loco-client/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "loco-client" +version = "0.1.0" +edition = "2018" + +[dependencies] +futures = "0.3.14" +loco = { path = "../loco" } +tokio = "1.5.0" +tokio-native-tls = "0.3.0" +tokio-util = { version = "0.6.6", features = ["codec"] } diff --git a/loco-client/src/lib.rs b/loco-client/src/lib.rs new file mode 100644 index 0000000..3d67d4e --- /dev/null +++ b/loco-client/src/lib.rs @@ -0,0 +1,45 @@ +use loco::types::response::DataStatus; + +pub mod reactor; + +#[derive(Debug)] +pub enum Error { + Loco(Box), + Io(std::io::Error), + Tls(tokio_native_tls::native_tls::Error), + ReactorFail, + RequestFail { status: DataStatus, method: String }, + PacketIdConflict(i32), +} + +pub type Result = std::result::Result; + +impl From for Error { + fn from(e: loco::Error) -> Self { + Self::Loco(Box::new(e)) + } +} + +impl From for Error { + fn from(error: std::io::Error) -> Self { + Self::Io(error) + } +} + +impl From for Error { + fn from(e: tokio_native_tls::native_tls::Error) -> Self { + Self::Tls(e) + } +} + +impl From for Error { + fn from(_: futures::channel::oneshot::Canceled) -> Self { + Self::ReactorFail + } +} + +impl From for Error { + fn from(_: futures::channel::mpsc::SendError) -> Self { + Self::ReactorFail + } +} diff --git a/loco-client/src/reactor/entrance.rs b/loco-client/src/reactor/entrance.rs new file mode 100644 index 0000000..b88b084 --- /dev/null +++ b/loco-client/src/reactor/entrance.rs @@ -0,0 +1,141 @@ +use futures::{SinkExt, StreamExt}; +use loco::{ + codec::{EncryptType, KeyEncryptType, LocoClientCodec, LocoPacket, LocoSecureClientCodec}, + config::{BookingConfig, CheckinConfig}, + crypto::LocoCrypto, + types::{ + request, + response::{self, LocoResponse, ResponseKind}, + UserId, + }, +}; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::net::TcpStream; +use tokio_native_tls::TlsStream; +use tokio_util::codec::{Decoder, Framed}; + +use crate::{Error, Result}; + +pub type LocoSecureClientStream = Framed>; +pub type LocoClientStream = Framed; + +async fn create_tls_stream( + host: &str, + port: u16, + // keep_alive: bool, +) -> Result> { + let connector = tokio_native_tls::native_tls::TlsConnector::new().unwrap(); + let connector = tokio_native_tls::TlsConnector::from(connector); + let stream = TcpStream::connect((host, port)).await?; + let tls_stream = connector.connect(host, stream).await?; + Ok(tls_stream) +} + +pub async fn get_config(config: &impl BookingConfig) -> Result { + let (host, port) = config.booking_host(); + let stream = create_tls_stream(host, port).await?; + let mut framed = LocoClientCodec::default().framed(stream); + get_booking_data(&mut framed, config).await +} + +pub async fn get_checkin(config: &impl CheckinConfig) -> Result { + let crypto = config.new_crypto(); + let try_checkin = match get_config(config).await { + Ok(response) => { + let host = response.ticket_hosts.lsl[0].as_str(); + let port = response.config_wifi.ports[0] as u16; + let stream = TcpStream::connect((host, port)).await?; + let framed = LocoSecureClientCodec::new(crypto.clone()) + .wrap( + stream, + KeyEncryptType::RsaOaepSha1Mgf1Sha1, + EncryptType::AesCfb128, + &config.public_key(), + ) + .await?; + Ok(framed) + } + Err(e) => Err(e), + }; + let mut stream = match try_checkin { + Ok(stream) => stream, + Err(_) => { + let (host, port) = config.checkin_fallback_host(); + let stream = TcpStream::connect((host, port)).await?; + let framed = LocoSecureClientCodec::new(crypto) + .wrap( + stream, + KeyEncryptType::RsaOaepSha1Mgf1Sha1, + EncryptType::AesCfb128, + &config.public_key(), + ) + .await?; + framed + } + }; + + get_checkin_data(&mut stream, config, None).await +} + +async fn get_booking_data( + stream: &mut LocoClientStream, + config: &impl BookingConfig, +) -> Result +where + S: AsyncRead + AsyncWrite + Unpin, +{ + let request = request::GetConf::from_config(config); + let packet = LocoPacket::from_request(0, request); + stream.send(packet).await?; + while let Some(packet) = stream.next().await { + let packet = packet?; + if packet.id == 0 { + match packet.payload { + LocoResponse::Success { status: _, kind } => { + if let ResponseKind::GetConf(get_conf) = *kind { + return Ok(get_conf); + } + } + LocoResponse::Fail { status } => { + return Err(Error::RequestFail { + status, + method: packet.method, + }) + } + } + } + } + Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "No server response").into()) +} + +async fn get_checkin_data( + stream: &mut LocoSecureClientStream, + config: &impl CheckinConfig, + user_id: Option, +) -> Result +where + S: AsyncRead + AsyncWrite + Unpin, +{ + let request = request::Checkin::from_config(config).with_user(user_id); + let packet = LocoPacket::from_request(0, request); + stream.send(packet).await?; + while let Some(packet) = stream.next().await { + let packet = packet?; + if packet.id == 0 { + match packet.payload { + LocoResponse::Success { status: _, kind } => { + if let ResponseKind::Checkin(checkin) = *kind { + return Ok(checkin); + } + } + LocoResponse::Fail { status } => { + return Err(Error::RequestFail { + status, + method: packet.method, + }) + } + } + } + } + Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "No server response").into()) +} diff --git a/loco-client/src/reactor/mod.rs b/loco-client/src/reactor/mod.rs new file mode 100644 index 0000000..967d62d --- /dev/null +++ b/loco-client/src/reactor/mod.rs @@ -0,0 +1,146 @@ +use std::collections::HashMap; + +use futures::{ + channel::{mpsc, oneshot}, + future::Either, + SinkExt, Stream, StreamExt, +}; +use loco::{ + codec::{self, EncryptType, KeyEncryptType, LocoPacket, LocoSecureDecoder, LocoSecureEncoder}, + config::ClientConfig, + types::{ + request::LocoRequest, + response::{LocoResponse, ResponseKind}, + }, +}; +use tokio::net::TcpStream; +use tokio_util::codec::{FramedRead, FramedWrite}; + +use crate::{Error, Result}; + +mod entrance; + +#[derive(Clone)] +pub struct Sender { + tx: mpsc::Sender<(LocoRequest, Option>)>, +} + +impl Sender { + pub async fn spawn(&mut self, request: impl Into) -> Result<()> { + self.tx.send((request.into(), None)).await?; + Ok(()) + } + + pub async fn send(&mut self, request: impl Into) -> Result { + let (res_tx, res_rx) = oneshot::channel(); + let request: LocoRequest = request.into(); + let method = request.to_string(); + self.tx.send((request, Some(res_tx))).await?; + let response = res_rx.await?; + match response { + LocoResponse::Success { kind, .. } => Ok(*kind), + LocoResponse::Fail { status } => Err(Error::RequestFail { status, method }), + } + } +} + +pub struct Reactor { + config: Config, + sender: Sender, + receiver: mpsc::Receiver<(LocoRequest, Option>)>, + packet_tx: Option)>>, +} + +impl Reactor { + pub fn new(config: Config) -> Self { + let (sender, receiver) = mpsc::channel(16); + Self { + config, + sender: Sender { tx: sender }, + receiver, + packet_tx: None, + } + } + + pub fn packets(&mut self) -> impl Stream)> { + let (packet_tx, packet_rx) = mpsc::channel(16); + self.packet_tx = Some(packet_tx); + packet_rx + } + + pub fn sender(&self) -> &Sender { + &self.sender + } +} + +impl Reactor +where + Config: ClientConfig + Send + 'static, +{ + pub async fn spawn(self) -> Result<()> { + let checkin = entrance::get_checkin(&self.config).await?; + let mut socket = TcpStream::connect((checkin.host.as_str(), checkin.port as u16)).await?; + let crypto = self.config.new_crypto(); + codec::send_handshake( + &mut socket, + &crypto, + KeyEncryptType::RsaOaepSha1Mgf1Sha1, + EncryptType::AesCfb128, + &self.config.public_key(), + ) + .await?; + let (rx, tx) = socket.into_split(); + let reader = FramedRead::new(rx, LocoSecureDecoder::new(crypto.clone())); + let mut writer = FramedWrite::new(tx, LocoSecureEncoder::new(crypto)); + let (mut req_tx, req_rx) = mpsc::channel(16); + + let mut packet_tx = self.packet_tx; + let sender = self.sender; + let read_task = async move { + let mut notifier_registry = + HashMap::>>::new(); + + let reader_stream = reader.map(Either::Left); + let register_stream = req_rx.map(Either::Right); + + let mut stream = futures::stream::select(reader_stream, register_stream); + while let Some(input) = stream.next().await { + match input { + Either::Left(Ok(packet)) => { + if let Some(Some(notifier)) = notifier_registry.remove(&packet.id) { + notifier + .send(packet.payload) + .expect("Response notification failed"); + continue; + } + if let Some(tx) = &mut packet_tx { + tx.send((sender.clone(), packet)).await?; + } + } + Either::Left(Err(e)) => return Err(e.into()), + Either::Right((id, notifier)) => { + notifier_registry.insert(id, notifier); + } + } + } + + Ok(()) + }; + + let mut receiver = self.receiver; + let write_task = async move { + let mut packet_id = 0; + while let Some((request, maybe_notifier)) = receiver.next().await { + let packet = LocoPacket::from_request(packet_id, request); + writer.send(packet).await?; + req_tx.send((packet_id, maybe_notifier)).await?; + packet_id += 1; + } + + Ok(()) + }; + + let (try_read, try_write) = futures::future::join(read_task, write_task).await; + try_read.and(try_write) + } +} diff --git a/loco-derive/Cargo.toml b/loco-derive/Cargo.toml deleted file mode 100644 index c47168a..0000000 --- a/loco-derive/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "loco-derive" -version = "0.1.0" -authors = ["djdisodo "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -proc-macro = true - -[dependencies] -syn = "1.0" -quote = "1.0" -bson = "1.1.0" \ No newline at end of file diff --git a/loco-derive/src/lib.rs b/loco-derive/src/lib.rs deleted file mode 100644 index f10e44e..0000000 --- a/loco-derive/src/lib.rs +++ /dev/null @@ -1,133 +0,0 @@ -extern crate proc_macro; - -use proc_macro::TokenStream; -use quote::quote; -use syn::parse::ParseBuffer; -use syn::Token; -use syn::{self, DeriveInput, Error, Ident}; - -struct LocoPacketPair(Ident, Ident); - -impl syn::parse::Parse for LocoPacketPair { - fn parse<'a>(input: &'a ParseBuffer<'a>) -> Result { - let content; - syn::parenthesized!(content in input); - let type1 = content.parse()?; - content.parse::()?; - let type2 = content.parse()?; - Ok(LocoPacketPair(type1, type2)) - } -} - -#[proc_macro_derive(LocoPacketPair, attributes(loco_packet_pair))] -pub fn derive_loco_packet_pair(input: TokenStream) -> TokenStream { - let derive_input: DeriveInput = syn::parse(input).unwrap(); - let attribute = derive_input - .attrs - .iter() - .find(|a| a.path.segments.len() == 1 && a.path.segments[0].ident == "loco_packet_pair") - .expect("attribute loco_packet_pair(request, response)"); - - let command_pair: LocoPacketPair = - syn::parse2(attribute.tokens.clone()).expect("Invalid loco_packet_pair attribute!"); - - let name = derive_input.ident; - let request = command_pair.0; - let response = command_pair.1; - let name_uppercase = Ident::new(&name.to_string().to_uppercase(), name.span()); - - let token_stream = quote! { - - impl crate::protocol::LocoPacket for #request { - const NAME: &'static str = &stringify!(#name_uppercase); - } - - impl crate::protocol::LocoRequest for #request {} - - impl crate::protocol::LocoPacket for #response { - const NAME: &'static str = &stringify!(#name_uppercase); - } - - impl crate::protocol::LocoResponse for #response {} - }; - - token_stream.into() -} - -#[proc_macro_derive(LocoPacket)] -pub fn derive_loco_packet(input: TokenStream) -> TokenStream { - let derive_input: DeriveInput = syn::parse(input).unwrap(); - let name = derive_input.ident; - let name_uppercase = Ident::new(&name.to_string().to_uppercase(), name.span()); - - let token_stream = quote! { - impl crate::protocol::LocoPacket for #name { - const NAME: &'static str = &stringify!(#name_uppercase); - } - }; - - token_stream.into() -} - -#[proc_macro_derive(LocoRequest)] -pub fn derive_loco_request(input: TokenStream) -> TokenStream { - let derive_input: DeriveInput = syn::parse(input).unwrap(); - let name = derive_input.ident; - let name_uppercase = Ident::new(&name.to_string().to_uppercase(), name.span()); - - let token_stream = quote! { - impl crate::protocol::LocoPacket for #name { - const NAME: &'static str = &stringify!(#name_uppercase); - } - - impl crate::protocol::LocoRequest for #name {} - }; - - token_stream.into() -} - -#[proc_macro_derive(LocoResponse)] -pub fn derive_loco_response(input: TokenStream) -> TokenStream { - let derive_input: DeriveInput = syn::parse(input).unwrap(); - let name = derive_input.ident; - let name_uppercase = Ident::new(&name.to_string().to_uppercase(), name.span()); - - let token_stream = quote! { - impl crate::protocol::LocoPacket for #name { - const NAME: &'static str = &stringify!(#name_uppercase); - } - - impl crate::protocol::LocoResponse for #name {} - }; - - token_stream.into() -} - -#[proc_macro_derive(BsonData)] -pub fn bson_data(input: TokenStream) -> TokenStream { - let ast = syn::parse(input).unwrap(); - - impl_bson_data(&ast) -} - -fn impl_bson_data(ast: &syn::DeriveInput) -> TokenStream { - let name = &ast.ident; - - let gen = quote! { - impl crate::protocol::BsonData<'_> for #name {} //for implementation checK - - impl crate::protocol::Encode for #name { - fn encode(&self, buffer: &mut U) { - bson::ser::to_document(&self).unwrap().to_writer(buffer).unwrap(); - } - } - - impl crate::protocol::Decode for #name { - fn decode(&self, buffer: &mut U) -> Self { - bson::de::from_document(bson::Document::from_reader(buffer).unwrap()).unwrap() - } - } - }; - - gen.into() -} diff --git a/loco/Cargo.toml b/loco/Cargo.toml new file mode 100644 index 0000000..0cb5ec5 --- /dev/null +++ b/loco/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "loco" +version = "0.1.0" +authors = [ + "Seungjae Park ", + "JellyBrick ", + "kiwiyou ", + "Sangwon Ryu ", + "nnnlog " +] +edition = "2018" +description = "Loco Protocol Wrapper for Rust" +documentation = "https://docs.rs/loco" +readme = "README.md" +repository = "https://github.com/organization/loco.rs" +license = "Apache-2.0" + +[dependencies] +bincode = "1.3.3" +bson = "1.2.2" +bytes = "1.0.1" +futures = "0.3.14" +openssl = "0.10.34" +reqwest = { version = "0.11.3", features = ["json"] } +serde = { version = "1.0.125", features = ["derive"] } +serde_repr = "0.1.6" +strum = { version = "0.20.0", features = ["derive"] } +tokio = { version = "1.5.0", features = ["io-util"], default-features = false } +tokio-util = { version = "0.6.6", features = ["codec"] } + +[dev-dependencies] +serde_test = "1.0.125" diff --git a/loco/src/api/login.rs b/loco/src/api/login.rs new file mode 100644 index 0000000..ff2820c --- /dev/null +++ b/loco/src/api/login.rs @@ -0,0 +1,98 @@ +use crate::config::{WebApiConfig, XvcProvider}; +use crate::Result; +use reqwest::{header::HeaderMap, Client}; +use serde::{Deserialize, Serialize}; + +use crate::config::WebApiRequest; + +pub struct LoginClient { + client: Client, + config: WebApi, + xvc_provider: Xvc, + device_uuid: String, + device_name: String, +} + +#[derive(Serialize)] +struct LoginForm<'form> { + email: &'form str, + password: &'form str, + forced: Option, + device_uuid: &'form str, + device_name: &'form str, + model_name: Option<&'form str>, +} + +impl LoginClient +where + WebApi: WebApiConfig, + Xvc: XvcProvider, +{ + pub async fn login( + &self, + email: impl AsRef, + password: impl AsRef, + forced: Option, + ) -> Result { + let api_path = self.config.api_path("login.json"); + let model_name = self.config.device_model(); + let form = LoginForm { + email: email.as_ref(), + password: password.as_ref(), + forced, + device_uuid: &self.device_uuid, + device_name: &self.device_name, + model_name: (!model_name.is_empty()).then(|| model_name), + }; + let result = self + .client + .post(&api_path) + .with_api_a_header(&self.config) + .with_api_base_header(&self.config) + .headers( + self.headers(email.as_ref()) + .expect("Invalid web api configuration"), + ) + .form(&form) + .send() + .await? + .json() + .await?; + Ok(result) + } + + fn headers( + &self, + email: &str, + ) -> std::result::Result { + let mut header_map = HeaderMap::new(); + let user_agent = self.config.user_agent(); + let xvc = self + .xvc_provider + .to_full_xvc_key(&self.device_uuid, &user_agent, email); + header_map.insert( + reqwest::header::USER_AGENT, + self.config.user_agent().parse()?, + ); + header_map.insert("X-VC", xvc.parse()?); + Ok(header_map) + } +} + +#[derive(Debug, Deserialize)] +pub struct LoginResponse { + pub access_token: String, + pub account_id: String, + pub auto_login_account_id: String, + pub country_code: String, + pub country_iso: String, + pub device_uuid: String, + pub display_account_id: String, + pub main_device_agent_name: String, + pub main_device_app_version: String, + pub refresh_token: String, + pub reset_user_data: bool, + pub server_time: i64, + pub token_type: String, + pub user_id: i64, +} diff --git a/loco/src/api/mod.rs b/loco/src/api/mod.rs new file mode 100644 index 0000000..9c48ff1 --- /dev/null +++ b/loco/src/api/mod.rs @@ -0,0 +1,2 @@ +pub mod login; +pub mod oauth; diff --git a/loco/src/api/oauth.rs b/loco/src/api/oauth.rs new file mode 100644 index 0000000..152d3bc --- /dev/null +++ b/loco/src/api/oauth.rs @@ -0,0 +1,15 @@ +pub struct OAuthCredential { + pub device_uuid: String, + pub access_token: String, + pub refresh_token: String, +} + +pub struct OAuthInfo { + pub token_type: String, + pub credential: OAuthCredential, + pub expires_in: u64, +} + +pub trait CredentialProvider { + fn credential(&self) -> OAuthCredential; +} diff --git a/loco/src/codec/insecure.rs b/loco/src/codec/insecure.rs new file mode 100644 index 0000000..680f762 --- /dev/null +++ b/loco/src/codec/insecure.rs @@ -0,0 +1,132 @@ +use std::convert::TryFrom; + +use bytes::{Buf, BufMut, BytesMut}; +use serde::{de::DeserializeOwned, Serialize}; +use tokio_util::codec::{Decoder, Encoder}; + +use crate::{ + types::{request::LocoRequest, response::LocoResponse}, + Error, +}; + +use super::{LocoPacket, RawLocoHeader, RawLocoPacket}; + +#[derive(Default)] +pub struct LocoEncoder; + +impl Encoder> for LocoEncoder { + type Error = Error; + + fn encode(&mut self, item: LocoPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { + let packet = RawLocoPacket::try_from(item)?; + bincode::serialize_into(dst.writer(), &packet)?; + Ok(()) + } +} + +pub struct LocoDecoder { + prev_header: Option, + _phantom: std::marker::PhantomData, +} + +impl Default for LocoDecoder { + fn default() -> Self { + Self { + prev_header: None, + _phantom: Default::default(), + } + } +} + +impl LocoDecoder { + pub fn new() -> Self { + Default::default() + } +} + +const HEADER_LEN: usize = 22; + +impl Decoder for LocoDecoder { + type Item = LocoPacket; + + type Error = Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + let header = if let Some(header) = self.prev_header.take() { + header + } else if src.len() < HEADER_LEN { + src.reserve(HEADER_LEN); + return Ok(None); + } else { + bincode::deserialize_from(src.reader())? + }; + + let data_size = header.data_size as usize; + if src.len() < data_size { + src.reserve(data_size); + self.prev_header = Some(header); + Ok(None) + } else if header.data_type == 0 || header.data_type == 8 { + Ok(Some(LocoPacket::from_raw(header, &src[..data_size])?)) + } else { + src.advance(data_size); + Err(Error::UnsupportedPacketType) + } + } +} + +#[derive(Default)] +pub struct LocoClientCodec { + encoder: LocoEncoder, + decoder: LocoDecoder, +} + +impl Encoder> for LocoClientCodec { + type Error = Error; + + fn encode( + &mut self, + item: LocoPacket, + dst: &mut BytesMut, + ) -> Result<(), Self::Error> { + self.encoder.encode(item, dst) + } +} + +impl Decoder for LocoClientCodec { + type Item = LocoPacket; + + type Error = Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + self.decoder.decode(src) + } +} + +#[derive(Default)] +pub struct LocoServerCodec { + encoder: LocoEncoder, + decoder: LocoDecoder, +} + +impl Encoder> for LocoServerCodec { + type Error = Error; + + fn encode( + &mut self, + item: LocoPacket, + dst: &mut BytesMut, + ) -> Result<(), Self::Error> { + self.encoder.encode(item, dst) + } +} + +impl Decoder for LocoServerCodec { + type Item = LocoPacket; + + type Error = Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + self.decoder.decode(src) + } +} diff --git a/loco/src/codec/mod.rs b/loco/src/codec/mod.rs new file mode 100644 index 0000000..6142183 --- /dev/null +++ b/loco/src/codec/mod.rs @@ -0,0 +1,116 @@ +mod insecure; +mod secure; + +pub use insecure::*; +pub use secure::*; + +use std::convert::TryFrom; + +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +use crate::{ + types::{ + request::LocoRequest, + response::{DataStatus, LocoResponse, ResponseKind}, + }, + Error, +}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +struct RawLocoPacket { + #[serde(flatten)] + header: RawLocoHeader, + data: Vec, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +struct RawLocoHeader { + id: i32, + status: i16, + method: [u8; 11], + data_type: u8, + data_size: u32, +} + +pub struct LocoPacket { + pub id: i32, + pub method: String, + pub payload: Payload, +} + +impl TryFrom> for RawLocoPacket { + type Error = Error; + + fn try_from(value: LocoPacket) -> Result { + use std::convert::TryInto; + let method = value + .method + .bytes() + .chain(std::iter::repeat(0)) + .take(11) + .collect::>() + .try_into() + .unwrap(); + let payload = bson::to_document(&value.payload)?; + let mut data = Vec::new(); + payload.to_writer(&mut data)?; + let header = RawLocoHeader { + id: value.id, + status: 0, + method, + data_type: 0, + data_size: data.len() as u32, + }; + Ok(Self { header, data }) + } +} + +impl LocoPacket { + fn from_raw(header: RawLocoHeader, mut data: &[u8]) -> Result { + let method_slice = header.method.split(|byte| *byte == 0).next().unwrap(); + let method = String::from_utf8(method_slice.into()).unwrap(); + let document = bson::Document::from_reader(&mut data)?; + let payload = bson::from_document(document)?; + Ok(Self { + id: header.id, + method, + payload, + }) + } +} + +impl LocoPacket { + pub fn from_request(id: i32, req: impl Into) -> Self { + let payload = req.into(); + Self { + id, + method: payload.to_string(), + payload, + } + } +} + +impl LocoPacket { + pub fn from_success(id: i32, status: DataStatus, res: impl Into) -> Self { + let kind = res.into(); + let method = kind.to_string(); + let payload = LocoResponse::Success { + status, + kind: Box::new(kind), + }; + Self { + id, + method, + payload, + } + } + + pub fn from_fail(id: i32, status: DataStatus, method: String) -> Self { + let payload = LocoResponse::Fail { status }; + Self { + id, + method, + payload, + } + } +} diff --git a/loco/src/codec/secure.rs b/loco/src/codec/secure.rs new file mode 100644 index 0000000..2db5236 --- /dev/null +++ b/loco/src/codec/secure.rs @@ -0,0 +1,297 @@ +use bytes::{Buf, BufMut, BytesMut}; +use openssl::{ + pkey::{HasPrivate, HasPublic}, + rsa::Rsa, +}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; +use tokio_util::codec::{Decoder, Encoder, Framed}; + +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use crate::{ + crypto::RsaAesCrypto, + types::{request::LocoRequest, response::LocoResponse}, + Error, Result, +}; + +use super::{LocoDecoder, LocoEncoder, LocoPacket}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +struct CryptoHeader { + iv: [u8; IV_LEN], + size_plus_16: u32, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +struct CryptoPacket { + #[serde(flatten)] + header: CryptoHeader, + data: Vec, +} + +const CRYPTO_HEADER_LEN: usize = 20; +const IV_LEN: usize = 16; + +pub struct LocoSecureEncoder { + crypto_provider: Crypto, + inner: LocoEncoder, +} + +impl LocoSecureEncoder { + pub fn new(crypto_provider: Crypto) -> Self { + Self { + crypto_provider, + inner: LocoEncoder, + } + } +} + +impl Encoder> for LocoSecureEncoder +where + Crypto: RsaAesCrypto, + Payload: Serialize, +{ + type Error = Error; + + fn encode(&mut self, item: LocoPacket, dst: &mut bytes::BytesMut) -> Result<()> { + let iv = Crypto::random_iv(); + let encrypted = { + let mut raw = BytesMut::new(); + self.inner.encode(item, &mut raw)?; + self.crypto_provider.encrypt_aes(&raw, &iv)? + }; + let header = CryptoHeader { + size_plus_16: encrypted.len() as u32 + 16, + iv, + }; + let packet = CryptoPacket { + header, + data: encrypted, + }; + bincode::serialize_into(dst.writer(), &packet)?; + Ok(()) + } +} + +pub struct LocoSecureDecoder { + crypto_provider: Crypto, + prev_crypto_header: Option, + inner: LocoDecoder, +} + +impl LocoSecureDecoder { + pub fn new(crypto_provider: Crypto) -> Self { + Self { + crypto_provider, + prev_crypto_header: None, + inner: LocoDecoder::new(), + } + } +} + +impl Decoder for LocoSecureDecoder +where + Crypto: RsaAesCrypto, + Payload: DeserializeOwned, +{ + type Item = LocoPacket; + + type Error = Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result> { + let header = if let Some(header) = self.prev_crypto_header.take() { + header + } else if src.len() < CRYPTO_HEADER_LEN { + src.reserve(CRYPTO_HEADER_LEN); + return Ok(None); + } else { + bincode::deserialize_from(src.reader())? + }; + + let data_size = header.size_plus_16 as usize - 16; + if src.len() < data_size { + src.reserve(data_size); + self.prev_crypto_header = Some(header); + Ok(None) + } else { + let decrypted = self + .crypto_provider + .decrypt_aes(&src[..data_size], &header.iv)?; + src.advance(decrypted.len()); + let mut inner_src = BytesMut::from(&decrypted[..]); + let item = self + .inner + .decode(&mut inner_src)? + .expect("Size specified in secure header is not equal to actual size"); + Ok(Some(item)) + } + } +} + +pub struct LocoSecureClientCodec { + encoder: LocoSecureEncoder, + decoder: LocoSecureDecoder, +} + +impl Encoder> for LocoSecureClientCodec { + type Error = Error; + + fn encode(&mut self, item: LocoPacket, dst: &mut BytesMut) -> Result<()> { + self.encoder.encode(item, dst) + } +} + +impl Decoder for LocoSecureClientCodec { + type Item = LocoPacket; + + type Error = Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result> { + self.decoder.decode(src) + } +} + +pub struct LocoSecureServerCodec { + encoder: LocoSecureEncoder, + decoder: LocoSecureDecoder, + pub key_encrypt_type: KeyEncryptType, + pub encrypt_type: EncryptType, +} + +impl Encoder> for LocoSecureServerCodec { + type Error = Error; + + fn encode(&mut self, item: LocoPacket, dst: &mut BytesMut) -> Result<()> { + self.encoder.encode(item, dst) + } +} + +impl Decoder for LocoSecureServerCodec { + type Item = LocoPacket; + + type Error = Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result> { + self.decoder.decode(src) + } +} + +impl LocoSecureClientCodec { + pub fn new(crypto: Crypto) -> Self + where + Crypto: Clone, + { + Self { + encoder: LocoSecureEncoder::new(crypto.clone()), + decoder: LocoSecureDecoder::new(crypto), + } + } + + pub async fn wrap( + self, + mut stream: Stream, + key_encrypt_type: KeyEncryptType, + encrypt_type: EncryptType, + key: &Rsa, + ) -> Result> + where + Crypto: RsaAesCrypto, + Stream: AsyncRead + AsyncWrite + Unpin, + { + send_handshake( + &mut stream, + &self.encoder.crypto_provider, + key_encrypt_type, + encrypt_type, + key, + ) + .await?; + Ok(Framed::new(stream, self)) + } +} + +impl LocoSecureServerCodec { + pub async fn framed( + mut stream: Stream, + mut crypto: Crypto, + key: &Rsa, + ) -> Result> + where + Crypto: RsaAesCrypto + Clone, + Stream: AsyncRead + AsyncWrite + Unpin, + { + let handshake = recv_handshake(&mut stream, &mut crypto, key).await?; + Ok(Self { + encoder: LocoSecureEncoder::new(crypto.clone()), + decoder: LocoSecureDecoder::new(crypto), + key_encrypt_type: handshake.key_encrypt_type, + encrypt_type: handshake.encrypt_type, + } + .framed(stream)) + } +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] +#[repr(u32)] +pub enum EncryptType { + AesCfb128 = 2, +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] +#[repr(u32)] +pub enum KeyEncryptType { + RsaOaepSha1Mgf1Sha1 = 12, +} + +pub struct LocoHandshake { + pub key_encrypt_type: KeyEncryptType, + pub encrypt_type: EncryptType, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +struct RawLocoHandshake { + pub key_size: u32, + pub key_encrypt_type: KeyEncryptType, + pub encrypt_type: EncryptType, +} + +const HANDSHAKE_HEADER_LEN: usize = 12; + +pub async fn send_handshake( + socket: &mut (impl AsyncWrite + Unpin), + crypto: &impl RsaAesCrypto, + key_encrypt_type: KeyEncryptType, + encrypt_type: EncryptType, + key: &Rsa, +) -> Result { + let encrypted_key = crypto.encrypt_key(key)?; + + let mut buffer = bincode::serialize(&RawLocoHandshake { + key_size: encrypted_key.len() as u32, + key_encrypt_type, + encrypt_type, + })?; + buffer.reserve(encrypted_key.len()); + buffer.extend_from_slice(&encrypted_key[..]); + + socket.write_all(&buffer).await?; + Ok(buffer.len()) +} + +pub async fn recv_handshake( + socket: &mut (impl AsyncRead + Unpin), + crypto: &mut impl RsaAesCrypto, + key: &Rsa, +) -> Result { + let mut buffer = [0u8; HANDSHAKE_HEADER_LEN]; + socket.read_exact(&mut buffer).await?; + let header: RawLocoHandshake = bincode::deserialize(&buffer[..])?; + let mut encrypted_key = vec![0u8; header.key_size as usize]; + socket.read_exact(&mut encrypted_key).await?; + crypto.apply_encrypted_key(&encrypted_key, key)?; + Ok(LocoHandshake { + key_encrypt_type: header.key_encrypt_type, + encrypt_type: header.encrypt_type, + }) +} diff --git a/loco/src/config.rs b/loco/src/config.rs new file mode 100644 index 0000000..8ea8731 --- /dev/null +++ b/loco/src/config.rs @@ -0,0 +1,78 @@ +use crate::{crypto::LocoCrypto, types::NetType}; + +pub trait AgentConfig { + fn agent(&self) -> &str; + fn device_model(&self) -> &str; +} + +pub trait LanguageConfig { + fn language(&self) -> &str; +} + +pub trait WebApiConfig: AgentConfig + LanguageConfig { + fn os_version(&self) -> &str; + fn version(&self) -> &str; + + fn api_path(&self, api: impl AsRef) -> String; + fn user_agent(&self) -> String; +} + +pub trait XvcProvider { + fn to_full_xvc_key( + &self, + device_uuid: impl AsRef, + user_agent: impl AsRef, + email: impl AsRef, + ) -> String; +} + +pub trait BookingConfig: AgentConfig { + fn booking_host(&self) -> (&str, u16); + fn mccmnc(&self) -> &str; +} + +pub trait CheckinConfig: BookingConfig + LanguageConfig { + fn checkin_fallback_host(&self) -> (&str, u16); + fn use_sub_device(&self) -> bool; + fn app_version(&self) -> &str; + fn country_iso(&self) -> &str; + fn net_type(&self) -> NetType; + fn new_crypto(&self) -> LocoCrypto; + fn public_key(&self) -> &Rsa; +} + +use openssl::{pkey::Public, rsa::Rsa}; +pub use CheckinConfig as SessionConfig; + +pub type DeviceType = i32; +pub trait ClientConfig: SessionConfig + WebApiConfig { + fn device_type(&self) -> DeviceType; +} + +pub trait OAuthLoginConfig: WebApiConfig { + fn login_token_seeds(&self) -> (&str, &str); +} + +pub(crate) trait WebApiRequest { + fn with_api_a_header(self, web_api: &impl WebApiConfig) -> Self; + fn with_api_base_header(self, web_api: &impl WebApiConfig) -> Self; +} + +impl WebApiRequest for reqwest::RequestBuilder { + fn with_api_a_header(self, web_api: &impl WebApiConfig) -> Self { + self.header( + "A", + &format!( + "{}/{}/{}", + web_api.agent(), + web_api.version(), + web_api.language() + ), + ) + } + + fn with_api_base_header(self, web_api: &impl WebApiConfig) -> Self { + self.header(reqwest::header::ACCEPT, "*/*") + .header(reqwest::header::ACCEPT_LANGUAGE, web_api.language()) + } +} diff --git a/loco/src/crypto.rs b/loco/src/crypto.rs new file mode 100644 index 0000000..31d09bb --- /dev/null +++ b/loco/src/crypto.rs @@ -0,0 +1,80 @@ +use openssl::{ + pkey::{HasPrivate, HasPublic}, + rsa::Rsa, +}; + +use crate::{Error, Result}; + +pub trait RsaAesCrypto { + fn encrypt_key(&self, key: &Rsa) -> Result>; + fn apply_encrypted_key( + &mut self, + encrypted_aes_key: &[u8], + key: &Rsa, + ) -> Result<()>; + + fn encrypt_aes(&self, data: &[u8], iv: &[u8; 16]) -> Result>; + fn decrypt_aes(&self, data: &[u8], iv: &[u8; 16]) -> Result>; + + fn random_iv() -> [u8; 16] { + let mut iv = [0_u8; 16]; + openssl::rand::rand_bytes(&mut iv).expect("This shouldn't happen!"); + iv + } +} + +#[derive(Clone)] +pub struct LocoCrypto { + aes_key: [u8; 16], +} + +impl LocoCrypto { + pub fn new() -> Result { + let mut aes_key = [0u8; 16]; + openssl::rand::rand_bytes(&mut aes_key)?; + Ok(Self::new_with_key(aes_key)) + } + + pub fn new_with_key(aes_key: [u8; 16]) -> Self { + Self { aes_key } + } +} + +impl RsaAesCrypto for LocoCrypto { + fn encrypt_key(&self, key: &Rsa) -> Result> { + let mut out = vec![0u8; 256]; + key.public_encrypt(&self.aes_key, &mut out, openssl::rsa::Padding::PKCS1_OAEP)?; + Ok(out) + } + + fn apply_encrypted_key( + &mut self, + encrypted_aes_key: &[u8], + key: &Rsa, + ) -> Result<()> { + let mut aes_key = vec![0_u8; 256]; + let size = key.private_decrypt( + &encrypted_aes_key, + &mut aes_key, + openssl::rsa::Padding::PKCS1_OAEP, + )?; + if size != 16 { + Err(Error::InvalidCryptoKey) + } else { + self.aes_key.copy_from_slice(&aes_key[..16]); + Ok(()) + } + } + + fn encrypt_aes(&self, data: &[u8], iv: &[u8; 16]) -> Result> { + let cipher = openssl::symm::Cipher::aes_128_cfb128(); + let encrypted = openssl::symm::encrypt(cipher, &self.aes_key, Some(iv), data)?; + Ok(encrypted) + } + + fn decrypt_aes(&self, data: &[u8], iv: &[u8; 16]) -> Result> { + let cipher = openssl::symm::Cipher::aes_128_cfb128(); + let decrypted = openssl::symm::decrypt(cipher, &self.aes_key, Some(iv), data)?; + Ok(decrypted) + } +} diff --git a/loco/src/error.rs b/loco/src/error.rs new file mode 100644 index 0000000..a486cfc --- /dev/null +++ b/loco/src/error.rs @@ -0,0 +1,49 @@ +#[derive(Debug)] +pub enum Error { + Io(std::io::Error), + Openssl(openssl::error::ErrorStack), + Reqwest(reqwest::Error), + BsonSerialize(Box), + BsonDeserialize(Box), + Bincode(bincode::Error), + InvalidCryptoKey, + UnsupportedPacketType, +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { + Self::Io(e) + } +} + +impl From for Error { + fn from(e: openssl::error::ErrorStack) -> Self { + Self::Openssl(e) + } +} + +impl From for Error { + fn from(e: reqwest::Error) -> Self { + Self::Reqwest(e) + } +} + +impl From for Error { + fn from(e: bson::ser::Error) -> Self { + Self::BsonSerialize(Box::new(e)) + } +} + +impl From for Error { + fn from(e: bson::de::Error) -> Self { + Self::BsonDeserialize(Box::new(e)) + } +} + +impl From for Error { + fn from(e: bincode::Error) -> Self { + Self::Bincode(e) + } +} + +pub type Result = std::result::Result; diff --git a/loco/src/lib.rs b/loco/src/lib.rs new file mode 100644 index 0000000..20fe749 --- /dev/null +++ b/loco/src/lib.rs @@ -0,0 +1,50 @@ +pub mod api; +pub mod codec; +pub mod config; +pub mod crypto; +mod error; +pub mod types; + +pub use error::*; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(untagged)] +pub enum Nonexhaustive { + Known(T), + Unknown(i32), +} + +impl Nonexhaustive { + pub fn is_known(&self) -> bool { + matches!(self, Known(_)) + } +} + +pub use Nonexhaustive::*; + +#[cfg(test)] +mod test { + use super::*; + use serde_repr::{Deserialize_repr, Serialize_repr}; + use serde_test::{assert_tokens, Token}; + + #[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] + #[repr(i32)] + enum MyEnum { + TheOnlyOne = 1, + } + + #[test] + fn nonexhaustive_known_ser_de() { + let known = Known(MyEnum::TheOnlyOne); + assert_tokens(&known, &[Token::I32(1)]); + } + + #[test] + fn nonexhaustive_unknown_ser_de() { + let unknown: Nonexhaustive = Unknown(13); + assert_tokens(&unknown, &[Token::I32(13)]); + } +} diff --git a/loco/src/types/booking.rs b/loco/src/types/booking.rs new file mode 100644 index 0000000..446e430 --- /dev/null +++ b/loco/src/types/booking.rs @@ -0,0 +1,130 @@ +use serde::{Deserialize, Serialize}; + +/// Network related settings. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct NetworkConfig { + /// Background keep interval. + #[serde(rename = "bgKeepItv")] + pub background_keep_interval: i32, + + /// Background reconnect interval. + #[serde(rename = "bgReconnItv")] + pub background_reconnect_interval: i32, + + /// Background ping interval. + #[serde(rename = "bgPingItv")] + pub background_ping_interval: i32, + + /// Foreground keep interval. + #[serde(rename = "fgPingItv")] + pub foreground_ping_interval: i32, + + /// Request timeout. + #[serde(rename = "reqTimeout")] + pub request_timeout: i32, + + /// Encrypt type. Used in secure layer. + #[serde(rename = "encType")] + pub encrypt_type: i32, + + /// Connection timeout. + #[serde(rename = "connTimeout")] + pub connection_timeout: i32, + + /// Packet header receive timeout. + #[serde(rename = "recvHeaderTimeout")] + pub header_receive_timeout: i32, + + #[serde(rename = "inSegTimeout")] + pub in_segment_timeout: i32, + + #[serde(rename = "outSegTimeout")] + pub out_segment_timeout: i32, + + /// Max tcp packet size. (uncertain) + #[serde(rename = "blockSendBufSize")] + pub block_send_buffer_size: i32, + + /// Usable port list. + pub ports: Vec, +} + +/// Checkin server host list. +/// Only lsl and lsl6 work. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct TicketHosts { + pub ssl: Vec, + pub v2sl: Vec, + pub lsl: Vec, + pub lsl6: Vec, +} + +/// Video profile information. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct VideoProfile { + #[serde(rename = "vBitrate")] + pub bitrate: i32, + #[serde(rename = "vResolution")] + pub resolution: i32, +} + +/// Miscellaneous settings. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ExtraConfig { + pub write_retry_timeout: i32, + pub traceroute_host: Vec, + pub traceroute_host_6: Vec, +} + +/// Video / Audio / File related config. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Trailer { + #[serde(rename = "tokenExpireTime")] + pub token_expire_time: i32, + pub resolution: i32, + #[serde(rename = "resolutionHD")] + pub resolution_hd: i32, + #[serde(rename = "compRatio")] + pub compress_ratio: i32, + #[serde(rename = "compRatioHD")] + pub compress_ratio_hd: i32, + #[serde(rename = "downMode")] + pub download_mode: i32, + #[serde(rename = "concurrentDownLimit")] + pub concurrent_download_limit: i32, + #[serde(rename = "concurrentUpLimit")] + pub concurrent_upload_limit: i32, + pub max_relay_size: i32, + #[serde(rename = "downCheckSize")] + pub download_check_size: i32, + #[serde(rename = "upMaxSize")] + pub upload_max_size: i32, + #[serde(rename = "videoUpMaxSize")] + pub video_upload_max_size: i32, + #[serde(rename = "vCodec")] + pub video_codec: i32, + #[serde(rename = "vFps")] + pub video_fps: i32, + #[serde(rename = "aCodec")] + pub audio_codec: i32, + #[serde(rename = "contentExpireTime")] + pub content_expire_time: i32, + #[serde(rename = "vResolution")] + pub video_resolution: i32, + #[serde(rename = "vBitrate")] + pub video_bitrate: i32, + #[serde(rename = "aFrequency")] + pub audio_frequency: i32, +} + +/// HD video / audio settings. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct TrailerHD { + #[serde(rename = "vResolution")] + pub video_resolution: i32, + #[serde(rename = "vBitrate")] + pub video_bitrate: i32, + #[serde(rename = "aFrequency")] + pub audio_frequency: i32, +} diff --git a/loco/src/types/channel.rs b/loco/src/types/channel.rs new file mode 100644 index 0000000..e69de29 diff --git a/loco/src/types/chat.rs b/loco/src/types/chat.rs new file mode 100644 index 0000000..d16a171 --- /dev/null +++ b/loco/src/types/chat.rs @@ -0,0 +1,43 @@ +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use crate::Nonexhaustive; + +use super::UserId; + +pub type ChatId = i64; +pub type LogId = i64; +pub type MessageId = i64; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct ChatLog { + #[serde(rename = "logId")] + pub log_id: LogId, + #[serde(rename = "chatId")] + pub chat_id: ChatId, + #[serde(rename = "type")] + pub chat_type: ChatType, + #[serde(rename = "authorId")] + pub sender_id: UserId, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + #[serde(rename = "sendAt")] + pub sent_at: i64, + #[serde(rename = "prevId", skip_serializing_if = "Option::is_none")] + pub attachment: Option, + #[serde(rename = "msgId")] + pub msg_id: MessageId, + #[serde(rename = "prevId", skip_serializing_if = "Option::is_none")] + pub prev_log_id: Option, + + pub referer: Option>, +} + +pub type ChatType = i32; + +#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] +#[repr(i32)] +pub enum ChatReferer { + KakaoI = 1, + Bot = 2, +} diff --git a/loco/src/types/mod.rs b/loco/src/types/mod.rs new file mode 100644 index 0000000..28c67e4 --- /dev/null +++ b/loco/src/types/mod.rs @@ -0,0 +1,13 @@ +mod booking; +mod chat; +mod openlink; +pub mod request; +pub mod response; +mod user; + +pub use booking::*; +pub use chat::*; +pub use openlink::*; +pub use user::*; + +pub type NetType = i32; diff --git a/loco/src/types/openlink.rs b/loco/src/types/openlink.rs new file mode 100644 index 0000000..e0ba5a2 --- /dev/null +++ b/loco/src/types/openlink.rs @@ -0,0 +1,154 @@ +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use super::OpenlinkChannelUser; + +pub type LinkId = i64; + +/// Openlink information. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Openlink { + /// Link ID. + #[serde(rename = "li")] + link_id: LinkId, + + /// Open token. + #[serde(rename = "otk")] + open_token: i32, + + /// Link name. + #[serde(rename = "ln")] + name: String, + + /// Link URL. + #[serde(rename = "lu")] + url: String, + + /// Link image URL. + #[serde(rename = "liu")] + image_url: String, + + /// Link cover URL. + #[serde(rename = "lcu")] + cover_url: String, + + /// Owner of this channel. + #[serde(rename = "olu")] + owner: OpenlinkChannelUser, + + /// Unknown. + vt: i32, + + /// Link type. + #[serde(rename = "lt")] + link_type: OpenlinkType, + + /// Description. + #[serde(rename = "desc")] + description: String, + + /// Unknown. + pc: String, + + /// Unknown. + pa: bool, + + /// Channel activation status. + /// `true` if this channel is activated. + #[serde(rename = "ac")] + activated: bool, + + /// Channel searchable status. + /// `true` if this channel is searchable. + #[serde(rename = "sc")] + searchable: bool, + + /// Link privilege mask. + #[serde(rename = "pv")] + privilege: i32, + + /// Unknown. + ex: bool, + + // /// Unknown. + // omt: unknown, + /// Link creation time. + #[serde(rename = "ca")] + created_at: i32, + + /// Open channel cover. + #[serde(rename = "oc")] + cover: Option, + + /// Open profile cover. + #[serde(rename = "op")] + op: Option, + + #[serde(flatten)] + extra: Option, +} + +/// Open channel cover. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct OpenChannelCover { + /// Open link type. + #[serde(rename = "t")] + link_type: OpenlinkType, + + #[serde(rename = "co")] + option: OpenChannelCoverOption, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct OpenChannelCoverOption { + /// Channel description. + #[serde(rename = "desc")] + description: String, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct OpenProfileCover { + /// Profile description. + #[serde(rename = "desc")] + description: String, + + tags: Option>, +} + +/// Openlink extra information. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct OpenlinkExtra { + /// Max user limit. (for channel) + #[serde(rename = "ml")] + max_user: Option, + + /// Max direct limit. (for profile) + #[serde(rename = "dcl")] + max_direct: Option, +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] +#[repr(i32)] +pub enum OpenChannelPermission { + Owner = 1, + None = 2, + Manager = 4, + Bot = 8, +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] +#[repr(i32)] +pub enum OpenlinkType { + Profile = 1, + Channel = 2, +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] +#[repr(i32)] +pub enum OpenProfileType { + Main = 1, + AnonymousKakao = 2, + AnonymousKakao2 = 4, + Unknown = 8, + OpenProfile = 16, +} diff --git a/loco/src/types/request/booking.rs b/loco/src/types/request/booking.rs new file mode 100644 index 0000000..0b45826 --- /dev/null +++ b/loco/src/types/request/booking.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; + +use crate::config::BookingConfig; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct GetConf { + #[serde(rename = "MCCMNC")] + pub mccmnc: String, + pub model: String, + pub os: String, +} + +impl GetConf { + pub fn from_config(config: &impl BookingConfig) -> Self { + Self { + mccmnc: config.mccmnc().into(), + model: config.device_model().into(), + os: config.agent().into(), + } + } +} diff --git a/loco/src/types/request/checkin.rs b/loco/src/types/request/checkin.rs new file mode 100644 index 0000000..8ffa8f6 --- /dev/null +++ b/loco/src/types/request/checkin.rs @@ -0,0 +1,52 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + config::CheckinConfig, + types::{NetType, UserId}, +}; + +/// Checkin request. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Checkin { + #[serde(rename = "MCCMNC")] + pub mccmnc: String, + + #[serde(rename = "appVer")] + pub app_version: String, + + #[serde(rename = "countryISO")] + pub country_iso: String, + + #[serde(rename = "lang")] + pub language: String, + + #[serde(rename = "ntype")] + pub net_type: NetType, + + #[serde(rename = "useSub")] + pub use_sub_device: bool, + + pub os: String, + + #[serde(rename = "userId", skip_serializing_if = "Option::is_none")] + pub user_id: Option, +} + +impl Checkin { + pub fn from_config(config: &impl CheckinConfig) -> Self { + Self { + mccmnc: config.mccmnc().into(), + app_version: config.app_version().into(), + country_iso: config.country_iso().into(), + language: config.language().into(), + net_type: config.net_type(), + use_sub_device: config.use_sub_device(), + os: config.agent().into(), + user_id: None, + } + } + + pub fn with_user(self, user_id: Option) -> Self { + Self { user_id, ..self } + } +} diff --git a/loco/src/types/request/mod.rs b/loco/src/types/request/mod.rs new file mode 100644 index 0000000..c2901bb --- /dev/null +++ b/loco/src/types/request/mod.rs @@ -0,0 +1,39 @@ +use serde::{Deserialize, Serialize}; +use strum::ToString; + +mod booking; +mod checkin; +mod ping; + +pub use booking::*; +pub use checkin::*; +pub use ping::*; + +#[derive(Serialize, Deserialize, ToString, Debug, PartialEq, Clone)] +#[serde(untagged)] +pub enum LocoRequest { + #[strum(serialize = "PING")] + Ping(Ping), + #[strum(serialize = "GETCONF")] + GetConf(GetConf), + #[strum(serialize = "CHECKIN")] + Checkin(Checkin), +} + +impl From for LocoRequest { + fn from(ping: Ping) -> Self { + Self::Ping(ping) + } +} + +impl From for LocoRequest { + fn from(get_conf: GetConf) -> Self { + Self::GetConf(get_conf) + } +} + +impl From for LocoRequest { + fn from(checkin: Checkin) -> Self { + Self::Checkin(checkin) + } +} diff --git a/loco/src/types/request/ping.rs b/loco/src/types/request/ping.rs new file mode 100644 index 0000000..971001a --- /dev/null +++ b/loco/src/types/request/ping.rs @@ -0,0 +1,4 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Ping; diff --git a/loco/src/types/response/booking.rs b/loco/src/types/response/booking.rs new file mode 100644 index 0000000..b672c59 --- /dev/null +++ b/loco/src/types/response/booking.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; + +use crate::types::*; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct GetConf { + /// Last revision. + #[serde(rename = "revision")] + pub last_revision: i32, + + /// Network config for high network speed environment + #[serde(rename = "3g")] + pub config_3g: NetworkConfig, + + /// Network config for low network speed environment + #[serde(rename = "wifi")] + pub config_wifi: NetworkConfig, + + /// Checkin server host list. + #[serde(rename = "ticket")] + pub ticket_hosts: TicketHosts, + + /// Video profile. + #[serde(rename = "profile")] + pub video_profile: VideoProfile, + + /// Other configuration. + #[serde(rename = "etc")] + pub extra: ExtraConfig, + /// Video / Audio / File related config. + pub trailer: Trailer, + + /// HD video / audio config. + #[serde(rename = "trailer.h")] + pub trailer_hd: TrailerHD, +} diff --git a/loco/src/types/response/checkin.rs b/loco/src/types/response/checkin.rs new file mode 100644 index 0000000..a4fb045 --- /dev/null +++ b/loco/src/types/response/checkin.rs @@ -0,0 +1,43 @@ +use serde::{Deserialize, Serialize}; + +/// Checkin response. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Checkin { + /// IPv4 loco host. + pub host: String, + + /// IPv6 loco host. + #[serde(rename = "host6")] + pub host_ipv6: String, + + /// Loco port. + pub port: i32, + + /// Cache expire time. + #[serde(rename = "cacheExpire")] + pub cache_expire: i32, + + /// IPv4 call server host. + #[serde(rename = "cshost")] + pub call_server_host: String, + + /// Call server port. + #[serde(rename = "csport")] + pub call_server_port: i32, + + /// IPv6 call server host. + #[serde(rename = "cshost6")] + pub call_server_host_ipv6: String, + + /// IPv4 video server host. + #[serde(rename = "vsshost")] + pub video_server_host: String, + + /// Video server port. + #[serde(rename = "vssport")] + pub video_server_port: i32, + + /// IPv6 video server host. + #[serde(rename = "vsshost6")] + pub video_server_host_ipv6: String, +} diff --git a/loco/src/types/response/mod.rs b/loco/src/types/response/mod.rs new file mode 100644 index 0000000..3f33960 --- /dev/null +++ b/loco/src/types/response/mod.rs @@ -0,0 +1,86 @@ +mod booking; +mod checkin; + +use serde::{Deserialize, Serialize}; +use strum::ToString; + +pub use booking::*; +pub use checkin::*; + +pub type DataStatus = i32; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub enum LocoResponse { + Fail { + status: DataStatus, + }, + Success { + status: DataStatus, + #[serde(flatten)] + kind: Box, + }, +} + +#[derive(Serialize, Deserialize, ToString, Debug, PartialEq, Clone)] +#[serde(untagged)] +pub enum ResponseKind { + #[strum(serialize = "GETCONF")] + GetConf(GetConf), + #[strum(serialize = "CHECKIN")] + Checkin(Checkin), +} + +impl From for ResponseKind { + fn from(get_conf: GetConf) -> Self { + Self::GetConf(get_conf) + } +} + +impl From for ResponseKind { + fn from(checkin: Checkin) -> Self { + Self::Checkin(checkin) + } +} + +impl LocoResponse { + pub const SUCCESS: DataStatus = 0; + pub const INVALID_USER: DataStatus = -1; + pub const CLIENT_ERROR: DataStatus = -200; + pub const NOT_LOGON: DataStatus = -201; + pub const INVALID_METHOD: DataStatus = -202; + pub const INVALID_PARAMETER: DataStatus = -203; + pub const INVALID_BODY: DataStatus = -203; + pub const INVALID_HEADER: DataStatus = -204; + pub const UNAUTHORIZED_CHAT_DELETE: DataStatus = -210; + pub const MEDIA_SERVER_ERROR: DataStatus = -300; + pub const CHAT_SPAM_LIMIT: DataStatus = -303; + pub const RESTRICTED_APP: DataStatus = -304; + pub const LOGINLIST_CHATLIST_FAILED: DataStatus = -305; + pub const MEDIA_NOT_FOUND: DataStatus = -306; + pub const MEDIA_THUMB_GEN_FAILED: DataStatus = -307; + pub const UNSUPPORTED: DataStatus = -308; + pub const PARTIAL: DataStatus = -310; + pub const LINK_JOIN_TPS_EXCEEDED: DataStatus = -312; + pub const CHAT_SEND_RESTRICTED: DataStatus = -321; + pub const CHANNEL_CREATE_TEMP_RESTRICTED: DataStatus = -322; + pub const CHANNEL_CREATE_RESTRICTED: DataStatus = -323; + pub const OPENLINK_UNAVAILABLE: DataStatus = -324; + pub const INVITE_COUNT_LIMITED: DataStatus = -325; + pub const OPENLINK_CREATE_RESTRICTED: DataStatus = -326; + pub const INVALID_CHANNEL: DataStatus = -401; + pub const CHAT_BLOCKED_BY_FRIEND: DataStatus = -402; + pub const NOT_CHATABLE_USER: DataStatus = -403; + pub const GAME_MESSAGE_BLOCKED: DataStatus = -406; + pub const BLOCKED_IP: DataStatus = -444; + pub const BACKGROUND_LOGIN_BLOCKED: DataStatus = -445; + pub const OPERATION_DENIED: DataStatus = -500; + pub const CHANNEL_USER_LIMITED: DataStatus = -501; + pub const WRITE_WHILE_BLOCKED: DataStatus = -814; + pub const OPENCHAT_REJOIN_REQUIRED: DataStatus = -815; + pub const OPENCHAT_TIME_RESTRICTED: DataStatus = -819; + pub const INVALID_ACCESS_TOKEN: DataStatus = -950; + pub const BLOCKED_ACCOUNT: DataStatus = -997; + pub const AUTH_REQUIRED: DataStatus = -998; + pub const UPDATE_REQUIRED: DataStatus = -999; + pub const SERVER_UNDER_MAINTENANCE: DataStatus = -9797; +} diff --git a/loco/src/types/user.rs b/loco/src/types/user.rs new file mode 100644 index 0000000..3121b3a --- /dev/null +++ b/loco/src/types/user.rs @@ -0,0 +1,166 @@ +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use super::{ChatId, LinkId, OpenChannelPermission, OpenProfileType}; + +pub type UserId = i64; + +/// Normal channel member. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct NormalMember { + /// User ID. + user_id: UserId, + + /// Account ID. + account_id: i32, + + /// User nickname. + #[serde(rename = "nickName")] + nickname: String, + + /// User's country in ISO 3166 format. + country_iso: String, + + /// Profile image URL. + profile_image_url: String, + + /// Full profile image URL. + full_profile_image_url: String, + + /// Original profile image URL. + original_profile_image_url: String, + + /// Profile status message. + status_message: String, + + /// Linked kakao services. + linked_services: String, + + /// Account suspension state. + /// `true` if the account is suspended. + suspended: bool, + + /// User type. (uncertain) + #[serde(rename = "ut")] + user_type: i32, +} + +/// Open channel member. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct OpenMember { + /// User ID. + #[serde(rename = "userId")] + user_id: UserId, + + /// User type. + #[serde(rename = "type")] + user_type: UserType, + + /// Account suspension state. + /// `true` if the account is suspended. + suspended: bool, + + /// User nickname. + #[serde(rename = "nickName")] + nickname: String, + + /// Profile image URL. + #[serde(rename = "pi")] + profile_image_url: String, + + /// Full profile image URL. + #[serde(rename = "fpi")] + full_profile_image_url: String, + + /// Original profile image URL. + #[serde(rename = "opi")] + original_profile_image_url: String, + + /// Open token. + #[serde(rename = "opt")] + open_token: i32, + + /// Profile link ID. Only presents if user is using open profile. + pli: Option, + + /// Open channel user permission. + #[serde(rename = "mt")] + user_permission: OpenChannelPermission, +} + +/// Kicked openlink member. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct KickedOpenlinkMember { + /// User ID. + #[serde(rename = "userId")] + user_id: UserId, + + /// User nickname. + #[serde(rename = "nickName")] + nickname: String, + + /// Profile image URL. + #[serde(rename = "pi")] + profile_image_url: String, + + /// Original channel ID. + #[serde(rename = "c")] + kicked_from: ChatId, + + /// Unknown. + dc: bool, +} + +/// Openlink channel user. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct OpenlinkChannelUser { + /// User ID. + #[serde(rename = "userId")] + user_id: UserId, + + /// Openlink profile type. + #[serde(rename = "ptp")] + profile_type: OpenProfileType, + + /// Open chat user permission. + #[serde(rename = "lmt")] + lmt: OpenChannelPermission, + + /// User nickname. + #[serde(rename = "nn")] + nickname: String, + + /// Profile image URL. + #[serde(rename = "pi")] + profile_image_url: String, + + /// Full profile image URL. + #[serde(rename = "fpi")] + full_profile_image_url: String, + + /// Original profile image URL. + #[serde(rename = "opi")] + original_profile_image_url: String, + + /// Open token. + #[serde(rename = "opt")] + open_token: i32, + + /// Profile link ID. + pli: LinkId, + + /// Special link privilege mask. + #[serde(rename = "pv")] + privilege: i32, +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] +#[repr(i32)] +pub enum UserType { + Undefined = -999999, + NotFriend = -100, + Deactivated = 9, + Friend = 100, + OpenProfile = 1000, +} diff --git a/src/internal/account.rs b/src/internal/account.rs deleted file mode 100644 index f67aca9..0000000 --- a/src/internal/account.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::internal::{XVCKey, AUTH_HEADER_WITHOUT_AGENT, AUTH_USER_AGENT, LANGUAGE}; -use crate::types::Os; -use crate::{define, define_host}; -use reqwest::header::{self, HeaderMap, HeaderValue}; -use reqwest::Url; - -define! {account_path, "account"} - -define_host!(account, "ac-sb-talk.kakao.com"); - -pub fn get_internal_path(agent: &Os, path: &str) -> String { - format!(concat!("{}/", account_path!(), "/{}"), agent.as_str(), path) -} - -pub fn get_auth_header(agent: &Os, xvc_key: &XVCKey) -> HeaderMap { - let mut header_map = HeaderMap::new(); - header_map.append( - header::CONTENT_TYPE, - HeaderValue::from_static("application/x-www-form-urlencoded"), - ); - header_map.append(header::HOST, HeaderValue::from_static(account::HOST)); - header_map.append( - "A", - HeaderValue::from_str(&format!("{}{}", agent.as_str(), AUTH_HEADER_WITHOUT_AGENT)) - .expect("Invalid value for header A"), - ); - header_map.append( - "X-VC", - HeaderValue::from_str(&xvc_key[0..16]).expect("Invalid value for header X-VC"), - ); - header_map.append( - header::USER_AGENT, - HeaderValue::from_static(AUTH_USER_AGENT), - ); - header_map.append(header::ACCEPT_LANGUAGE, HeaderValue::from_static(LANGUAGE)); - header_map -} - -pub fn get_login_url(os: &Os) -> Url { - let mut url: Url = account::url(); - url.set_path(&get_internal_path(os, paths::LOGIN)); - url -} - -pub fn get_request_passcode_url(os: &Os) -> Url { - let mut url: Url = account::url(); - url.set_path(&get_internal_path(os, paths::REQUEST_PASSCODE)); - url -} - -pub fn get_register_device_url(os: &Os) -> Url { - let mut url: Url = account::url(); - url.set_path(&get_internal_path(os, paths::REGISTER_DEVICE)); - url -} - -pub mod paths { - #![allow(dead_code)] - pub const LOGIN: &str = "login.json"; - pub const REGISTER_DEVICE: &str = "register_device.json"; - pub const REQUEST_PASSCODE: &str = "request_passcode.json"; - pub const LOGIN_TOKEN: &str = "login_token.json"; - pub const REQUEST_VERIFY_EMAIL: &str = "request_verify_email.json"; - pub const RENEW_TOKEN: &str = "renew_token.json"; - pub const CHANGE_UUID: &str = "change_uuid.json"; - pub const CAN_CHANGE_UUID: &str = "can_change_uuid.json"; -} diff --git a/src/internal/attachment.rs b/src/internal/attachment.rs deleted file mode 100644 index 728cc20..0000000 --- a/src/internal/attachment.rs +++ /dev/null @@ -1,51 +0,0 @@ -use reqwest::Url; - -use crate::define_host; - -define_host!(profile_upload, "up-p.talk.kakao.com"); -define_host!(media_upload, "up-gp.talk.kakao.com"); -define_host!(video_upload, "up-m.talk.kakao.com"); -define_host!(audio_upload, "up-v.talk.kakao.com"); -define_host!(group_profile_upload, "up-a.talk.kakao.com"); -define_host!(file, "up-p.talk.kakao.com"); -define_host!(media_file, "up-p.talk.kakao.com"); -define_host!(audio_file, "up-p.talk.kakao.com"); -define_host!(video_file, "up-p.talk.kakao.com"); - -pub enum AttachmentType { - // image/jpeg - Image, - // audio/mp4 - Audio, - // video/mp4 - Video, - // image/jpeg, (application/*) - File, -} - -impl AttachmentType { - pub fn get_upload_url(&self) -> Url { - match self { - AttachmentType::Image => media_upload::url(), - AttachmentType::Audio => audio_upload::url(), - AttachmentType::Video => video_upload::url(), - _ => media_upload::url(), - } - } - - pub fn get_attachment_url(&self) -> Url { - match self { - AttachmentType::Image => media_file::url(), - AttachmentType::Audio => audio_file::url(), - AttachmentType::Video => video_file::url(), - AttachmentType::File => media_file::url(), - /*_ => media_file::URL, */ - } - } - - pub fn get_uploaded_file_url(&self, upload_path: &str) -> Url { - let mut url: Url = self.get_attachment_url(); - url.set_path(upload_path); - url - } -} diff --git a/src/internal/device_register_data.rs b/src/internal/device_register_data.rs deleted file mode 100644 index eacbb38..0000000 --- a/src/internal/device_register_data.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::internal::LoginData; -use serde::{Deserialize, Serialize}; -use std::ops::Deref; - -#[derive(Debug, PartialEq, Deserialize, Serialize)] -pub struct DeviceRegisterData { - #[serde(flatten)] - login_data: LoginData, - pub passcode: String, -} - -impl Deref for DeviceRegisterData { - type Target = LoginData; - - fn deref(&self) -> &Self::Target { - &self.login_data - } -} - -impl DeviceRegisterData { - pub fn new(login_data: LoginData, passcode: String) -> DeviceRegisterData { - DeviceRegisterData { - login_data, - passcode, - } - } -} diff --git a/src/internal/emoticon.rs b/src/internal/emoticon.rs deleted file mode 100644 index dacb482..0000000 --- a/src/internal/emoticon.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::internal::Language; -use reqwest::Url; - -pub fn get_url(lang: &Language) -> Url { - Url::parse( - format!( - "http://item-{lang}.talk.kakao.co.kr", - lang = lang.to_string() - ) - .as_ref(), - ) - .expect("Illegal url specified") -} - -pub fn get_image_url(path: &str, lang: &Language) -> Url { - let mut url = get_url(lang); - url.set_path(path); - url -} - -pub fn get_title_url(id: &str, ext: &str, lang: &Language) -> Url { - let mut url = get_url(lang); - url.set_path(format!("dw/{}.title.{}", id, ext).as_ref()); - url -} - -pub fn get_pack_url(id: &str, lang: &Language) -> Url { - let mut url = get_url(lang); - url.set_path(format!("dw/{}.file.pack.zip", id).as_ref()); - url -} - -pub fn get_thumbnail_pack_url(id: &str, lang: &Language) -> Url { - let mut url = get_url(lang); - url.set_path(format!("dw/{}.file.thumb_pack.zip", id).as_ref()); - url -} diff --git a/src/internal/key.rs b/src/internal/key.rs deleted file mode 100644 index a30d052..0000000 --- a/src/internal/key.rs +++ /dev/null @@ -1,26 +0,0 @@ -pub const LOCO_PEM_PUB_KEY: &str = include_str!("loco_pem_pub_key"); - -// Type check required -pub const LOCO_PUB_KEY: ([u8; 256], u8) = ( - hex_literal::hex!( - " -a449 6044 1c7e 83bb 2789 8156 ecb1 3c8a -faf0 5d28 4a4d 1155 f255 cd22 d317 6cde -5048 2f2f 27f7 1348 e4d2 eb5f 57bf 9671 -ef15 c922 4e04 2b1b 567a c106 6e06 6911 -43f6 c50f 8878 7f68 cf42 716b 210c bef0 -f59d 5340 5a0a 5613 8a68 7221 2802 bb0a -eea6 3763 05db d428 831e 8f61 a232 efed -d8db a377 305e f972 321e 1352 b5f6 4630 -993e 5549 c64f cb56 3cdc 97da 2124 b925 -ddea 12ad fd00 1389 10f6 6937 fab6 8486 -ae43 bfe2 03c4 a617 f9f2 32b5 458a 9ab4 -09ba c8ed adef 6855 45f9 b013 9867 4773 -7b3f d76a 9bac 1215 1622 6981 ea67 2255 -77d1 5d0f 082b 8207 eaf7 cdcb 1312 3937 -cb12 1458 3764 8c2f 3a65 0181 6231 5e77 -ead2 d2dd 5986 e462 5176 4a43 b9ba 8f79 - " - ), - 0x03, -); diff --git a/src/internal/language.rs b/src/internal/language.rs deleted file mode 100644 index 31bee4a..0000000 --- a/src/internal/language.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub enum Language { - Korean, - Raw(String), -} - -impl ToString for Language { - fn to_string(&self) -> String { - match self { - Language::Korean => "ko".to_string(), - Language::Raw(language) => language.to_owned(), - } - } -} diff --git a/src/internal/loco_pem_pub_key b/src/internal/loco_pem_pub_key deleted file mode 100644 index 36c4326..0000000 --- a/src/internal/loco_pem_pub_key +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEApElgRBx+g7sniYFW7LE8ivrwXShKTRFV8lXNItMXbN5QSC8vJ/\ -cTSOTS619Xv5Zx7xXJIk4EKxtWesEGbgZpEUP2xQ+IeH9oz0JxayEMvvD1nVNAWgpWE4pociEoArsK7qY3YwXb1CiDHo9hojLv7djbo3cwXvlyMh4TUrX2RjCZPlVJxk/\ -LVjzcl9ohJLkl3eoSrf0AE4kQ9mk3+raEhq5Dv+IDxKYX+fIytUWKmrQJusjtre9oVUX5sBOYZ0dzez/\ -XapusEhUWImmB6mciVXfRXQ8IK4IH6vfNyxMSOTfLEhRYN2SMLzplAYFiMV536tLS3VmG5GJRdkpDubqPeQIBAw== ------END PUBLIC KEY----- \ No newline at end of file diff --git a/src/internal/loco_pub_key b/src/internal/loco_pub_key deleted file mode 100644 index c2443da..0000000 --- a/src/internal/loco_pub_key +++ /dev/null @@ -1,16 +0,0 @@ -a449 6044 1c7e 83bb 2789 8156 ecb1 3c8a -faf0 5d28 4a4d 1155 f255 cd22 d317 6cde -5048 2f2f 27f7 1348 e4d2 eb5f 57bf 9671 -ef15 c922 4e04 2b1b 567a c106 6e06 6911 -43f6 c50f 8878 7f68 cf42 716b 210c bef0 -f59d 5340 5a0a 5613 8a68 7221 2802 bb0a -eea6 3763 05db d428 831e 8f61 a232 efed -d8db a377 305e f972 321e 1352 b5f6 4630 -993e 5549 c64f cb56 3cdc 97da 2124 b925 -ddea 12ad fd00 1389 10f6 6937 fab6 8486 -ae43 bfe2 03c4 a617 f9f2 32b5 458a 9ab4 -09ba c8ed adef 6855 45f9 b013 9867 4773 -7b3f d76a 9bac 1215 1622 6981 ea67 2255 -77d1 5d0f 082b 8207 eaf7 cdcb 1312 3937 -cb12 1458 3764 8c2f 3a65 0181 6231 5e77 -ead2 d2dd 5986 e462 5176 4a43 b9ba 8f79 \ No newline at end of file diff --git a/src/internal/login_access_data.rs b/src/internal/login_access_data.rs deleted file mode 100644 index c5e2540..0000000 --- a/src/internal/login_access_data.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::internal::StatusCode; -use serde::{Deserialize, Serialize}; - -// Maps to LoginAccessDataStruct -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LoginAccessData { - pub status: Option, - pub story_url: Option, - pub user_id: Option, - pub country_iso: Option, - pub country_code: Option, - pub account_id: Option, - pub server_time: Option, - pub reset_user_data: Option, - pub access_token: Option, - pub refresh_token: Option, - pub token_type: Option, - pub auto_login_id: Option, - pub display_id: Option, - pub main_device: Option, - pub main_device_app_version: Option, -} diff --git a/src/internal/login_data.rs b/src/internal/login_data.rs deleted file mode 100644 index a00f405..0000000 --- a/src/internal/login_data.rs +++ /dev/null @@ -1,45 +0,0 @@ -use data_encoding::BASE64; -use serde::{Deserialize, Serialize}; - -use crate::internal::XVCKey; - -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -pub struct LoginData { - email: String, - password: String, - device_uuid: String, - device_name: String, - os_version: String, - permanent: bool, - forced: bool, -} - -impl LoginData { - pub fn new( - email: String, - password: String, - device_uuid: &str, - device_name: String, - os_version: String, - permanent: bool, - forced: bool, - ) -> Self { - LoginData { - email, - password, - device_uuid: BASE64.encode(device_uuid.as_bytes()), - device_name, - os_version, - permanent, - forced, - } - } - - pub fn to_xvc_key(&self, auth_user_agent: &str) -> XVCKey { - XVCKey::new( - auth_user_agent, - self.email.as_ref(), - self.device_uuid.as_ref(), - ) - } -} diff --git a/src/internal/mod.rs b/src/internal/mod.rs deleted file mode 100644 index b470c49..0000000 --- a/src/internal/mod.rs +++ /dev/null @@ -1,72 +0,0 @@ -pub use attachment::AttachmentType; -pub use device_register_data::DeviceRegisterData; -pub use language::Language; -pub use login_access_data::LoginAccessData; -pub use login_data::LoginData; -pub use status_code::StatusCode; -pub use token_client::TokenClient; -pub use xvc_key::XVCKey; - -pub mod account; -pub mod emoticon; -pub mod key; - -mod attachment; -mod device_register_data; -mod language; -mod login_access_data; -mod login_data; -mod status_code; -mod token_client; -mod xvc_key; - -/*** macros ***/ -#[macro_export] -macro_rules! define { - ($i:ident, $e:expr) => { - #[macro_export] - macro_rules! $i { - () => { - $e - }; - } - }; -} - -#[macro_export] -macro_rules! define_host { - ($name:ident, $host:literal) => { - pub mod $name { - #![allow(dead_code)] - use reqwest::Url; - pub const HOST: &str = $host; - pub const URL: &str = concat!("https://", $host); - pub fn url() -> Url { - Url::parse(URL).expect(concat!("Illegal url: ", "https://", $host)) - } - } - }; -} - -/*** defines ***/ -define! {version, "3.1.1"} -define! {internal_app_subversion, 2441} -define! {os_version, "10.0"} -define! {language, "ko"} -//define!{internal_protocol, "https"} -//hosts -define_host!(internal, "sb-talk.kakao.com"); - -/*** constants ***/ -// Maps to InternalAppVersion -pub const APP_VERSION: &str = concat!(version!(), ".", internal_app_subversion!()); -// Maps to InternalAppSubVersion -pub const INTERNAL_APP_SUBVERSION: u16 = internal_app_subversion!(); -pub const OS_VERSION: &str = os_version!(); -pub const LANGUAGE: &str = language!(); -pub const AUTH_USER_AGENT: &str = - concat!("KT/", version!(), " Wd/", os_version!(), " ", language!()); -pub const AUTH_HEADER_WITHOUT_AGENT: &str = concat!("/", version!(), "/", language!()); -// LOCO entry -pub const LOCO_ENTRY: &str = "booking-loco.kakao.com"; -pub const LOCO_ENTRY_PORT: u16 = 443; diff --git a/src/internal/status_code.rs b/src/internal/status_code.rs deleted file mode 100644 index ac23a1d..0000000 --- a/src/internal/status_code.rs +++ /dev/null @@ -1,15 +0,0 @@ -use serde_repr::*; -#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone, Copy)] -#[repr(i32)] -pub enum StatusCode { - Success = 0, - WrongPassword = 12, - CannotFindId = 30, - - DeviceNotRegistered = -100, - - WrongConfirmCode = -111, - TooManyConfirmRequest = -112, - - Failed = -500, -} diff --git a/src/internal/token_client.rs b/src/internal/token_client.rs deleted file mode 100644 index 24a01bd..0000000 --- a/src/internal/token_client.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::ops::Deref; - -use reqwest::blocking::Response; -use reqwest::Error; - -use crate::internal::{account, DeviceRegisterData, LoginAccessData, LoginData, AUTH_USER_AGENT}; -use crate::types::Os; - -pub struct TokenClient { - client: reqwest::blocking::Client, - agent: Os, -} - -impl Deref for TokenClient { - type Target = reqwest::blocking::Client; - - fn deref(&self) -> &Self::Target { - &self.client - } -} - -impl TokenClient { - pub fn new(agent: Os) -> Self { - TokenClient { - client: Default::default(), - agent, - } - } - - pub fn request_login(&self, login_data: &LoginData) -> Result { - let result: Result = self - .post(account::get_login_url(&self.agent)) - .headers(account::get_auth_header( - &self.agent, - &login_data.to_xvc_key(AUTH_USER_AGENT), - )) - .form(login_data) - .send(); - - match result { - Ok(response) => Ok(serde_json::from_str(&response.text().unwrap()).unwrap()), - Err(error) => Err(error), - } - } - - pub fn request_passcode(&self, login_data: &LoginData) -> Result { - let result = self - .post(account::get_request_passcode_url(&self.agent)) - .headers(account::get_auth_header( - &self.agent, - &login_data.to_xvc_key(AUTH_USER_AGENT), - )) - .form(login_data) - .send(); - match result { - Ok(response) => Ok(serde_json::from_str(&response.text().unwrap()).unwrap()), - Err(error) => Err(error), - } - } - - pub fn register_device( - &self, - device_register_data: &DeviceRegisterData, - ) -> Result { - let result = self - .post(account::get_register_device_url(&self.agent)) - .headers(account::get_auth_header( - &self.agent, - &device_register_data.to_xvc_key(AUTH_USER_AGENT), - )) - .form(device_register_data) - .send(); - match result { - Ok(response) => { - let text = response.text().unwrap(); - println!("{}", &text); - Ok(serde_json::from_str(&text).unwrap()) - } - Err(error) => Err(error), - } - } -} diff --git a/src/internal/xvc_key.rs b/src/internal/xvc_key.rs deleted file mode 100644 index 45d0618..0000000 --- a/src/internal/xvc_key.rs +++ /dev/null @@ -1,24 +0,0 @@ -use sha2::{Digest, Sha512}; -use std::ops::Deref; - -pub struct XVCKey { - key: String, -} - -impl XVCKey { - pub fn new(header: &str, email: &str, device_uuid: &str) -> Self { - XVCKey { - key: hex::encode(Sha512::digest( - format!("HEATH|{}|DEMIAN|{}|{}", header, email, device_uuid).as_bytes(), - )), - } - } -} - -impl Deref for XVCKey { - type Target = String; - - fn deref(&self) -> &Self::Target { - &self.key - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 68ff6a6..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(associated_type_defaults)] - -pub mod internal; -pub mod protocol; -pub mod types; diff --git a/src/protocol/booking/get_conf.rs b/src/protocol/booking/get_conf.rs deleted file mode 100644 index 138f944..0000000 --- a/src/protocol/booking/get_conf.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::protocol::structs::connection::{ConnectionData, HostData}; -use crate::types::Os; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(GetConfRequest, GetConfResponse)] -pub struct GetConf; - -/// Request checkin server information -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct GetConfRequest { - /// Network MCCMNC - #[serde(rename = "MCCMNC")] - pub mccmnc: String, - - /// Current OS (win32, android, mac, etc.) - pub os: Os, - - /// Device model (mobile only) leave it empty if it's not mobile device. - pub model: String, -} - -/// Answer checkin server information -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct GetConfResponse { - /// Unknown - pub revision: i32, - - /// Ceullar (3g) config - #[serde(rename = "3g")] - pub ceullar: ConnectionData, - - /// WiFi, wired config - pub wifi: ConnectionData, - - /// Contains Checkin host - pub ticket: HostData, - - /// voice / video talk configuration(?) - pub trailer: Trailer, - - /// voice / video talk high resolution configuration(?) - #[serde(rename = "trailer.h")] - pub trailer_high: TrailerHigh, -} - -/// Additional config -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Trailer { - #[serde(rename = "tokenExpireTime")] - pub token_expire_time: i32, - - pub resolution: i32, - - #[serde(rename = "resolutionHD")] - pub resolution_hd: i32, - - #[serde(rename = "compRatio")] - pub compress_ratio: i8, - - #[serde(rename = "compRatioHD")] - pub compress_ratio_hd: i8, - - #[serde(rename = "downMode")] - pub down_mode: i8, - - /// Concurrent file download limit - #[serde(rename = "concurrentDownLimit")] - pub concurrent_down_limit: i16, - - /// Concurrent file upload limit - #[serde(rename = "concurrentUpLimit")] - pub concurrent_up_limit: i16, - - #[serde(rename = "maxRelaySize")] - pub max_relay_size: i32, - - #[serde(rename = "downCheckSize")] - pub down_check_size: i32, - - /// Maximium attachment upload size - #[serde(rename = "upMaxSize")] - pub up_max_size: i32, - - #[serde(rename = "videoUpMaxSize")] - pub video_up_max_size: i32, - - #[serde(rename = "vCodec")] - pub video_codec: i8, - - #[serde(rename = "vFps")] - pub video_fps: i16, - - #[serde(rename = "aCodec")] - pub audio_codec: i8, - - /// Period that server store uploaded files - #[serde(rename = "contentExpireTime")] - pub content_expire_time: i32, - - #[serde(rename = "vResolution")] - pub video_resolution: i32, - - #[serde(rename = "vBitrate")] - pub video_bitrate: i32, - - #[serde(rename = "aFrequency")] - pub audio_frequency: i32, -} - -/// High speed trailer configuration -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TrailerHigh { - #[serde(rename = "vResolution")] - pub video_resolution: i32, - - #[serde(rename = "vBitrate")] - pub video_bitrate: i32, - - #[serde(rename = "aFrequency")] - pub audio_frequency: i32, -} diff --git a/src/protocol/booking/mod.rs b/src/protocol/booking/mod.rs deleted file mode 100644 index 24994f2..0000000 --- a/src/protocol/booking/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod get_conf; diff --git a/src/protocol/chat/change_svr.rs b/src/protocol/chat/change_svr.rs deleted file mode 100644 index 21f118c..0000000 --- a/src/protocol/chat/change_svr.rs +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// If received, Client must change server or client will get disconencted soon. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct ChangeSvr; diff --git a/src/protocol/chat/chat_info.rs b/src/protocol/chat/chat_info.rs deleted file mode 100644 index 2457ebc..0000000 --- a/src/protocol/chat/chat_info.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chatroom::ChatroomInfo; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(ChatInfoRequest, ChatInfoResponse)] -pub struct ChatInfo; - -/// Request Chatroom info -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct ChatInfoRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, -} - -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct ChatInfoResponse { - /// Chatroom info - #[serde(rename = "chatInfo")] - pub chat_info: ChatroomInfo, - - /// Unknown. Only appears on openchat rooms. - #[serde(skip_serializing_if = "Option::is_none")] - pub o: Option, -} diff --git a/src/protocol/chat/chat_on_room.rs b/src/protocol/chat/chat_on_room.rs deleted file mode 100644 index 49fc129..0000000 --- a/src/protocol/chat/chat_on_room.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::open_link::OpenLinkUser; -use crate::protocol::structs::user::UserVariant; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(ChatOnRoomRequest, ChatOnRoomResponse)] -pub struct ChatOnRoom; - -/// Send before opening chatroom window. Notice server the user opening chatroom window. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct ChatOnRoomRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Last chat log id or 0 - pub token: i64, - - /// Openlink token of chatroom if openchat. - #[serde(rename = "opt", skip_serializing_if = "Option::is_none")] - pub open_token: Option, -} - -/// Contains user info, watermark list. -/// Client can update chatroom information before opening chatroom window. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct ChatOnRoomResponse { - /// Chatroom id - #[serde(rename = "c")] - pub chat_id: i64, - - /// Chatroom type. - /// Check `structs/chatroom.rs` ChatroomListData chatroom_type for types. - #[serde(rename = "t")] - pub chat_type: String, - - /// watermark user ids - #[serde(rename = "a")] - pub watermark_user_ids: Vec, - - /// Chat read count watermark(chat log id) list. - /// Decrease every chat read count above watermark. - #[serde(rename = "w")] - pub watermarks: Vec, - - /// Chatroom open token if openchat - #[serde(rename = "otk", skip_serializing_if = "Option::is_none")] - pub open_token: Option, - - /// User list. Variant different by chatroom type. - /// The list may not have every user data, especially non active users. - /// If chatroom is openchat doesn't contain client user. - /// See open_link_user instead. - /// If there are too many users it will be null. See user_ids instead. - /// - /// TODO: Figure out the max limit. - #[serde(rename = "m")] - pub users: Option>, - - /// If there are too many users, server will send this instead. - /// The list may not have every user data, especially non active users. - #[serde(rename = "mi")] - pub user_ids: Option>, - - /// Client open link user if openchat - #[serde(rename = "olu", skip_serializing_if = "Option::is_none")] - pub open_link_user: Option, -} diff --git a/src/protocol/chat/chg_meta.rs b/src/protocol/chat/chg_meta.rs deleted file mode 100644 index 5787222..0000000 --- a/src/protocol/chat/chg_meta.rs +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chatroom::ChatroomMeta; -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// Sync Chatroom meta update -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct ChgMeta { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Chatroom meta item. Update same type meta. - pub meta: ChatroomMeta, -} diff --git a/src/protocol/chat/decun_read.rs b/src/protocol/chat/decun_read.rs deleted file mode 100644 index 3858ca9..0000000 --- a/src/protocol/chat/decun_read.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// Message read by someone -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct DecunRead { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Read user id - #[serde(rename = "userId")] - pub user_id: i64, - - /// Read message log id - /// - /// Official client decrease every unread chat read count till this chat. - pub watermark: i64, -} diff --git a/src/protocol/chat/delete_msg.rs b/src/protocol/chat/delete_msg.rs deleted file mode 100644 index 1eb9715..0000000 --- a/src/protocol/chat/delete_msg.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(DeleteMsgRequest, DeleteMsgResponse)] -pub struct DeleteMsg; - -/// Delete chat. Official server only deletes message sent before 5 mins max. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct DeleteMsgRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Chat log id - #[serde(rename = "logId")] - pub log_id: i64, -} - -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct DeleteMsgResponse; diff --git a/src/protocol/chat/get_mem.rs b/src/protocol/chat/get_mem.rs deleted file mode 100644 index 437e4ff..0000000 --- a/src/protocol/chat/get_mem.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::user::UserVariant; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(GetMemRequest, GetMemResponse)] -pub struct GetMem; - -/// Request simplified member list of chatroom. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct GetMemRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, -} - -/// Responses simplified member list of chatroom. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct GetMemResponse { - /// User list - pub members: Vec, -} diff --git a/src/protocol/chat/kick_out.rs b/src/protocol/chat/kick_out.rs deleted file mode 100644 index fb93b4a..0000000 --- a/src/protocol/chat/kick_out.rs +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// Send before server disconnect connection -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct KickOut { - /// Kicked reasoon - /// - /// * Change server = 2 - /// * Login another = 0 - /// * Account deleted = 1 - pub reason: i16, -} diff --git a/src/protocol/chat/l_chat_list.rs b/src/protocol/chat/l_chat_list.rs deleted file mode 100644 index 092948b..0000000 --- a/src/protocol/chat/l_chat_list.rs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chatroom::ChatroomListData; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(LChatListRequest, LChatListResponse)] -pub struct LChatList; - -/// Request every chatroom list -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct LChatListRequest { - /// Known chatroom id list - #[serde(rename = "chatIds")] - pub chat_ids: Vec, - - /// Unknown - #[serde(rename = "maxIds")] - pub max_ids: Vec, - - /// Unknown - #[serde(rename = "lastTokenId")] - pub last_token_id: i64, -} - -/// Request every chatroom list -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct LChatListResponse { - #[serde(rename = "chatDatas")] - pub chat_datas: Vec, -} diff --git a/src/protocol/chat/leave.rs b/src/protocol/chat/leave.rs deleted file mode 100644 index 5222ca5..0000000 --- a/src/protocol/chat/leave.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(LeaveRequest, LeaveResponse)] -pub struct Leave; - -/// Leave chatroom -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct LeaveRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Block chatroom. Cannot rejoin chatroom if true. - pub block: bool, -} - -/// Leave chatroom -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct LeaveResponse { - /// Last token(?) id - #[serde(rename = "lastTokenId")] - pub last_token_id: i64, -} diff --git a/src/protocol/chat/left.rs b/src/protocol/chat/left.rs deleted file mode 100644 index a05bfb7..0000000 --- a/src/protocol/chat/left.rs +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// Sync client left chatroom -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct Left { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Last token(?) id - #[serde(rename = "lastTokenId")] - pub last_token_id: i64, -} diff --git a/src/protocol/chat/login_list.rs b/src/protocol/chat/login_list.rs deleted file mode 100644 index 0d048b4..0000000 --- a/src/protocol/chat/login_list.rs +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::chat::l_chat_list::{LChatListRequest, LChatListResponse}; -use crate::protocol::structs::client::ClientInfo; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(LoginListRequest, LoginListResponse)] -pub struct LoginList; - -/// Login to loco server -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct LoginListRequest { - #[serde(flatten)] - pub client: ClientInfo, - - /// Protocol version, seems like always "1" - #[serde(rename = "prtVer")] - pub protocol_version: String, - - /// Device uuid String. Usually hashed unique id. - #[serde(rename = "duuid")] - pub device_uuid: String, - - /// OAuth access token - #[serde(rename = "oauthToken")] - pub oauth_token: String, - - #[serde(rename = "lang")] - pub language: String, - - /// Device type (2 for pc) - #[serde(rename = "dtype")] - pub device_type: i8, - - /// Unknown - pub revision: i32, - - /// Unknown. Always None(?) - pub rp: (), - - #[serde(flatten)] - pub chat_list: LChatListRequest, - - /// Unknown - #[serde(rename = "lbk")] - pub last_block_token: i32, - - /// background checking(?) - #[serde(rename = "bg")] - pub background: bool, -} - -/// Contains userId, tokens, chatroom list. -/// The purposes of tokens, revisions are unknown yet. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct LoginListResponse { - /// Logon user id - #[serde(rename = "userId")] - pub user_id: i64, - - #[serde(flatten)] - pub chat_list: LChatListResponse, - - /// Deleted chatroom ids(?) - #[serde(rename = "delChatIds")] - pub deleted_chat_ids: Vec, - - /// Unknown - pub eof: bool, - - /// Latest chatroom id - #[serde(rename = "lastChatId")] - pub last_chat_id: i64, - - /// Latest token(Unknown) id - #[serde(rename = "lastTokenId")] - pub last_token_id: i64, - - /// Oldest chat id (?) - #[serde(rename = "minLogId")] - pub min_log_id: i64, - - /// Latest token(Unknown)(?) - #[serde(rename = "ltk")] - pub last_token: i64, - - /// Latest block token(Unknown)(?) - #[serde(rename = "lbk")] - pub last_block_token: i64, - - /// Latest mcm(?) revision - #[serde(rename = "mcmRevision")] - pub mcm_revision: i64, - - /// Unknown - pub revision: i32, - - /// Revision(?) Info (Json) - #[serde(rename = "revisionInfo")] - pub revision_info: String, - - /// Unknown - pub sb: i32, - // Unknown, Unknown item type - //pub kc: Vec<()> -} diff --git a/src/protocol/chat/member.rs b/src/protocol/chat/member.rs deleted file mode 100644 index b589168..0000000 --- a/src/protocol/chat/member.rs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::user::UserVariant; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(MemberRequest, MemberResponse)] -pub struct Member; - -/// Request detailed members of chatroom. -/// Official client send this when clicking profile on chatroom. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct MemberRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// List of requesting user id list - #[serde(rename = "memberIds")] - pub user_ids: Vec, -} - -/// Responses detailed members of chatroom. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct MemberResponse { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// List of requested user list - #[serde(rename = "members")] - pub members: Vec, -} diff --git a/src/protocol/chat/mod.rs b/src/protocol/chat/mod.rs deleted file mode 100644 index 0bdfaf6..0000000 --- a/src/protocol/chat/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Created on Tue Dec 01 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -pub mod change_svr; -pub mod chat_info; -pub mod chat_on_room; -pub mod chg_meta; -pub mod decun_read; -pub mod delete_msg; -pub mod get_mem; -pub mod kick_out; -pub mod l_chat_list; -pub mod leave; -pub mod left; -pub mod login_list; -pub mod member; -pub mod msg; -pub mod new_mem; -pub mod noti_read; -pub mod set_meta; -pub mod set_st; -pub mod sync; -pub mod sync_link; -pub mod sync_msg; -pub mod update_chat; -pub mod write; diff --git a/src/protocol/chat/msg.rs b/src/protocol/chat/msg.rs deleted file mode 100644 index 2e7f8df..0000000 --- a/src/protocol/chat/msg.rs +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chat::Chatlog; -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// Message sent from chatroom -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct Msg { - /// Sent chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Sent chat log id - #[serde(rename = "logId")] - pub log_id: i64, - - #[serde(rename = "chatLog")] - pub chatlog: Option, - - /// Sender nickname - #[serde(rename = "authorNickname")] - pub author_nick: String, - - /// false If sender sent message without reading. - /// - /// If it's false, sent message doesn't decrease read count of last chat. - #[serde(rename = "noSeen")] - pub no_seen: bool, - - #[serde(rename = "li", skip_serializing_if = "Option::is_none")] - pub link_id: Option, - - /// Act like no_seen.(?) - /// Only appears on openchat - #[serde(rename = "notiRead", skip_serializing_if = "Option::is_none")] - pub noti_read: Option, -} diff --git a/src/protocol/chat/new_mem.rs b/src/protocol/chat/new_mem.rs deleted file mode 100644 index 912df28..0000000 --- a/src/protocol/chat/new_mem.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chat::Chatlog; -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// Send when new user join. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct NewMem { - /// Join feed chat.(?) - #[serde(rename = "chatLog")] - pub chat_log: Chatlog, -} diff --git a/src/protocol/chat/noti_read.rs b/src/protocol/chat/noti_read.rs deleted file mode 100644 index 2049696..0000000 --- a/src/protocol/chat/noti_read.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoRequest}; -use serde::{Deserialize, Serialize}; - -/// Read message in chatroom -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoRequest)] -pub struct NotiRead { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Read message log id - /// - /// Official client decrease every unread chat read count till this chat. - pub watermark: i64, - - /// Openchat link id - #[serde(rename = "linkId", skip_serializing_if = "Option::is_none")] - pub link_id: Option, -} diff --git a/src/protocol/chat/set_meta.rs b/src/protocol/chat/set_meta.rs deleted file mode 100644 index f15ec08..0000000 --- a/src/protocol/chat/set_meta.rs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chatroom::ChatroomMeta; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(SetMetaRequest, SetMetaResponse)] -pub struct SetMeta; - -/// Set Chatroom meta -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct SetMetaRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Meta type. See `structs/chatroom.rs` ChatroomMetaType for predefined types. - #[serde(rename = "type")] - pub meta_type: i8, - - /// Json or String content. Different depending on type. - pub content: String, -} - -/// SETMETA response -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct SetMetaResponse { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Updated chatroom meta item. - pub meta: ChatroomMeta, -} diff --git a/src/protocol/chat/set_st.rs b/src/protocol/chat/set_st.rs deleted file mode 100644 index 6cc45a0..0000000 --- a/src/protocol/chat/set_st.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(SetStRequest, SetStResponse)] -pub struct SetSt; - -/// Update client status -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct SetStRequest { - /// Status - /// - /// * Unlocked = 1 - /// * Locked = 2 - #[serde(rename = "st")] - pub status: i8, -} - -/// Update client status -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct SetStResponse; diff --git a/src/protocol/chat/sync.rs b/src/protocol/chat/sync.rs deleted file mode 100644 index 96be9f2..0000000 --- a/src/protocol/chat/sync.rs +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chat::Chatlog; -use crate::protocol::structs::chatroom::ChatroomInfo; -use loco_derive::{BsonData, LocoResponse}; -use serde::{Deserialize, Serialize}; - -/// Sync Chatroom join -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct SyncJoin { - /// Chatroom id - #[serde(rename = "c")] - pub chat_id: i64, - - /// Last chat - #[serde(rename = "chatLog")] - pub chat_log: Option, -} - -/// Sync chat delete -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct SyncDlMsg { - /// Deleted chat - #[serde(rename = "chatLog")] - pub chat_log: Chatlog, -} - -/// Sync openlink creation -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct SyncLinkCr { - /// Openlink id - #[serde(rename = "ol")] - pub link_id: i64, - - /// Only presents if the openlink is openchat. - #[serde(rename = "chatRoom", skip_serializing_if = "Option::is_none")] - pub chat_room: Option, -} - -/// Sync openchat member type -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct SyncMemT { - /// Chatroom id - #[serde(rename = "c")] - pub chat_id: i64, - - /// Chatroom Openlink id - #[serde(rename = "li")] - pub link_id: i64, - - /// User id list - #[serde(rename = "mids")] - pub member_ids: Vec, - - /// User member type list. - /// Check `src/structs/open_link` OpenMemberType for predefined types. - #[serde(rename = "mts")] - pub mem_types: Vec, -} - -/// Sync openchat user profile -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct SyncLinkPf { - /// Chatroom id - #[serde(rename = "c")] - pub chat_id: i64, - - /// Chatroom Openlink id - #[serde(rename = "li")] - pub link_id: i64, -} - -/// Sync openchat chat hide -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoResponse)] -pub struct SyncRewr { - /// Chatlog - #[serde(rename = "chatLog")] - pub chat_log: Chatlog, -} diff --git a/src/protocol/chat/sync_link.rs b/src/protocol/chat/sync_link.rs deleted file mode 100644 index 4484edc..0000000 --- a/src/protocol/chat/sync_link.rs +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ diff --git a/src/protocol/chat/sync_msg.rs b/src/protocol/chat/sync_msg.rs deleted file mode 100644 index 64b6e51..0000000 --- a/src/protocol/chat/sync_msg.rs +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::chat::Chatlog; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(SyncMsgRequest, SyncMsgResponse)] -pub struct SyncMsg; - -/// Sync skipped chats. -/// Official client send this when last log id written is different with actual last log id. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct SyncMsgRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Current written last chat log id in client. - #[serde(rename = "cur")] - pub current: i64, - - /// Max number to receive once. - /// The default is 300. But the server always seems to send up to 300 regardless of the number. - #[serde(rename = "cnt")] - pub count: i32, - - /// Last chat log id received by server. - pub max: i64, -} - -/// Responses chatlogs between "current" and "max". Chatlog list sliced to 300 or "max" value max. -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct SyncMsgResponse { - /// true if no more chat left below. - #[serde(rename = "isOK")] - is_ok: bool, - - /// Chatlog list - #[serde(rename = "chatLogs")] - chat_logs: Vec, - - /// Unknown - #[serde(rename = "jsi")] - jsi: i64, - - #[serde(rename = "lastTokenId")] - last_token_id: i64, -} diff --git a/src/protocol/chat/update_chat.rs b/src/protocol/chat/update_chat.rs deleted file mode 100644 index aef9114..0000000 --- a/src/protocol/chat/update_chat.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(UpdateChatRequest, UpdateChatResponse)] -pub struct UpdateChat; - -/// Update chatroom push setting -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct UpdateChatRequest { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - #[serde(rename = "pushAlert")] - pub push_alert: bool, -} - -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct UpdateChatResponse; diff --git a/src/protocol/chat/write.rs b/src/protocol/chat/write.rs deleted file mode 100644 index 5d0e4af..0000000 --- a/src/protocol/chat/write.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoRequest}; -use serde::{Deserialize, Serialize}; - -/// Write message to chatroom -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoRequest)] -pub struct Write { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Chat type - #[serde(rename = "type")] - pub chat_type: i8, - - /// Message id - /// - /// Client send count?? - #[serde(rename = "msgId")] - pub msg_id: i32, - - /// Message content - /// - /// Usually String, but can be json String according to chat type. - #[serde(rename = "msg")] - pub message: String, - - /// If true, server will assume the client read last message. - #[serde(rename = "noSeen")] - pub no_seen: bool, - - /// Attachment content - /// - /// Json data. Have contents and extra data according to chat type. - /// Also known as `extra`. - #[serde(rename = "extra", skip_serializing_if = "Option::is_none")] - pub attachment: Option, - - /// Used on pluschat. - /// - /// Cannot be used to send by normal user - #[serde(skip_serializing_if = "Option::is_none")] - pub supplement: Option, -} diff --git a/src/protocol/checkin/buy_cs.rs b/src/protocol/checkin/buy_cs.rs deleted file mode 100644 index c0ebdd5..0000000 --- a/src/protocol/checkin/buy_cs.rs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Created on Tue Dec 01 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::client::ClientInfo; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(BuyCSRequest, BuyCSResponse)] -pub struct BuyCS; - -/// Request call server host data. -/// Checkin response already contains call server info -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct BuyCSRequest { - #[serde(flatten)] - pub client: ClientInfo, - - #[serde(rename = "countryISO")] - pub country_iso: String, -} - -/// Answer call server information -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct BuyCSResponse { - /// Call server ip - #[serde(rename = "cshost")] - pub cs_host: String, - - /// Call server ip(v6) - #[serde(rename = "cshost6")] - pub cs_host6: String, - - /// Call server port - #[serde(rename = "csport")] - pub cs_port: i32, - - /// Unknown server ip - #[serde(rename = "vsshost")] - pub vss_host: String, - - /// Unknown server ip(v6) - #[serde(rename = "vsshost6")] - pub vss_host6: String, - - /// Unknown server port - #[serde(rename = "vssport")] - pub vss_port: i32, -} diff --git a/src/protocol/checkin/checkin.rs b/src/protocol/checkin/checkin.rs deleted file mode 100644 index 3f77ca6..0000000 --- a/src/protocol/checkin/checkin.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Created on Tue Dec 01 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use crate::protocol::structs::client::ClientInfo; -use loco_derive::{BsonData, LocoPacketPair}; -use serde::{Deserialize, Serialize}; - -#[derive(LocoPacketPair)] -#[loco_packet_pair(CheckinRequest, CheckinResponse)] -pub struct Checkin; - -/// Request loco server host data -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct CheckinRequest { - /// Client user id. Login to acquire. - #[serde(rename = "userId")] - pub user_id: i64, - - #[serde(flatten)] - pub client: ClientInfo, - - #[serde(rename = "lang")] - pub language: String, - - #[serde(rename = "countryISO")] - pub country_iso: String, - - /// Subdevice(PC, Tablet) or not - #[serde(rename = "useSub")] - pub use_usb: bool, -} - -/// Answer loco server information -#[derive(Debug, Clone, Serialize, Deserialize, BsonData)] -pub struct CheckinResponse { - /// Loco server ip - pub host: String, - - /// Loco server ip(v6) - pub host6: String, - - /// Loco server port - pub port: i32, - - /// Info cache expire time(?) - #[serde(rename = "cacheExpire")] - pub cache_expire: i32, - - /// Call server ip - #[serde(rename = "cshost")] - pub cs_host: String, - - /// Call server ip(v6) - #[serde(rename = "cshost6")] - pub cs_host6: String, - - /// Call server port - #[serde(rename = "csport")] - pub cs_port: i32, - - /// Unknown server ip - #[serde(rename = "vsshost")] - pub vss_host: String, - - /// Unknown server ip(v6) - #[serde(rename = "vsshost6")] - pub vss_host6: String, - - /// Unknown server port - #[serde(rename = "vssport")] - pub vss_port: i32, -} diff --git a/src/protocol/checkin/mod.rs b/src/protocol/checkin/mod.rs deleted file mode 100644 index 6c22158..0000000 --- a/src/protocol/checkin/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Created on Tue Dec 01 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -pub mod buy_cs; -#[allow(clippy::module_inception)] -pub mod checkin; diff --git a/src/protocol/header.rs b/src/protocol/header.rs deleted file mode 100644 index 1aa21da..0000000 --- a/src/protocol/header.rs +++ /dev/null @@ -1,27 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::string::FromUtf8Error; - -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] -pub struct LocoHeader { - pub id: u32, - pub status: i16, - pub name: [u8; 11], - pub data_type: u8, - pub data_size: u32, -} - -impl LocoHeader { - /// Extract String from name field - pub fn name(&self) -> Result { - let size = self.name.iter().position(|&c| c == b'\0').unwrap_or(11); - - String::from_utf8(self.name[..size].into()) - } - - /// set name field from str. Will be sliced to 11 bytes max. - pub fn set_name(&mut self, name: &str) { - self.name = [0u8; 11]; - let bytes = name.as_bytes(); - self.name.copy_from_slice(bytes); - } -} diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs deleted file mode 100644 index 9ff0ed4..0000000 --- a/src/protocol/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Created on Sat Nov 28 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use std::io::{Read, Write}; - -mod header; -mod raw_loco_client; - -use serde::{Deserialize, Serialize}; - -pub use header::LocoHeader; -pub use raw_loco_client::RawLocoClient; -pub mod structs; - -pub mod booking; -pub mod chat; -pub mod checkin; - -mod ping; - -pub use ping::Ping; - -pub trait BsonData<'a>: Serialize + Deserialize<'a> {} - -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] -pub struct RawLocoPacket { - pub header: LocoHeader, - pub data: Vec, -} - -pub trait LocoPacket: Encode + Decode { - const NAME: &'static str; -} - -pub trait LocoPacketPair { - const NAME: &'static str; - type Request = T; - type Response = U; -} - -pub trait LocoRequest: LocoPacket {} - -pub trait LocoResponse: LocoPacket {} - -pub trait Encode { - fn encode(&self, buffer: &mut T); -} - -pub trait Decode { - fn decode(&self, buffer: &mut T) -> Self; -} diff --git a/src/protocol/ping.rs b/src/protocol/ping.rs deleted file mode 100644 index 7b465f7..0000000 --- a/src/protocol/ping.rs +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use loco_derive::{BsonData, LocoRequest}; -use serde::{Deserialize, Serialize}; - -/// Signal server to keep connection -#[derive(Debug, Clone, Serialize, Deserialize, BsonData, LocoRequest)] -pub struct Ping; diff --git a/src/protocol/raw_loco_client.rs b/src/protocol/raw_loco_client.rs deleted file mode 100644 index 051ed1f..0000000 --- a/src/protocol/raw_loco_client.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Created on Mon Nov 30 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -//todo error handle - -use std::io::{Read, Write}; - -use super::RawLocoPacket; -use std::ops::{Deref, DerefMut}; - -/// Like BufReader and BufWriter, provide optimized Command read/write operation to stream. -pub struct RawLocoClient { - pub stream: S, - read_buffer: [u8; 2048], -} - -impl RawLocoClient { - pub fn new(stream: S) -> Self { - Self { - stream, - read_buffer: [0u8; 2048], - } - } - - pub fn read_raw_loco_packet(&mut self) -> Option { - match self.stream.read(&mut self.read_buffer) { - Ok(read_bytes) => { - if read_bytes < 22 { - return None; - } - let buffer = &self.read_buffer[0..read_bytes]; - Some(bincode::deserialize(buffer).unwrap()) - } - Err(_) => None, - } - } - - pub fn write_raw_loco_packet(&mut self, raw_loco_packet: RawLocoPacket) { - let mut cursor = Vec::with_capacity(raw_loco_packet.header.data_size as usize + 22); - bincode::serialize_into(&mut cursor, &raw_loco_packet).unwrap(); - - self.write_all(&cursor).unwrap(); - } -} - -impl Deref for RawLocoClient { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.stream - } -} - -impl DerefMut for RawLocoClient { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.stream - } -} diff --git a/src/protocol/structs/chat.rs b/src/protocol/structs/chat.rs deleted file mode 100644 index 26a79f4..0000000 --- a/src/protocol/structs/chat.rs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use serde::{Deserialize, Serialize}; - -/// Chat -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Chatlog { - /// Chatlog id - #[serde(rename = "logId")] - pub log_id: i64, - - /// Previous Chatlog id - #[serde(rename = "prevId", skip_serializing_if = "Option::is_none")] - pub prev_log_id: Option, - - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Chat type - #[serde(rename = "type")] - pub chat_type: i8, - - /// Sender id - #[serde(rename = "authorId")] - pub author_id: i64, - - /// Message content - /// - /// Usually String, but can be json String according to chat type. - pub message: String, - - /// Send time - /// - /// Multiply by 1000 to convert to Unix time - #[serde(rename = "sendAt")] - pub send_at: i32, - - /// Attachment content - /// - /// Json data. Have contents and extra data according to chat type. - #[serde(skip_serializing_if = "Option::is_none")] - pub attachment: Option, - - /// Used on pluschat. - /// - /// * KakaoI = 1 - /// * Bot = 2 - #[serde(skip_serializing_if = "Option::is_none")] - pub referer: Option, - - /// Used on pluschat. - /// - /// Json data like attachment. Having extra pluschat data like quick reply. - #[serde(skip_serializing_if = "Option::is_none")] - pub supplement: Option, - - /// Unknown id (Client send count??). Don't confuse with log_id. - #[serde(rename = "msgId")] - pub msg_id: i32, -} diff --git a/src/protocol/structs/chatroom.rs b/src/protocol/structs/chatroom.rs deleted file mode 100644 index 86e156f..0000000 --- a/src/protocol/structs/chatroom.rs +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use serde::{Deserialize, Serialize}; - -use super::{chat::Chatlog, open_link::OpenLinkId, user::DisplayUserInfo}; - -/// LOGINLIST chatroom list item. -/// Including essential chatroom info. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ChatroomListData { - /// Chatroom id - #[serde(rename = "c")] - pub id: i64, - - /// Chatroom type - /// - /// * group = "MultiChat" - /// * direct = "DirectChat" - /// * pluschat = "PlusChat" - /// * self = "MemoChat" - /// * openchat group = "OM" - /// * openchat direct = "OD" - #[serde(rename = "t")] - pub chatroom_type: String, - - /// Last chat log id - #[serde(rename = "ll")] - pub last_log_id: i64, - - /// Last Chatlog - #[serde(rename = "l")] - pub chatlog: Option, - - /// Member count - #[serde(rename = "a")] - pub member_count: i32, - - /// Unread message count - #[serde(rename = "n")] - pub unread_count: i32, - - // /// Chatroom metadata(?) - // #[serde(rename = "m")] - // pub metadata: () - /// Push alert setting - #[serde(rename = "p")] - pub push_alert: bool, - - /// Only present if chatroom is Openchat - #[serde(flatten, skip_serializing_if = "Option::is_none")] - pub link: Option, - - /// Chatroom preview icon target user id list - #[serde(rename = "i", skip_serializing_if = "Option::is_none")] - pub icon_user_ids: Option>, - - /// Chatroom preview icon target user name list - #[serde(rename = "k", skip_serializing_if = "Option::is_none")] - pub icon_user_nicknames: Option>, - - /// Unknown. Always 0 on openchat rooms. - pub mmr: i64, - - /// Unknown - pub s: i64, - - /// Openlink token. - #[serde(rename = "o", skip_serializing_if = "Option::is_none")] - pub open_token: Option, - - /// Unknown. Only appears on non openchat rooms. - #[serde(skip_serializing_if = "Option::is_none")] - pub jn: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ChatroomInfo { - /// Chatroom id - #[serde(rename = "chatId")] - pub chat_id: i64, - - /// Chatroom type. - /// Check ChatroomListData chatroom_type for types. - #[serde(rename = "type")] - pub chatroom_type: String, - - /// Only present if chatroom is openchat - #[serde(flatten, skip_serializing_if = "Option::is_none")] - pub link: Option, - - /// Active member count. May not match the actual user count. - #[serde(rename = "activeMembersCount")] - pub active_member_count: i32, - - /// Used for creating chatroom icon - #[serde(rename = "displayMembers")] - pub display_members: Vec, - - /// Unread message count - #[serde(rename = "newMessageCount")] - pub new_message_count: i32, - - /// true if new_message_count is invalid(?). Does not present on openchat. - #[serde( - rename = "invalidNewMessageCount", - skip_serializing_if = "Option::is_none" - )] - pub new_message_count_invalid: Option, - - // /// Chatroom metadata(?) - // #[serde(rename = "m")] - // pub metadata: (), - - // /// Unknown - // #[serde(rename = "lastUpdatedAt")] - // pub last_updated_at: Option, - - // /// Unknown - // #[serde(rename = "lastMessage")] - // pub last_message: Option<()>, - /// Last chat log id - #[serde(rename = "lastLogId")] - pub last_log_id: i64, - - /// Last seen(?) chat log id - #[serde(rename = "lastSeenLogId")] - pub last_seen_log_id: i64, - - /// Last chat log - #[serde(rename = "lastChatLog")] - pub last_chat_log: Option, - - /// Push alert setting - #[serde(rename = "pushAlert")] - pub push_alert: bool, - - /// Chatroom metas - #[serde(rename = "chatMetas")] - pub chat_metas: Vec, - - /// true if Openchat direct chat. Only presents on openchat room. - #[serde(rename = "directChat")] - pub direct_chat: Option, - - /// Unknown. Client user join time. (?) Does not present on openchat room. - #[serde(rename = "joinedAtForNewMem", skip_serializing_if = "Option::is_none")] - pub joined_at: Option, - - /// true if room is invalid(Only client user left, etc.). (?) Does not present on openchat room. - #[serde(skip_serializing_if = "Option::is_none")] - pub left: Option, -} - -/// Chatroom meta. Like chatroom profile, notice, etc. -/// -/// serde does not support integer tag yet. We will switch to enum as fast as the support added. -/// Check serde#745 -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ChatroomMeta { - /// Meta type. See ChatroomMetaType for predefined types. - #[serde(rename = "type")] - pub meta_type: i8, - - pub revision: i64, - - /// Meta user id - #[serde(rename = "authorId")] - pub author_id: i64, - - /// Updated time. Multiply by 1000 to convert to Unix time. - #[serde(rename = "updatedAt")] - pub updated_at: i32, - - /// Json or String content. Different depending on type. - pub content: String, -} - -#[repr(i8)] -pub enum ChatroomMetaType { - Notice = 1, - Group = 2, - Title = 3, - Profile = 4, - Tv = 5, - Privilege = 6, - TvLive = 7, - PlusBackground = 8, - LiveTalkInfo = 11, - LiveTalkCount = 12, - OpenChatChat = 13, - Bot = 14, -} diff --git a/src/protocol/structs/client.rs b/src/protocol/structs/client.rs deleted file mode 100644 index e8aa357..0000000 --- a/src/protocol/structs/client.rs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Created on Tue Dec 01 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use serde::{Deserialize, Serialize}; - -/// Describes response status info -/// -/// Compare these predefined status before to process data -#[derive(Debug, PartialEq)] -#[repr(i16)] -pub enum Status { - Success = 0, - Fail = -500, - Restricted = -997, - Maintenance = -9797, - NotLogon = -201, -} - -/// Common client info struct -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ClientInfo { - /// Current OS (win32, android, mac, etc.) - pub os: String, - - /// Network type (0 for wired) - #[serde(rename = "ntype")] - pub net_type: i16, - - /// Official app version - #[serde(rename = "appVer")] - pub app_version: String, - - /// Network MCCMNC ("999" for pc) - #[serde(rename = "MCCMNC")] - pub mccmnc: String, -} diff --git a/src/protocol/structs/connection.rs b/src/protocol/structs/connection.rs deleted file mode 100644 index 891fa41..0000000 --- a/src/protocol/structs/connection.rs +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Created on Tue Dec 01 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use serde::{Deserialize, Serialize}; - -/// ConnectionData includes ports, connection configuartion -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ConnectionData { - /// Keep interval(?) when background - #[serde(rename = "bgKeepItv")] - pub background_keep_interval: i32, - - /// Reconnect interval when background - #[serde(rename = "bgReconnItv")] - pub background_reconnect_interval: i32, - - /// Ping interval when background - #[serde(rename = "bgPingItv")] - pub background_interval: i32, - - /// Ping interval - #[serde(rename = "fgPingItv")] - pub ping_interval: i32, - - /// Request timeout - #[serde(rename = "reqTimeout")] - pub request_timeout: i32, - - /// Encrypt type, but loco_protocol only supports 2 and server seems to use 2 only. - #[serde(rename = "encType")] - pub encrypt_type: i32, - - /// Connection timeout - #[serde(rename = "connTimeout")] - pub connection_timeout: i32, - - /// Header timeout - #[serde(rename = "recvHeaderTimeout")] - pub receive_header_timeout: i32, - - /// IN segment timeout - #[serde(rename = "inSegTimeout")] - pub in_seg_timeout: i32, - - /// OUT segment timeout - #[serde(rename = "outSegTimeout")] - pub out_seg_timeout: i32, - - /// TCP buffer size - #[serde(rename = "blockSendBufSize")] - pub block_send_buffer_size: i32, - - /// Port list - pub ports: Vec, -} - -/// HostData includes host list -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct HostData { - /// Unknown - pub ssl: Vec, - - /// Unknown - pub v2sl: Vec, - - /// Usable host list - pub lsl: Vec, - - /// Usable host list (ipv6) - pub lsl6: Vec, -} diff --git a/src/protocol/structs/mod.rs b/src/protocol/structs/mod.rs deleted file mode 100644 index 22a3bcf..0000000 --- a/src/protocol/structs/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Created on Tue Dec 01 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -pub mod chat; -pub mod chatroom; -pub mod client; -pub mod connection; -pub mod open_link; -pub mod user; diff --git a/src/protocol/structs/open_link.rs b/src/protocol/structs/open_link.rs deleted file mode 100644 index 6651dbf..0000000 --- a/src/protocol/structs/open_link.rs +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Created on Wed Dec 02 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use serde::{Deserialize, Serialize}; - -/// Openlink info -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct OpenLinkId { - /// Openlink identifier - #[serde(rename = "li")] - pub link_id: i64, - - /// Openlink token. - /// Multiply by 1000 to convert to Unix time. - #[serde(rename = "otk")] - pub open_token: i32, -} - -// Openlink types -#[repr(i8)] -pub enum OpenLinkType { - Profile = 1, - Chatroom = 2, -} - -/// Openchat user member types -#[repr(i8)] -pub enum OpenMemberType { - Owner = 1, - None = 2, - Manager = 4, - Bot = 8, -} - -/// Openchat user profile types -#[repr(i8)] -pub enum OpenProfileType { - Main = 1, - Anon = 2, - Anon2 = 4, - Unknown = 8, - LinkProfile = 16, -} - -/// Privilege bitmask -#[repr(i16)] -pub enum LinkPrivilegeMask { - UrlSharable = 2, - Reportable = 4, - ProfileEditable = 8, - AnyProfileAllowed = 32, - UsePassCode = 64, - Blindable = 128, - NonSpecialLink = 512, - UseBot = 1024, -} - -impl LinkPrivilegeMask { - pub fn contains(self, privilege: i16) -> bool { - let mask = self as i16; - privilege & mask == mask - } -} - -/// Openchat kicked user info -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct OpenKickedUserInfo { - #[serde(rename = "userId")] - pub user_id: i64, - - #[serde(rename = "nickName")] - pub nickname: String, - - #[serde(rename = "pi")] - pub profile_image_url: Option, - - /// Kicked chatroom id - #[serde(rename = "c")] - pub chat_id: i64, - - /// Unknown - pub dc: bool, -} - -/// Openchat user -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct OpenUser { - #[serde(rename = "userId")] - pub user_id: i64, - - #[serde(rename = "nickName")] - pub nickname: String, - - #[serde(rename = "pi")] - pub profile_image_url: Option, - - #[serde(rename = "fpi")] - pub full_profile_image_url: Option, - - #[serde(rename = "opi")] - pub original_profile_image_url: Option, - - /// See `struct/user` UserType for types. - #[serde(rename = "type")] - pub user_type: i32, - - /// See OpenMemberType for types. - #[serde(rename = "mt")] - pub open_member_type: i8, - - #[serde(rename = "opt")] - pub open_token: i32, - - /// Profile link id. Only presents if user using openlink profile. - #[serde(rename = "pli", skip_serializing_if = "Option::is_none")] - pub profile_link_id: Option, -} - -/// Openlink user. Dont confuse with OpenUser. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct OpenLinkUser { - #[serde(rename = "userId")] - pub user_id: i64, - - #[serde(rename = "nn")] - pub nickname: String, - - #[serde(rename = "pi")] - pub profile_image_url: Option, - - #[serde(rename = "fpi")] - pub full_profile_image_url: Option, - - #[serde(rename = "opi")] - pub original_profile_image_url: Option, - - /// See OpenMemberType for types. - #[serde(rename = "lmt")] - pub open_member_type: i8, - - /// See OpenProfileType for types. - #[serde(rename = "ptp")] - pub profile_type: i8, - - /// Profile link id - #[serde(rename = "pli", skip_serializing_if = "Option::is_none")] - pub profile_link_id: Option, - - #[serde(rename = "opt")] - pub open_token: i64, - - /// See LinkPrivilegeMask for more detail. - #[serde(rename = "pv")] - pub privilege: i16, -} diff --git a/src/protocol/structs/user.rs b/src/protocol/structs/user.rs deleted file mode 100644 index 8176a24..0000000 --- a/src/protocol/structs/user.rs +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Created on Thu Dec 03 2020 - * - * Copyright (c) storycraft. Licensed under the MIT Licence. - */ - -use serde::{Deserialize, Serialize}; - -use super::open_link::OpenUser; - -/// Minimal user info for chatroom display -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct DisplayUserInfo { - /// User id - #[serde(rename = "userId")] - pub user_id: i64, - - /// User nickname - #[serde(rename = "nickName")] - pub nickname: String, - - /// Profile image URL. None if profile image is default. - #[serde(rename = "pi")] - pub profile_image_url: Option, - - /// Country Iso, does not present on openchat. - #[serde(rename = "countryIso", skip_serializing_if = "Option::is_none")] - pub country_iso: Option, -} - -/// User -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct User { - #[serde(rename = "userId")] - pub user_id: i64, - - #[serde(rename = "nickName")] - pub nickname: String, - - #[serde(rename = "countryIso")] - pub country_iso: String, - - #[serde(rename = "profileImageUrl")] - pub profile_image_url: Option, - - #[serde(rename = "fullProfileImageUrl")] - pub full_profile_image_url: Option, - - #[serde(rename = "OriginalProfileImageUrl")] - pub original_profile_image_url: Option, - - /// See UserType for types. - #[serde(rename = "type")] - pub user_type: i32, - - #[serde(rename = "accountId")] - pub account_id: i64, - - #[serde(rename = "linkedServices")] - pub linked_services: String, - - #[serde(rename = "statusMessage")] - pub status_message: String, - - pub suspended: bool, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum UserVariant { - Normal(User), - Open(OpenUser), -} - -/// User types. Don't confuse with OpenMemberType. -#[repr(i32)] -pub enum UserType { - Unknown = -999999, - NotFriend = -100, - Deactivated = 9, - Friend = 100, - Openchat = 1000, -} diff --git a/src/types/channel.rs b/src/types/channel.rs deleted file mode 100644 index d13f9f3..0000000 --- a/src/types/channel.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub type ChannelId = u64; - -pub struct Channel {} diff --git a/src/types/chat_room/attachment/custom.rs b/src/types/chat_room/attachment/custom.rs deleted file mode 100644 index 985385d..0000000 --- a/src/types/chat_room/attachment/custom.rs +++ /dev/null @@ -1,265 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum CustomType { - Feed, - List, - Commerce, - Carousel, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ButtonStyle { - Horizontal = 0, - Vertical = 1, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ButtonDisplayTarget { - #[serde(rename = "both")] - All, - #[serde(rename = "sender")] - Sender, - #[serde(rename = "receiver")] - Receiver, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ImageCropStyle { - Square = 0, - None = 1, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct TextFragment { - #[serde(rename = "T")] - text: String, - #[serde(rename = "D")] - description: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct LinkFragment { - #[serde(rename = "LPC")] - windows_link: String, - #[serde(rename = "LMO")] - macos_link: String, - #[serde(rename = "LCA")] - android_link: String, - #[serde(rename = "LCI")] - ios_link: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ImageFragment { - #[serde(rename = "THU")] - url: String, - #[serde(rename = "W")] - width: u32, - #[serde(rename = "H")] - height: u32, - #[serde(rename = "SC")] - crop_style: ImageCropStyle, - #[serde(rename = "LI")] - is_live: bool, - #[serde(rename = "PT")] - playtime: u32, -} - -#[derive(Debug, Clone)] -pub struct ButtonFragment { - text: String, - display_target: Option, - link: LinkFragment, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SocialFragment { - #[serde(rename = "LK")] - link: u32, - #[serde(rename = "CM")] - comment: u32, - #[serde(rename = "SH")] - share: u32, - #[serde(rename = "VC")] - view: u32, - #[serde(rename = "SB")] - subscriber: u32, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ProfileFragment { - #[serde(rename = "TD")] - description: TextFragment, - #[serde(rename = "L")] - link: LinkFragment, - #[serde(rename = "BG")] - background_image: ImageFragment, - #[serde(rename = "TH")] - thumbnail_image: ImageFragment, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CustomContent {} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CustomFeedContent { - description: TextFragment, - button_style: ButtonStyle, - button_list: Vec, - thumbnail_list: Vec, - thumbnail_count: u32, - text_link: Option, - full_text: bool, - link: Option, - profile: Option, - social: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CarouselCover { - #[serde(rename = "TD")] - text: TextFragment, - #[serde(rename = "TH")] - thumbnail_image: Option, - #[serde(rename = "BG")] - background_image: Option, - #[serde(rename = "L")] - link: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CustomCarouselContent { - card_type: CustomType, - #[serde(rename = "CIL")] - content_list: Vec, - #[serde(rename = "CHD")] - content_head: Option, - #[serde(rename = "CTA")] - content_tail: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CustomInfo { - #[serde(rename = "ME")] - message: String, - #[serde(rename = "TP")] - custom_type: CustomType, - #[serde(rename = "SID")] - service_id: String, - #[serde(rename = "DID")] - provider_id: String, - #[serde(rename = "VA")] - android_version: String, - #[serde(rename = "VI")] - ios_version: String, - #[serde(rename = "VW")] - windows_version: String, - #[serde(rename = "VM")] - macos_version: String, - #[serde(rename = "SNM")] - service_nickname: Option, - #[serde(rename = "SIC")] - service_icon: Option, - #[serde(rename = "SL")] - service_link: Option, - #[serde(rename = "L")] - link: Option, - #[serde(rename = "LOCK")] - secure: Option, - #[serde(rename = "FW")] - fw: Option, - #[serde(rename = "RF")] - reference: String, - #[serde(rename = "AD")] - ad: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct KakaoLinkInfo { - #[serde(rename = "ai")] - app_id: String, - #[serde(rename = "ti")] - template_id: Option, - #[serde(rename = "lv")] - link_version: Option, - #[serde(rename = "ak")] - app_key: Option, - #[serde(rename = "av")] - app_version: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct CustomAttachment { - #[serde(rename = "P")] - info: CustomInfo, - #[serde(rename = "C")] - content: Option, - #[serde(rename = "K")] - link_info: Option, -} - -impl<'de> Deserialize<'de> for ButtonFragment { - fn deserialize(deserializer: D) -> Result - where - D: serde::de::Deserializer<'de>, - { - #[derive(Deserialize)] - struct ButtonFragmentRaw { - #[serde(rename = "BU")] - inner: ButtonFragmentRawInner, - #[serde(rename = "L")] - link: LinkFragment, - } - - #[derive(Deserialize)] - struct ButtonFragmentRawInner { - #[serde(rename = "T")] - text: String, - #[serde(rename = "SR")] - display_target: Option, - } - - let raw = ButtonFragmentRaw::deserialize(deserializer)?; - Ok(Self { - text: raw.inner.text, - display_target: raw.inner.display_target, - link: raw.link, - }) - } -} - -impl Serialize for ButtonFragment { - fn serialize(&self, serializer: S) -> Result - where - S: serde::ser::Serializer, - { - #[derive(Serialize)] - struct ButtonFragmentRaw<'a> { - #[serde(rename = "BU")] - inner: ButtonFragmentRawInner<'a>, - #[serde(rename = "L")] - link: &'a LinkFragment, - } - - #[derive(Serialize)] - struct ButtonFragmentRawInner<'a> { - #[serde(rename = "T")] - text: &'a str, - #[serde(rename = "SR")] - display_target: &'a Option, - } - - let inner = ButtonFragmentRawInner { - text: &self.text, - display_target: &self.display_target, - }; - - let raw = ButtonFragmentRaw { - inner, - link: &self.link, - }; - - raw.serialize(serializer) - } -} diff --git a/src/types/chat_room/attachment/emoticon.rs b/src/types/chat_room/attachment/emoticon.rs deleted file mode 100644 index ad98c79..0000000 --- a/src/types/chat_room/attachment/emoticon.rs +++ /dev/null @@ -1,19 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct EmoticonAttachment { - pub path: String, - - pub name: String, - #[serde(rename = "type")] - pub sticker_type: String, - // TODO: what is `type` format? - #[serde(rename = "s")] - pub stop_at: Option, - // TODO: what is `stop_at` format? - pub alt: Option, - - pub width: Option, - pub height: Option, - pub sound: Option, // TODO: what is `sound` format? -} diff --git a/src/types/chat_room/attachment/file.rs b/src/types/chat_room/attachment/file.rs deleted file mode 100644 index 62b2837..0000000 --- a/src/types/chat_room/attachment/file.rs +++ /dev/null @@ -1,66 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::types::Timestamp; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct PhotoAttachment { - #[serde(rename = "k")] - pub key_path: String, - - pub url: String, - #[serde(rename = "w")] - pub width: usize, - #[serde(rename = "h")] - pub height: usize, - - #[serde(rename = "thumbnailUrl")] - pub thumbnail_url: Option, - #[serde(rename = "thumbnailWidth")] - pub thumbnail_width: Option, - #[serde(rename = "thumbnailHeight")] - pub thumbnail_height: Option, - - #[serde(rename = "s", alias = "size")] - pub file_size: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct VideoAttachment { - #[serde(rename = "tk")] - pub key_path: String, - - pub url: String, - #[serde(rename = "w")] - pub width: usize, - #[serde(rename = "h")] - pub height: usize, - - #[serde(rename = "s", alias = "size")] - pub file_size: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct FileAttachment { - #[serde(rename = "k")] - pub key_path: String, - - pub url: String, - - #[serde(rename = "name")] - pub file_name: String, - #[serde(rename = "s", alias = "size")] - pub file_size: Option, - #[serde(rename = "expire")] - pub expired_at: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct AudioAttachment { - #[serde(rename = "tk")] - pub path: String, - - pub url: String, - - #[serde(rename = "s", alias = "size")] - pub file_size: Option, -} diff --git a/src/types/chat_room/attachment/mod.rs b/src/types/chat_room/attachment/mod.rs deleted file mode 100644 index 0577763..0000000 --- a/src/types/chat_room/attachment/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -pub use custom::*; -pub use emoticon::*; -pub use file::*; -pub use sharp::*; -pub use text::*; - -pub mod custom; -pub mod emoticon; -pub mod file; -pub mod sharp; -pub mod text; - -pub enum ChatAttachment { - Emoticon(EmoticonAttachment), - - Photo(PhotoAttachment), - Video(VideoAttachment), - File(FileAttachment), - Audio(AudioAttachment), - - Sharp(SharpAttachment), - - LongText(LongTextAttachment), - Reply(ReplyAttachment), -} diff --git a/src/types/chat_room/attachment/sharp.rs b/src/types/chat_room/attachment/sharp.rs deleted file mode 100644 index c3b340c..0000000 --- a/src/types/chat_room/attachment/sharp.rs +++ /dev/null @@ -1,221 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct SharpAttachment { - #[serde(rename = "Q")] - pub question: String, - #[serde(rename = "L")] - pub link: String, - - #[serde(rename = "I")] - pub thumbnail_url: Option, - - #[serde(rename = "V")] - pub resource_type: String, - // TODO: what is `V`? - #[serde(rename = "R")] - pub resources: Vec, - - #[serde(rename = "F")] - pub footer: Option, -} - -pub mod resource { - use serde::{Deserialize, Serialize}; - - use super::*; - - // TODO: will be integrated with `ResourceKind` in future. - #[derive(Serialize, Deserialize, Debug, Clone)] - pub enum Type { - None, - List, - Image, - VideoClip, - Weather, - Movie, - Media, - Rank, - Simple, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Resource { - pub kind: ResourceKind, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub enum ResourceKind { - ButtonList(ButtonList), - Image(Image), - Media(Media), - Movie(Movie), - Rank(Rank), - Video(Video), - Weather(Weather), - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct ButtonList { - #[serde(rename = "BU")] - pub buttons: Vec, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Image { - #[serde(rename = "I")] - pub image: Option, - #[serde(rename = "L")] - pub link: String, - #[serde(rename = "T")] - pub text: Option, - #[serde(rename = "D")] - pub description: Option, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Media { - #[serde(rename = "I")] - pub image: Option, - #[serde(rename = "L")] - pub link: String, - #[serde(rename = "T")] - pub text: Option, - #[serde(rename = "D")] - pub description: Option, - #[serde(rename = "DL")] - pub details: Vec, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Movie { - #[serde(rename = "IL")] - pub images: Vec, - #[serde(rename = "L")] - pub link: String, - #[serde(rename = "T")] - pub text: Option, - #[serde(rename = "D")] - pub description: Option, - #[serde(rename = "DL")] - pub details: Vec, - #[serde(rename = "ST")] - pub stars: String, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Rank { - #[serde(rename = "I")] - pub image: Option, - #[serde(rename = "L")] - pub link: String, - #[serde(rename = "T")] - pub text: Option, - #[serde(rename = "RA")] - pub rank: Option, - #[serde(rename = "ST")] - pub stars: String, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Video { - #[serde(rename = "I")] - pub image: Option, - #[serde(rename = "L")] - pub link: String, - #[serde(rename = "T")] - pub text: Option, - #[serde(rename = "D")] - pub description: Option, - #[serde(rename = "PT")] - pub playtime: i32, // TODO: what is `playtime` format? - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Weather { - #[serde(rename = "MA")] - pub main_weather: Vec, - #[serde(rename = "SU")] - pub sub_weather: Vec, - #[serde(rename = "L")] - pub link: String, - #[serde(rename = "PL")] - pub place: Option, - #[serde(rename = "D")] - pub description: Option, - #[serde(rename = "TM")] - pub updated_at: String, - } -} - -pub mod fragment { - use serde::{Deserialize, Serialize}; - - #[allow(dead_code)] - pub struct Fragment { - kind: FragmentKind, - } - - pub enum FragmentKind { - Button(Button), - Image(Image), - Simple(Simple), - Text(Text), - Weather(Weather), - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Button { - #[serde(rename = "T")] - pub text: String, - #[serde(rename = "L")] - pub link: Option, - #[serde(rename = "TP")] - pub icon: Option, // TODO: what is `TP`? - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Image { - #[serde(rename = "I")] - pub url: String, - #[serde(rename = "W")] - pub width: Option, - #[serde(rename = "H")] - pub height: Option, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Simple { - #[serde(rename = "L")] - pub link: String, - #[serde(rename = "T")] - pub text: Option, - #[serde(rename = "D")] - pub description: Option, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Text { - #[serde(rename = "T")] - pub text: String, - #[serde(rename = "DE")] - pub description: Option, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub struct Weather { - #[serde(rename = "T")] - pub text: Option, - #[serde(rename = "TE")] - pub temperature: String, - #[serde(rename = "IC")] - pub icon: WeatherIcon, - } - - #[derive(Serialize, Deserialize, Debug, Clone)] - pub enum WeatherIcon { - Sunny = 0, - CloudyDay = 3, - CloudyNight = 2, - } -} diff --git a/src/types/chat_room/attachment/text.rs b/src/types/chat_room/attachment/text.rs deleted file mode 100644 index 700512a..0000000 --- a/src/types/chat_room/attachment/text.rs +++ /dev/null @@ -1,30 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::types::{ChatType, LogId, Mention, UserId}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct LongTextAttachment { - #[serde(rename = "k")] - key_path: String, - path: String, - #[serde(rename = "s", alias = "size")] - length: Option, - #[serde(rename = "sd")] - sd: Option, // TODO: what is `sd`? -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ReplyAttachment { - #[serde(rename = "src_type")] - source_type: ChatType, - #[serde(rename = "src_logId")] - source_log_id: LogId, - #[serde(rename = "src_userId")] - source_user_id: UserId, - #[serde(rename = "src_message")] - source_message: String, - #[serde(rename = "src_mentions")] - source_mentions: Vec, - #[serde(rename = "src_linkId")] - source_link_id: Option, // TODO: what is `link_id`? -} diff --git a/src/types/chat_room/chat.rs b/src/types/chat_room/chat.rs deleted file mode 100644 index ae68df5..0000000 --- a/src/types/chat_room/chat.rs +++ /dev/null @@ -1,119 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::types::{Channel, ChatAttachment, LogId, Timestamp, User, UserId}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ChatType { - Feed = 0, - Text = 1, - Photo = 2, - Video = 3, - Contact = 4, - Audio = 5, - DitemEmoticon = 6, - DitemGift = 7, - DitemImg = 8, - KakaoLink = 9, - Avatar = 11, - Sticker = 12, - Schedule = 13, - Vote = 14, - Lottery = 15, - Location = 16, - Profile = 17, - File = 18, - StickerAni = 20, - Nudge = 21, - Actioncon = 22, - Search = 23, - Reply = 26, - MultiPhoto = 27, - Mvoip = 51, - Custom = 71, - PlusFriend = 81, - PlusFriendViral = 83, - Template = 90, - ApiTemplate = 91, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Mention { - pub user_id: UserId, - #[serde(rename = "len")] - pub length: u32, - #[serde(rename = "at")] - pub index_list: Vec, -} - -pub struct Chat { - pub kind: ChatKind, - pub log_id: LogId, - pub prev_log_id: LogId, - pub channel: Channel, - pub sender: User, - pub counter: i32, - pub text: String, - pub attachments: Vec, - pub mentions: Vec, - pub send_at: Timestamp, -} - -impl Chat { - pub fn get_mentions(&self, user_id: UserId) -> Vec<&Mention> { - self.mentions - .iter() - .filter(|mention| mention.user_id == user_id) - .collect() - } - - pub fn is_mentioned(&self, user_id: UserId) -> bool { - !self.get_mentions(user_id).is_empty() - } -} - -#[derive(Debug, Clone)] -pub enum ChatKind { - Feed(FeedChat), - Text(TextChat), - LongText(LongTextChat), - Photo(PhotoChat), - MultiPhoto(MultiPhotoChat), - StaticEmoticon(StaticEmoticonChat), - AnimatedEmoticon(AnimatedEmoticonChat), - SharpSearch(SharpSearchChat), - Reply(ReplyChat), - KakaoLinkV2(KakaoLinkV2Chat), -} - -#[derive(Debug, Clone)] -pub struct FeedChat {} - -#[derive(Debug, Clone)] -pub struct TextChat {} - -#[derive(Debug, Clone)] -pub struct LongTextChat {} - -#[derive(Debug, Clone)] -pub struct PhotoChat {} - -#[derive(Debug, Clone)] -pub struct MultiPhotoChat {} - -#[derive(Debug, Clone)] -pub struct StaticEmoticonChat {} - -#[derive(Debug, Clone)] -pub struct AnimatedEmoticonChat {} - -#[derive(Debug, Clone)] -pub struct VideoChat {} - -#[derive(Debug, Clone)] -pub struct SharpSearchChat {} - -#[derive(Debug, Clone)] -pub struct ReplyChat {} - -#[derive(Debug, Clone)] -pub struct KakaoLinkV2Chat {} diff --git a/src/types/chat_room/feed.rs b/src/types/chat_room/feed.rs deleted file mode 100644 index f6fb339..0000000 --- a/src/types/chat_room/feed.rs +++ /dev/null @@ -1,33 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::types::Member; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Feed { - #[serde(rename = "feedType")] - pub feed_type: FeedType, - pub text: Option, - pub member: Option, - pub members: Vec, - pub inviter: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum FeedType { - Undefined = -999_999, - LocalLeave = -1, - Invite = 1, - Leave = 2, - SecretLeave = 3, - OpenLinkJoin = 4, - OpenLinkDeleteLink = 5, - OpenLinkKicked = 6, - ChatKicked = 7, - ChatDeleted = 8, - RichContent = 10, - OpenLinkStaffOn = 11, - OpenLinkStaffOff = 12, - OpenLinkRewriteFeed = 13, - DeleteToAll = 14, - OpenLinkHandOverHost = 15, -} diff --git a/src/types/chat_room/log.rs b/src/types/chat_room/log.rs deleted file mode 100644 index c7c43b5..0000000 --- a/src/types/chat_room/log.rs +++ /dev/null @@ -1,27 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::types::{ChannelId, ChatAttachment, ChatType, LogId, Timestamp, UserId}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ChatLog { - #[serde(rename = "logId")] - pub log_id: LogId, - #[serde(rename = "prevId")] - pub prev_log_id: LogId, - - #[serde(rename = "chatId")] - pub channel_id: ChannelId, - #[serde(rename = "authorId")] - pub sender_id: UserId, - #[serde(rename = "type")] - pub chat_type: ChatType, - #[serde(rename = "msgId")] - pub chat_counter: i32, - - #[serde(rename = "message")] - pub text: String, - #[serde(rename = "sendAt")] - pub send_at: Timestamp, - #[serde(rename = "attachment")] - pub attachment: ChatAttachment, -} diff --git a/src/types/chat_room/member.rs b/src/types/chat_room/member.rs deleted file mode 100644 index 0b272c1..0000000 --- a/src/types/chat_room/member.rs +++ /dev/null @@ -1,50 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::types::{UserId, UserType}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Member { - #[serde(rename = "userId")] - user_id: UserId, - #[serde(rename = "type", default)] - user_type: UserType, - - #[serde(rename = "nickName")] - nickname: String, - - #[serde(rename = "pi", alias = "profileImageUrl")] - profile_image_url: Option, - #[serde(rename = "opi", alias = "originalProfileImageUrl")] - original_profile_image_url: Option, - #[serde(rename = "fpi", alias = "fullProfileImageUrl")] - full_profile_image_url: Option, - - #[serde(rename = "accountId")] - account_id: Option, - // TODO: what is `account_id` format? - #[serde(rename = "linkedService")] - linked_service: Option, - #[serde(rename = "statusMessage")] - status_message: Option, - - #[serde(rename = "opt")] - open_profile_token: Option, - #[serde(rename = "mt", default)] - open_chat_member_type: OpenChatMemberType, - #[serde(rename = "pli")] - profile_link_id: Option, - // TODO: what is `profile_link_id` format? -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum OpenChatMemberType { - Unknown = 1, - None = 2, - Manager = 4, -} - -impl Default for OpenChatMemberType { - fn default() -> Self { - OpenChatMemberType::Unknown - } -} diff --git a/src/types/chat_room/mod.rs b/src/types/chat_room/mod.rs deleted file mode 100644 index c530677..0000000 --- a/src/types/chat_room/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use attachment::*; -pub use chat::*; -pub use feed::*; -pub use member::*; - -mod attachment; -mod chat; -mod feed; -mod member; diff --git a/src/types/mod.rs b/src/types/mod.rs deleted file mode 100644 index 5ebdb9d..0000000 --- a/src/types/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub mod channel; -pub mod chat_room; -pub mod open_chat; -pub mod structs; -pub mod user; - -mod os; - -pub use channel::*; -pub use chat_room::*; -pub use os::*; -pub use user::*; - -pub type LogId = u64; -pub type Timestamp = u64; diff --git a/src/types/open_chat.rs b/src/types/open_chat.rs deleted file mode 100644 index a45a5a6..0000000 --- a/src/types/open_chat.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[derive(Debug, Clone)] -pub struct OpenChatManager {} - -#[derive(Debug, Clone)] -pub enum OpenChatLinkType { - Profile = 1, - Chatroom = 2, -} diff --git a/src/types/os.rs b/src/types/os.rs deleted file mode 100644 index 14c7d0c..0000000 --- a/src/types/os.rs +++ /dev/null @@ -1,21 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum Os { - Win32, - Mac, - IPad, - UWP, -} - -impl Os { - pub fn as_str(&self) -> &'static str { - match self { - Os::Win32 => "win32", - Os::Mac => "mac", - Os::IPad => "ipad", - Os::UWP => "uwp", - } - } -} diff --git a/src/types/structs/channel.rs b/src/types/structs/channel.rs deleted file mode 100644 index 8d42e3b..0000000 --- a/src/types/structs/channel.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Maps to ChannelMetaSetStruct -#[derive(Debug, Clone)] -pub struct ChannelMetaSet { - channel_id: u64, - meta_list: Vec, -} - -// Maps to ChannelMetaStruct -#[derive(Debug, Clone)] -pub struct ChannelMeta { - channel_meta_type: ChannelMetaType, - revision: u64, - author_id: u64, - content: String, - updated_at: i32, -} - -#[derive(Debug, Clone)] -pub enum ChannelMetaType { - Notice = 1, - Group = 2, - Title = 3, - Profile = 4, - TV = 5, - Privilege = 6, - LiveTV = 7, - PlusBackground = 8, - LiveTalkInfo = 11, - LiveTalkCount = 12, -} - -// Maps to ChannelBoardMetaStruct -pub struct ChannelBoardMeta {} - -pub enum ChannelBoardType { - None = 0, - FloatingNotice = 1, - SideNotice = 2, - Badge = 3, -} diff --git a/src/types/structs/chat.rs b/src/types/structs/chat.rs deleted file mode 100644 index e7f17b7..0000000 --- a/src/types/structs/chat.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Maps to ChatInfoStruct -pub struct ChatInfo {} - -// Maps to ChatMetaStruct -pub struct ChatMeta {} - -// Maps to ChatDataStruct -pub struct ChatData {} - -// Maps to ChatDataMetaStruct -pub struct ChatDataMeta {} - -// Maps to ChatLogStruct -pub struct ChatLog {} diff --git a/src/types/structs/mod.rs b/src/types/structs/mod.rs deleted file mode 100644 index 086b03b..0000000 --- a/src/types/structs/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use channel::*; -pub use chat::*; -pub use open_link::*; -pub use settings::*; - -pub mod channel; -pub mod chat; -pub mod open_link; -pub mod settings; diff --git a/src/types/structs/open_link.rs b/src/types/structs/open_link.rs deleted file mode 100644 index 761accd..0000000 --- a/src/types/structs/open_link.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::types::open_chat::OpenChatLinkType; - -// Maps to OpenLinkStruct -#[derive(Debug, Clone)] -pub struct OpenLink { - link_id: u64, - token: i32, - link_name: String, - link_url: String, - link_type: OpenChatLinkType, - owner: OpenMember, - description: String, - cover_url: String, -} - -// Maps to OpenMemberStruct -#[derive(Debug, Clone)] -pub struct OpenMember { - user_id: u64, - nickname: String, - profile_image_url: String, - original_profile_image_url: String, - full_profile_image_url: String, - member_type: i32, - open_chat_token: i32, -} diff --git a/src/types/structs/settings.rs b/src/types/structs/settings.rs deleted file mode 100644 index fc39159..0000000 --- a/src/types/structs/settings.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Maps to ClientSettingsStruct -#[derive(Debug, Clone)] -pub struct ClientSettings { - status: i32, - allow_pay: bool, - allow_story: bool, - allow_story_post: bool, - background_image_url: String, - original_background_image_url: String, - profile_image_url: String, - status_message: String, - story_url: String, - suspended: bool, - user_id: u64, -} diff --git a/src/types/user.rs b/src/types/user.rs deleted file mode 100644 index febb9e8..0000000 --- a/src/types/user.rs +++ /dev/null @@ -1,26 +0,0 @@ -use serde::{Deserialize, Serialize}; - -pub type UserId = u64; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum UserType { - Undefined = -999_999, - NotFriend = -100, - Deactivated = 9, - Friend = 100, - OpenProfile = 1000, -} - -impl Default for UserType { - fn default() -> Self { - UserType::Undefined - } -} - -pub struct User {} - -pub struct ClientChatUser {} - -pub struct ClientChannelUser {} - -pub struct ClientUserInfo {} diff --git a/tests/token_client.rs b/tests/token_client.rs deleted file mode 100644 index 1ebe7ac..0000000 --- a/tests/token_client.rs +++ /dev/null @@ -1,37 +0,0 @@ -use loco::internal::{agent::Os, DeviceRegisterData, LoginData, TokenClient}; - -pub fn get_device_register_data() -> DeviceRegisterData { - DeviceRegisterData::new( - LoginData::new( - "test@gmail.com".to_string(), - "password".to_string(), - "2bf46274-780c-4af1-9583-c5e1d7e866b7", - "loco.rs".to_string(), - "10.0".to_string(), - false, - false, - ), - "0000".to_string(), - ) -} - -#[tokio::test] -async fn login() { - let result = TokenClient::new(Os::Win32).request_login(&get_device_register_data()); - let data = result.unwrap(); - println!("{}", data.status); -} - -#[tokio::test] -async fn register_device() { - let result = TokenClient::new(Os::Win32).register_device(&get_device_register_data()); - let text = result.unwrap(); - println!("{}", text.text().unwrap()); -} - -#[tokio::test] -async fn request_passcode() { - let result = TokenClient::new(Os::Win32).request_passcode(&get_device_register_data()); - let text = result.unwrap(); - println!("{}", text.text().unwrap()); -}