async-websocket 0.4.1 → 0.5.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/.editorconfig +4 -0
- data/.travis.yml +5 -5
- data/README.md +1 -1
- data/async-websocket.gemspec +2 -2
- data/examples/chat/client.rb +6 -6
- data/examples/middleware/client.rb +45 -0
- data/examples/middleware/config.ru +77 -0
- data/examples/utopia/.bowerrc +4 -0
- data/examples/utopia/.gitignore +9 -0
- data/examples/utopia/.rspec +4 -0
- data/examples/utopia/Gemfile +35 -0
- data/examples/utopia/Guardfile +29 -0
- data/examples/utopia/README.md +16 -0
- data/examples/utopia/Rakefile +8 -0
- data/examples/utopia/config.ru +47 -0
- data/examples/utopia/config/README.md +7 -0
- data/examples/utopia/config/environment.rb +8 -0
- data/examples/utopia/lib/readme.txt +1 -0
- data/examples/utopia/pages/_heading.xnode +2 -0
- data/examples/utopia/pages/_page.xnode +30 -0
- data/examples/utopia/pages/client/client.js +28 -0
- data/examples/utopia/pages/client/controller.rb +0 -0
- data/examples/utopia/pages/client/index.xnode +8 -0
- data/examples/utopia/pages/errors/exception.xnode +5 -0
- data/examples/utopia/pages/errors/file-not-found.xnode +5 -0
- data/examples/utopia/pages/links.yaml +2 -0
- data/examples/utopia/pages/server/controller.rb +21 -0
- data/examples/utopia/public/_static/icon.png +0 -0
- data/examples/utopia/public/_static/site.css +205 -0
- data/examples/utopia/public/_static/utopia-background.svg +1 -0
- data/examples/utopia/public/_static/utopia.svg +1 -0
- data/examples/utopia/public/readme.txt +1 -0
- data/examples/utopia/spec/spec_helper.rb +31 -0
- data/examples/utopia/spec/website_context.rb +11 -0
- data/examples/utopia/spec/website_spec.rb +56 -0
- data/examples/utopia/tasks/bower.rake +45 -0
- data/examples/utopia/tasks/deploy.rake +13 -0
- data/examples/utopia/tasks/development.rake +34 -0
- data/examples/utopia/tasks/environment.rake +17 -0
- data/examples/utopia/tasks/log.rake +17 -0
- data/examples/utopia/tasks/static.rake +43 -0
- data/lib/async/websocket.rb +2 -0
- data/lib/async/websocket/connection.rb +11 -1
- data/lib/async/websocket/version.rb +1 -1
- metadata +51 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c110468d58034b4bbdd08e4d39482bf24cf99207dba5f5fa478251c8751f3dbe
|
4
|
+
data.tar.gz: cd992b36fb505345834c51ae31523e35e9058d846bd1b4a85ddf43143eebc17a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36c2509873572672d504f0de96785840b52d3993b3cc7febca16d9f08ed85f7e3e73c4995380aea74de3a2d431f4db772ed4c1b4bc268c698fea7ecf7445cf01
|
7
|
+
data.tar.gz: d226a93fa0f972789b5e1f9d842fe0ec1dcffefff3b846b2e977555fc29cafa23ffe2c20782f28d39dbdea6d67bccce5fc00120e0829fe0876019f08963c39ba
|
data/.editorconfig
ADDED
data/.travis.yml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
language: ruby
|
2
|
-
sudo: false
|
3
|
-
dist: trusty
|
4
2
|
cache: bundler
|
5
3
|
|
4
|
+
before_script:
|
5
|
+
- gem update --system
|
6
|
+
- gem install bundler
|
7
|
+
|
6
8
|
matrix:
|
7
9
|
include:
|
8
|
-
- rvm: 2.0
|
9
|
-
- rvm: 2.1
|
10
|
-
- rvm: 2.2
|
11
10
|
- rvm: 2.3
|
12
11
|
- rvm: 2.4
|
12
|
+
- rvm: 2.5
|
13
13
|
- rvm: jruby-head
|
14
14
|
env: JRUBY_OPTS="--debug -X+O"
|
15
15
|
- rvm: ruby-head
|
data/README.md
CHANGED
@@ -46,7 +46,7 @@ run lambda {|env|
|
|
46
46
|
}
|
47
47
|
```
|
48
48
|
|
49
|
-
And [here is a client program](
|
49
|
+
And [here is a client program](examples/chat/client.rb) which can read input from `stdin` and send messages to the server.
|
50
50
|
|
51
51
|
## Contributing
|
52
52
|
|
data/async-websocket.gemspec
CHANGED
@@ -20,9 +20,9 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.add_dependency "async-io"
|
21
21
|
|
22
22
|
spec.add_development_dependency "async-rspec"
|
23
|
-
|
23
|
+
spec.add_development_dependency "falcon", "~> 0.15.0"
|
24
|
+
|
24
25
|
spec.add_development_dependency "bundler", "~> 1.6"
|
25
26
|
spec.add_development_dependency "rspec", "~> 3.6"
|
26
27
|
spec.add_development_dependency "rake"
|
27
|
-
spec.add_development_dependency "falcon"
|
28
28
|
end
|
data/examples/chat/client.rb
CHANGED
@@ -5,10 +5,14 @@ require 'async/io/stream'
|
|
5
5
|
require 'async/http/url_endpoint'
|
6
6
|
require 'async/websocket/client'
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
USER = ARGV.pop || "anonymous"
|
9
|
+
URL = ARGV.pop || "ws://localhost:9292"
|
10
10
|
|
11
11
|
Async::Reactor.run do |task|
|
12
|
+
stdin = Async::IO::Stream.new(
|
13
|
+
Async::IO::Generic.new($stdin)
|
14
|
+
)
|
15
|
+
|
12
16
|
endpoint = Async::HTTP::URLEndpoint.parse(URL)
|
13
17
|
|
14
18
|
endpoint.connect do |socket|
|
@@ -20,10 +24,6 @@ Async::Reactor.run do |task|
|
|
20
24
|
})
|
21
25
|
|
22
26
|
task.async do
|
23
|
-
stdin = Async::IO::Stream.new(
|
24
|
-
Async::IO::Generic.new($stdin)
|
25
|
-
)
|
26
|
-
|
27
27
|
puts "Waiting for input..."
|
28
28
|
while line = stdin.read_until("\n")
|
29
29
|
puts "Sending text: #{line}"
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'async/reactor'
|
4
|
+
require 'async/io/stream'
|
5
|
+
require 'async/http/url_endpoint'
|
6
|
+
require 'async/websocket/client'
|
7
|
+
|
8
|
+
USER = ARGV.pop || "anonymous"
|
9
|
+
URL = ARGV.pop || "ws://localhost:9292"
|
10
|
+
|
11
|
+
Async::Reactor.run do |task|
|
12
|
+
stdin = Async::IO::Stream.new(
|
13
|
+
Async::IO::Generic.new($stdin)
|
14
|
+
)
|
15
|
+
|
16
|
+
endpoint = Async::HTTP::URLEndpoint.parse(URL)
|
17
|
+
|
18
|
+
endpoint.connect do |socket|
|
19
|
+
connection = Async::WebSocket::Client.new(socket, URL)
|
20
|
+
|
21
|
+
connection.send_message({
|
22
|
+
user: USER,
|
23
|
+
status: "connected",
|
24
|
+
})
|
25
|
+
|
26
|
+
task.async do
|
27
|
+
puts "Waiting for input..."
|
28
|
+
begin
|
29
|
+
while line = stdin.read_until("\n")
|
30
|
+
puts "Sending text: #{line}"
|
31
|
+
connection.send_message({
|
32
|
+
user: USER,
|
33
|
+
text: line,
|
34
|
+
})
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
puts "Client error: #{$!}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
while message = connection.next_message
|
42
|
+
puts "From server: #{message.inspect}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env falcon --verbose serve --concurrency 1 -c
|
2
|
+
|
3
|
+
require 'async/websocket/server'
|
4
|
+
|
5
|
+
Async.logger.level = Logger::DEBUG
|
6
|
+
|
7
|
+
class RackUpgrade
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
if ::WebSocket::Driver.websocket?(env)
|
14
|
+
env['rack.upgrade?'] = :websocket
|
15
|
+
|
16
|
+
response = @app.call(env)
|
17
|
+
|
18
|
+
if handler = env['rack.upgrade']
|
19
|
+
Async::WebSocket::Server.open(env) do |connection|
|
20
|
+
begin
|
21
|
+
while event = connection.next_event
|
22
|
+
if event.is_a? ::WebSocket::Driver::OpenEvent
|
23
|
+
handler.on_open(connection) if handler.respond_to? :on_open
|
24
|
+
elsif event.is_a? ::WebSocket::Driver::MessageEvent
|
25
|
+
handler.on_message(connection, JSON.parse(event.data))
|
26
|
+
elsif event.is_a? ::WebSocket::Driver::CloseEvent
|
27
|
+
handler.on_close(connection) if handler.respond_to? :on_close
|
28
|
+
end
|
29
|
+
end
|
30
|
+
ensure
|
31
|
+
handler.on_shutdown(connection) if handler.respond_to? :on_shutdown
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
return @app.call(env)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Chatty
|
42
|
+
def initialize
|
43
|
+
@connections = Set.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_open(connection)
|
47
|
+
Async.logger.info(self) {"on_open: #{connection}"}
|
48
|
+
@connections << connection
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_message(connection, message)
|
52
|
+
Async.logger.info(self) {"on_message: #{connection} -> #{message}"}
|
53
|
+
|
54
|
+
@connections.each do |connection|
|
55
|
+
connection.send_message(message)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_shutdown(connection)
|
60
|
+
Async.logger.info(self) {"on_shutdown: #{connection}"}
|
61
|
+
@connections.delete(connection)
|
62
|
+
|
63
|
+
@connections.each do |connection|
|
64
|
+
connection.send_message(message)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
use RackUpgrade
|
70
|
+
|
71
|
+
CHATTY = Chatty.new
|
72
|
+
|
73
|
+
run lambda {|env|
|
74
|
+
env['rack.upgrade'] = CHATTY
|
75
|
+
|
76
|
+
return [200, {}, []]
|
77
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
source "https://rubygems.org"
|
3
|
+
|
4
|
+
gem "utopia", "~> 2.3.0"
|
5
|
+
# gem "utopia-gallery"
|
6
|
+
# gem "utopia-analytics"
|
7
|
+
|
8
|
+
gem "rake"
|
9
|
+
gem "bundler"
|
10
|
+
|
11
|
+
gem 'async-websocket'
|
12
|
+
|
13
|
+
gem "rack-freeze", "~> 1.2"
|
14
|
+
|
15
|
+
group :development do
|
16
|
+
# For `rake server`:
|
17
|
+
gem "guard-falcon", require: false
|
18
|
+
gem 'guard-rspec', require: false
|
19
|
+
|
20
|
+
# For `rake console`:
|
21
|
+
gem "pry"
|
22
|
+
gem "rack-test"
|
23
|
+
|
24
|
+
# For `rspec` testing:
|
25
|
+
gem "rspec"
|
26
|
+
gem "simplecov"
|
27
|
+
|
28
|
+
# For testing:
|
29
|
+
gem 'async-rspec'
|
30
|
+
end
|
31
|
+
|
32
|
+
group :production do
|
33
|
+
# Used for passenger-config to restart server after deployment:
|
34
|
+
gem "passenger"
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
group :development do
|
3
|
+
guard :falcon, port: 9292 do
|
4
|
+
watch('Gemfile.lock')
|
5
|
+
watch('config.ru')
|
6
|
+
watch(%r{^config|lib|pages/.*})
|
7
|
+
|
8
|
+
notification :off
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
group :test do
|
13
|
+
guard :rspec, cmd: 'rspec' do
|
14
|
+
# Notifications can get a bit tedious:
|
15
|
+
# notification :off
|
16
|
+
|
17
|
+
# Re-run specs if they are changed:
|
18
|
+
watch(%r{^spec/.+_spec\.rb$})
|
19
|
+
watch('spec/spec_helper.rb') {'spec'}
|
20
|
+
|
21
|
+
# Run relevent specs if files in `lib/` or `pages/` are changed:
|
22
|
+
watch(%r{^lib/(.+)\.rb$}) {|match| "spec/lib/#{match[1]}_spec.rb" }
|
23
|
+
watch(%r{^pages/(.+)\.(rb|xnode)$}) {|match| "spec/pages/#{match[1]}_spec.rb"}
|
24
|
+
watch(%r{^pages/(.+)controller\.rb$}) {|match| Dir.glob("spec/pages/#{match[1]}*_spec.rb")}
|
25
|
+
|
26
|
+
# If any files in pages changes, ensure the website still works:
|
27
|
+
watch(%r{^pages/.*}) {'spec/website_spec.rb'}
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Example WebSocket Chat Server
|
2
|
+
|
3
|
+
This is a simple chat client/server implementation with specs.
|
4
|
+
|
5
|
+
## Starting Development Server
|
6
|
+
|
7
|
+
To start the development server, simply execute
|
8
|
+
|
9
|
+
> rake
|
10
|
+
Generating transient session key for development...
|
11
|
+
20:57:36 - INFO - Starting Falcon HTTP server on localhost:9292
|
12
|
+
20:57:36 - INFO - Guard::RSpec is running
|
13
|
+
20:57:36 - INFO - Guard is now watching at '...'
|
14
|
+
[1] guard(main)>
|
15
|
+
|
16
|
+
Then browse http://localhost:9292 (or as specified) to see your new site.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env rackup
|
2
|
+
|
3
|
+
require_relative 'config/environment'
|
4
|
+
|
5
|
+
require 'rack/freeze'
|
6
|
+
|
7
|
+
if RACK_ENV == :production
|
8
|
+
# Handle exceptions in production with a error page and send an email notification:
|
9
|
+
use Utopia::Exceptions::Handler
|
10
|
+
use Utopia::Exceptions::Mailer
|
11
|
+
else
|
12
|
+
# We want to propate exceptions up when running tests:
|
13
|
+
use Rack::ShowExceptions unless RACK_ENV == :test
|
14
|
+
|
15
|
+
# Serve the public directory in a similar way to the web server:
|
16
|
+
use Utopia::Static, root: 'public'
|
17
|
+
end
|
18
|
+
|
19
|
+
use Rack::Sendfile
|
20
|
+
|
21
|
+
use Utopia::ContentLength
|
22
|
+
|
23
|
+
use Utopia::Redirection::Rewrite,
|
24
|
+
'/' => '/client/index'
|
25
|
+
|
26
|
+
use Utopia::Redirection::DirectoryIndex
|
27
|
+
|
28
|
+
use Utopia::Redirection::Errors,
|
29
|
+
404 => '/errors/file-not-found'
|
30
|
+
|
31
|
+
use Utopia::Localization,
|
32
|
+
:default_locale => 'en',
|
33
|
+
:locales => ['en', 'de', 'ja', 'zh']
|
34
|
+
|
35
|
+
require 'utopia/session'
|
36
|
+
use Utopia::Session,
|
37
|
+
:expires_after => 3600 * 24,
|
38
|
+
:secret => ENV['UTOPIA_SESSION_SECRET']
|
39
|
+
|
40
|
+
use Utopia::Controller
|
41
|
+
|
42
|
+
use Utopia::Static
|
43
|
+
|
44
|
+
# Serve dynamic content
|
45
|
+
use Utopia::Content
|
46
|
+
|
47
|
+
run lambda { |env| [404, {}, []] }
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Utopia Config
|
2
|
+
|
3
|
+
This directory contains `environment.rb` which is used to initialize the running environment for tasks and servers.
|
4
|
+
|
5
|
+
## Setting Environment Variables
|
6
|
+
|
7
|
+
If you wish to set environment variables on a per-deployment basis, you can do so by creating an `config/environment.yaml` and populating it with key-value pairs.
|
@@ -0,0 +1 @@
|
|
1
|
+
You can add additional code for your application in this directory, and require it directly from the config.ru.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<?r response.cache! ?>
|
5
|
+
|
6
|
+
<?r if title = self[:title] ?>
|
7
|
+
<title>#{title.gsub(/<.*?>/, "")} - Utopia</title>
|
8
|
+
<?r else ?>
|
9
|
+
<title>Utopia</title>
|
10
|
+
<?r end ?>
|
11
|
+
|
12
|
+
<base href="#{first.node.uri_path}"/>
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
14
|
+
|
15
|
+
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" />
|
16
|
+
|
17
|
+
<link rel="icon" type="image/png" href="/_static/icon.png" />
|
18
|
+
<link rel="stylesheet" href="/_static/site.css" type="text/css" media="screen" />
|
19
|
+
</head>
|
20
|
+
|
21
|
+
<body class="#{attributes[:class]}">
|
22
|
+
<header>
|
23
|
+
<img src="/_static/utopia.svg" />
|
24
|
+
</header>
|
25
|
+
|
26
|
+
<div id="page">
|
27
|
+
<utopia:content/>
|
28
|
+
</div>
|
29
|
+
</body>
|
30
|
+
</html>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
var url = new URL('/server/connect', window.location.href);
|
3
|
+
url.protocol = url.protocol.replace('http', 'ws');
|
4
|
+
|
5
|
+
console.log("Connecting to server", url);
|
6
|
+
var server = new WebSocket(url.href);
|
7
|
+
console.log("Connected to", server);
|
8
|
+
|
9
|
+
server.onopen = function(event) {
|
10
|
+
chat.onkeypress = function(event) {
|
11
|
+
if (event.keyCode == 13) {
|
12
|
+
server.send(JSON.stringify({text: chat.value}));
|
13
|
+
|
14
|
+
chat.value = "";
|
15
|
+
}
|
16
|
+
}
|
17
|
+
};
|
18
|
+
|
19
|
+
server.onmessage = function(event) {
|
20
|
+
console.log("Got message", event);
|
21
|
+
|
22
|
+
var message = JSON.parse(event.data);
|
23
|
+
|
24
|
+
var pre = document.createElement('pre');
|
25
|
+
pre.innerText = message.text;
|
26
|
+
|
27
|
+
response.appendChild(pre);
|
28
|
+
};
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
prepend Actions
|
3
|
+
|
4
|
+
require 'async/websocket/server'
|
5
|
+
|
6
|
+
$connections = []
|
7
|
+
|
8
|
+
on 'connect' do |request|
|
9
|
+
Async::WebSocket::Server.open(request.env) do |connection|
|
10
|
+
$connections << connection
|
11
|
+
|
12
|
+
while message = connection.next_message
|
13
|
+
$connections.each do |connection|
|
14
|
+
puts "Server sending message: #{message.inspect}"
|
15
|
+
connection.send_message(message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
succeed!
|
21
|
+
end
|
Binary file
|
@@ -0,0 +1,205 @@
|
|
1
|
+
|
2
|
+
html {
|
3
|
+
font-family: "PT Sans", Verdana, Helvetica, Arial, sans-serif;
|
4
|
+
font-size: 16px;
|
5
|
+
}
|
6
|
+
|
7
|
+
pre {
|
8
|
+
tab-size: 2;
|
9
|
+
}
|
10
|
+
|
11
|
+
@media (min-width: 40em) {
|
12
|
+
html {
|
13
|
+
font-size: 18px;
|
14
|
+
}
|
15
|
+
|
16
|
+
pre {
|
17
|
+
tab-size: 4;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
@media (min-width: 80em) {
|
22
|
+
html {
|
23
|
+
font-size: 20px;
|
24
|
+
}
|
25
|
+
|
26
|
+
pre {
|
27
|
+
tab-size: 4;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
body {
|
32
|
+
padding: 0;
|
33
|
+
margin: 0;
|
34
|
+
|
35
|
+
background-color: #fafafa;
|
36
|
+
}
|
37
|
+
|
38
|
+
body > header {
|
39
|
+
margin: 1rem 0 1rem 0;
|
40
|
+
|
41
|
+
background-color: white;
|
42
|
+
|
43
|
+
background-image: url(utopia-background.svg);
|
44
|
+
|
45
|
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
|
46
|
+
}
|
47
|
+
|
48
|
+
body > header img {
|
49
|
+
display: block;
|
50
|
+
margin: auto;
|
51
|
+
height: 4rem;
|
52
|
+
}
|
53
|
+
|
54
|
+
p, ul, ol {
|
55
|
+
color: #555;
|
56
|
+
}
|
57
|
+
|
58
|
+
p strong {
|
59
|
+
color: #222;
|
60
|
+
}
|
61
|
+
|
62
|
+
h1, h2, h3, h4, h5, h6 {
|
63
|
+
margin: 2rem 1rem 1rem 1rem;
|
64
|
+
color: #4E8DD9;
|
65
|
+
}
|
66
|
+
|
67
|
+
h1 {
|
68
|
+
margin-bottom: 4rem;
|
69
|
+
}
|
70
|
+
|
71
|
+
h2 {
|
72
|
+
margin-top: 6rem;
|
73
|
+
}
|
74
|
+
|
75
|
+
img {
|
76
|
+
border: none;
|
77
|
+
}
|
78
|
+
|
79
|
+
a {
|
80
|
+
color: #33a;
|
81
|
+
}
|
82
|
+
|
83
|
+
a:hover {
|
84
|
+
color: #55c;
|
85
|
+
}
|
86
|
+
|
87
|
+
p, ul, ol, dl, h3 {
|
88
|
+
margin: 2rem;
|
89
|
+
}
|
90
|
+
|
91
|
+
li {
|
92
|
+
margin: 0.2rem;
|
93
|
+
}
|
94
|
+
|
95
|
+
li > ul, li > ol {
|
96
|
+
margin: 0;
|
97
|
+
}
|
98
|
+
|
99
|
+
pre {
|
100
|
+
overflow: auto;
|
101
|
+
|
102
|
+
padding: 1rem 2rem;
|
103
|
+
font-size: 0.8rem;
|
104
|
+
|
105
|
+
border-top: 1px solid #ccc;
|
106
|
+
border-bottom: 1px solid #ccc;
|
107
|
+
|
108
|
+
background-color: #eee;
|
109
|
+
}
|
110
|
+
|
111
|
+
h3 {
|
112
|
+
border-bottom: 1px solid #ccf;
|
113
|
+
}
|
114
|
+
|
115
|
+
ul {
|
116
|
+
margin-bottom: 1rem;
|
117
|
+
}
|
118
|
+
|
119
|
+
h2, h3, h4, h5, h6 {
|
120
|
+
font-weight: normal;
|
121
|
+
}
|
122
|
+
|
123
|
+
body.front h1 {
|
124
|
+
font-weight: normal;
|
125
|
+
font-size: 300%;
|
126
|
+
color: #F89432;
|
127
|
+
|
128
|
+
text-align: center;
|
129
|
+
}
|
130
|
+
|
131
|
+
footer {
|
132
|
+
text-align: right;
|
133
|
+
margin: 2rem;
|
134
|
+
font-size: 0.65rem;
|
135
|
+
color: #aaa;
|
136
|
+
}
|
137
|
+
|
138
|
+
nav {
|
139
|
+
position: absolute;
|
140
|
+
margin: 2.5rem;
|
141
|
+
font-size: 0.8rem;
|
142
|
+
color: #aaa;
|
143
|
+
}
|
144
|
+
|
145
|
+
section.features {
|
146
|
+
display: flex;
|
147
|
+
flex-wrap: wrap;
|
148
|
+
justify-content: space-around;
|
149
|
+
|
150
|
+
margin: 1rem;
|
151
|
+
}
|
152
|
+
|
153
|
+
section.features > div {
|
154
|
+
box-sizing: border-box;
|
155
|
+
|
156
|
+
flex-basis: 20rem;
|
157
|
+
flex-grow: 1;
|
158
|
+
|
159
|
+
color: #171e42;
|
160
|
+
margin: 1rem;
|
161
|
+
padding: 1rem;
|
162
|
+
|
163
|
+
padding-left: 3rem;
|
164
|
+
|
165
|
+
position: relative;
|
166
|
+
}
|
167
|
+
|
168
|
+
section.features > div i {
|
169
|
+
position: absolute;
|
170
|
+
left: 0rem;
|
171
|
+
|
172
|
+
font-size: 1.5rem;
|
173
|
+
text-align: center;
|
174
|
+
|
175
|
+
width: 3rem;
|
176
|
+
color: #fafafa;
|
177
|
+
text-shadow: 0px 0px 1px #000;
|
178
|
+
}
|
179
|
+
|
180
|
+
section.features p {
|
181
|
+
margin: 0;
|
182
|
+
maring-bottom: 1rem;
|
183
|
+
font-size: 80%;
|
184
|
+
}
|
185
|
+
|
186
|
+
section.features h2 {
|
187
|
+
margin: 0;
|
188
|
+
font-size: 1.1rem;
|
189
|
+
padding: 0;
|
190
|
+
}
|
191
|
+
|
192
|
+
form fieldset {
|
193
|
+
border: 0;
|
194
|
+
}
|
195
|
+
|
196
|
+
form fieldset textarea {
|
197
|
+
box-sizing: border-box;
|
198
|
+
|
199
|
+
width: 100%;
|
200
|
+
height: 10rem;
|
201
|
+
}
|
202
|
+
|
203
|
+
form fieldset.footer {
|
204
|
+
text-align: right;
|
205
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 10 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><rect x="0" y="0" width="10" height="56" style="fill:#f79433;"/><rect x="0" y="56" width="10" height="24" style="fill:#4e8dd8;"/></svg>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 420 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><g><rect x="0" y="0" width="420" height="56" style="fill:#f79433;"/><rect x="0" y="56" width="420" height="24" style="fill:#4e8dd8;"/><g><path d="M75.145,70.819c2.37,-3.097 4.173,-6.921 5.111,-11.365c0.91,-4.318 1.498,-9.261 1.498,-14.692l0,-44.762l-62.754,0l0,44.762c0,2.628 0.244,5.333 0.407,8.035c0.168,2.782 0.674,5.515 1.345,8.118c0.68,2.644 1.739,5.173 3.067,7.517c1.363,2.405 3.263,4.526 5.609,6.303c2.319,1.755 5.245,3.163 8.677,4.172c1.617,0.478 3.416,1.093 5.354,1.093l13.856,0c3.071,0 5.797,-1.058 8.131,-2.001c4.042,-1.631 7.305,-4.049 9.699,-7.18Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M151.481,18.701l0,-18.701l-62.754,-0.022l0,18.723l22.246,0l0.02,61.299l17.93,0l-0.02,-61.299l22.578,0Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M229.926,39.999c0,-22.051 -16.979,-39.992 -37.852,-39.992c-20.872,0 -37.851,17.942 -37.851,39.992c0,22.054 16.979,39.994 37.851,39.994c20.873,0 37.852,-17.94 37.852,-39.994Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M269.238,50.909c9.717,0 17.181,-2.066 22.183,-6.395c5.087,-4.399 7.667,-10.942 7.667,-19.575c0,-3.257 -0.393,-5.962 -1.167,-8.476c-0.778,-2.528 -1.883,-4.934 -3.281,-6.814c-1.401,-1.882 -3.098,-3.458 -5.045,-4.703c-1.895,-1.21 -4.003,-2.198 -6.264,-2.943c-2.239,-0.737 -4.64,-1.263 -7.139,-1.56c-2.464,-0.292 -5.016,-0.443 -7.587,-0.443l-29.468,0l0,80l17.93,0l0,-29.091l12.171,0Z" style="fill:#fff;fill-rule:nonzero;"/><rect x="304.879" y="0" width="17.93" height="80" style="fill:#fff;"/><path d="M362.589,0l-29.477,80l75.888,0l-31.247,-80l-15.164,0Z" style="fill:#fff;fill-rule:nonzero;"/></g></g></svg>
|
@@ -0,0 +1 @@
|
|
1
|
+
This directory is required by Apache/Phusion Passenger and contains static assets that are typically served using sendfile.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
if ENV['COVERAGE']
|
3
|
+
begin
|
4
|
+
require 'simplecov'
|
5
|
+
|
6
|
+
SimpleCov.start do
|
7
|
+
add_filter "/spec/"
|
8
|
+
end
|
9
|
+
|
10
|
+
if ENV['TRAVIS']
|
11
|
+
require 'coveralls'
|
12
|
+
Coveralls.wear!
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
warn "Could not load simplecov: #{$!}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'bundler/setup'
|
20
|
+
require 'utopia'
|
21
|
+
|
22
|
+
require 'async/rspec'
|
23
|
+
|
24
|
+
RSpec.configure do |config|
|
25
|
+
# Enable flags like --only-failures and --next-failure
|
26
|
+
config.example_status_persistence_file_path = '.rspec_status'
|
27
|
+
|
28
|
+
config.expect_with :rspec do |c|
|
29
|
+
c.syntax = :expect
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
require 'rack/test'
|
3
|
+
|
4
|
+
RSpec.shared_context "website" do
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
let(:rackup_path) {File.expand_path('../config.ru', __dir__)}
|
8
|
+
let(:rackup_directory) {File.dirname(rackup_path)}
|
9
|
+
|
10
|
+
let(:app) {Rack::Builder.parse_file(rackup_path).first}
|
11
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
require_relative 'website_context'
|
3
|
+
|
4
|
+
require 'falcon/server'
|
5
|
+
require 'falcon/adapters/rack'
|
6
|
+
|
7
|
+
require 'async/http/url_endpoint'
|
8
|
+
require 'async/websocket/client'
|
9
|
+
|
10
|
+
# Learn about best practice specs from http://betterspecs.org
|
11
|
+
RSpec.describe "my website" do
|
12
|
+
include_context "website"
|
13
|
+
|
14
|
+
it "should have an accessible front page" do
|
15
|
+
get "/"
|
16
|
+
|
17
|
+
follow_redirect!
|
18
|
+
|
19
|
+
expect(last_response.status).to be == 200
|
20
|
+
end
|
21
|
+
|
22
|
+
context "websockets" do
|
23
|
+
include_context Async::RSpec::Reactor
|
24
|
+
|
25
|
+
let(:endpoint) {Async::HTTP::URLEndpoint.parse("http://localhost:9282")}
|
26
|
+
let(:server) {Falcon::Server.new(Falcon::Adapters::Rack.new(app), endpoint)}
|
27
|
+
|
28
|
+
let(:hello_message) do
|
29
|
+
{
|
30
|
+
"user" => "test",
|
31
|
+
"text" => "Hello World",
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
let!(:server_task) do
|
36
|
+
server_task = reactor.async do
|
37
|
+
server.run
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
after(:each) do
|
42
|
+
server_task.stop
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can connect to server" do
|
46
|
+
endpoint.connect do |socket|
|
47
|
+
connection = Async::WebSocket::Client.new(socket, "ws://localhost/server/connect")
|
48
|
+
|
49
|
+
connection.send_message(hello_message)
|
50
|
+
|
51
|
+
message = connection.next_message
|
52
|
+
expect(message).to be == hello_message
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
namespace :bower do
|
3
|
+
desc 'Load the .bowerrc file and setup the environment for other tasks.'
|
4
|
+
task :bowerrc do
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
bowerrc_path = SITE_ROOT + ".bowerrc"
|
8
|
+
bowerrc = JSON.load(File.read(bowerrc_path))
|
9
|
+
|
10
|
+
@bower_package_root = SITE_ROOT + bowerrc['directory']
|
11
|
+
@bower_install_root = SITE_ROOT + bowerrc['public']
|
12
|
+
@bower_install_method = (bowerrc['install'] || :copy).to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Update the bower packages and link into the public directory.'
|
16
|
+
task :update => :bowerrc do
|
17
|
+
require 'fileutils'
|
18
|
+
require 'utopia/path'
|
19
|
+
|
20
|
+
#sh %W{bower update}
|
21
|
+
|
22
|
+
@bower_package_root.children.select(&:directory?).collect(&:basename).each do |package_directory|
|
23
|
+
install_path = @bower_install_root + package_directory
|
24
|
+
package_path = @bower_package_root + package_directory
|
25
|
+
dist_path = package_path + 'dist'
|
26
|
+
|
27
|
+
FileUtils::Verbose.rm_rf install_path
|
28
|
+
FileUtils::Verbose.mkpath(install_path.dirname)
|
29
|
+
|
30
|
+
# If a package has a dist directory, we only symlink that... otherwise we have to do the entire package, and hope that bower's ignore was setup correctly:
|
31
|
+
if File.exist? dist_path
|
32
|
+
link_path = Utopia::Path.shortest_path(dist_path, install_path)
|
33
|
+
else
|
34
|
+
link_path = Utopia::Path.shortest_path(package_path, install_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
if @bower_install_method == :symlink
|
38
|
+
# This is useful for some
|
39
|
+
FileUtils::Verbose.ln_s link_path, install_path
|
40
|
+
else
|
41
|
+
FileUtils::Verbose.cp_r File.expand_path(link_path, install_path), install_path
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
desc 'Run by git post-update hook when deployed to a web server'
|
3
|
+
task :deploy do
|
4
|
+
# This task is typiclly run after the site is updated but before the server is restarted.
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'Restart the application server'
|
8
|
+
task :restart do
|
9
|
+
# This task is run after the deployment task above.
|
10
|
+
if passenger_config = `which passenger-config`.chomp!
|
11
|
+
sh(passenger_config, 'restart-app', '--ignore-passenger-not-running', SITE_ROOT.to_s)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:test) do |task|
|
5
|
+
task.rspec_opts = %w{--require simplecov} if ENV['COVERAGE']
|
6
|
+
end
|
7
|
+
|
8
|
+
task :coverage do
|
9
|
+
ENV['COVERAGE'] = 'y'
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Start the development server.'
|
13
|
+
task :server => :environment do
|
14
|
+
exec('guard', '-g', 'development')
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Start the development environment which includes web server and tests.'
|
18
|
+
task :development => :environment do
|
19
|
+
exec('guard', '-g', 'development,test')
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Start an interactive console for your web application'
|
23
|
+
task :console => :environment do
|
24
|
+
require 'pry'
|
25
|
+
require 'rack/test'
|
26
|
+
|
27
|
+
include Rack::Test::Methods
|
28
|
+
|
29
|
+
def app
|
30
|
+
@app ||= Rack::Builder.parse_file(SITE_ROOT + 'config.ru').first
|
31
|
+
end
|
32
|
+
|
33
|
+
Pry.start
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
desc 'Set up the environment for running your web application'
|
3
|
+
task :environment do |task|
|
4
|
+
require SITE_ROOT + 'config/environment'
|
5
|
+
|
6
|
+
# We ensure this is part of the shell environment so if other commands are invoked they will work correctly.
|
7
|
+
ENV['RACK_ENV'] = RACK_ENV.to_s if defined?(RACK_ENV)
|
8
|
+
ENV['DATABASE_ENV'] = DATABASE_ENV.to_s if defined?(DATABASE_ENV)
|
9
|
+
|
10
|
+
# This generates a consistent session secret if one was not already provided:
|
11
|
+
if ENV['UTOPIA_SESSION_SECRET'].nil?
|
12
|
+
require 'securerandom'
|
13
|
+
|
14
|
+
warn 'Generating transient session key for development...'
|
15
|
+
ENV['UTOPIA_SESSION_SECRET'] = SecureRandom.hex(32)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
task :log do
|
3
|
+
require 'utopia/logger'
|
4
|
+
LOGGER = Utopia::Logger.new
|
5
|
+
end
|
6
|
+
|
7
|
+
namespace :log do
|
8
|
+
desc "Increase verbosity of logger to info."
|
9
|
+
task :info => :log do
|
10
|
+
LOGGER.level = Logger::INFO
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Increase verbosity of global debug."
|
14
|
+
task :debug => :log do
|
15
|
+
LOGGER.level = Logger::DEBUG
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
namespace :static do
|
3
|
+
task :static_environment do
|
4
|
+
RACK_ENV ||= :static
|
5
|
+
DATABASE_ENV ||= :production
|
6
|
+
SERVER_PORT ||= 9291
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Generate a static copy of the site."
|
10
|
+
task :generate => [:static_environment, :environment] do
|
11
|
+
require 'falcon/server'
|
12
|
+
require 'async/io'
|
13
|
+
require 'async/container'
|
14
|
+
|
15
|
+
config_path = SITE_ROOT + 'config.ru'
|
16
|
+
container_class = Async::Container::Threaded
|
17
|
+
|
18
|
+
app, options = Rack::Builder.parse_file(config_path.to_s)
|
19
|
+
|
20
|
+
container = container_class.new(concurrency: 2) do
|
21
|
+
server = Falcon::Server.new(app, [
|
22
|
+
Async::IO::Endpoint.parse("tcp://localhost:#{SERVER_PORT}", reuse_port: true)
|
23
|
+
])
|
24
|
+
|
25
|
+
server.run
|
26
|
+
end
|
27
|
+
|
28
|
+
output_path = ENV.fetch('OUTPUT_PATH') {SITE_ROOT + 'static'}
|
29
|
+
|
30
|
+
# Delete any existing stuff:
|
31
|
+
FileUtils.rm_rf(output_path)
|
32
|
+
|
33
|
+
# Copy all public assets:
|
34
|
+
Dir.glob(SITE_ROOT + 'public/*').each do |path|
|
35
|
+
FileUtils.cp_r(path, output_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Generate HTML pages:
|
39
|
+
system("wget", "--mirror", "--recursive", "--continue", "--convert-links", "--adjust-extension", "--no-host-directories", "--directory-prefix", output_path.to_s, "http://localhost:#{SERVER_PORT}")
|
40
|
+
|
41
|
+
container.stop
|
42
|
+
end
|
43
|
+
end
|
data/lib/async/websocket.rb
CHANGED
@@ -21,10 +21,14 @@
|
|
21
21
|
require 'websocket/driver'
|
22
22
|
require 'json'
|
23
23
|
|
24
|
+
require 'async/io/stream'
|
25
|
+
|
24
26
|
module Async
|
25
27
|
module WebSocket
|
26
28
|
# This is a basic synchronous websocket client:
|
27
29
|
class Connection
|
30
|
+
BLOCK_SIZE = Async::IO::Stream::BLOCK_SIZE
|
31
|
+
|
28
32
|
EVENTS = [:open, :message, :close]
|
29
33
|
|
30
34
|
def initialize(socket, driver)
|
@@ -50,8 +54,10 @@ module Async
|
|
50
54
|
attr :url
|
51
55
|
|
52
56
|
def next_event
|
57
|
+
@socket.flush
|
58
|
+
|
53
59
|
while @queue.empty?
|
54
|
-
data = @socket.
|
60
|
+
data = @socket.readpartial(BLOCK_SIZE)
|
55
61
|
|
56
62
|
if data and !data.empty?
|
57
63
|
@driver.parse(data)
|
@@ -75,6 +81,10 @@ module Async
|
|
75
81
|
end
|
76
82
|
end
|
77
83
|
|
84
|
+
def send_text(text)
|
85
|
+
@driver.text(text)
|
86
|
+
end
|
87
|
+
|
78
88
|
def send_message(message)
|
79
89
|
@driver.text(JSON.dump(message))
|
80
90
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-websocket
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: websocket-driver
|
@@ -53,49 +53,49 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: falcon
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.15.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.15.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '1.6'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '1.6'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '3.6'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '3.6'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rake
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
@@ -115,6 +115,7 @@ executables: []
|
|
115
115
|
extensions: []
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
|
+
- ".editorconfig"
|
118
119
|
- ".gitignore"
|
119
120
|
- ".rspec"
|
120
121
|
- ".travis.yml"
|
@@ -124,6 +125,42 @@ files:
|
|
124
125
|
- async-websocket.gemspec
|
125
126
|
- examples/chat/client.rb
|
126
127
|
- examples/chat/config.ru
|
128
|
+
- examples/middleware/client.rb
|
129
|
+
- examples/middleware/config.ru
|
130
|
+
- examples/utopia/.bowerrc
|
131
|
+
- examples/utopia/.gitignore
|
132
|
+
- examples/utopia/.rspec
|
133
|
+
- examples/utopia/Gemfile
|
134
|
+
- examples/utopia/Guardfile
|
135
|
+
- examples/utopia/README.md
|
136
|
+
- examples/utopia/Rakefile
|
137
|
+
- examples/utopia/config.ru
|
138
|
+
- examples/utopia/config/README.md
|
139
|
+
- examples/utopia/config/environment.rb
|
140
|
+
- examples/utopia/lib/readme.txt
|
141
|
+
- examples/utopia/pages/_heading.xnode
|
142
|
+
- examples/utopia/pages/_page.xnode
|
143
|
+
- examples/utopia/pages/client/client.js
|
144
|
+
- examples/utopia/pages/client/controller.rb
|
145
|
+
- examples/utopia/pages/client/index.xnode
|
146
|
+
- examples/utopia/pages/errors/exception.xnode
|
147
|
+
- examples/utopia/pages/errors/file-not-found.xnode
|
148
|
+
- examples/utopia/pages/links.yaml
|
149
|
+
- examples/utopia/pages/server/controller.rb
|
150
|
+
- examples/utopia/public/_static/icon.png
|
151
|
+
- examples/utopia/public/_static/site.css
|
152
|
+
- examples/utopia/public/_static/utopia-background.svg
|
153
|
+
- examples/utopia/public/_static/utopia.svg
|
154
|
+
- examples/utopia/public/readme.txt
|
155
|
+
- examples/utopia/spec/spec_helper.rb
|
156
|
+
- examples/utopia/spec/website_context.rb
|
157
|
+
- examples/utopia/spec/website_spec.rb
|
158
|
+
- examples/utopia/tasks/bower.rake
|
159
|
+
- examples/utopia/tasks/deploy.rake
|
160
|
+
- examples/utopia/tasks/development.rake
|
161
|
+
- examples/utopia/tasks/environment.rake
|
162
|
+
- examples/utopia/tasks/log.rake
|
163
|
+
- examples/utopia/tasks/static.rake
|
127
164
|
- lib/async/websocket.rb
|
128
165
|
- lib/async/websocket/client.rb
|
129
166
|
- lib/async/websocket/connection.rb
|