mirror of
https://gitea.mizah.xyz/mizah/dergchat
synced 2024-11-21 18:45:01 -05:00
Reset Cargo.lock.
Added ability to leave rooms, join rooms. General restyling.
This commit is contained in:
parent
4da80010ff
commit
fd56718960
961
Cargo.lock
generated
961
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,10 @@ edition = "2021"
|
|||||||
tokio = "1.34.0"
|
tokio = "1.34.0"
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
env_logger = "0.10.1"
|
env_logger = "0.10.1"
|
||||||
dioxus = "0.4.0"
|
dioxus = "0.4.3"
|
||||||
dioxus-desktop = "0.4.0"
|
dioxus-desktop = "0.4.3"
|
||||||
|
dioxus-hot-reload = { version="0.4.3", features=["file_watcher"] }
|
||||||
futures-util = "0.3.29"
|
futures-util = "0.3.29"
|
||||||
xmpp = { git = "https://gitlab.com/xmpp-rs/xmpp-rs.git", rev="05a0b6cd8f870ff2fe9b773d7eefb8205b45f4b9"}
|
xmpp = { git = "https://gitlab.com/werner.kroneman/xmpp-rs.git", rev="ecd0be4aad985e9812626d6c4499c2586c158aba"}
|
||||||
|
keyring = "2.1.0"
|
||||||
|
jid = "0.10.0"
|
189
src/main.rs
189
src/main.rs
@ -5,15 +5,18 @@ use std::future::Future;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use futures_util::stream::StreamExt;
|
use futures_util::stream::StreamExt;
|
||||||
use dioxus::html::textarea;
|
use dioxus::html::{hr, input, textarea};
|
||||||
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
|
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_desktop::Config;
|
use dioxus_desktop::Config;
|
||||||
use dioxus_elements::{h1, li, ul};
|
use dioxus_elements::{h1, li, ul};
|
||||||
|
use keyring::Entry;
|
||||||
use log::info;
|
use log::info;
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
use xmpp::{BareJid, ClientBuilder, ClientType, RoomNick};
|
use xmpp::{BareJid, ClientBuilder, ClientType, FullJid, RoomNick};
|
||||||
use xmpp::parsers::message::MessageType;
|
use xmpp::parsers::message::MessageType;
|
||||||
|
use env_logger::init;
|
||||||
|
use jid::ResourcePart;
|
||||||
|
|
||||||
const STYLESHEET: &str = r#"
|
const STYLESHEET: &str = r#"
|
||||||
body {
|
body {
|
||||||
@ -37,28 +40,57 @@ const STYLESHEET: &str = r#"
|
|||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
|
let entry = keyring::Entry::new("dergchat", "dergchat").expect("Failed to create keyring entry");
|
||||||
|
|
||||||
|
entry.set_password("topS3cr3tP4$$w0rd").expect("Failed to set password");
|
||||||
|
let password = entry.get_password().expect("Failed to get password");
|
||||||
|
println!("My password is '{}'", password);
|
||||||
|
entry.delete_password().expect("Failed to delete password");
|
||||||
|
|
||||||
|
hot_reload_init!();
|
||||||
|
|
||||||
// launch the dioxus app in a webview
|
// launch the dioxus app in a webview
|
||||||
dioxus_desktop::launch_cfg(App,
|
dioxus_desktop::launch_cfg(App,
|
||||||
Config::default()
|
Config::default()
|
||||||
.with_custom_head(format!(r#"<style>{}</style>"#, STYLESHEET))
|
.with_custom_head(format!(r#"<style>{}</style>"#, STYLESHEET))
|
||||||
.with_background_color((32,64,32,255)));
|
.with_background_color((32, 64, 32, 255)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Props)]
|
#[derive(Props)]
|
||||||
struct RoomListProps<'a> {
|
struct RoomListProps<'a> {
|
||||||
rooms: Vec<BareJid>,
|
rooms: Vec<BareJid>,
|
||||||
on_room_picked: EventHandler<'a, BareJid>,
|
on_room_picked: EventHandler<'a, BareJid>,
|
||||||
|
on_room_left: EventHandler<'a, BareJid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Dioxus component that renders a list of rooms
|
/// A Dioxus component that renders a list of rooms
|
||||||
fn RoomList<'a>(cx: Scope<'a, RoomListProps>) -> Element<'a> {
|
fn RoomList<'a>(cx: Scope<'a, RoomListProps>) -> Element<'a> {
|
||||||
render! {
|
render! {
|
||||||
ul {
|
ul {
|
||||||
|
list_style: "none",
|
||||||
|
flex_grow: 1,
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
for room in cx.props.rooms.iter() {
|
for room in cx.props.rooms.iter() {
|
||||||
rsx! { li {
|
rsx! { li {
|
||||||
// onclick: move |_| cx.props.room_selected.call(room.to_owned()),
|
display: "flex",
|
||||||
|
flex_direction: "row",
|
||||||
|
|
||||||
onclick: |evt| cx.props.on_room_picked.call(room.to_owned()),
|
onclick: |evt| cx.props.on_room_picked.call(room.to_owned()),
|
||||||
|
|
||||||
|
div {
|
||||||
|
flex_grow: 1,
|
||||||
"{room}"
|
"{room}"
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
|
||||||
|
onclick: |evt| {
|
||||||
|
evt.stop_propagation();
|
||||||
|
cx.props.on_room_left.call(room.to_owned());
|
||||||
|
},
|
||||||
|
"X"
|
||||||
|
}
|
||||||
} }
|
} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,21 +110,54 @@ struct RoomViewProps<'a> {
|
|||||||
on_message_sent: EventHandler<'a, String>,
|
on_message_sent: EventHandler<'a, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Props)]
|
||||||
|
struct SendMessageProps<'a> {
|
||||||
|
on_message_sent: EventHandler<'a, String>,
|
||||||
|
}
|
||||||
|
|
||||||
fn RoomView<'a>(cx: Scope<'a, RoomViewProps>) -> Element<'a> {
|
fn RoomView<'a>(cx: Scope<'a, RoomViewProps>) -> Element<'a> {
|
||||||
|
|
||||||
let message = use_state(cx, || "".to_owned());
|
let message = use_state(cx, || "".to_owned());
|
||||||
|
|
||||||
render! {
|
render! {
|
||||||
|
div {
|
||||||
|
padding: "5mm",
|
||||||
|
flex_grow: 1,
|
||||||
|
display: "flex",
|
||||||
|
background_color: "#166322",
|
||||||
|
flex_direction: "column",
|
||||||
|
h2 {
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
border_bottom: "1px solid lightgray",
|
||||||
|
"{cx.props.room}"
|
||||||
|
}
|
||||||
ul {
|
ul {
|
||||||
|
flex_grow: 1,
|
||||||
|
overflow_y: "scroll",
|
||||||
for message in cx.props.messages.iter() {
|
for message in cx.props.messages.iter() {
|
||||||
rsx! { li {
|
rsx! { li {
|
||||||
"{message.sender}: {message.body}"
|
"{message.sender}: {message.body}"
|
||||||
} }
|
} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SendMessage {
|
||||||
|
on_message_sent: |x:String| cx.props.on_message_sent.call(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SendMessage<'a>(cx: Scope<'a, SendMessageProps>) -> Element<'a> {
|
||||||
|
|
||||||
|
let message = use_state(cx, || "".to_owned());
|
||||||
|
|
||||||
|
render! {
|
||||||
div {
|
div {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flex_direction: "row",
|
flex_direction: "row",
|
||||||
textarea {
|
textarea {
|
||||||
|
resize: "none",
|
||||||
flex_grow: 1,
|
flex_grow: 1,
|
||||||
oninput: |evt| {
|
oninput: |evt| {
|
||||||
message.set(evt.value.clone());
|
message.set(evt.value.clone());
|
||||||
@ -109,23 +174,33 @@ fn RoomView<'a>(cx: Scope<'a, RoomViewProps>) -> Element<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn handle_event(event: xmpp::Event,
|
async fn handle_event(event: xmpp::Event,
|
||||||
agent: &mut xmpp::Agent,
|
agent: &mut xmpp::Agent,
|
||||||
rooms: &mut UseState<Vec<BareJid>>,
|
rooms: &mut UseState<Vec<BareJid>>,
|
||||||
messages: &mut UseState<HashMap<BareJid, Vec<Message>>>) {
|
messages: &mut UseState<HashMap<BareJid, Vec<Message>>>) {
|
||||||
match event {
|
match event {
|
||||||
xmpp::Event::JoinRoom(jid, conference) => {
|
xmpp::Event::JoinRoom(jid, conference) => {
|
||||||
println!("Joining room: {}", &jid);
|
println!("Will auto-join room: {}", &jid);
|
||||||
rooms.make_mut().push(jid.clone());
|
|
||||||
agent.join_room(jid, None, None, "en/us", "online").await;
|
agent.join_room(jid, None, None, "en/us", "online").await;
|
||||||
},
|
}
|
||||||
|
xmpp::Event::RoomJoined(room_jid) => {
|
||||||
|
println!("Joined room: {}", &room_jid);
|
||||||
|
messages.make_mut().entry(room_jid.clone()).or_insert(vec![]);
|
||||||
|
rooms.make_mut().push(room_jid);
|
||||||
|
}
|
||||||
|
xmpp::Event::RoomLeft(room_jid) => {
|
||||||
|
println!("Left room: {}", &room_jid);
|
||||||
|
messages.make_mut().remove(&room_jid);
|
||||||
|
rooms.make_mut().retain(|x| x != &room_jid);
|
||||||
|
}
|
||||||
xmpp::Event::ChatMessage(id, sender, body) => {
|
xmpp::Event::ChatMessage(id, sender, body) => {
|
||||||
println!("Message from {}: {}", &sender, &body.0);
|
println!("Message from {}: {}", &sender, &body.0);
|
||||||
messages.make_mut().entry(sender.clone()).or_insert(vec![]).push(Message {
|
messages.make_mut().entry(sender.clone()).or_insert(vec![]).push(Message {
|
||||||
sender: sender.to_string(),
|
sender: sender.to_string(),
|
||||||
body: body.0,
|
body: body.0,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
xmpp::Event::RoomMessage(id, room_jid, sender_nick, body) => {
|
xmpp::Event::RoomMessage(id, room_jid, sender_nick, body) => {
|
||||||
println!("Message in {} from {}: {}", &room_jid, &sender_nick, &body.0);
|
println!("Message in {} from {}: {}", &room_jid, &sender_nick, &body.0);
|
||||||
messages.make_mut().entry(room_jid).or_insert(vec![]).push(Message {
|
messages.make_mut().entry(room_jid).or_insert(vec![]).push(Message {
|
||||||
@ -139,18 +214,46 @@ async fn handle_event(event: xmpp::Event,
|
|||||||
sender: sender_nick,
|
sender: sender_nick,
|
||||||
body: body.0,
|
body: body.0,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::debug!("Received unsupported event {:?}", event);
|
log::debug!("Received unsupported event {:?}", event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SendMessage {
|
enum NetworkCommand {
|
||||||
recipient: BareJid,
|
JoinRoom { room: BareJid },
|
||||||
message: String,
|
LeaveRoom { room: BareJid },
|
||||||
|
SendMessage { recipient: BareJid, message: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props)]
|
||||||
|
struct RoomJoinProps<'a> {
|
||||||
|
on_join_room: EventHandler<'a, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn RoomJoinWidget<'a>(cx: Scope<'a, RoomJoinProps>) -> Element<'a> {
|
||||||
|
|
||||||
|
let room = use_state(cx, || "".to_owned());
|
||||||
|
|
||||||
|
render! {
|
||||||
|
div {
|
||||||
|
display: "flex",
|
||||||
|
flex_direction: "row",
|
||||||
|
input {
|
||||||
|
flex_grow: 1,
|
||||||
|
display: "block",
|
||||||
|
oninput: |evt| {
|
||||||
|
room.set(evt.value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
onclick: move |_| cx.props.on_join_room.call(room.current().to_string()),
|
||||||
|
"Join"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// define a component that renders a div with the text "Hello, world!"
|
// define a component that renders a div with the text "Hello, world!"
|
||||||
@ -161,7 +264,7 @@ fn App(cx: Scope) -> Element {
|
|||||||
let current_room = use_state(cx, || None::<BareJid>);
|
let current_room = use_state(cx, || None::<BareJid>);
|
||||||
|
|
||||||
let cr = use_coroutine(cx,
|
let cr = use_coroutine(cx,
|
||||||
|rx: UnboundedReceiver<SendMessage>| run_xmpp(rooms.clone(), messages.clone(), rx)
|
|rx: UnboundedReceiver<NetworkCommand>| run_xmpp(rooms.clone(), messages.clone(), rx),
|
||||||
);
|
);
|
||||||
|
|
||||||
render! {
|
render! {
|
||||||
@ -173,18 +276,33 @@ fn App(cx: Scope) -> Element {
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
|
|
||||||
div {
|
div {
|
||||||
|
padding: "5mm",
|
||||||
background_color: "#1d852d",
|
background_color: "#1d852d",
|
||||||
|
display: "flex",
|
||||||
|
flex_direction: "column",
|
||||||
|
div {
|
||||||
|
border_bottom: "1px solid lightgray",
|
||||||
|
"Mizah"
|
||||||
|
}
|
||||||
RoomList {
|
RoomList {
|
||||||
rooms: rooms.to_vec(),
|
rooms: rooms.to_vec(),
|
||||||
on_room_picked: move |x:BareJid| {
|
on_room_picked: move |x:BareJid| {
|
||||||
println!("Room selected: {:?}", x);
|
println!("Room selected: {:?}", x);
|
||||||
current_room.set(Some(x));
|
current_room.set(Some(x));
|
||||||
},
|
},
|
||||||
|
on_room_left: move |x:BareJid| {
|
||||||
|
println!("Leaving room: {:?}", x);
|
||||||
|
cr.send(NetworkCommand::LeaveRoom { room: x });
|
||||||
|
},
|
||||||
|
}
|
||||||
|
RoomJoinWidget {
|
||||||
|
on_join_room: move |x:String| {
|
||||||
|
println!("Joining room: {:?}", x);
|
||||||
|
cr.send(NetworkCommand::JoinRoom { room: BareJid::from_str(&x).unwrap() });
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div {
|
|
||||||
flex_grow: 1,
|
|
||||||
background_color: "#166322",
|
|
||||||
if let Some(room) = current_room.get() {
|
if let Some(room) = current_room.get() {
|
||||||
let messages = messages.get().get(&room).expect("Selected non-existant room").to_vec();
|
let messages = messages.get().get(&room).expect("Selected non-existant room").to_vec();
|
||||||
|
|
||||||
@ -194,20 +312,23 @@ fn App(cx: Scope) -> Element {
|
|||||||
messages: messages,
|
messages: messages,
|
||||||
on_message_sent: move |x:String| {
|
on_message_sent: move |x:String| {
|
||||||
println!("Message sent: {:?}", x);
|
println!("Message sent: {:?}", x);
|
||||||
cr.send(SendMessage {
|
cr.send(NetworkCommand::SendMessage { recipient: room.clone(), message: x });
|
||||||
recipient: room.clone(),
|
|
||||||
message: x,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
"No room selected"
|
padding: "5mm",
|
||||||
}
|
flex_grow: 1,
|
||||||
|
display: "flex",
|
||||||
|
background_color: "#166322",
|
||||||
|
"No room selected. Pick one from the list on the left."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,12 +336,13 @@ fn App(cx: Scope) -> Element {
|
|||||||
|
|
||||||
fn run_xmpp(mut rooms: UseState<Vec<BareJid>>,
|
fn run_xmpp(mut rooms: UseState<Vec<BareJid>>,
|
||||||
mut messages: UseState<HashMap<BareJid, Vec<Message>>>,
|
mut messages: UseState<HashMap<BareJid, Vec<Message>>>,
|
||||||
mut commands: UnboundedReceiver<SendMessage>) -> impl Future<Output=()> + Sized {
|
mut commands: UnboundedReceiver<NetworkCommand>) -> impl Future<Output=()> + Sized {
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
|
||||||
let jid = BareJid::from_str("bot@mizah.xyz").unwrap();
|
let jid = BareJid::from_str("bot@mizah.xyz").unwrap();
|
||||||
|
|
||||||
let password = "G0cEiYp98G8nBzOdkKMF";
|
let password = "TLOwnPNPDGN9nfRRqPwh";
|
||||||
|
|
||||||
let mut agent = ClientBuilder::new(jid, &password)
|
let mut agent = ClientBuilder::new(jid, &password)
|
||||||
.set_client(ClientType::Pc, "dergchat")
|
.set_client(ClientType::Pc, "dergchat")
|
||||||
@ -240,8 +362,21 @@ fn run_xmpp(mut rooms: UseState<Vec<BareJid>>,
|
|||||||
},
|
},
|
||||||
command = commands.next() => {
|
command = commands.next() => {
|
||||||
if let Some(command) = command {
|
if let Some(command) = command {
|
||||||
println!("Sending command: {:?}", command);
|
match command {
|
||||||
agent.send_message(command.recipient.into(), MessageType::Groupchat, "en-us", &command.message).await;
|
NetworkCommand::JoinRoom { room } => {
|
||||||
|
agent.join_room(room.clone(), None, None, "en-us", "online").await;
|
||||||
|
},
|
||||||
|
NetworkCommand::LeaveRoom { room } => {
|
||||||
|
agent.leave_room(
|
||||||
|
room,
|
||||||
|
"dergchat".to_string(),
|
||||||
|
"en-us",
|
||||||
|
"User left the room.").await;
|
||||||
|
},
|
||||||
|
NetworkCommand::SendMessage { recipient, message } => {
|
||||||
|
agent.send_message(recipient.into(), MessageType::Groupchat, "en-us", &message).await;
|
||||||
|
},
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("Command channel closed");
|
info!("Command channel closed");
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user