staticme 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c83685ffa08a0f05408fb3fada3051c45ee9b88d
4
- data.tar.gz: 771cecf1e3cd1b65b484a2833e9254be9f423569
3
+ metadata.gz: d051eed734b566be6c2d086913e8c92866e7db57
4
+ data.tar.gz: 9bbdc61c67b0db02b7e12bd494f0c446a8751dde
5
5
  SHA512:
6
- metadata.gz: 832e547bb2acc6bf7f24d025b3cfdaa48c692db8a596c868f4f8f785d4012a84c07cbe2abadd283b2ae094d3c417a5a823117fe9081a2ad0d4930df0dcd00400
7
- data.tar.gz: 0cfcd02b083d1664099833c3c502125c8075827f054bba98f4feb46f6393ac32d3964ed68c702a0c7509ad25ee7d277d58bad572e29611d1d143e8f68858e97d
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: 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
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
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'staticme'
3
3
 
4
- Staticme.run! Hash[*ARGV]
4
+ Staticme.run! Hash[*ARGV]
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
- use Rack::CommonLogger
19
-
20
- index = params[:index]
21
- path = params[:path]
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
@@ -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
@@ -6,7 +6,11 @@ module Staticme
6
6
  :server_super
7
7
 
8
8
  def start(app, params, &blk)
9
- server_super.run(app, params) do |server|
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,4 @@
1
+ module Staticme
2
+ module Scripts
3
+ end
4
+ end
@@ -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
- attr_accessor :runner
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
- app = Staticme::App.new(params).bind
37
+ register_event_handlers
21
38
 
22
- runner = Staticme::ThinRunner.new
39
+ emit(:staticme_inited)
23
40
 
24
- runner.start(app, params, &blk)
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.2.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-02-21 00:00:00.000000000 Z
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