Update to UI and server

This commit is contained in:
Michael Zhang 2023-05-09 03:14:54 -05:00
parent 5884bff2c0
commit 87ccab7a4b
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
13 changed files with 440 additions and 22 deletions

218
client/package-lock.json generated
View file

@ -15,6 +15,8 @@
"devDependencies": {
"@tauri-apps/cli": "^1.3.0",
"@types/react-dom": "^18.2.4",
"sass": "^1.62.1",
"scss": "^0.2.4",
"vite": "^4.3.4"
}
},
@ -701,6 +703,40 @@
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/case-anything": {
"version": "2.1.10",
"resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz",
@ -712,6 +748,33 @@
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
],
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
@ -778,6 +841,18 @@
"@esbuild/win32-x64": "0.17.18"
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
@ -792,6 +867,18 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@ -814,6 +901,54 @@
"url": "https://opencollective.com/immer"
}
},
"node_modules/immutable": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
"integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
"dev": true
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -853,6 +988,15 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-hash": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz",
@ -861,12 +1005,33 @@
"node": ">= 0.10.0"
}
},
"node_modules/ometa": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/ometa/-/ometa-0.2.2.tgz",
"integrity": "sha512-LZuoK/yjU3FvrxPjUXUlZ1bavCfBPqauA7fsNdwi+AVhRdyk2IzgP3JRnevvjzQ6fKHdUw8YISshf53FmpHrng==",
"dev": true,
"engines": {
"node": ">= 0.2.0"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/postcss": {
"version": "8.4.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
@ -986,6 +1151,18 @@
}
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/redux": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
@ -1028,6 +1205,23 @@
"fsevents": "~2.3.2"
}
},
"node_modules/sass": {
"version": "1.62.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
"integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@ -1036,6 +1230,18 @@
"loose-envify": "^1.1.0"
}
},
"node_modules/scss": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/scss/-/scss-0.2.4.tgz",
"integrity": "sha512-4u8V87F+Q/upVhUmhPnB4C1R11xojkRkWjExL2v0CX2EXTg18VrKd+9JWoeyCp2VEMdSpJsyAvVU+rVjogh51A==",
"dev": true,
"dependencies": {
"ometa": "0.2.2"
},
"engines": {
"node": ">= 0.2.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@ -1045,6 +1251,18 @@
"node": ">=0.10.0"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/ts-poet": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.4.1.tgz",

View file

@ -5,6 +5,8 @@
"devDependencies": {
"@tauri-apps/cli": "^1.3.0",
"@types/react-dom": "^18.2.4",
"sass": "^1.62.1",
"scss": "^0.2.4",
"vite": "^4.3.4"
},
"dependencies": {

View file

@ -12,13 +12,15 @@ type MyGreeterClient = GreeterClient<Channel>;
#[tauri::command]
async fn send_message(
state: tauri::State<'_, Mutex<MyGreeterClient>>,
message: String,
) -> Result<(), ()> {
println!("SHIET {state:?}");
let mut client = state.lock().await;
client
.say_hello(HelloRequest {
name: "Hellosu".into(),
message,
..Default::default()
})
.await;

View file

@ -0,0 +1,9 @@
body, html {
margin: 0;
}
.app {
display: flex;
width: 100%;
height: 100%;
}

View file

@ -3,28 +3,34 @@ import { Provider } from "react-redux";
import { store } from "./store";
import { useState } from "react";
import styles from "./App.module.scss";
import LeftSidebar from "./components/LeftSidebar";
export default function App() {
const [currentMessage, setCurrentMessage] = useState("");
const onSubmit = (e) => {
e.preventDefault();
invoke("send_message", { content: currentMessage });
invoke("send_message", { message: currentMessage });
setCurrentMessage("");
};
return (
<Provider store={store}>
<h1>mraow chat</h1>
<div className={styles.app}>
<LeftSidebar />
<h1>mraow chat</h1>
<form onSubmit={onSubmit}>
<input
type="text"
placeholder="Send message..."
value={currentMessage}
onChange={(e) => setCurrentMessage(e.currentTarget.value)}
autoFocus
/>
</form>
<form onSubmit={onSubmit}>
<input
type="text"
placeholder="Send message..."
value={currentMessage}
onChange={(e) => setCurrentMessage(e.currentTarget.value)}
autoFocus
/>
</form>
</div>
</Provider>
);
}

View file

@ -0,0 +1 @@
export default function CenterPanel() {}

View file

@ -0,0 +1,3 @@
.leftSidebar {
background-color: var(--left-sidebar-background-color);
}

View file

@ -0,0 +1,5 @@
import styles from "./LeftSidebar.module.scss";
export default function LeftSidebar() {
return <div className={styles.leftSidebar}>Rooms</div>;
}

View file

@ -1,5 +1,6 @@
import { createRoot } from "react-dom/client";
import App from "./App";
import "./variables.scss";
// Render your React component instead
const el = document.getElementById("app");

View file

@ -0,0 +1,7 @@
:root {
--main-background-color: #eee;
--left-sidebar-background-color: #ddd;
@mixin dark-mode() {
}
}

View file

@ -12,7 +12,9 @@ message ChatMessage {
message Channel {}
message UserList {}
message UserList { repeated User user = 1; }
message RoomList {}
message User { string username = 1; }
@ -22,6 +24,8 @@ service Chat {
rpc join(User) returns (JoinResponse) {}
rpc sendMsg(ChatMessage) returns (google.protobuf.Empty) {}
rpc receiveMsg(google.protobuf.Empty) returns (stream ChatMessage) {}
rpc listRooms(google.protobuf.Empty) returns (RoomList) {}
rpc getAllUsers(google.protobuf.Empty) returns (UserList) {}
}
@ -34,7 +38,10 @@ service Greeter {
}
// The request message containing the user's name.
message HelloRequest { string name = 1; }
message HelloRequest {
string name = 1;
string message = 2;
}
// The response message containing the greetings
message HelloReply { string message = 1; }

View file

@ -1,5 +1,9 @@
mod mux;
use futures::Stream;
use hyper::Body;
use std::{
pin::Pin,
task::{Context, Poll},
time::Duration,
};
@ -7,36 +11,91 @@ use tonic::{body::BoxBody, transport::Server, Request, Response, Status};
use tower::{Layer, Service};
use mraow_common::chat_proto::{
greeter_server::{Greeter, GreeterServer},
HelloReply, HelloRequest,
chat_server::{Chat, ChatServer},
ChatMessage, HelloReply, HelloRequest, JoinResponse, RoomList, User,
UserList,
};
type ResponseStream =
Pin<Box<dyn Stream<Item = Result<ChatMessage, Status>> + Send>>;
#[derive(Default)]
pub struct MyGreeter {}
pub struct ChatImpl {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
impl Chat for ChatImpl {
type receiveMsgStream = ResponseStream;
async fn join(
&self,
request: Request<User>,
) -> Result<Response<JoinResponse>, Status> {
println!("Join {request:?}");
todo!()
}
async fn send_msg(
&self,
request: Request<ChatMessage>,
) -> Result<Response<()>, Status> {
println!("Send message {request:?}");
todo!()
}
async fn receive_msg(
&self,
request: Request<()>,
) -> Result<Response<Self::receiveMsgStream>, Status> {
println!("Receive message {request:?}");
todo!()
}
async fn list_rooms(
&self,
request: Request<()>,
) -> Result<Response<RoomList>, Status> {
println!("Get all rooms {request:?}");
todo!()
}
async fn get_all_users(
&self,
request: Request<()>,
) -> Result<Response<UserList>, Status> {
println!("Get all users {request:?}");
todo!()
}
/*
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
println!("Got a request from {:?}", request.remote_addr());
let addr = request.remote_addr();
let request = request.into_inner();
println!(
"Got a request from {:?}: {}",
addr,
request.message
);
let reply = HelloReply {
message: format!("Hello {}!", request.into_inner().name),
message: format!("Hello {}!", request.name),
};
Ok(Response::new(reply))
}
*/
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();
let greeter = ChatImpl::default();
println!("GreeterServer listening on {}", addr);
let svc = GreeterServer::new(greeter);
let svc = ChatServer::new(greeter);
// The stack of middleware that our service will be wrapped in
let layer = tower::ServiceBuilder::new()

98
server/src/mux.rs Normal file
View file

@ -0,0 +1,98 @@
use std::{
collections::HashMap,
pin::Pin,
task::{Context, Poll},
};
use anyhow::Result;
use futures::{future, Future, FutureExt, Sink, Stream};
use tokio::{
sync::{
broadcast::{Receiver, Sender},
mpsc::{self, UnboundedReceiver, UnboundedSender},
},
task::JoinHandle,
};
pub struct Mux {}
#[derive(Clone)]
pub enum RoomMessage {}
pub struct Room {
name: String,
tx: Sender<RoomMessage>,
rx: Receiver<RoomMessage>,
}
impl Room {
pub fn get_handle(&self) -> RoomHandle {
RoomHandle {
name: self.name.clone(),
tx: self.tx.clone(),
rx: self.tx.subscribe(),
}
}
}
pub struct RoomHandle {
name: String,
tx: Sender<RoomMessage>,
rx: Receiver<RoomMessage>,
}
pub enum CompositeListenerMessage {
Room { name: String, message: RoomMessage },
JoinRoom(String),
DropRoom(String),
}
pub struct CompositeListener {
current_listening_rooms: HashMap<String, RoomHandle>,
}
impl CompositeListener {}
fn create_listener() -> (
JoinHandle<()>,
UnboundedSender<CompositeListenerMessage>,
UnboundedReceiver<CompositeListenerMessage>,
) {
let (tx, rx) = mpsc::unbounded_channel();
/*
let join_handle = tokio::spawn(async {
let mut currently_listening_to: HashMap<String, RoomHandle> =
HashMap::new();
loop {
// Build select targets
let ouais = rx.recv().boxed();
let mut select_targets: Vec<
Pin<Box<dyn Future<Output = Option<CompositeListenerMessage>>>>,
> = vec![ouais];
for (_, room_handle) in currently_listening_to.iter() {
select_targets.push(
room_handle
.rx
.recv()
.map(|f| {
f.ok().map(|m| CompositeListenerMessage::Room {
name: room_handle.name.clone(),
message: m,
})
})
.boxed(),
);
}
// Select
let result = future::select_all(select_targets).await;
}
});
(join_handle, tx, rx)
*/
todo!()
}