Skip to content

Commit

Permalink
clients reconnect better, basic save/load events.
Browse files Browse the repository at this point in the history
  • Loading branch information
danthedeckie committed Aug 14, 2019
1 parent 34ce544 commit 6f2b7f2
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 32 deletions.
45 changes: 27 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,57 @@
# never-f5

I need to make a quick mockup of a site, or page/SPA/app concept. Or I want to play with a new javascript library.
I need to make a quick mockup of a site, or page/SPA/app concept.

I don't want a node.js based server to get auto-refresh on save, or nice stuff like that.
Or work with a designer quickly iterating HTML changes to a design, and the
"save", "switch to a browser window", "press f5" loop is getting pretty old.

I want auto refreshing, fast, without needing to install a massive node.js
multi-layer complex beast.

I want it to be fast. I want a stand-alone binary I can install anywhere.

(I want an excuse to learn rust...)
(I want an excuse to code in rust...)

## Voila!
## ta DAA! Here is "never-f5" to save the day.

1) Serve a directory locally. (Port 8088)
2) Notify file changes by websocket
3) embed a websocket script into pages to auto refresh.

Makes quick page design / scripting a million times nicer. WIP.
Makes quick page design / scripting a million times nicer.

You can access normal static files as normal:

/index.html

for instance. But if you add a `'!'`, then you get the auto-refresh websocket magic attached.
for instance. But if you add a `'!'`, then you get the auto-refresh websocket
magic attached.

/index.html!

Now, whenever any files in that directory are changed, it'll refresh the page.

## NEXT STEPS:

0) Tidying up - general fixing / cleaning / organising / documenting / refactoring.
0) *Commandline arguments.*
Need to have port & ip options, directory, websocket address, and injection
file, to allow easy inserting extra callbacks, doing clever CSS stuff,
event debounce time, etc.

1) I don't want it to refresh UNLESS YOU WANT IT TO. So there should be a hook to allow it to call a user-defined 'file-changed' callback in the page. This should allow you to save state (if you want to).
1) *Tidying up* - general fixing / cleaning / organising / documenting / refactoring.

2) Make sure all the actix-web settings are tuned for this kind of work. We aren't expecting a million requests and hundreds of simultanious connections. - THAT SAID - It should allow you to have a bunch of different browsers, devices, etc. all viewing the same document.

3) Have a 'save-state/load-state' kind of route, so that you could make changes on one device, and see them reflected on multiple devices instantly - is this a good idea?
2) Have a `save-state/load-state` kind of route, so that you could make changes
on one device, and see them reflected on multiple devices instantly - /is this a
good idea?/

## Current State:

Very 'Work in Progress'. I hacked this together very quickly, learning Rust and Actix-Web in the process.
It currently only works when serving directly in the current directory - so what I need, but I could see need for more configurability.

So it's technically usable for me now, already, which is pretty awesome.
I put this together pretty quickly, learning Rust and Actix-Web in the
process. It seems to work very well.

I put this on github now simply as an off-site backup from my laptop - and in case anyone else wants a similar tool.
## Saving state.

It could really do with tidying up a lot.
Since it's sometimes nice to have state in web apps or pages (who knew, right)
there's a couple of callbacks you can add to your page: `window._autoreload_save`
and `window._autoreload_load`, which you can use to save and reload your state
to local storage or whatever before and after reloads.
17 changes: 10 additions & 7 deletions src/filewatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,14 @@ use std::collections::HashSet;
use std::io;
use std::path::PathBuf;
use std::fs::canonicalize;
use std::time::Duration;

use actix::prelude::*;
use actix::Arbiter;
//use futures::Future;
use actix;

//extern crate crossbeam_channel;
//extern crate notify;

use crossbeam_channel::{unbounded, Sender, Receiver};
use crossbeam_channel::{unbounded, Sender, Receiver, RecvError};
use notify::{RecommendedWatcher, RecursiveMode, Result as NResult, Watcher, Event};
use std::time::Duration;

// Messages:

Expand Down Expand Up @@ -84,6 +80,7 @@ impl WatcherHandler {
match rx.recv() {
Ok(Ok(event)) => {
for path in event.paths {

let result = me.try_send(SomethingChanged {filename: String::from(path.to_str().unwrap()) });
match result {
Ok(()) => (),
Expand All @@ -92,7 +89,13 @@ impl WatcherHandler {
}
},
Ok(Err(err)) => println!("recieved an error? {:?}", err),
Err(err) => println!("watch error... {:?}", err),
Err(RecvError) => {
// Channel Disconnected. Goodbye!
break
},
Err(err) => {
println!("watch error... {:?}", err)
},
};
}
});
Expand Down
23 changes: 19 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,24 @@ use crate::websockets::*;

const WS_INJECTION: &str = "
<script>
var ws = new WebSocket('ws://' + document.URL.match('.*://([^/]*)/')[1] + '/!!/');
ws.onmessage = function (evt) {
(function() {
var ws_url = 'ws://' + document.URL.match('.*://([^/]*)/')[1] + '/!!/';
var ws = new WebSocket(ws_url);
var reload = function() {
window._autoreload_save && window._autoreload_save();
document.location.replace(document.URL);
// document.location.reload(true);
}
};
ws.onmessage = reload;
ws.onclose = function(evt) {
console.log('Server disconnected! Retrying...');
setInterval(function() {
var ws = new WebSocket(ws_url);
ws.onopen = reload;
}, 1000);
};
window._autoreload_load && window._autoreload_load();
})();
</script>";

fn nonstatic_handler(req: HttpRequest) -> Result<HttpResponse, Error> {
Expand Down Expand Up @@ -110,5 +123,7 @@ fn main() {
server.bind("127.0.0.1:8088").unwrap()
};

println!("Listening on 127.0.0.1:8088");

server.run().unwrap();
}
18 changes: 15 additions & 3 deletions src/websockets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ impl Message for ClientMsgSomethingChanged { type Result = (); }

struct ClientConnect { pub addr:Recipient<ClientMsgSomethingChanged> }
impl Message for ClientConnect { type Result = (); }

struct ClientDisconnect { pub addr:Recipient<ClientMsgSomethingChanged> }
impl Message for ClientDisconnect { type Result = (); }

Expand Down Expand Up @@ -48,13 +49,17 @@ impl Handler<ClientConnect> for ClientList {
type Result = ();
fn handle(&mut self, msg: ClientConnect, _: &mut Context<Self>) -> Self::Result {
self.sessions.push(msg.addr);
println!("{} clients connected", self.sessions.len());
}
}

impl Handler<ClientDisconnect> for ClientList {
type Result = ();
fn handle(&mut self, msg: ClientDisconnect, _: &mut Context<Self>) -> Self::Result {
// TODO
if let Some(i) = self.sessions.iter().position(|x| x == &msg.addr) {
self.sessions.swap_remove(i);
}
println!("{} clients connected", self.sessions.len());
}
}

Expand Down Expand Up @@ -86,7 +91,14 @@ impl Handler<ClientMsgSomethingChanged> for Client {
}

impl StreamHandler<ws::Message, ws::ProtocolError> for Client {
fn handle(&mut self, msg: ws::Message, _ctx: &mut Self::Context) {
println!("WS Message from client: {:?}", msg);
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
ws::Message::Close(_) => {
ctx.stop();
},
_ => {
println!("WS Message from client: {:?}", msg);
}
};
}
}

0 comments on commit 6f2b7f2

Please sign in to comment.