Skip to content

Commit

Permalink
Update view
Browse files Browse the repository at this point in the history
  • Loading branch information
nanoqsh committed May 31, 2022
1 parent 3200bd5 commit 4203e39
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 71 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ To build application with `release` profile make:
cargo run release
```

That runs a build script which creates `dock` directory with a ready to start `Dockerfile`. Build a container with:
That runs a build script which creates `dock` directory with a ready to start `Dockerfile`. Build and run a container with:
```
docker build -t voki ./dock
docker-compose up -d --build
```

## Run
todo!()
Visit [localhost](http://localhost/) to open the application. Currently only http support, so ensure the browser opens a page with `http://` prefix.

To show the server log make:
```
docker-compose logs
```
14 changes: 11 additions & 3 deletions base/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,21 @@ pub struct Channel {
pub id: u32,
pub name: String,
pub icon: Option<String>,
pub history: Vec<Message>,
}

#[derive(BorrowDecode, Encode)]
pub enum ServerMessage<'a> {
#[derive(Clone, Decode, Encode)]
pub struct Message {
pub from: u32,
pub chan: u32,
pub text: String,
}

#[derive(Decode, Encode)]
pub enum ServerMessage {
Closed,
LoggedIn(Result<u32, LoginError>),
User(User),
Channel(Channel),
Said { from: u32, chan: u32, text: &'a str },
Message(Message),
}
8 changes: 8 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: "3.9"
services:
voki:
build: ./dock
container_name: voki
ports:
- 80:80
- 4567:4567
6 changes: 4 additions & 2 deletions http/Rocket.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[default]
[global]
address = "0.0.0.0"
port = 8000
port = 80
log_level = "debug"
cli_colors = false
5 changes: 4 additions & 1 deletion http/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use http::index;
use rocket::{fs::FileServer, launch, routes};
use std::process::Command;

#[launch]
fn rocket() -> _ {
async fn rocket() -> _ {
Command::new("./server").spawn().expect("run server");

rocket::build()
.mount("/", FileServer::from("./static"))
.mount("/api", routes![index])
Expand Down
23 changes: 16 additions & 7 deletions server/src/manage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ pub async fn manage(mut receiver: Receiver<Event>) -> ! {
let mut users = Users::new();
let channels = Channels::new();
let mut clients: HashMap<SocketAddr, Client> = HashMap::default();
let mut history = vec![];

loop {
let event = receiver.recv().await.expect("channel is open");
Expand Down Expand Up @@ -164,16 +165,19 @@ pub async fn manage(mut receiver: Receiver<Event>) -> ! {
let name = &user.name;
println!("{name} ({chan}): {text}");

// Send this to all
let message = Message {
from: id,
chan,
text: text.into(),
};

// Send this to all clients
for client in clients.values() {
let message = ServerMessage::Said {
from: id,
chan,
text,
};
let message = ServerMessage::Message(message.clone());
send(&client.sender, message).await;
}

history.push(message);
continue;
}
None => ServerMessage::Closed,
Expand Down Expand Up @@ -208,6 +212,11 @@ pub async fn manage(mut receiver: Receiver<Event>) -> ! {
id: chan.id,
name: chan.name,
icon: chan.icon,
history: history
.iter()
.filter(|message| message.chan == chan.id)
.cloned()
.collect(),
});
send(sender, message).await;
}
Expand All @@ -217,7 +226,7 @@ pub async fn manage(mut receiver: Receiver<Event>) -> ! {
}
}

async fn send(sender: &Sender<Vec<u8>>, message: api::ServerMessage<'_>) {
async fn send(sender: &Sender<Vec<u8>>, message: api::ServerMessage) {
let mut buf = Vec::with_capacity(64);
encode(&message, &mut buf).expect("encode");
let _ = sender.send(buf).await;
Expand Down
24 changes: 10 additions & 14 deletions src/info.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
macro_rules! info {
($l:expr, $e:expr) => {{
use termion::{color, style};

($l:expr, $e:expr) => {
println!(
"{}{}{:>12}{}{} {}",
color::Fg(color::Blue),
style::Bold,
::termion::color::Fg(::termion::color::Blue),
::termion::style::Bold,
$l,
color::Fg(color::Reset),
style::Reset,
::termion::color::Fg(::termion::color::Reset),
::termion::style::Reset,
$e
);
}};
};
}

pub(crate) use info;

macro_rules! error {
($e:expr) => {
use termion::{color, style};

println!(
"{}{}error{}{}: {}",
color::Fg(color::Red),
style::Bold,
color::Fg(color::Reset),
style::Reset,
::termion::color::Fg(::termion::color::Red),
::termion::style::Bold,
::termion::color::Fg(::termion::color::Reset),
::termion::style::Reset,
$e
);
};
Expand Down
24 changes: 17 additions & 7 deletions web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,28 @@ pub fn main() -> Result<(), JsValue> {
view.update();
}
ServerMessage::Channel(chan) => {
state
.borrow_mut()
.push_channel(Channel::new(&chan.name, chan.icon.as_deref()));
{
let mut state = state.borrow_mut();
state.push_channel(chan.id, Channel::new(&chan.name, chan.icon.as_deref()));
for message in chan.history {
state.push_message(
message.chan,
Message {
from: message.from,
text: message.text.into(),
},
);
}
}

view.update();
}
ServerMessage::Said { from, chan, text } => {
ServerMessage::Message(message) => {
state.borrow_mut().push_message(
chan,
message.chan,
Message {
from,
text: text.into(),
from: message.from,
text: message.text.into(),
},
);

Expand Down
29 changes: 13 additions & 16 deletions web/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use im::{HashMap, Vector};
use im::{HashMap, OrdMap, Vector};
use std::{fmt, rc::Rc};

#[derive(Clone, PartialEq)]
Expand Down Expand Up @@ -74,11 +74,9 @@ impl PartialEq for Channel {
return false;
}

if lhs.is_inline() {
lhs == rhs
} else {
lhs.ptr_eq(rhs)
}
lhs.is_inline()
.then(|| lhs == rhs)
.unwrap_or_else(|| lhs.ptr_eq(rhs))
}

self.name == rhs.name && self.icon == rhs.icon && possibly_eq(&self.messages, &rhs.messages)
Expand All @@ -102,23 +100,22 @@ impl Default for User {

#[derive(Default, PartialEq)]
pub struct State {
channels: Vector<Channel>,
channels: OrdMap<u32, Channel>,
users: HashMap<u32, User>,
}

impl State {
pub fn channels(&self) -> impl Iterator<Item = &Channel> {
self.channels.iter()
self.channels.values()
}

pub fn messages(&self, channel: u32) -> Vector<(u32, Vector<Rc<str>>)> {
pub fn messages(&self, chan: u32) -> Vector<(u32, Vector<Rc<str>>)> {
use itertools::Itertools;

self.channels
.get(channel as usize)
.map(|channel| {
channel
.messages
.get(&chan)
.map(|chan| {
chan.messages
.iter()
.group_by(|message| message.from)
.into_iter()
Expand All @@ -137,12 +134,12 @@ impl State {
self.users.get(&user)
}

pub fn push_channel(&mut self, chan: Channel) {
self.channels.push_back(chan);
pub fn push_channel(&mut self, id: u32, chan: Channel) {
self.channels.insert(id, chan);
}

pub fn push_message(&mut self, chan: u32, message: Message) {
if let Some(chan) = self.channels.get_mut(chan as usize) {
if let Some(chan) = self.channels.get_mut(&chan) {
chan.messages.push_back(message);
}
}
Expand Down
23 changes: 7 additions & 16 deletions web/src/view/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,16 @@ pub struct Props {
pub onsend: Callback<(u32, Rc<str>)>,
}

pub struct Chat {
scroll_to_end: bool,
}
pub struct Chat;

impl Chat {
fn scroll_to_end(&mut self) {
if self.scroll_to_end {
let height = gloo::utils::document()
.body()
.expect_throw("body")
.scroll_height();

gloo::utils::window().scroll_by_with_x_and_y(0., height as f64);
let height = gloo::utils::document()
.body()
.expect_throw("body")
.scroll_height();

self.scroll_to_end = false;
}
gloo::utils::window().scroll_by_with_x_and_y(0., height as f64);
}
}

Expand All @@ -140,16 +134,13 @@ impl Component for Chat {
type Properties = Props;

fn create(_: &Context<Self>) -> Self {
Self {
scroll_to_end: true,
}
Self
}

fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Event::Send { channel, text } if !text.trim().is_empty() => {
ctx.props().onsend.emit((channel, text));
self.scroll_to_end = true;
}
_ => {}
}
Expand Down
2 changes: 1 addition & 1 deletion web/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="./favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="./style.css">
<title>Voki</title>
<title>Chat</title>
</head>

<body>
Expand Down

0 comments on commit 4203e39

Please sign in to comment.