jstp 0.5.7 → 1.0.2
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.
- data/README.md +26 -3
- data/jstp.gemspec +2 -1
- data/lib/jstp.rb +23 -11
- data/lib/jstp/configuration.rb +68 -0
- data/lib/jstp/controller.rb +49 -11
- data/lib/jstp/dispatch.rb +106 -0
- data/lib/jstp/engine.rb +77 -13
- data/lib/jstp/version.rb +1 -1
- data/lib/reader/jstp/dispatch.rb +36 -0
- data/lib/reader/jstp/engine.rb +66 -0
- data/lib/writer/jstp/dispatch.rb +95 -0
- data/samples/api-1.5/modular_style.rb +22 -0
- data/samples/api-1.5/references.rb +12 -0
- data/samples/api-1.5/sinatra_style.rb +18 -0
- data/samples/api-2.0/a_la_rack.rb +22 -0
- data/samples/api-2.0/clearer_sample.rb +12 -0
- data/samples/api-2.0/middleware.rb +23 -0
- data/samples/api-2.0/references.rb +11 -0
- data/samples/diff.rb +12 -0
- data/samples/hooks.rb +9 -0
- data/samples/micro.rb +6 -0
- data/samples/new_api.rb +62 -0
- data/samples/websocket.rb +11 -0
- data/spec/jstp/engine_spec.rb +39 -0
- data/spec/spec_helper.rb +0 -1
- metadata +40 -32
- data/features/map_a_la_rest.feature +0 -148
- data/features/step_definitions/map_a_la_rest_steps.rb +0 -19
- data/features/support/env.rb +0 -11
- data/lib/jstp/api.rb +0 -25
- data/lib/jstp/base.rb +0 -7
- data/lib/jstp/connector.rb +0 -17
- data/lib/jstp/tcp.rb +0 -12
- data/lib/jstp/web_socket.rb +0 -45
- data/lib/reader/jstp/connector.rb +0 -31
- data/lib/writer/jstp/connector.rb +0 -46
- data/spec/jstp/api_spec.rb +0 -79
- data/spec/jstp/base_spec.rb +0 -5
- data/spec/jstp/connector_spec.rb +0 -16
- data/spec/jstp/tcp_spec.rb +0 -7
- data/spec/jstp/web_socket_spec.rb +0 -78
- data/spec/reader/jstp/connector_spec.rb +0 -32
- data/spec/writer/jstp/connector_spec.rb +0 -71
data/lib/jstp/version.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
# http://www.youtube.com/watch?v=pXPzZezGu8k
|
2
|
+
module Reader
|
3
|
+
module JSTP
|
4
|
+
class Dispatch < Discoverer::Pattern
|
5
|
+
def hash the_hash
|
6
|
+
the_hash.each do |key, value|
|
7
|
+
@source[key] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
@source
|
11
|
+
end
|
12
|
+
|
13
|
+
# Actually, is JSON
|
14
|
+
def string the_string
|
15
|
+
Oj.load(the_string).each do |key, value|
|
16
|
+
@source[key] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
@source
|
20
|
+
end
|
21
|
+
|
22
|
+
def array the_array
|
23
|
+
@source.method = the_array.first if the_array.first
|
24
|
+
@source.resource = the_array[1] if the_array[1]
|
25
|
+
@source.body = the_array[2] if the_array[2]
|
26
|
+
if the_array[3]
|
27
|
+
the_array[3].each do |key, value|
|
28
|
+
@source[key] = value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@source
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Reader
|
2
|
+
module JSTP
|
3
|
+
class Engine
|
4
|
+
def initialize source
|
5
|
+
@config = ::JSTP::Configuration.instance
|
6
|
+
@source = source
|
7
|
+
end
|
8
|
+
|
9
|
+
# Start the server with the websocket strategy
|
10
|
+
def websocket
|
11
|
+
EM.run do
|
12
|
+
EM::WebSocket
|
13
|
+
.start host: "0.0.0.0", port: @config.port.inbound do |server|
|
14
|
+
|
15
|
+
server.onopen do
|
16
|
+
@source.clients[UUID.new.generate] = server
|
17
|
+
if @source.respond_to? :open
|
18
|
+
@source.open server, @source.clients.key(server)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
server.onmessage do |message|
|
23
|
+
begin
|
24
|
+
@message = ::JSTP::Dispatch.new message
|
25
|
+
@source.dispatch(@message, server)
|
26
|
+
rescue Exception => exception
|
27
|
+
log_exception exception, @message
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
server.onclose do
|
32
|
+
if @source.respond_to? :close
|
33
|
+
@source.close server, @source.clients.key(server)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Start the server with the TCP strategy
|
41
|
+
def tcp
|
42
|
+
@server = TCPServer.open @config.port.inbound
|
43
|
+
loop {
|
44
|
+
Thread.start(@server.accept) { |client|
|
45
|
+
begin
|
46
|
+
@source.clients[UUID.new.generate] = client
|
47
|
+
@message = ::JSTP::Dispatch.new client.gets
|
48
|
+
@source.dispatch @message, client
|
49
|
+
client.close
|
50
|
+
rescue Exception => exception
|
51
|
+
log_exception exception, @message
|
52
|
+
client.close
|
53
|
+
end
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def log_exception exception, message
|
60
|
+
@config.logger.error "#{exception.class}: #{exception.message}"
|
61
|
+
@config.logger.debug exception.backtrace.to_s
|
62
|
+
@config.logger.debug Oj.dump message if message
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Writer
|
2
|
+
module JSTP
|
3
|
+
class Dispatch < Discoverer::Pattern
|
4
|
+
|
5
|
+
def initialize source
|
6
|
+
super source
|
7
|
+
@config = ::JSTP::Configuration.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
# Dispatch this applying the websocket strategy
|
11
|
+
def websocket port = nil
|
12
|
+
host = @source["resource"].first
|
13
|
+
path = @source["resource"][1..-1].join('/')
|
14
|
+
if port.nil?
|
15
|
+
connection_uri = "ws://#{host}:#{@config.port.outbound}/#{path}"
|
16
|
+
else
|
17
|
+
connection_uri = "ws://#{host}:#{port}/#{path}"
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
ws = EM::WebSocketClient.connect connection_uri
|
22
|
+
ws.callback do
|
23
|
+
ws.send_msg @source.to.json
|
24
|
+
@config.logger.debug @source.to_s
|
25
|
+
ws.close_connection_after_writing
|
26
|
+
end
|
27
|
+
rescue RuntimeError => e
|
28
|
+
EM.run do
|
29
|
+
ws = EM::WebSocketClient.connect connection_uri
|
30
|
+
|
31
|
+
ws.callback do
|
32
|
+
ws.send_msg @source.to.json
|
33
|
+
@config.logger.debug @source.to_s
|
34
|
+
ws.close_connection_after_writing
|
35
|
+
end
|
36
|
+
|
37
|
+
ws.disconnect do
|
38
|
+
EM::stop_event_loop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Dispatch thid applying the TCP strategy
|
45
|
+
def tcp port = nil
|
46
|
+
if port.nil?
|
47
|
+
client = TCPSocket.open @source["resource"].first, @config.port.outbound
|
48
|
+
else
|
49
|
+
client = TCPSocket.open @source["resource"].first, port
|
50
|
+
end
|
51
|
+
|
52
|
+
client.puts @source.to.json
|
53
|
+
@config.logger.debug @source.to_s
|
54
|
+
client.close
|
55
|
+
end
|
56
|
+
|
57
|
+
def json
|
58
|
+
Oj.dump @source
|
59
|
+
end
|
60
|
+
|
61
|
+
def string
|
62
|
+
response = "#{@source.method} #{@source.resource.join('/')} #{@source.protocol.join('/')}\n"
|
63
|
+
@source.each do |key, value|
|
64
|
+
unless key == "method" || key == "resource" || key == "protocol" || key == "body"
|
65
|
+
if value.is_a? Array
|
66
|
+
response += "#{key}: #{value.join('/')}\n"
|
67
|
+
else
|
68
|
+
response += "#{key}: #{value}\n"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
unless @source.body.nil?
|
74
|
+
response += "\n"
|
75
|
+
if @source.body.is_a? Hash
|
76
|
+
@source.body.each do |key, value|
|
77
|
+
response += "#{key}: #{Oj.dump(value)}\n"
|
78
|
+
end
|
79
|
+
else
|
80
|
+
response += Oj.dump @source.body
|
81
|
+
end
|
82
|
+
end
|
83
|
+
response
|
84
|
+
end
|
85
|
+
|
86
|
+
def short
|
87
|
+
unless @source.body
|
88
|
+
"#{@source.method} #{@source.resource.join('/')}"
|
89
|
+
else
|
90
|
+
"#{@source.method} #{@source.resource.join('/')}?#{Oj.dump(@source.body)}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class MyEngine < JSTP::Engine
|
2
|
+
|
3
|
+
strategy.inbound :websocket
|
4
|
+
port.inbound 44444
|
5
|
+
logger Logger.new $stdout
|
6
|
+
|
7
|
+
resource :user do
|
8
|
+
get do
|
9
|
+
end
|
10
|
+
|
11
|
+
post do
|
12
|
+
end
|
13
|
+
|
14
|
+
resource :source do
|
15
|
+
get do
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
MyEngine.run
|
@@ -0,0 +1,22 @@
|
|
1
|
+
resource :User do
|
2
|
+
get do
|
3
|
+
# Something
|
4
|
+
end
|
5
|
+
|
6
|
+
delete do
|
7
|
+
# Something
|
8
|
+
end
|
9
|
+
|
10
|
+
resource :Rating do
|
11
|
+
put do
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
resource :Article do
|
17
|
+
get do
|
18
|
+
# Something with article
|
19
|
+
end
|
20
|
+
|
21
|
+
resource User # Includes User here. Along with Rating within
|
22
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Article < JSTP::Resource
|
2
|
+
def get
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
class Blog < JSTP::Resource
|
7
|
+
resource Article # Declaratively set Article as a resource within Blog
|
8
|
+
end
|
9
|
+
|
10
|
+
Blog.new # Starts Blog as the engine
|
11
|
+
|
12
|
+
# The JSTP::Resource class its a combination of Engine and Controller
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class TokenEmptier < JSTP::Resource
|
2
|
+
get do
|
3
|
+
original.token = [] # Not useful, just first thing to cross mind
|
4
|
+
end
|
5
|
+
|
6
|
+
all do # Same as def all
|
7
|
+
puts "This will be printed everytime"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class App < JSTP::Resource
|
12
|
+
use TokenEmptier
|
13
|
+
|
14
|
+
get do
|
15
|
+
# => "This will be printed everytime"
|
16
|
+
# from TokenEmptier#all
|
17
|
+
puts token # => nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
App.new
|
22
|
+
|
23
|
+
# Nice, huh?
|
data/samples/diff.rb
ADDED
data/samples/hooks.rb
ADDED
data/samples/micro.rb
ADDED
data/samples/new_api.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# {
|
2
|
+
# "protocol": ["JSTP", "0.1"],
|
3
|
+
# "method": "GET",
|
4
|
+
# "resource": ["localhost", "User", "4"],
|
5
|
+
# "timestamp": 1536345124,
|
6
|
+
# "token": ["8ugw324", "34fqwer"],
|
7
|
+
# "X-Server": "EventMachine",
|
8
|
+
# "referer": ["google.com", "search"]
|
9
|
+
# "body": {
|
10
|
+
# "name": "Xavier"
|
11
|
+
# }
|
12
|
+
# }
|
13
|
+
|
14
|
+
class Localhost < JSTP::Engine
|
15
|
+
class User < JSTP::Controller
|
16
|
+
def get
|
17
|
+
protocol # => ["JSTP", "0.1"]
|
18
|
+
method # => "GET"
|
19
|
+
resource # => ["localhost", "User", "4"]
|
20
|
+
query # => ["4"]
|
21
|
+
timestamp # => 1536345124
|
22
|
+
referer # => ["google.com", "search"]
|
23
|
+
token # => ["8ugw324", "34fqwer"]
|
24
|
+
headers # => {"token" => ..., timestamp => ..., "X-Server" => ...}
|
25
|
+
body # => {"name" => "Xavier"}
|
26
|
+
original # => {"protocol" => ..., method" => "GET", "resource" => ...}
|
27
|
+
|
28
|
+
dispatch(
|
29
|
+
:post,
|
30
|
+
"remote.host/Login/success",
|
31
|
+
{ "message" => "Login successful for user #{body['name']}" },
|
32
|
+
{ "X-Greet" => "Hello" }
|
33
|
+
).to.websocket
|
34
|
+
# => {
|
35
|
+
# "protocol": ["JSTP", "0.1"],
|
36
|
+
# "method": "POST",
|
37
|
+
# "resource": ["remote.host", "Login", "success"],
|
38
|
+
# "timestamp": 1536358924,
|
39
|
+
# "token": ["8ugw324", "34fqwer"],
|
40
|
+
# "X-Greet": "Hello",
|
41
|
+
# "body": {
|
42
|
+
# "message": "Login successful for user Xavier"
|
43
|
+
# }
|
44
|
+
# }
|
45
|
+
|
46
|
+
original.to_s
|
47
|
+
# =>
|
48
|
+
# GET localhost/User/4
|
49
|
+
# timestamp: 1536345124
|
50
|
+
# token: 8ugw324/34fqwer
|
51
|
+
# X-Server: EventMachine
|
52
|
+
# referer: google.com/search
|
53
|
+
#
|
54
|
+
# name: Xavier
|
55
|
+
|
56
|
+
original.to.short
|
57
|
+
# => GET localhost/User/4?name:Xavier
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Localhost.new
|