staticme 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -4
- data/bin/staticme +1 -1
- data/lib/staticme/app.rb +10 -8
- data/lib/staticme/arguments.rb +10 -6
- data/lib/staticme/events/dispatcher.rb +34 -0
- data/lib/staticme/events/emitters/file_changed.rb +76 -0
- data/lib/staticme/runner.rb +6 -2
- data/lib/staticme/scripts/autoreload.rb +96 -0
- data/lib/staticme/scripts.rb +4 -0
- data/lib/staticme/web_socket.rb +46 -0
- data/lib/staticme.rb +46 -5
- metadata +35 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d051eed734b566be6c2d086913e8c92866e7db57
|
4
|
+
data.tar.gz: 9bbdc61c67b0db02b7e12bd494f0c446a8751dde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d71b11562c1cc46e9bde1a5b13b815c72f06a85919bc585219a20069c1f1dd93d4c6ae061e5bfcdcbbe7c3b1372ec04e9343a71aff710003486517bd3b58168
|
7
|
+
data.tar.gz: f9a45456d0e19dba2d2d80b35b7020542eae609dff94f330bf96e5bf9f5753d62e4319f2031f3476ae427cb5af40e1ac029c78ac370baff7c3a6e4f50da547aa
|
data/README.md
CHANGED
@@ -14,9 +14,10 @@ gem install staticme
|
|
14
14
|
|
15
15
|
### Options:
|
16
16
|
|
17
|
-
* -f, --path:
|
18
|
-
* -p, --port:
|
19
|
-
* -h, --host:
|
17
|
+
* -f, --path: path to be served in, current if omitted
|
18
|
+
* -p, --port: port to bind, 8080 by default
|
19
|
+
* -h, --host: host to start up, 0.0.0.0 by default
|
20
|
+
* -i, --index: index file name, index.html by default
|
20
21
|
|
21
22
|
### Starting up
|
22
23
|
|
@@ -30,4 +31,4 @@ staticme
|
|
30
31
|
>> Listening on 0.0.0.0:8080, CTRL+C to stop
|
31
32
|
```
|
32
33
|
|
33
|
-
In browser open page http://127.0.0.1:8080
|
34
|
+
In browser open page http://127.0.0.1:8080
|
data/bin/staticme
CHANGED
data/lib/staticme/app.rb
CHANGED
@@ -12,13 +12,15 @@ module Staticme
|
|
12
12
|
|
13
13
|
def bind
|
14
14
|
params = self.params
|
15
|
-
|
15
|
+
|
16
16
|
Rack::StaticmeBuilder.new do
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
|
18
|
+
index = params[:index]
|
19
|
+
path = params[:path]
|
20
|
+
|
21
|
+
map '/staticme/autoreload.js' do
|
22
|
+
run Staticme::Scripts::Autoreload
|
23
|
+
end
|
22
24
|
|
23
25
|
map /^\/.+/ do
|
24
26
|
run Rack::Directory.new( path )
|
@@ -29,10 +31,10 @@ module Staticme
|
|
29
31
|
run Rack::File.new( File.join( path, index ) )
|
30
32
|
end
|
31
33
|
end
|
32
|
-
|
34
|
+
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
38
|
end
|
37
39
|
|
38
|
-
end
|
40
|
+
end
|
data/lib/staticme/arguments.rb
CHANGED
@@ -3,28 +3,32 @@ module Staticme
|
|
3
3
|
module Arguments
|
4
4
|
|
5
5
|
ARGS = {
|
6
|
-
:path
|
6
|
+
:path => {
|
7
7
|
:short => 'f',
|
8
8
|
:default => Proc.new { Dir.pwd }
|
9
9
|
},
|
10
|
-
:port
|
10
|
+
:port => {
|
11
11
|
:short => 'p',
|
12
12
|
:default => 8080,
|
13
13
|
:sanitizer => Proc.new { |v| v.to_i }
|
14
14
|
},
|
15
|
-
:host
|
15
|
+
:host => {
|
16
16
|
:short => 'h',
|
17
17
|
:default => '0.0.0.0'
|
18
18
|
},
|
19
|
-
:index
|
19
|
+
:index => {
|
20
20
|
:short => 'i',
|
21
21
|
:default => 'index.html'
|
22
|
+
},
|
23
|
+
:ws_port => {
|
24
|
+
:short => 'ws',
|
25
|
+
:default => 8090,
|
22
26
|
}
|
23
27
|
}
|
24
28
|
|
25
29
|
def parse_input(argv)
|
26
30
|
params = Hash.new
|
27
|
-
|
31
|
+
|
28
32
|
ARGS.each_pair do |param_name, param_attrs|
|
29
33
|
param_shorten_name = param_attrs[:shorten]
|
30
34
|
default = param_attrs[:default]
|
@@ -44,4 +48,4 @@ module Staticme
|
|
44
48
|
|
45
49
|
end
|
46
50
|
|
47
|
-
end
|
51
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Staticme
|
2
|
+
|
3
|
+
module Events
|
4
|
+
|
5
|
+
module Dispatcher
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
|
10
|
+
attr_accessor :events
|
11
|
+
|
12
|
+
def on(event_name, &event_handler)
|
13
|
+
((self.events ||= {})[event_name.to_sym] ||= []).push(event_handler)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def emit(event_name, *args)
|
18
|
+
((self.events ||= {})[event_name.to_sym]).tap do |event_pool|
|
19
|
+
return if event_pool.nil?
|
20
|
+
event_pool.map do |handler|
|
21
|
+
handler.call(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rb-fsevent'
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
module Staticme
|
6
|
+
|
7
|
+
module Events
|
8
|
+
|
9
|
+
module Emitters
|
10
|
+
|
11
|
+
class FileChanged
|
12
|
+
|
13
|
+
attr_accessor :fsevent
|
14
|
+
attr_accessor :_broadcast_tail
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
self.fsevent = FSEvent.new
|
18
|
+
self._broadcast_tail = Hash.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def bind!
|
22
|
+
|
23
|
+
params = Staticme.params
|
24
|
+
|
25
|
+
Staticme.on(:fs_changed) do
|
26
|
+
Staticme.broadcast(:event => 'fs_change')
|
27
|
+
end.on(:staticme_terminated) do
|
28
|
+
self.stop!
|
29
|
+
end
|
30
|
+
|
31
|
+
fsevent.watch params[:path] do |dirs|
|
32
|
+
signature = get_signature(dirs)
|
33
|
+
next if already_broadcasted?(signature)
|
34
|
+
tail_broadcast(signature)
|
35
|
+
Staticme.logger.info 'FS change, publishing the event.'
|
36
|
+
Staticme.emit(:fs_changed, dirs)
|
37
|
+
end
|
38
|
+
|
39
|
+
Thread.abort_on_exception = true
|
40
|
+
|
41
|
+
Thread.new do
|
42
|
+
fsevent.run
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def stop!
|
48
|
+
fsevent.stop
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def get_signature(params)
|
54
|
+
Digest::MD5.hexdigest(params.to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
def already_broadcasted?(signature)
|
58
|
+
!self._broadcast_tail[signature].nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
def tail_broadcast(signature)
|
62
|
+
self._broadcast_tail[signature] = true
|
63
|
+
# fsevent triggers 2 events in a row
|
64
|
+
# just a simple filtering
|
65
|
+
EM.add_timer 1 do
|
66
|
+
self._broadcast_tail.delete(signature)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
data/lib/staticme/runner.rb
CHANGED
@@ -6,7 +6,11 @@ module Staticme
|
|
6
6
|
:server_super
|
7
7
|
|
8
8
|
def start(app, params, &blk)
|
9
|
-
|
9
|
+
server_params = Hash.new
|
10
|
+
%w(host port).map(&:to_sym).each do |k|
|
11
|
+
(server_params[k.to_s.capitalize.to_sym] = params[k]) if !params[k].nil?
|
12
|
+
end
|
13
|
+
server_super.run(app, server_params) do |server|
|
10
14
|
self.server = server
|
11
15
|
blk.call(server) if block_given?
|
12
16
|
end
|
@@ -18,4 +22,4 @@ module Staticme
|
|
18
22
|
|
19
23
|
end
|
20
24
|
|
21
|
-
end
|
25
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Staticme
|
2
|
+
|
3
|
+
module Scripts
|
4
|
+
|
5
|
+
module Autoreload
|
6
|
+
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def js_output
|
10
|
+
<<-eos
|
11
|
+
(function() {
|
12
|
+
window.addEventListener('DOMContentLoaded', function() {
|
13
|
+
|
14
|
+
var WS_RECONNECT_TIMEOUT = 1000;
|
15
|
+
|
16
|
+
var Dispatcher = function(routes) {
|
17
|
+
this.init(routes);
|
18
|
+
}
|
19
|
+
|
20
|
+
Dispatcher.prototype.init = function(routes) {
|
21
|
+
this.routes = routes;
|
22
|
+
}
|
23
|
+
|
24
|
+
Dispatcher.prototype.dispatch = function(message) {
|
25
|
+
console.log('Dispatching data: ', message);
|
26
|
+
var event_name = message.event;
|
27
|
+
if (this.routes[event_name]) {
|
28
|
+
this.routes[event_name](message);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
var location = window.location,
|
33
|
+
ws_url = "ws://" + location.hostname + ':#{Staticme.params[:ws_port].to_i}',
|
34
|
+
dispatcher = new Dispatcher({
|
35
|
+
'fs_change': function() {
|
36
|
+
console.log('Remote fs change, reloading the page...');
|
37
|
+
window.location.reload();
|
38
|
+
}
|
39
|
+
}),
|
40
|
+
ws = _open_ws(),
|
41
|
+
_reconnect_timer;
|
42
|
+
|
43
|
+
function _open_ws() {
|
44
|
+
|
45
|
+
if (ws) {
|
46
|
+
_close_ws();
|
47
|
+
}
|
48
|
+
|
49
|
+
ws = new WebSocket(ws_url);
|
50
|
+
|
51
|
+
ws.onopen = function() {
|
52
|
+
window.clearTimeout(_reconnect_timer);
|
53
|
+
console.info('WebSocket connection has been established.');
|
54
|
+
}
|
55
|
+
|
56
|
+
ws.onmessage = function(event) {
|
57
|
+
var message = JSON.parse(event.data);
|
58
|
+
console.info('A new message received: ' . message);
|
59
|
+
dispatcher.dispatch(message);
|
60
|
+
}
|
61
|
+
|
62
|
+
ws.onerror = function(e) {
|
63
|
+
window.clearTimeout(_reconnect_timer);
|
64
|
+
console.error('An unexpected error occured.', e);
|
65
|
+
_reconnect_timer = window.setTimeout(_open_ws, WS_RECONNECT_TIMEOUT);
|
66
|
+
}
|
67
|
+
|
68
|
+
ws.onclose = function() {
|
69
|
+
window.clearTimeout(_reconnect_timer);
|
70
|
+
console.warn('WebSocket connection has been closed by the server.');
|
71
|
+
_reconnect_timer = window.setTimeout(_open_ws, WS_RECONNECT_TIMEOUT);
|
72
|
+
}
|
73
|
+
|
74
|
+
return ws;
|
75
|
+
}
|
76
|
+
|
77
|
+
function _close_ws() {
|
78
|
+
ws.close();
|
79
|
+
ws = null;
|
80
|
+
}
|
81
|
+
|
82
|
+
}, false);
|
83
|
+
})(window);
|
84
|
+
eos
|
85
|
+
end
|
86
|
+
|
87
|
+
def call(arg)
|
88
|
+
[200, {:'Content-Type' => 'application/javascript'}, [js_output]]
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'em-websocket'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Staticme
|
6
|
+
|
7
|
+
class WebSocket
|
8
|
+
|
9
|
+
attr_accessor :params
|
10
|
+
|
11
|
+
def initialize(params)
|
12
|
+
self.params = params
|
13
|
+
@pool = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def run!(&block)
|
17
|
+
EM.next_tick do
|
18
|
+
Staticme.logger.debug "Starting WebSocket server on ws://#{params[:host]}:#{params[:ws_port]}"
|
19
|
+
EM::WebSocket.run(:host => params[:host], :port => params[:ws_port]) do |ws|
|
20
|
+
@pool.push ws
|
21
|
+
ws.onclose do
|
22
|
+
@pool.delete ws
|
23
|
+
end
|
24
|
+
end
|
25
|
+
block.call if block_given?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def emit(event)
|
30
|
+
Staticme.logger.debug("Broadcasting event: #{event.to_json}")
|
31
|
+
@pool.each do |ws|
|
32
|
+
next if ws.nil?
|
33
|
+
ws.send event.to_json
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop!
|
38
|
+
Staticme.logger.debug('Stopping WebSocket server')
|
39
|
+
EM.stop!
|
40
|
+
@pool = []
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
data/lib/staticme.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'logger'
|
2
3
|
|
3
4
|
require 'staticme/app'
|
4
5
|
require 'staticme/arguments'
|
6
|
+
require 'staticme/events/dispatcher'
|
7
|
+
require 'staticme/events/emitters/file_changed'
|
5
8
|
require 'staticme/runner'
|
6
9
|
require 'staticme/thin_runner'
|
10
|
+
require 'staticme/scripts'
|
11
|
+
require 'staticme/scripts/autoreload'
|
12
|
+
require 'staticme/web_socket'
|
7
13
|
|
8
14
|
module Staticme
|
9
15
|
|
@@ -11,22 +17,57 @@ module Staticme
|
|
11
17
|
|
12
18
|
extend Staticme::Arguments
|
13
19
|
|
14
|
-
|
20
|
+
include Staticme::Events::Dispatcher
|
21
|
+
|
22
|
+
attr_accessor :app,
|
23
|
+
:logger,
|
24
|
+
:params,
|
25
|
+
:runner,
|
26
|
+
:ws
|
15
27
|
|
16
28
|
def run!(argv, &blk)
|
17
29
|
|
18
|
-
params = parse_input(argv)
|
30
|
+
self.params = parse_input(argv)
|
31
|
+
self.app = Staticme::App.new(params).bind
|
32
|
+
self.logger = ::Logger.new(STDOUT)
|
33
|
+
self.logger.level = ::Logger::DEBUG
|
34
|
+
self.runner = Staticme::ThinRunner.new
|
35
|
+
self.ws = Staticme::WebSocket.new(params)
|
19
36
|
|
20
|
-
|
37
|
+
register_event_handlers
|
21
38
|
|
22
|
-
|
39
|
+
emit(:staticme_inited)
|
23
40
|
|
24
|
-
runner.start(app, params
|
41
|
+
runner.start(app, params) do |server|
|
42
|
+
emit(:web_server_started, server)
|
43
|
+
logger.debug('Web server started')
|
44
|
+
ws.run!
|
45
|
+
blk.call(server) if !blk.nil?
|
46
|
+
end
|
47
|
+
end
|
25
48
|
|
49
|
+
def broadcast(data)
|
50
|
+
begin
|
51
|
+
ws.emit(data)
|
52
|
+
rescue
|
53
|
+
logger.warn('Unable to broadcast event')
|
54
|
+
end
|
26
55
|
end
|
27
56
|
|
28
57
|
def stop!
|
58
|
+
self.emit(:staticme_terminated)
|
29
59
|
runner.stop
|
30
60
|
end
|
31
61
|
|
62
|
+
private
|
63
|
+
|
64
|
+
def register_event_handlers
|
65
|
+
%w(FileChanged).each do |emitter_name|
|
66
|
+
klass = Object.const_get "Staticme::Events::Emitters::#{emitter_name}"
|
67
|
+
logger.debug("Registering event emitter: #{klass.to_s}")
|
68
|
+
emitter = klass.new
|
69
|
+
emitter.bind!
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
32
73
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: staticme
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 4pcbr
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: em-websocket
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rb-fsevent
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: shoulda
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,8 +137,13 @@ files:
|
|
109
137
|
- lib/staticme.rb
|
110
138
|
- lib/staticme/app.rb
|
111
139
|
- lib/staticme/arguments.rb
|
140
|
+
- lib/staticme/events/dispatcher.rb
|
141
|
+
- lib/staticme/events/emitters/file_changed.rb
|
112
142
|
- lib/staticme/runner.rb
|
143
|
+
- lib/staticme/scripts.rb
|
144
|
+
- lib/staticme/scripts/autoreload.rb
|
113
145
|
- lib/staticme/thin_runner.rb
|
146
|
+
- lib/staticme/web_socket.rb
|
114
147
|
- LICENSE.txt
|
115
148
|
- README.md
|
116
149
|
- bin/staticme
|