WIP: rfc 6121 data(base)types
This commit is contained in:
parent
8e6aa698b3
commit
05b0d38490
|
@ -73,6 +73,7 @@ file/media sharing (further research needed):
|
|||
- [ ] xep-0234: jingle file transfer
|
||||
|
||||
need more research:
|
||||
- [ ] xep-0154: user profile
|
||||
- [ ] message editing
|
||||
- [ ] xep-0308: last message correction (should not be used for older than last message according to spec)
|
||||
- [ ] chat read markers
|
||||
|
|
|
@ -15,3 +15,4 @@ tokio-stream = "0.1.17"
|
|||
tokio-util = "0.7.13"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.19"
|
||||
uuid = "1.13.1"
|
||||
|
|
|
@ -1,5 +1,53 @@
|
|||
CREATE TABLE roster(
|
||||
id INTEGER PRIMARY KEY,
|
||||
jid TEXT NOT NULL,
|
||||
nickname TEXT,
|
||||
PRAGMA foreign_keys = on;
|
||||
|
||||
-- a user jid will never change, only a chat user will change
|
||||
-- TODO: avatar, nick, etc.
|
||||
create table user(
|
||||
jid jid primary key,
|
||||
cached_status text,
|
||||
);
|
||||
|
||||
-- enum for subscription state
|
||||
create table subscription(
|
||||
state text primary key,
|
||||
);
|
||||
|
||||
insert into subscription ( state ) values ('none'), ('pending-out'), ('pending-in'), ('only-out'), ('only-in'), ('out-pending-in'), ('in-pending-out'), ('buddy');
|
||||
|
||||
-- a roster contains users, with client-set nickname
|
||||
CREATE TABLE roster(
|
||||
jid jid primary key,
|
||||
name TEXT,
|
||||
subscription text not null,
|
||||
foreign key(subscription) references subscription(state),
|
||||
foreign key(jid) references users(jid)
|
||||
);
|
||||
|
||||
create table groups(
|
||||
group text primary key
|
||||
);
|
||||
|
||||
create table groups_roster(
|
||||
group_id text,
|
||||
contact_id jid,
|
||||
foreign key(group_id) references group(id),
|
||||
foreign key(contact_id) references roster(id),
|
||||
primary key(group_id, contact_id)
|
||||
);
|
||||
|
||||
-- chat includes reference to user jid chat is with
|
||||
create table chats (
|
||||
id uuid primary key,
|
||||
contact_id jid not null unique,
|
||||
);
|
||||
|
||||
-- messages include reference to chat they are in, and who sent them.
|
||||
create table messages (
|
||||
id uuid primary key,
|
||||
body text,
|
||||
chat_id uuid not null,
|
||||
from jid not null,
|
||||
-- TODO: read bool not null,
|
||||
foreign key(chat_id) references chats(id),
|
||||
foreign key(from) references users(jid)
|
||||
);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::roster::Contact;
|
||||
|
||||
pub enum Chat {
|
||||
Direct(DM),
|
||||
Channel(Channel),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Message {
|
||||
id: Uuid,
|
||||
// contains full contact information
|
||||
from: Contact,
|
||||
// TODO: rich text, other contents, threads
|
||||
body: Body,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Body {
|
||||
body: String,
|
||||
}
|
||||
|
||||
pub struct DM {
|
||||
contact: Contact,
|
||||
message_history: Vec<Message>,
|
||||
}
|
||||
|
||||
// TODO: group chats
|
||||
pub struct Channel {}
|
|
@ -1,11 +1,23 @@
|
|||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
AlreadyConnected,
|
||||
Presence(Reason),
|
||||
Roster(Reason),
|
||||
SendMessage(Reason),
|
||||
AlreadyDisconnected,
|
||||
LostConnection,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Reason {
|
||||
// TODO: organisastion of error into internal error thing
|
||||
Timeout,
|
||||
Stream(stanza::stream_error::Error),
|
||||
Stanza(stanza::stanza_error::Error),
|
||||
Jabber(jabber::Error),
|
||||
XML(peanuts::Error),
|
||||
SQL(sqlx::Error),
|
||||
JID(jid::ParseError),
|
||||
AlreadyDisconnected,
|
||||
// JID(jid::ParseError),
|
||||
LostConnection,
|
||||
}
|
||||
|
||||
|
@ -15,11 +27,11 @@ impl From<peanuts::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<jid::ParseError> for Error {
|
||||
fn from(e: jid::ParseError) -> Self {
|
||||
Self::JID(e)
|
||||
}
|
||||
}
|
||||
// impl From<jid::ParseError> for Error {
|
||||
// fn from(e: jid::ParseError) -> Self {
|
||||
// Self::JID(e)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<sqlx::Error> for Error {
|
||||
fn from(e: sqlx::Error) -> Self {
|
||||
|
|
|
@ -4,27 +4,31 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use chat::{Body, Message};
|
||||
use connection::{write::WriteMessage, SupervisorSender};
|
||||
use jabber::JID;
|
||||
use presence::{Offline, Online, Presence};
|
||||
use roster::Contact;
|
||||
use sqlx::SqlitePool;
|
||||
use stanza::{
|
||||
client::{
|
||||
iq::{self, Iq, IqType},
|
||||
Stanza,
|
||||
},
|
||||
roster::{self, Query},
|
||||
use stanza::client::{
|
||||
iq::{self, Iq, IqType},
|
||||
Stanza,
|
||||
};
|
||||
use tokio::{
|
||||
sync::{mpsc, oneshot, Mutex},
|
||||
task::JoinSet,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::connection::write::WriteHandle;
|
||||
use crate::connection::{SupervisorCommand, SupervisorHandle};
|
||||
use crate::error::Error;
|
||||
|
||||
mod chat;
|
||||
mod connection;
|
||||
mod error;
|
||||
mod presence;
|
||||
mod roster;
|
||||
|
||||
pub struct Luz {
|
||||
receiver: mpsc::Receiver<CommandMessage>,
|
||||
|
@ -190,7 +194,7 @@ impl CommandMessage {
|
|||
to: None,
|
||||
r#type: IqType::Get,
|
||||
lang: None,
|
||||
query: Some(iq::Query::Roster(roster::Query {
|
||||
query: Some(iq::Query::Roster(stanza::roster::Query {
|
||||
ver: None,
|
||||
items: Vec::new(),
|
||||
})),
|
||||
|
@ -265,16 +269,62 @@ impl LuzHandle {
|
|||
}
|
||||
|
||||
pub enum CommandMessage {
|
||||
/// connect to XMPP chat server. gets roster and
|
||||
Connect,
|
||||
/// disconnect from XMPP chat server.
|
||||
Disconnect,
|
||||
/// gets the roster. if offline, retreives cached version from database. should be stored in application memory.
|
||||
/// get the roster. if offline, retreive cached version from database. should be stored in application memory
|
||||
GetRoster,
|
||||
SendMessage(JID, String),
|
||||
// add a contact to your roster, with a status of none, no subscriptions
|
||||
AddContact(JID),
|
||||
/// send a friend request i.e. a subscription request with a subscription pre-approval. if not already added to roster server adds to roster.
|
||||
BuddyRequest(JID),
|
||||
/// send a subscription request, without pre-approval. if not already added to roster server adds to roster.
|
||||
SubscriptionRequest(JID),
|
||||
/// accept a friend request by accepting a pending subscription and sending a subscription request back. if not already added to roster adds to roster.
|
||||
AcceptBuddyRequest(JID),
|
||||
/// accept a pending subscription and doesn't send a subscription request back. if not already added to roster adds to roster.
|
||||
AcceptSubscriptionRequest(JID),
|
||||
/// unsubscribe to a contact, but don't remove their subscription.
|
||||
UnsubscribeFromContact(JID),
|
||||
/// stop a contact from being subscribed, but stay subscribed to the contact.
|
||||
UnsubscribeContact(JID),
|
||||
/// remove subscriptions to and from contact, but keep in roster.
|
||||
UnfriendContact(JID),
|
||||
/// remove a contact from the contact list. will remove subscriptions if not already done then delete contact from roster.
|
||||
DeleteContact(JID),
|
||||
/// set online status
|
||||
SendStatus(Online),
|
||||
SendOffline(Offline),
|
||||
/// send a directed presence (usually to a non-contact).
|
||||
// TODO: should probably make it so people can add non-contact auto presence sharing in the client.
|
||||
SendDirectedPresence {
|
||||
to: JID,
|
||||
presence: Presence,
|
||||
},
|
||||
SendMessage {
|
||||
id: Uuid,
|
||||
to: JID,
|
||||
body: Body,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UpdateMessage {
|
||||
Error(Error),
|
||||
Connected,
|
||||
Roster(Vec<roster::Item>),
|
||||
Connected(Online),
|
||||
Disconnected(Offline),
|
||||
/// full roster (replace full app roster state with this)
|
||||
Roster(Vec<Contact>),
|
||||
/// roster update (only update app roster state)
|
||||
RosterPush(Contact),
|
||||
Presence {
|
||||
from: JID,
|
||||
presence: Presence,
|
||||
},
|
||||
MessageDispatched(Uuid),
|
||||
Message {
|
||||
from: JID,
|
||||
message: Message,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
use stanza::client::presence::Show;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Online {
|
||||
show: Option<Show>,
|
||||
status: Option<String>,
|
||||
priority: Option<i8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Offline {
|
||||
status: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Presence {
|
||||
Online(Online),
|
||||
Offline(Offline),
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use jid::JID;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Contact {
|
||||
// jid is the id used to reference everything, but not the primary key
|
||||
jid: JID,
|
||||
subscription: Subscription,
|
||||
/// client user defined name
|
||||
name: Option<String>,
|
||||
// TODO: avatar, nickname
|
||||
/// nickname picked by contact
|
||||
// nickname: Option<String>,
|
||||
groups: HashSet<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Subscription {
|
||||
None,
|
||||
PendingOut,
|
||||
PendingIn,
|
||||
OnlyOut,
|
||||
OnlyIn,
|
||||
OutPendingIn,
|
||||
InPendingOut,
|
||||
Buddy,
|
||||
}
|
Loading…
Reference in New Issue