diff --git a/Cargo.toml b/Cargo.toml index 9a08972..c70c6f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,16 @@ authors = ["CympleTech "] edition = "2021" license = "MIT/Apache-2.0" +[workspace] +members = [ + "types/chat", + "types/group", + "types/dao", + "types/domain", + "types/cloud", + "types/data" +] + [lib] name = "esse" crate-type = ["cdylib", "staticlib"] @@ -39,19 +49,13 @@ tokio = { version = "1", features = ["full"] } web3 = { version = "0.17", default-features = false, features = ["http-tls", "signing"] } tdn = { version = "0.6", default-features = false, features = ["full"] } tdn_did = { version = "0.6" } -tdn_storage = { git = "https://github.com/cypherlink/tdn_storage", branch="main" } - -chat_types = { git = "https://github.com/cympletech/esse_types", branch="main" } -group_types = { git = "https://github.com/cympletech/esse_types", branch="main" } -cloud_types = { git = "https://github.com/cympletech/esse_types", branch="main" } -domain_types = { git = "https://github.com/cympletech/esse_types", branch="main" } -dao_types = { git = "https://github.com/cympletech/esse_types", branch="main" } -data = { git = "https://github.com/cympletech/esse_types", branch="main" } -#chat_types = { path = "../esse_types/chat" } -#group_types = { path = "../esse_types/group" } -#dao_types = { path = "../esse_types/dao" } -#domain_types = { path = "../esse_types/domain" } -#cloud_types = { path = "../esse_types/cloud" } +tdn_storage = { git = "https://github.com/cympletech/tdn", branch="main" } +chat_types = { version = "0.1", path = "./types/chat" } +group_types = { version = "0.1", path = "./types/group" } +cloud_types = { version = "0.1", path = "./types/cloud" } +domain_types = { version = "0.1", path = "./types/domain" } +dao_types = { version = "0.1", path = "./types/dao" } +data = { version = "0.1", path = "./types/data" } openssl = { version = "0.10", features = ["vendored"] } # Add for cross-compile. diff --git a/types/README.md b/types/README.md new file mode 100644 index 0000000..2001082 --- /dev/null +++ b/types/README.md @@ -0,0 +1,7 @@ +# esse_types + +ESSE bulit-in app open types. + +### Open Apps +- Group Chat +- Domain diff --git a/types/chat/Cargo.toml b/types/chat/Cargo.toml new file mode 100644 index 0000000..bbd1e6f --- /dev/null +++ b/types/chat/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "chat_types" +version = "0.1.0" +authors = ["CympleTech "] +edition = "2021" +readme = "README.md" +description = "ESSE common chat types." +repository = "https://github.com/cympletech/esse_types/chat" +keywords = ["distributed", "p2p", "chat", "ESSE"] +license = "MIT/Apache-2.0" + +[dependencies] +serde = { version = "1", features = ["derive"] } +tdn_types = { version = "0.6", default-features = false } \ No newline at end of file diff --git a/types/chat/src/lib.rs b/types/chat/src/lib.rs new file mode 100644 index 0000000..06939b0 --- /dev/null +++ b/types/chat/src/lib.rs @@ -0,0 +1,65 @@ +use serde::{Deserialize, Serialize}; +use tdn_types::{group::GroupId, primitive::PeerId}; + +/// message type use in network. +#[derive(Serialize, Deserialize, Clone)] +pub enum NetworkMessage { + String(String), // content + Image(Vec), // image bytes. + File(String, Vec), // filename, file bytes. + Contact(String, GroupId, PeerId, Vec), // name, gid, addr, avatar bytes. + Record(Vec, u32), // record audio bytes. + Emoji, + Phone, + Video, + Invite(String), + Transfer(String), +} + +/// common message types. +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum MessageType { + String, + Image, + File, + Contact, + Record, + Emoji, + Phone, + Video, + Invite, + Transfer, +} + +impl MessageType { + pub fn to_int(&self) -> i64 { + match self { + MessageType::String => 0, + MessageType::Image => 1, + MessageType::File => 2, + MessageType::Contact => 3, + MessageType::Record => 4, + MessageType::Emoji => 5, + MessageType::Phone => 6, + MessageType::Video => 7, + MessageType::Invite => 8, + MessageType::Transfer => 9, + } + } + + pub fn from_int(i: i64) -> MessageType { + match i { + 0 => MessageType::String, + 1 => MessageType::Image, + 2 => MessageType::File, + 3 => MessageType::Contact, + 4 => MessageType::Record, + 5 => MessageType::Emoji, + 6 => MessageType::Phone, + 7 => MessageType::Video, + 8 => MessageType::Invite, + 9 => MessageType::Transfer, + _ => MessageType::String, + } + } +} diff --git a/types/cloud/Cargo.toml b/types/cloud/Cargo.toml new file mode 100644 index 0000000..e94f071 --- /dev/null +++ b/types/cloud/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "cloud_types" +version = "0.1.0" +authors = ["CympleTech "] +edition = "2021" +readme = "README.md" +description = "ESSE personal data cloud service types." +repository = "https://github.com/cympletech/esse_types/group" +keywords = ["distributed", "p2p", "cloud", "data", "storage", "ESSE"] +license = "MIT/Apache-2.0" + +[dependencies] +serde = { version = "1", features = ["derive"] } +tdn_types = { version = "0.6", default-features = false } +tdn_did = { version = "0.6", default-features = false } diff --git a/types/cloud/src/lib.rs b/types/cloud/src/lib.rs new file mode 100644 index 0000000..7c03db5 --- /dev/null +++ b/types/cloud/src/lib.rs @@ -0,0 +1,35 @@ +use serde::{Deserialize, Serialize}; +use tdn_did::Proof; +use tdn_types::group::GroupId; + +/// Personal data cloud service default TDN GROUP ID. +#[rustfmt::skip] +pub const CLOUD_ID: GroupId = GroupId([ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, +]); + +/// ESSE service to peer layer Event. +#[derive(Serialize, Deserialize)] +pub struct LayerServerEvent(pub ServerEvent, pub Proof); + +/// ESSE peer to layer Event. +#[derive(Serialize, Deserialize)] +pub struct LayerPeerEvent(pub PeerEvent, pub Proof); + +/// ESSE service to peer Event. +#[derive(Serialize, Deserialize)] +pub enum ServerEvent { + /// check result status. + /// params: provider name, is support request proxy. + Status(String, bool), +} + +/// ESSE peer to service Event. +#[derive(Serialize, Deserialize)] +pub enum PeerEvent { + /// check service status is ok. + Check, +} diff --git a/types/dao/Cargo.toml b/types/dao/Cargo.toml new file mode 100644 index 0000000..869e847 --- /dev/null +++ b/types/dao/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "dao_types" +version = "0.1.0" +authors = ["CympleTech "] +edition = "2021" +readme = "README.md" +description = "ESSE dao service types." +repository = "https://github.com/cympletech/esse_types/dao" +keywords = ["distributed", "p2p", "DAO", "ESSE"] +license = "MIT/Apache-2.0" + +[dependencies] +chat_types = { path = "../chat", version = "0.1" } +serde = { version = "1", features = ["derive"] } +tdn_types = { version = "0.6", default-features = false } +tdn_did = { version = "0.6", default-features = false } diff --git a/types/dao/src/lib.rs b/types/dao/src/lib.rs new file mode 100644 index 0000000..efb0758 --- /dev/null +++ b/types/dao/src/lib.rs @@ -0,0 +1,269 @@ +use serde::{Deserialize, Serialize}; +use tdn_did::Proof; +use tdn_types::{group::GroupId, primitive::PeerId}; + +use chat_types::NetworkMessage; + +/// Dao app(service) default TDN GROUP ID. +#[rustfmt::skip] +pub const DAO_ID: GroupId = GroupId([ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, +]); + +/// Group chat types. include: Encrypted, Private, Open. +#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)] +pub enum GroupType { + /// encrypted group type, data is encrypted, and it can need manager + /// or take manager's zero-knowledge-proof. + Encrypted, + /// private group type, data not encrypted, and need group manager agree. + Private, + /// opened group type, data not encrypted, anyone can join this group. + Open, + /// tmp group. can use descrip local tmp group chat. + Tmp, +} + +impl GroupType { + pub fn to_i64(&self) -> i64 { + match self { + GroupType::Tmp => 0, + GroupType::Open => 1, + GroupType::Private => 2, + GroupType::Encrypted => 3, + } + } + + pub fn from_i64(u: i64) -> Self { + match u { + 0 => GroupType::Tmp, + 1 => GroupType::Open, + 2 => GroupType::Private, + 3 => GroupType::Encrypted, + _ => GroupType::Tmp, + } + } +} + +/// DaoInfo transfer in the network. +#[derive(Serialize, Deserialize)] +pub enum DaoInfo { + /// params: owner, owner_name, owner_avatar, Group ID, group_type, is_must_agree_by_manager, + /// group_name, group_bio, group_avatar. + Common( + GroupId, + String, + Vec, + GroupId, + GroupType, + bool, + String, + String, + Vec, + ), + /// params: owner, owner_name, owner_avatar, Group ID, is_must_agree_by_manager, key_hash, + /// group_name(bytes), group_bio(bytes), group_avatar(bytes). + Encrypted( + GroupId, + String, + Vec, + GroupId, + bool, + Vec, + Vec, + Vec, + Vec, + ), +} + +/// Dao chat connect data structure. +/// params: Group ID, join_proof. +#[derive(Serialize, Deserialize)] +pub struct LayerConnect(pub GroupId, pub ConnectProof); + +/// Dao chat connect success result data structure. +/// params: Group ID, group current height. +#[derive(Serialize, Deserialize)] +pub struct LayerResult(pub GroupId, pub i64); + +/// Dao chat connect proof. +#[derive(Serialize, Deserialize)] +pub enum ConnectProof { + /// when is joined in group chat, can only use had to join (connect). + /// params: proof. + Common(Proof), + /// zero-knowledge-proof. not has account id. + /// verify(proof, key_hash, current_peer_addr). + Zkp(Proof), // TODO MOCK-PROOF +} + +/// Dao chat join proof. +#[derive(Serialize, Deserialize)] +pub enum JoinProof { + /// when join the open group chat. + /// params: member name, member avatar. + Open(String, Vec), + /// when is invate, it will take group_manager's proof for invate. + /// params: invite_by_account, invite_proof, member name, member avatar. + Invite(GroupId, Proof, String, Vec), + /// zero-knowledge-proof. not has account id. + /// verify(proof, key_hash, current_peer_addr). + Zkp(Proof), // TODO MOCK-PROOF +} + +/// check result type. +#[derive(Serialize, Deserialize, Debug)] +pub enum CheckType { + /// allow to create new group. + Allow, + /// cannot created, remain = 0. + None, + /// account is suspended. + Suspend, + /// cannot created, no permission. + Deny, +} + +impl CheckType { + pub fn to_u32(&self) -> u32 { + match self { + CheckType::Allow => 0, + CheckType::None => 1, + CheckType::Suspend => 2, + CheckType::Deny => 3, + } + } +} + +/// ESSE Dao chat app's layer Event. +#[derive(Serialize, Deserialize)] +pub enum LayerEvent { + /// offline. as BaseLayerEvent. + Offline(GroupId), + /// suspend. as BaseLayerEvent. + Suspend(GroupId), + /// actived. as BaseLayerEvent. + Actived(GroupId), + /// check if account has permission to create group, and supported group types. + Check, + /// result check. + /// params: check type, provider name, remain, supported_group_types. + CheckResult(CheckType, String, i64, Vec), + /// create a Group Chat. + /// params: group_info, proof. + Create(DaoInfo, Proof), + /// result create group success. + /// params: Group ID, is_ok. + CreateResult(GroupId, bool), + /// join group request. Group ID, Join Proof and info, request db id. + Request(GroupId, JoinProof), + /// request need manager to handle. + RequestHandle(GroupId, GroupId, PeerId, JoinProof, i64, i64), + /// manager handle request result. Group ID, request db id, is ok. + RequestResult(GroupId, i64, bool), + /// agree join request. + Agree(GroupId, DaoInfo), + /// reject join request. Group ID, if lost efficacy. + Reject(GroupId, bool), + /// online group member. Group ID, member id, member address. + MemberOnline(GroupId, GroupId, PeerId), + /// offline group member. Group ID, member id. + MemberOffline(GroupId, GroupId), + /// sync online members. + MemberOnlineSync(GroupId), + /// sync online members result. + MemberOnlineSyncResult(GroupId, Vec<(GroupId, PeerId)>), + /// sync group event. Group ID, height, event. + Sync(GroupId, i64, Event), + /// packed sync event request. Group ID, from. + SyncReq(GroupId, i64), + /// packed sync event. Group ID, current height, from height, to height, packed events. + Packed(GroupId, i64, i64, i64, Vec), +} + +impl LayerEvent { + /// get event's group id. + pub fn gcd(&self) -> Option<&GroupId> { + match self { + Self::Offline(gcd) => Some(gcd), + Self::Suspend(gcd) => Some(gcd), + Self::Actived(gcd) => Some(gcd), + Self::Check => None, + Self::CheckResult(..) => None, + Self::Create(..) => None, + Self::CreateResult(gcd, _) => Some(gcd), + Self::Request(gcd, _) => Some(gcd), + Self::RequestHandle(gcd, ..) => Some(gcd), + Self::RequestResult(gcd, ..) => Some(gcd), + Self::Agree(gcd, ..) => Some(gcd), + Self::Reject(gcd, ..) => Some(gcd), + Self::MemberOnline(gcd, ..) => Some(gcd), + Self::MemberOffline(gcd, ..) => Some(gcd), + Self::MemberOnlineSync(gcd) => Some(gcd), + Self::MemberOnlineSyncResult(gcd, ..) => Some(gcd), + Self::Sync(gcd, ..) => Some(gcd), + Self::SyncReq(gcd, ..) => Some(gcd), + Self::Packed(gcd, ..) => Some(gcd), + } + } + + /// check if handle this, remote must online frist. + pub fn need_online(&self) -> bool { + match self { + Self::Offline(..) => true, + Self::Suspend(..) => true, + Self::Actived(..) => true, + Self::RequestHandle(..) => true, + Self::RequestResult(..) => true, + Self::MemberOnline(..) => true, + Self::MemberOffline(..) => true, + Self::MemberOnlineSync(..) => true, + Self::MemberOnlineSyncResult(..) => true, + Self::Sync(..) => true, + Self::SyncReq(..) => true, + Self::Packed(..) => true, + _ => false, + } + } +} + +/// Dao chat packed event. +#[derive(Serialize, Deserialize)] +pub enum PackedEvent { + GroupInfo, + GroupTransfer, + GroupManagerAdd, + GroupManagerDel, + GroupClose, + /// params: member id, member address, member name, member avatar. + MemberInfo(GroupId, PeerId, String, Vec), + /// params: member id, member address, member name, member avatar, member join time. + MemberJoin(GroupId, PeerId, String, Vec, i64), + /// params: member id, + MemberLeave(GroupId), + /// params: member id, message, message time. + MessageCreate(GroupId, NetworkMessage, i64), + /// had in before. + None, +} + +/// Dao chat event. +#[derive(Serialize, Deserialize, Clone)] +pub enum Event { + GroupInfo, + GroupTransfer, + GroupManagerAdd, + GroupManagerDel, + GroupClose, + /// params: member id, member address, member name, member avatar. + MemberInfo(GroupId, PeerId, String, Vec), + /// params: member id, member address, member name, member avatar, member join time. + MemberJoin(GroupId, PeerId, String, Vec, i64), + /// params: member id, + MemberLeave(GroupId), + /// params: member id, message, height. + MessageCreate(GroupId, NetworkMessage, i64), +} diff --git a/types/data/Cargo.toml b/types/data/Cargo.toml new file mode 100644 index 0000000..7477206 --- /dev/null +++ b/types/data/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "data" +version = "0.1.0" +authors = ["CympleTech "] +edition = "2021" +readme = "README.md" +description = "ESSE common data structure." +repository = "https://github.com/cympletech/esse_types/data" +keywords = ["distributed", "data", "ESSE"] +license = "MIT/Apache-2.0" + +[features] +default = ["tdn"] +tdn = ["tdn_did", "tdn_types"] + +[dependencies] +tdn_did = { version = "0.6", default-features = false, optional = true } +tdn_types = { version = "0.6", default-features = false, optional = true } diff --git a/types/data/src/lib.rs b/types/data/src/lib.rs new file mode 100644 index 0000000..fffd072 --- /dev/null +++ b/types/data/src/lib.rs @@ -0,0 +1,105 @@ +pub type DataId = [u8; 32]; + +pub trait OwnerId: Clone + Eq + PartialEq { + type Proof: Clone + Eq + PartialEq; + + fn len() -> usize; + fn proof_len() -> usize; + + fn verify(&self, data: &Data) -> bool; + fn id_to_bytes(&self) -> Vec; + fn proof_to_bytes(proof: &Self::Proof) -> Vec; + fn id_from_bytes(id_bytes: &[u8]) -> Result; + fn proof_from_bytes(proof_bytes: &[u8]) -> Result; +} + +/// common data structure. +#[derive(Clone, Eq, PartialEq)] +pub struct Data { + /// Data unique ID, default generate method is other fields hash. + pub did: DataId, + /// ParentID, default is None. + pub pid: Option, + /// time lifetime, (from, to) timestamp. + pub time: (i64, i64), + /// Owner's info. + pub owner: T, + /// data owner proof. it can verify by owner. + pub proof: T::Proof, + /// MIME type, and value bytes. + pub value: (String, Vec), +} + +impl Data { + pub fn to_bytes(&self) -> Vec { + let mut bytes = vec![]; + bytes.extend_from_slice(&self.did); + if let Some(p) = self.pid { + bytes.extend_from_slice(&p); + } else { + bytes.extend_from_slice(&[0u8; 32]); + } + bytes.extend_from_slice(&mut self.time.0.to_le_bytes()); + bytes.extend_from_slice(&mut self.time.1.to_le_bytes()); + bytes.extend_from_slice(&mut self.owner.id_to_bytes()); + bytes.extend_from_slice(&mut T::proof_to_bytes(&self.proof)); + + let mut mime_bytes = self.value.0.as_bytes(); + bytes.extend_from_slice(&mut (mime_bytes.len() as u32).to_le_bytes()); + bytes.extend_from_slice(&mut mime_bytes); + bytes.extend_from_slice(&self.value.1); + + bytes + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() < 84 + T::len() + T::proof_len() { + return Err(()); + } + + let mut did_bytes = [0u8; 32]; + did_bytes.copy_from_slice(&bytes[0..32]); + let mut pid_bytes = [0u8; 32]; + pid_bytes.copy_from_slice(&bytes[32..64]); + let pid = if pid_bytes == [0u8; 32] { + None + } else { + Some(pid_bytes) + }; + let mut start_bytes = [0u8; 8]; + start_bytes.copy_from_slice(&bytes[64..72]); + let start_time = i64::from_le_bytes(start_bytes); + + let mut end_bytes = [0u8; 8]; + end_bytes.copy_from_slice(&bytes[72..80]); + let end_time = i64::from_le_bytes(end_bytes); + + let owner = T::id_from_bytes(&bytes[80..])?; + let proof = T::proof_from_bytes(&bytes[80 + T::len()..])?; + + let m_l = 80 + T::len() + T::proof_len(); + let mut mime_len_bytes = [0u8; 4]; + mime_len_bytes.copy_from_slice(&bytes[m_l..m_l + 4]); + let mime_len = u32::from_le_bytes(mime_len_bytes) as usize; + let last = &bytes[m_l + 4..]; + if last.len() < mime_len { + return Err(()); + } + let v_t = std::str::from_utf8(&last[0..mime_len]) + .map_err(|_| ())? + .to_owned(); + let v_v = last[mime_len..].to_vec(); + + Ok(Self { + pid, + owner, + proof, + did: did_bytes, + value: (v_t, v_v), + time: (start_time, end_time), + }) + } +} + +#[cfg(feature = "tdn")] +pub mod tdn; diff --git a/types/data/src/tdn.rs b/types/data/src/tdn.rs new file mode 100644 index 0000000..699a48d --- /dev/null +++ b/types/data/src/tdn.rs @@ -0,0 +1,51 @@ +use tdn_did::{Proof, PROOF_LENGTH}; +use tdn_types::group::{GroupId, GROUP_LENGTH}; + +use crate::{Data, OwnerId}; + +impl OwnerId for GroupId { + type Proof = Proof; + + fn len() -> usize { + PROOF_LENGTH + } + + fn proof_len() -> usize { + GROUP_LENGTH + } + + fn verify(&self, data: &Data) -> bool { + data.proof + .verify_bytes(&data.owner, &data.to_bytes()) + .is_ok() + } + + fn id_to_bytes(&self) -> Vec { + self.0.to_vec() + } + + fn proof_to_bytes(proof: &Self::Proof) -> Vec { + proof.0.clone() + } + + fn id_from_bytes(id_bytes: &[u8]) -> Result { + if id_bytes.len() >= GROUP_LENGTH { + let mut bytes = [0u8; GROUP_LENGTH]; + bytes.copy_from_slice(&id_bytes[0..GROUP_LENGTH]); + Ok(GroupId(bytes)) + } else { + Err(()) + } + } + + fn proof_from_bytes(proof_bytes: &[u8]) -> Result { + if proof_bytes.len() >= PROOF_LENGTH { + let bytes = proof_bytes[0..PROOF_LENGTH].to_vec(); + Ok(Proof(bytes)) + } else { + Err(()) + } + } +} + +pub type TdnData = Data; diff --git a/types/domain/Cargo.toml b/types/domain/Cargo.toml new file mode 100644 index 0000000..ba723fc --- /dev/null +++ b/types/domain/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "domain_types" +version = "0.1.0" +authors = ["CympleTech "] +edition = "2021" +readme = "README.md" +description = "ESSE domain service types." +repository = "https://github.com/cympletech/esse_types/group" +keywords = ["distributed", "p2p", "domain", "ESSE"] +license = "MIT/Apache-2.0" + +[dependencies] +serde = { version = "1", features = ["derive"] } +tdn_types = { version = "0.6", default-features = false } +tdn_did = { version = "0.6", default-features = false } diff --git a/types/domain/src/lib.rs b/types/domain/src/lib.rs new file mode 100644 index 0000000..ce6f9e9 --- /dev/null +++ b/types/domain/src/lib.rs @@ -0,0 +1,75 @@ +use serde::{Deserialize, Serialize}; +use tdn_did::Proof; +use tdn_types::{group::GroupId, primitive::PeerId}; + +// Same ID can has many name !. + +/// Group chat app(service) default TDN GROUP ID. +#[rustfmt::skip] +pub const DOMAIN_ID: GroupId = GroupId([ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4, +]); + +/// ESSE domain service layer Event. +#[derive(Serialize, Deserialize)] +pub struct LayerServerEvent(pub ServerEvent, pub Proof); + +/// ESSE domain service layer Event. +#[derive(Serialize, Deserialize)] +pub struct LayerPeerEvent(pub PeerEvent, pub Proof); + +/// ESSE domain service to peer layer Event. +#[derive(Serialize, Deserialize)] +pub enum ServerEvent { + /// check result status. + /// params: provider name, is support request proxy. + Status(String, bool), + /// register result. + /// params: name, is_ok. + Result(String, bool), + /// a identity info. + /// params: user_name, user_ID, user_address, user_bio, user_avatar. + Info(String, GroupId, PeerId, String, Vec), + /// not found a user by name. + None(String), + /// current name is active. + /// params: name, is_actived + Actived(String, bool), + /// current name is deleted. + /// params: name. + Deleted(String), + /// response the make friend. + /// params: remote_ID, name, is_ok. + Response(GroupId, String, bool), +} + +/// ESSE domain peer to service layer Event. +#[derive(Serialize, Deserialize)] +pub enum PeerEvent { + /// check service status is ok. + Check, + /// register new unique identity to service. + /// params: name, bio, avatar. + Register(String, String, Vec), + /// update user info. + /// params: name, bio, avatar. + Update(String, String, Vec), + /// search a identity info. + /// params: name. + Search(String), + /// make a friend request, + /// params: remote_name, my_name, request_remark. + Request(String, String, String), + /// suspend the name. + /// params: name. + Suspend(String), + /// active the name. + /// params: name. + Active(String), + /// delete the name. + /// params: name. + Delete(String), +} diff --git a/types/group/Cargo.toml b/types/group/Cargo.toml new file mode 100644 index 0000000..8afc51a --- /dev/null +++ b/types/group/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "group_types" +version = "0.1.0" +authors = ["Contact "] +edition = "2021" +readme = "README.md" +description = "ESSE group chat service types." +repository = "https://github.com/cympletech/esse_types/group" +keywords = ["distributed", "p2p", "group chat", "ESSE"] +license = "MIT/Apache-2.0" + +[dependencies] +chat_types = { path = "../chat", version = "0.1" } +serde = { version = "1", features = ["derive"] } +tdn_types = { version = "0.6", default-features = false } +tdn_did = { version = "0.6", default-features = false } diff --git a/types/group/src/lib.rs b/types/group/src/lib.rs new file mode 100644 index 0000000..451f5c2 --- /dev/null +++ b/types/group/src/lib.rs @@ -0,0 +1,96 @@ +use serde::{Deserialize, Serialize}; +use tdn_did::Proof; +use tdn_types::{group::GroupId, primitive::PeerId}; + +use chat_types::NetworkMessage; + +/// Group chat app(service) default TDN GROUP ID. +#[rustfmt::skip] +pub const GROUP_CHAT_ID: GroupId = GroupId([ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, +]); + +/// Group chat connect data structure. +/// params: Group ID, join_proof. +#[derive(Serialize, Deserialize)] +pub struct LayerConnect(pub GroupId, pub Proof); + +/// Group chat connect success result data structure. +/// params: Group ID, group name, group current height. +#[derive(Serialize, Deserialize)] +pub struct LayerResult(pub GroupId, pub String, pub i64); + +/// ESSE Group chat app's layer Event. +#[derive(Serialize, Deserialize)] +pub enum LayerEvent { + /// offline. as BaseLayerEvent. + Offline(GroupId), + /// suspend. as BaseLayerEvent. + Suspend(GroupId), + /// actived. as BaseLayerEvent. + Actived(GroupId), + /// online group member. Group ID, member id, member address. + MemberOnline(GroupId, GroupId, PeerId), + /// offline group member. Group ID, member id. + MemberOffline(GroupId, GroupId), + /// sync online members. + MemberOnlineSync(GroupId), + /// sync online members result. + MemberOnlineSyncResult(GroupId, Vec<(GroupId, PeerId)>), + /// Change the group name. + GroupName(GroupId, String), + /// close the group chat. + GroupClose(GroupId), + /// sync group event. Group ID, height, event. + Sync(GroupId, i64, Event), + /// peer sync event request. Group ID, from. + SyncReq(GroupId, i64), + /// sync members status. + /// Group ID, current height, from height, to height, + /// add members(height, member id, addr, name, avatar), + /// leaved members(height, member id), + /// add messages(height, member id, message, time). + SyncRes( + GroupId, + i64, + i64, + i64, + Vec<(i64, GroupId, PeerId, String, Vec)>, + Vec<(i64, GroupId)>, + Vec<(i64, GroupId, NetworkMessage, i64)>, + ), +} + +impl LayerEvent { + /// get event's group id. + pub fn gcd(&self) -> &GroupId { + match self { + Self::Offline(gcd) => gcd, + Self::Suspend(gcd) => gcd, + Self::Actived(gcd) => gcd, + Self::MemberOnline(gcd, ..) => gcd, + Self::MemberOffline(gcd, ..) => gcd, + Self::MemberOnlineSync(gcd) => gcd, + Self::MemberOnlineSyncResult(gcd, ..) => gcd, + Self::GroupName(gcd, ..) => gcd, + Self::GroupClose(gcd) => gcd, + Self::Sync(gcd, ..) => gcd, + Self::SyncReq(gcd, ..) => gcd, + Self::SyncRes(gcd, ..) => gcd, + } + } +} + +/// Group chat event. +#[derive(Serialize, Deserialize, Clone)] +pub enum Event { + /// params: member id, member address, member name, member avatar. + MemberJoin(GroupId, PeerId, String, Vec), + /// params: member id, + MemberLeave(GroupId), + /// params: member id, message, message time. + MessageCreate(GroupId, NetworkMessage, i64), +}