mirror of
https://gitea.mizah.xyz/mizah/dergchat
synced 2025-01-30 22:30:09 -05:00
Initial commit.
This commit is contained in:
commit
0d80360b58
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
4195
Cargo.lock
generated
Normal file
4195
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "chatclient"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = "1.34.0"
|
||||||
|
log = "0.4.20"
|
||||||
|
env_logger = "0.10.1"
|
||||||
|
dioxus = "0.4.0"
|
||||||
|
dioxus-desktop = "0.4.0"
|
||||||
|
futures-util = "0.3.29"
|
||||||
|
xmpp = { git = "https://gitlab.com/xmpp-rs/xmpp-rs.git", rev="05a0b6cd8f870ff2fe9b773d7eefb8205b45f4b9"}
|
27
flake.lock
Normal file
27
flake.lock
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701718080,
|
||||||
|
"narHash": "sha256-6ovz0pG76dE0P170pmmZex1wWcQoeiomUZGggfH9XPs=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "2c7f3c0fb7c08a0814627611d9d7d45ab6d75335",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
52
flake.nix
Normal file
52
flake.nix
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
description = "A devshell environment for an XMPP client thingy.";
|
||||||
|
|
||||||
|
nixConfig.bash-prompt = "[rust/chatthingy] ";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
rust-toolchain = pkgs.symlinkJoin {
|
||||||
|
name = "rust-toolchain";
|
||||||
|
paths = [pkgs.rustc pkgs.cargo pkgs.rustPlatform.rustcSrc];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.${system}.default =
|
||||||
|
pkgs.mkShell rec {
|
||||||
|
|
||||||
|
packages = with pkgs; [
|
||||||
|
rust-toolchain
|
||||||
|
rustfmt
|
||||||
|
pkg-config
|
||||||
|
alsaLib
|
||||||
|
udev
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXcursor
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXrandr
|
||||||
|
vulkan-loader
|
||||||
|
libxkbcommon
|
||||||
|
wayland
|
||||||
|
fontconfig
|
||||||
|
openssl
|
||||||
|
glibc
|
||||||
|
gtk3
|
||||||
|
webkitgtk_4_1
|
||||||
|
dioxus-cli
|
||||||
|
];
|
||||||
|
|
||||||
|
WEBKIT_DISABLE_COMPOSITING_MODE=1;
|
||||||
|
|
||||||
|
# LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath packages;
|
||||||
|
|
||||||
|
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
202
src/main.rs
Normal file
202
src/main.rs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use futures_util::stream::StreamExt;
|
||||||
|
use dioxus::html::textarea;
|
||||||
|
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_elements::{h1, li, ul};
|
||||||
|
use log::info;
|
||||||
|
use tokio::select;
|
||||||
|
use xmpp::{BareJid, ClientBuilder, ClientType, RoomNick};
|
||||||
|
use xmpp::parsers::message::MessageType;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
// launch the dioxus app in a webview
|
||||||
|
dioxus_desktop::launch(App);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props)]
|
||||||
|
struct RoomListProps<'a> {
|
||||||
|
rooms: Vec<BareJid>,
|
||||||
|
on_room_picked: EventHandler<'a, BareJid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Dioxus component that renders a list of rooms
|
||||||
|
fn RoomList<'a>(cx: Scope<'a, RoomListProps>) -> Element<'a> {
|
||||||
|
render! {
|
||||||
|
h1 { "Rooms" }
|
||||||
|
ul {
|
||||||
|
for room in cx.props.rooms.iter() {
|
||||||
|
rsx! { li {
|
||||||
|
// onclick: move |_| cx.props.room_selected.call(room.to_owned()),
|
||||||
|
onclick: |evt| cx.props.on_room_picked.call(room.to_owned()),
|
||||||
|
"{room}"
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props)]
|
||||||
|
struct RoomViewProps<'a> {
|
||||||
|
room: BareJid,
|
||||||
|
messages: Vec<String>,
|
||||||
|
on_message_sent: EventHandler<'a, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl PartialEq for RoomViewProps {
|
||||||
|
// fn eq(&self, other: &Self) -> bool {
|
||||||
|
// self.room == other.room && self.messages == other.messages
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn RoomView<'a>(cx: Scope<'a, RoomViewProps>) -> Element<'a> {
|
||||||
|
|
||||||
|
let message = use_state(cx, || "".to_owned());
|
||||||
|
|
||||||
|
render! {
|
||||||
|
div {
|
||||||
|
h1 { "Messages" }
|
||||||
|
ul {
|
||||||
|
for message in cx.props.messages.iter() {
|
||||||
|
rsx! { li {
|
||||||
|
"{message}"
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
oninput: |evt| {
|
||||||
|
message.set(evt.value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
onclick: move |_| {
|
||||||
|
cx.props.on_message_sent.call(message.current().to_string());
|
||||||
|
},
|
||||||
|
"Send"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// define a component that renders a div with the text "Hello, world!"
|
||||||
|
fn App(cx: Scope) -> Element {
|
||||||
|
|
||||||
|
let rooms = use_state(cx, || vec![]);
|
||||||
|
let messages = use_state(cx, || HashMap::new());
|
||||||
|
let current_room = use_state(cx, || None::<BareJid>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct SendMessage {
|
||||||
|
recipient: BareJid,
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let cr = use_coroutine(cx, |mut commands: UnboundedReceiver<SendMessage>| {
|
||||||
|
let mut rooms = rooms.to_owned();
|
||||||
|
let mut messages = messages.to_owned();
|
||||||
|
let current_room = current_room.to_owned();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
|
||||||
|
let jid = BareJid::from_str("bot@mizah.xyz").unwrap();
|
||||||
|
|
||||||
|
let password = "G0cEiYp98G8nBzOdkKMF";
|
||||||
|
|
||||||
|
let mut agent = ClientBuilder::new(jid, &password)
|
||||||
|
.set_client(ClientType::Pc, "dergchat")
|
||||||
|
.set_default_nick("dergchat")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// tokio::spawn({
|
||||||
|
// async move {
|
||||||
|
// while let Some(command) = commands.next().await {
|
||||||
|
// println!("Sending command: {:?}", command);
|
||||||
|
// agent.borrow_mut().send_message(command.recipient.into(), MessageType::Chat, "en/us", &command.message).await;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
loop {
|
||||||
|
|
||||||
|
select! {
|
||||||
|
events = agent.wait_for_events() => {
|
||||||
|
if let Some(events) = events {
|
||||||
|
for event in events {
|
||||||
|
match event {
|
||||||
|
xmpp::Event::JoinRoom(jid, conference) => {
|
||||||
|
println!("Joining room: {}", &jid);
|
||||||
|
rooms.make_mut().push(jid.clone());
|
||||||
|
agent.join_room(jid, None, None, "en/us", "online").await;
|
||||||
|
},
|
||||||
|
xmpp::Event::ChatMessage(id, sender, body) => {
|
||||||
|
println!("Message from {}: {}", &sender, &body.0);
|
||||||
|
messages.make_mut().entry(sender).or_insert(vec![]).push(body.0);
|
||||||
|
},
|
||||||
|
xmpp::Event::RoomMessage(id, room_jid, sender_nick, body) => {
|
||||||
|
println!("Message in {} from {}: {}", &room_jid, &sender_nick, &body.0);
|
||||||
|
messages.make_mut().entry(room_jid).or_insert(vec![]).push(body.0);
|
||||||
|
}
|
||||||
|
xmpp::Event::RoomPrivateMessage(id, room_jid, sender_nick, body) => {
|
||||||
|
println!("Private message in {} from {}: {}", &room_jid, &sender_nick, &body.0);
|
||||||
|
messages.make_mut().entry(room_jid).or_insert(vec![]).push(body.0);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
log::debug!("Received unsupported event {:?}", event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("Disconnected");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
command = commands.next() => {
|
||||||
|
if let Some(command) = command {
|
||||||
|
println!("Sending command: {:?}", command);
|
||||||
|
agent.send_message(command.recipient.into(), MessageType::Groupchat, "en-us", &command.message).await;
|
||||||
|
} else {
|
||||||
|
info!("Command channel closed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
render! {
|
||||||
|
RoomList {
|
||||||
|
rooms: rooms.to_vec(),
|
||||||
|
on_room_picked: move |x:BareJid| {
|
||||||
|
println!("Room selected: {:?}", x);
|
||||||
|
current_room.set(Some(x));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if let Some(room) = current_room.get() {
|
||||||
|
|
||||||
|
let messages = messages.get().get(&room).expect("Selected non-existant room").to_vec();
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
RoomView {
|
||||||
|
room: room.clone(),
|
||||||
|
messages: messages,
|
||||||
|
on_message_sent: move |x:String| {
|
||||||
|
println!("Message sent: {:?}", x);
|
||||||
|
cr.send(SendMessage {
|
||||||
|
recipient: room.clone(),
|
||||||
|
message: x,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user