flammarion_rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +3 -0
- data/Rakefile +26 -0
- data/app/assets/config/flammarion_rails_manifest.js +0 -0
- data/config/routes.rb +2 -0
- data/lib/flammarion/engraving.rb +95 -0
- data/lib/flammarion/revelator.rb +88 -0
- data/lib/flammarion/server.rb +88 -0
- data/lib/flammarion_rails.rb +5 -0
- data/lib/flammarion_rails/configuration.rb +25 -0
- data/lib/flammarion_rails/engine.rb +28 -0
- data/lib/flammarion_rails/version.rb +3 -0
- data/lib/rubame/server.rb +172 -0
- data/lib/tasks/flammarion_rails_tasks.rake +4 -0
- data/public/index.html +23 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +4 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/cable.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/products_controller.rb +4 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/app/views/products/index.html.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/flammarion +8 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +34 -0
- data/spec/dummy/bin/update +29 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +15 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +9 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +56 -0
- data/spec/dummy/config/environments/production.rb +88 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/flammarion_rails.rb +3 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/puma.rb +47 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +819 -0
- data/spec/dummy/log/test.log +16 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0M/0Mg2krTmzvpvndy5rHnhuun5BBfgA8mY3nz6myP6kdQ.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0P/0P6sKgG4-T4rwdhhAvLJKqmC2XHD18DbbxM7-oLWhXA.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/22/22E2TQFHi7XchzTLK5w8ZZ_iYCMIyyGwRmVazx3irqY.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2R/2RUaNi4ZIYrYbhyd2C-Ww2kZHGazuNcAfrKjQoSubl4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3L/3LxcdISAk1c4X--4-sTB_h--GZF2Epue7I2gjbgvkQ4.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3p/3pa5vZojTdQB44mkfj5buJFWDKREMuCNJoOEP84rcDU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/58/586fjw8FKooCH-968ZTIIrVkE9RuHmBnkYj5OYwcs9g.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Bu/BuE1MKiZRiA2ei8bcxwYLjyJdTpEy4wxW852s55oNNk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/JD/JDCUTDoF2rC0R-NS53x4NhZ_wcTPq8E_ccURRvkjrbg.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KH/KHGH8y7fyC26rhzb2-uu0cV4z5-pxa2N3NkDIL_feBk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LY/LYOt9-oLcF3-pZyrj-ObZCV5sJnzOX-ChSBrkZI72Oc.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Lu/LuB__cHcdlpiqGBKHUifyKQAk1Q8hYTNxvUnK1VPuJs.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Lv/LvkAiAXzEhMj_E-ZRx0qe2EAXBsm_M7MRf4ids1kxdw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mw/MwOabPFIFDte8ZBuoVOOtd1Qu476fF4T4E78To9L2Eo.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mx/MxvaxgCXDp1kMg4ZPyEj18UaF7hti7eGd5irCjj7CYA.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QF/QFvF-z4bMPE9dkk_vRFZYF8e2goQi8vWGeExjSUT92Q.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Re/Red0n__pXlXNH8SzCQTdfqRmTJxrcVN9AWr1__pJFP0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/SI/SI9DDWxIPbS6sVOJ772L6_Jbfq17xBHX_sJw6gutPq4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/SN/SNWLiOT9nptoa_fIBzkk6rau30FCwQnjLilnZtLUWKU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/TF/TFYV3Z2UC54NjsDNnfNTRAaCpEG-_o6wRVDYezsnnzk.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/X_/X_-4jxim1KTh1Fjxx8_IJyO-3Wzv3M4N70rE0Hi5ipY.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Z4/Z4xtfQJ5r3sHK5ASuH1nYxFVJM360rK3PnL_RtnWXAk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_h/_hwlFJ7l4uM_oLaUe5ZKud1WAQO5QCyqspXi5bIjitk.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/b_/b_Itlk9QZZd7Rvf8kcA4yLP1R5Acu7jB-m1xQiSU0qE.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ct/ctAKDrnI0EvuP7FAZXCRPZCWA3hmwlIMurxUpX4dOO8.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/dg/dg3wGWeFjow5LX98G4IGeWcMyoTHYsklNz3gOLQSXr8.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/lV/lVt8G4NTNqewg9C9PXeaR1Abtx7AHu0vaSkHAhGWR0M.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mX/mX1nlsL_SWOB4y22W5FheRX0YEONKyOY7xUeIvRiHco.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/me/me4uxBSFG-PjZ9e6iUX80JlbffE5GmRQ7Un-fsLO0QA.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oz/ozK4IPJj2CBcsem3fLJx3wqcOl6mI6B91PkN0wVfkyk.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pZ/pZoXZhq291Gxs21xFN0T4V1N1KwyFISSp7okEgbD7lY.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qP/qPmv5snMrDw830S6hSICDcnIy7kVEWoFKXhGKT38lG4.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/vA/vAcjLVwbHcbzsPpYo9NmFa4oW46YZoyQRriaJNpEoqw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/vu/vugy1YR_4jOXqgIEqNMSTWQ6DiSEhSEzsBTMqENWhxU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/x7/x7PYh8DJvPykcEqpVab2vcY9-GFz-3cqtoMlRAu94Uc.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/z1/z1pCDnU1k4aeEb3hZmNX4QNvaCUFbtHX4L7noBd035M.cache +1 -0
- data/spec/dummy/tmp/pids/server.pid +1 -0
- data/spec/rails_helper.rb +78 -0
- data/spec/rubame/server_spec.rb +113 -0
- data/spec/spec_helper.rb +99 -0
- metadata +414 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 15f7d10ed9788e61ebd810c34eeb3d67bf63ef9c
|
4
|
+
data.tar.gz: 6396f3d2703750b5026fd5e560b2b0ff9dd4265e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 99e21f6996bf87be7d1db17b57ecc6e9349403953ab039c85ed7dd73814f183163c104d71bb603518fdd88dedfce99114853f64f9020da06e14bdeef361bb110
|
7
|
+
data.tar.gz: 5c8b6fb0b2a96475dd74d278e513eeb548d55553eabdd477cd9dca47036a90a35916860c6aa6b0f0149f3a0ee11bf3084b0d4d053a3c873c8e37846dfc0f6f00
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Patrice Lebel
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'FlammarionRails'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
require 'bundler/gem_tasks'
|
26
|
+
|
File without changes
|
data/config/routes.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module Flammarion
|
2
|
+
class Engraving
|
3
|
+
include Revelator
|
4
|
+
|
5
|
+
attr_accessor :on_disconnect, :on_connect, :sockets
|
6
|
+
|
7
|
+
# Creates a new Engraving (i.e., a new display window)
|
8
|
+
# @option options [Proc] :on_connect Called when the display window is
|
9
|
+
# connected (i.e., displayed)
|
10
|
+
# @option options [Proc] :on_disconnect Called when the display windows is
|
11
|
+
# disconnected (i.e., closed)
|
12
|
+
# @option options [Boolean] :exit_on_disconnect (false) Will call +exit+
|
13
|
+
# when the widow is closed if this option is true.
|
14
|
+
# @option options [Boolean] :close_on_exit (false) Will close the window
|
15
|
+
# when the process exits if this is true. Otherwise, it will just stay
|
16
|
+
# around, but not actually be interactive.
|
17
|
+
# @raise {SetupError} if neither chrome is set up correctly and
|
18
|
+
# and Flammarion is unable to display the engraving.
|
19
|
+
def initialize(**options)
|
20
|
+
@chrome = OpenStruct.new
|
21
|
+
@sockets = []
|
22
|
+
@on_connect = options[:on_connect]
|
23
|
+
@on_disconnect = options[:on_disconnect]
|
24
|
+
@exit_on_disconnect = options.fetch(:exit_on_disconnect, false)
|
25
|
+
|
26
|
+
start_server
|
27
|
+
@window_id = @@server.register_window(self)
|
28
|
+
open_a_window(options) unless options[:no_window]
|
29
|
+
wait_for_a_connection unless options[:no_wait]
|
30
|
+
|
31
|
+
at_exit {close if window_open?} if options.fetch(:close_on_exit, true)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Blocks the current thread until the window has been closed. All user
|
35
|
+
# interactions and callbacks will continue in other threads.
|
36
|
+
def wait_until_closed
|
37
|
+
sleep 1 until @sockets.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Is this Engraving displayed on the screen.
|
41
|
+
def window_open?
|
42
|
+
!@sockets.empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
def disconnect(ws)
|
46
|
+
@sockets.delete ws
|
47
|
+
exit 0 if @exit_on_disconnect
|
48
|
+
@on_disconnect.call if @on_disconnect
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_message(msg)
|
52
|
+
result = dispatch(JSON.parse(msg).with_indifferent_access)
|
53
|
+
|
54
|
+
send_json(document: result.last.body)
|
55
|
+
|
56
|
+
rescue JSON::ParserError
|
57
|
+
Rails.logger.debug "Invalid JSON String #{msg}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def dispatch(params)
|
61
|
+
http_method = params.delete(:method) || :get
|
62
|
+
mapping = Rails.application.routes.recognize_path(params.delete(:url), method: http_method, **params)
|
63
|
+
|
64
|
+
unless mapping.key?(:controller)
|
65
|
+
Rails.logger.debug "Path not found"
|
66
|
+
return ActionDispatch::Request::PASS_NOT_FOUND
|
67
|
+
end
|
68
|
+
|
69
|
+
controller_name = "#{mapping[:controller].underscore.camelize}Controller"
|
70
|
+
controller = ActiveSupport::Dependencies.constantize(controller_name)
|
71
|
+
action = mapping[:action] || 'index'
|
72
|
+
request = ActionDispatch::Request.new('rack.input' => '', 'REQUEST_METHOD' => http_method.to_s.upcase!)
|
73
|
+
response = controller.make_response! request
|
74
|
+
|
75
|
+
controller.dispatch(action, request, response)
|
76
|
+
end
|
77
|
+
|
78
|
+
def start_server
|
79
|
+
@@server ||= Server.new
|
80
|
+
end
|
81
|
+
|
82
|
+
def server
|
83
|
+
@@server
|
84
|
+
end
|
85
|
+
|
86
|
+
def send_json(val)
|
87
|
+
if @sockets.empty?
|
88
|
+
open_a_window
|
89
|
+
wait_for_a_connection
|
90
|
+
end
|
91
|
+
@sockets.each{ |ws| ws.send val.to_json }
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Flammarion
|
2
|
+
class SetupError < StandardError; end
|
3
|
+
|
4
|
+
module Revelator
|
5
|
+
CHROME_PATH = ENV["FLAMMARION_REVELATOR_PATH"] || 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
|
6
|
+
|
7
|
+
def open_a_window(**options)
|
8
|
+
index_path = FlammarionRails::Engine.root.join('public', 'index.html')
|
9
|
+
index_path = `cygpath -w '#{index_path}'`.strip if RbConfig::CONFIG["host_os"] == "cygwin"
|
10
|
+
|
11
|
+
url = "file://#{index_path}?" + { port: server.port, path: @window_id, boot: FlammarionRails.config.boot_path }.to_query
|
12
|
+
@browser_options = options.merge(url: url)
|
13
|
+
@requested_browser = ENV["FLAMMARION_BROWSER"] || options[:browser]
|
14
|
+
|
15
|
+
@browser = @@browsers.find do |browser|
|
16
|
+
next if @requested_browser and browser.name.to_s != @requested_browser
|
17
|
+
begin
|
18
|
+
send(browser.name, @browser_options)
|
19
|
+
rescue Exception
|
20
|
+
next
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
raise SetupError.new("You must have google-chrome installed and accesible via your path.") unless @browser
|
25
|
+
end
|
26
|
+
|
27
|
+
def wait_for_a_connection
|
28
|
+
Timeout.timeout(20) { sleep 0.5 while @sockets.empty? }
|
29
|
+
rescue Timeout::Error
|
30
|
+
raise SetupError.new("Timed out while waiting for a connecting using #{@browser.name}.")
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
@@browsers = []
|
36
|
+
|
37
|
+
def self.browser(name, &block)
|
38
|
+
@@browsers << OpenStruct.new(name: name, method:define_method(name, block))
|
39
|
+
end
|
40
|
+
|
41
|
+
browser :osx do |options|
|
42
|
+
return false unless RbConfig::CONFIG["host_os"] =~ /darwin|mac os/
|
43
|
+
executable = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
44
|
+
@chrome.in, @chrome.out, @chrome.err, @chrome.thread = Open3.popen3("'#{executable}' --app='#{options[:url]}'")
|
45
|
+
true if @chrome.in
|
46
|
+
end
|
47
|
+
|
48
|
+
browser :chrome_windows do |options|
|
49
|
+
return false unless RbConfig::CONFIG["host_os"] =~ /cygwin|mswin|mingw/
|
50
|
+
file_path = File.absolute_path(File.join(File.dirname(__FILE__), ".."))
|
51
|
+
file_path = `cygpath -w '#{file_path}'`.strip if RbConfig::CONFIG["host_os"] == "cygwin"
|
52
|
+
resource = %[file\://#{file_path}/html/build/index.html]
|
53
|
+
resource = "http://localhost:4567/" if options[:development_mode]
|
54
|
+
chrome_path = CHROME_PATH
|
55
|
+
chrome_path = `cygpath -u '#{CHROME_PATH}'`.strip if RbConfig::CONFIG["host_os"] == "cygwin"
|
56
|
+
return false unless File.exist?(chrome_path)
|
57
|
+
Process.detach(spawn(chrome_path, %[--app=#{resource}?path=#{@window_id}&port=#{server.port}]))
|
58
|
+
end
|
59
|
+
|
60
|
+
browser :chrome do |options|
|
61
|
+
%w[google-chrome google-chrome-stable chromium chromium-browser chrome].each do |executable|
|
62
|
+
next unless which(executable)
|
63
|
+
@chrome.in, @chrome.out, @chrome.err, @chrome.thread = Open3.popen3("#{executable} --app='#{options[:url]}'")
|
64
|
+
return true if @chrome.in
|
65
|
+
end
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
browser :www do |options|
|
70
|
+
# Last ditch effort to display something
|
71
|
+
Launchy.open(options[:url].gsub(/\s/, "%20")) do |error|
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
def which(cmd)
|
78
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
79
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
80
|
+
exts.each do |ext|
|
81
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
82
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Flammarion
|
2
|
+
class Server
|
3
|
+
attr_accessor :port
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@windows = {}
|
7
|
+
@socket_paths = {}
|
8
|
+
@started = false
|
9
|
+
@launch_thread = Thread.current
|
10
|
+
@server_thread = Thread.new do
|
11
|
+
begin
|
12
|
+
start_server_internal
|
13
|
+
rescue StandardError => e
|
14
|
+
handle_exception(e)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
sleep 0.5 until @started
|
18
|
+
end
|
19
|
+
|
20
|
+
def start_server_internal
|
21
|
+
self.port =
|
22
|
+
if Gem.win_platform?
|
23
|
+
rand(65000 - 1024) + 1024
|
24
|
+
else
|
25
|
+
7870
|
26
|
+
end
|
27
|
+
begin
|
28
|
+
@server = Rubame::Server.new("0.0.0.0", port)
|
29
|
+
loop do
|
30
|
+
@started = true
|
31
|
+
@server.run do |ws|
|
32
|
+
ws.onopen {
|
33
|
+
log "Connection open"
|
34
|
+
if @windows.include?(ws.handshake.path)
|
35
|
+
@windows[ws.handshake.path].sockets << ws
|
36
|
+
@windows[ws.handshake.path].on_connect.call if @windows[ws.handshake.path].on_connect
|
37
|
+
@socket_paths[ws] = ws.handshake.path
|
38
|
+
else
|
39
|
+
log "No such window: #{handshake.path}"
|
40
|
+
end
|
41
|
+
}
|
42
|
+
|
43
|
+
ws.onclose do
|
44
|
+
log "Connection closed"
|
45
|
+
@windows[@socket_paths[ws]].disconnect(ws) if @windows[@socket_paths[ws]]
|
46
|
+
end
|
47
|
+
|
48
|
+
ws.onmessage { |msg|
|
49
|
+
Thread.new do
|
50
|
+
begin
|
51
|
+
@windows[@socket_paths[ws]].process_message(msg)
|
52
|
+
rescue StandardError => e
|
53
|
+
handle_exception(e)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
rescue RuntimeError, Errno::EADDRINUSE => e
|
60
|
+
if e.message == "no acceptor (port is in use or requires root privileges)" || e.is_a?(Errno::EADDRINUSE)
|
61
|
+
self.port = rand(65000 - 1024) + 1024
|
62
|
+
retry
|
63
|
+
else
|
64
|
+
raise
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@started = true
|
68
|
+
end
|
69
|
+
|
70
|
+
def stop
|
71
|
+
end
|
72
|
+
|
73
|
+
def log(str)
|
74
|
+
Rails.logger.debug str
|
75
|
+
end
|
76
|
+
|
77
|
+
def handle_exception(e)
|
78
|
+
@launch_thread.raise(e)
|
79
|
+
end
|
80
|
+
|
81
|
+
def register_window(window)
|
82
|
+
@new_path ||= 0
|
83
|
+
@new_path += 1
|
84
|
+
@windows["/w#{@new_path}"] = window
|
85
|
+
"w#{@new_path}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module FlammarionRails
|
2
|
+
@@config = nil
|
3
|
+
|
4
|
+
def self.configure
|
5
|
+
@@config ||= Configuration.new
|
6
|
+
|
7
|
+
if block_given?
|
8
|
+
yield config
|
9
|
+
end
|
10
|
+
|
11
|
+
config
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.config
|
15
|
+
@@config || configure
|
16
|
+
end
|
17
|
+
|
18
|
+
class Configuration
|
19
|
+
attr_accessor :boot_path
|
20
|
+
|
21
|
+
def boot_path
|
22
|
+
@boot_path ||= '/'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "flammarion_rails/configuration"
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
require "rubame/server"
|
5
|
+
require "flammarion/server"
|
6
|
+
require "flammarion/revelator"
|
7
|
+
require "flammarion/engraving"
|
8
|
+
|
9
|
+
module FlammarionRails
|
10
|
+
class Engine < ::Rails::Engine
|
11
|
+
# Initialize engine dependencies on wrapper application
|
12
|
+
Gem.loaded_specs["flammarion_rails"].dependencies.each do |d|
|
13
|
+
begin
|
14
|
+
require d.name
|
15
|
+
rescue LoadError => e
|
16
|
+
# Put exceptions here.
|
17
|
+
end
|
18
|
+
end
|
19
|
+
# Uncomment if migrations need to be shared
|
20
|
+
# initializer :append_migrations do |app|
|
21
|
+
# unless app.root.to_s.match root.to_s
|
22
|
+
# config.paths["db/migrate"].expanded.each do |expanded_path|
|
23
|
+
# app.config.paths["db/migrate"] << expanded_path
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module Rubame
|
2
|
+
class Server
|
3
|
+
def initialize(host, port)
|
4
|
+
Socket.do_not_reverse_lookup
|
5
|
+
@hostname = host
|
6
|
+
@port = port
|
7
|
+
|
8
|
+
@reading = []
|
9
|
+
@writing = []
|
10
|
+
|
11
|
+
@clients = {} # Socket as key, and Client as value
|
12
|
+
|
13
|
+
@socket = TCPServer.new(@hostname, @port)
|
14
|
+
@reading.push @socket
|
15
|
+
end
|
16
|
+
|
17
|
+
def accept
|
18
|
+
socket = @socket.accept_nonblock
|
19
|
+
@reading.push socket
|
20
|
+
handshake = WebSocket::Handshake::Server.new
|
21
|
+
client = Rubame::Client.new(socket, handshake, self)
|
22
|
+
|
23
|
+
while (line = socket.gets)
|
24
|
+
client.handshake << line
|
25
|
+
break if client.handshake.finished?
|
26
|
+
end
|
27
|
+
|
28
|
+
if client.handshake.valid?
|
29
|
+
@clients[socket] = client
|
30
|
+
client.write handshake.to_s
|
31
|
+
client.opened = true
|
32
|
+
return client
|
33
|
+
else
|
34
|
+
close(client)
|
35
|
+
end
|
36
|
+
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def read(client)
|
41
|
+
pairs = client.socket.recvfrom(2000)
|
42
|
+
messages = []
|
43
|
+
|
44
|
+
if pairs[0].length == 0
|
45
|
+
close(client)
|
46
|
+
else
|
47
|
+
client.frame << pairs[0]
|
48
|
+
|
49
|
+
while (f = client.frame.next)
|
50
|
+
if f.type == :close
|
51
|
+
close(client)
|
52
|
+
return messages
|
53
|
+
else
|
54
|
+
messages.push f
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
messages
|
60
|
+
end
|
61
|
+
|
62
|
+
def close(client)
|
63
|
+
@reading.delete client.socket
|
64
|
+
@clients.delete client.socket
|
65
|
+
begin
|
66
|
+
client.socket.close
|
67
|
+
rescue
|
68
|
+
# do nothing
|
69
|
+
end
|
70
|
+
client.closed = true
|
71
|
+
end
|
72
|
+
|
73
|
+
def run(&blk)
|
74
|
+
readable, _writable = IO.select(@reading, @writing)
|
75
|
+
|
76
|
+
if readable
|
77
|
+
readable.each do |socket|
|
78
|
+
client = @clients[socket]
|
79
|
+
if socket == @socket
|
80
|
+
client = accept
|
81
|
+
else
|
82
|
+
msg = read(client)
|
83
|
+
client.messaged = msg
|
84
|
+
end
|
85
|
+
|
86
|
+
blk.call(client) if client && blk
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop
|
92
|
+
@socket.close
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Client
|
97
|
+
attr_accessor :socket, :handshake, :frame, :opened, :messaged, :closed
|
98
|
+
|
99
|
+
def initialize(socket, handshake, server)
|
100
|
+
@socket = socket
|
101
|
+
@handshake = handshake
|
102
|
+
@frame = WebSocket::Frame::Incoming::Server.new(version: @handshake.version)
|
103
|
+
@opened = false
|
104
|
+
@messaged = []
|
105
|
+
@closed = false
|
106
|
+
@server = server
|
107
|
+
end
|
108
|
+
|
109
|
+
def write(data)
|
110
|
+
@socket.write data
|
111
|
+
end
|
112
|
+
|
113
|
+
def send(data)
|
114
|
+
frame = WebSocket::Frame::Outgoing::Server.new(version: @handshake.version, data: data, type: :text)
|
115
|
+
begin
|
116
|
+
@socket.write frame
|
117
|
+
@socket.flush
|
118
|
+
rescue
|
119
|
+
@server.close(self) unless @closed
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def onopen(&blk)
|
124
|
+
if @opened
|
125
|
+
begin
|
126
|
+
blk.call
|
127
|
+
ensure
|
128
|
+
@opened = false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def onmessage(&blk)
|
134
|
+
if @messaged.size > 0
|
135
|
+
begin
|
136
|
+
@messaged.each do |x|
|
137
|
+
blk.call(x.to_s)
|
138
|
+
end
|
139
|
+
ensure
|
140
|
+
@messaged = []
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def onclose(&blk)
|
146
|
+
if @closed
|
147
|
+
begin
|
148
|
+
blk.call
|
149
|
+
ensure
|
150
|
+
# do nothing
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
if __FILE__==$0
|
158
|
+
server = Rubame::Server.new("0.0.0.0", 25222)
|
159
|
+
while !$quit
|
160
|
+
server.run do |client|
|
161
|
+
client.onopen do
|
162
|
+
puts "Server reports: client open"
|
163
|
+
end
|
164
|
+
client.onmessage do |mess|
|
165
|
+
puts "Server reports: message received: #{mess}"
|
166
|
+
end
|
167
|
+
client.onclose do
|
168
|
+
puts "Server reports: client closed"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|