jstp 0.5.7 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|