bixby-common 0.3.16 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +55 -18
- data/Rakefile +1 -2
- data/VERSION +1 -1
- data/bixby-common.gemspec +21 -4
- data/lib/bixby-common/api/api_channel.rb +20 -0
- data/lib/bixby-common/api/encrypted_json_request.rb +19 -0
- data/lib/bixby-common/api/http_channel.rb +72 -0
- data/lib/bixby-common/api/json_request.rb +4 -0
- data/lib/bixby-common/api/json_response.rb +4 -0
- data/lib/bixby-common/api/rpc_handler.rb +35 -0
- data/lib/bixby-common/api/signed_json_request.rb +38 -0
- data/lib/bixby-common/command_spec.rb +1 -1
- data/lib/bixby-common/util/log.rb +21 -1
- data/lib/bixby-common/websocket/api_channel.rb +114 -0
- data/lib/bixby-common/websocket/async_response.rb +50 -0
- data/lib/bixby-common/websocket/client.rb +117 -0
- data/lib/bixby-common/websocket/message.rb +48 -0
- data/lib/bixby-common/websocket/request.rb +24 -0
- data/lib/bixby-common/websocket/response.rb +24 -0
- data/lib/bixby-common.rb +14 -0
- metadata +109 -121
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 53b5ec30f44a5f248d360a13d02bc46881e64f03
|
4
|
+
data.tar.gz: 4ad3d8400f6390ce4630a502e15e4fc9ca5d4507
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: db1b6968efb742cf556c6cfdeb4a0836a05869d5088abc126c5360d2e8d8494a209bd261d9bac3b5fdfb18fee17ce775b7d123bdd7a02149bd037970877726ef
|
7
|
+
data.tar.gz: 0ca4ee9520635bc97adea27f4c293b4a4797958a296eaf87d3d9d016618ff43c5db197522e99baf506cec46861001f4f5ec1233cc42787c9d79407084024fb2b
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/chetan/api_auth.git
|
3
|
+
revision: 6d9351de901a51d6a386d547a8d32e23c4314550
|
4
|
+
branch: bixby
|
5
|
+
specs:
|
6
|
+
api-auth (1.0.3)
|
7
|
+
|
1
8
|
GIT
|
2
9
|
remote: https://github.com/chetan/httpi.git
|
3
10
|
revision: f6e49303fee6778c714bcc556fa5f9247bc3a3f3
|
@@ -8,12 +15,16 @@ GIT
|
|
8
15
|
|
9
16
|
GIT
|
10
17
|
remote: https://github.com/chetan/jeweler.git
|
11
|
-
revision:
|
18
|
+
revision: 9b8b2376c79299b823a5e9aafae3d647df943b6f
|
12
19
|
branch: bixby
|
13
20
|
specs:
|
14
|
-
jeweler (1.8.
|
21
|
+
jeweler (1.8.7)
|
22
|
+
builder
|
15
23
|
bundler (~> 1.0)
|
16
24
|
git (>= 1.2.5)
|
25
|
+
github_api (= 0.10.1)
|
26
|
+
highline (>= 1.6.15)
|
27
|
+
nokogiri (= 1.5.10)
|
17
28
|
rake
|
18
29
|
rdoc
|
19
30
|
|
@@ -28,14 +39,14 @@ GIT
|
|
28
39
|
|
29
40
|
GIT
|
30
41
|
remote: https://github.com/chetan/test_guard.git
|
31
|
-
revision:
|
42
|
+
revision: 7d069b2d7e46fcbecd7a52966fda7d2d1945e2c9
|
32
43
|
specs:
|
33
|
-
test_guard (0.2.
|
44
|
+
test_guard (0.2.1)
|
34
45
|
awesome_print
|
35
46
|
debugger
|
36
47
|
debugger-pry
|
37
48
|
growl
|
38
|
-
|
49
|
+
listen
|
39
50
|
simplecov
|
40
51
|
simplecov-console
|
41
52
|
single_test
|
@@ -48,6 +59,7 @@ GEM
|
|
48
59
|
ansi (1.4.3)
|
49
60
|
awesome_print (1.1.0)
|
50
61
|
bouncy-castle-java (1.5.0147)
|
62
|
+
builder (3.2.2)
|
51
63
|
coderay (1.0.9)
|
52
64
|
colorize (0.5.8)
|
53
65
|
columnize (0.3.6)
|
@@ -63,24 +75,36 @@ GEM
|
|
63
75
|
debugger (~> 1)
|
64
76
|
pry (>= 0.9.9)
|
65
77
|
debugger-ruby_core_source (1.2.3)
|
78
|
+
eventmachine (1.0.3)
|
79
|
+
eventmachine (1.0.3-java)
|
80
|
+
faraday (0.8.8)
|
81
|
+
multipart-post (~> 1.2.0)
|
82
|
+
faye-websocket (0.6.3)
|
83
|
+
eventmachine (>= 0.12.0)
|
84
|
+
websocket-driver (>= 0.2.0)
|
66
85
|
ffi (1.9.0)
|
67
86
|
ffi (1.9.0-java)
|
68
|
-
|
69
|
-
|
87
|
+
git (1.2.6)
|
88
|
+
github_api (0.10.1)
|
89
|
+
addressable
|
90
|
+
faraday (~> 0.8.1)
|
91
|
+
hashie (>= 1.2)
|
92
|
+
multi_json (~> 1.4)
|
93
|
+
nokogiri (~> 1.5.2)
|
94
|
+
oauth2
|
70
95
|
growl (1.0.3)
|
71
|
-
|
72
|
-
|
73
|
-
listen (>= 1.0.0)
|
74
|
-
lumberjack (>= 1.0.2)
|
75
|
-
pry (>= 0.9.10)
|
76
|
-
thor (>= 0.14.6)
|
96
|
+
hashie (2.0.5)
|
97
|
+
highline (1.6.19)
|
77
98
|
hirb (0.7.1)
|
99
|
+
httpauth (0.2.0)
|
78
100
|
httpclient (2.3.4.1)
|
79
101
|
jruby-openssl (0.8.8)
|
80
102
|
bouncy-castle-java (>= 1.5.0147)
|
81
103
|
json (1.8.0)
|
82
104
|
json (1.8.0-java)
|
83
|
-
|
105
|
+
jwt (0.1.8)
|
106
|
+
multi_json (>= 1.5)
|
107
|
+
listen (1.3.0)
|
84
108
|
rb-fsevent (>= 0.9.3)
|
85
109
|
rb-inotify (>= 0.9)
|
86
110
|
rb-kqueue (>= 0.2)
|
@@ -88,13 +112,23 @@ GEM
|
|
88
112
|
logging (1.8.1)
|
89
113
|
little-plugger (>= 1.1.3)
|
90
114
|
multi_json (>= 1.3.6)
|
91
|
-
lumberjack (1.0.4)
|
92
115
|
metaclass (0.0.1)
|
93
116
|
method_source (0.8.2)
|
94
117
|
minitest (4.7.5)
|
95
118
|
mocha (0.14.0)
|
96
119
|
metaclass (~> 0.0.1)
|
97
120
|
multi_json (1.7.9)
|
121
|
+
multi_xml (0.5.5)
|
122
|
+
multipart-post (1.2.0)
|
123
|
+
nokogiri (1.5.10)
|
124
|
+
nokogiri (1.5.10-java)
|
125
|
+
oauth2 (0.9.2)
|
126
|
+
faraday (~> 0.8)
|
127
|
+
httpauth (~> 0.2)
|
128
|
+
jwt (~> 0.1.4)
|
129
|
+
multi_json (~> 1.0)
|
130
|
+
multi_xml (~> 0.5)
|
131
|
+
rack (~> 1.2)
|
98
132
|
oj (2.1.4)
|
99
133
|
pry (0.9.12.2)
|
100
134
|
coderay (~> 1.0.5)
|
@@ -123,18 +157,19 @@ GEM
|
|
123
157
|
hirb
|
124
158
|
simplecov
|
125
159
|
simplecov-html (0.7.1)
|
126
|
-
single_test (0.
|
127
|
-
rake
|
160
|
+
single_test (0.6.0)
|
161
|
+
rake
|
128
162
|
slop (3.4.6)
|
129
163
|
spoon (0.0.4)
|
130
164
|
ffi
|
131
165
|
test-unit (2.5.5)
|
132
|
-
thor (0.18.1)
|
133
166
|
turn (0.9.6)
|
134
167
|
ansi
|
135
168
|
webmock (1.13.0)
|
136
169
|
addressable (>= 2.2.7)
|
137
170
|
crack (>= 0.3.2)
|
171
|
+
websocket-driver (0.2.3)
|
172
|
+
websocket-driver (0.2.3-java)
|
138
173
|
yard (0.8.7)
|
139
174
|
|
140
175
|
PLATFORMS
|
@@ -142,8 +177,10 @@ PLATFORMS
|
|
142
177
|
ruby
|
143
178
|
|
144
179
|
DEPENDENCIES
|
180
|
+
api-auth!
|
145
181
|
bundler (~> 1.1)
|
146
182
|
curb
|
183
|
+
faye-websocket
|
147
184
|
httpclient
|
148
185
|
httpi!
|
149
186
|
jeweler!
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/bixby-common.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "bixby-common"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Chetan Sarva"]
|
12
|
-
s.date = "2013-08-
|
12
|
+
s.date = "2013-08-24"
|
13
13
|
s.description = "Bixby Common files/libs"
|
14
14
|
s.email = "chetan@pixelcop.net"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,8 +24,13 @@ Gem::Specification.new do |s|
|
|
24
24
|
"VERSION",
|
25
25
|
"bixby-common.gemspec",
|
26
26
|
"lib/bixby-common.rb",
|
27
|
+
"lib/bixby-common/api/api_channel.rb",
|
28
|
+
"lib/bixby-common/api/encrypted_json_request.rb",
|
29
|
+
"lib/bixby-common/api/http_channel.rb",
|
27
30
|
"lib/bixby-common/api/json_request.rb",
|
28
31
|
"lib/bixby-common/api/json_response.rb",
|
32
|
+
"lib/bixby-common/api/rpc_handler.rb",
|
33
|
+
"lib/bixby-common/api/signed_json_request.rb",
|
29
34
|
"lib/bixby-common/bixby.rb",
|
30
35
|
"lib/bixby-common/command_response.rb",
|
31
36
|
"lib/bixby-common/command_spec.rb",
|
@@ -40,6 +45,12 @@ Gem::Specification.new do |s|
|
|
40
45
|
"lib/bixby-common/util/jsonify.rb",
|
41
46
|
"lib/bixby-common/util/log.rb",
|
42
47
|
"lib/bixby-common/util/log/filtering_layout.rb",
|
48
|
+
"lib/bixby-common/websocket/api_channel.rb",
|
49
|
+
"lib/bixby-common/websocket/async_response.rb",
|
50
|
+
"lib/bixby-common/websocket/client.rb",
|
51
|
+
"lib/bixby-common/websocket/message.rb",
|
52
|
+
"lib/bixby-common/websocket/request.rb",
|
53
|
+
"lib/bixby-common/websocket/response.rb",
|
43
54
|
"test/bixby_common_test.rb",
|
44
55
|
"test/command_response_test.rb",
|
45
56
|
"test/command_spec_test.rb",
|
@@ -55,13 +66,15 @@ Gem::Specification.new do |s|
|
|
55
66
|
]
|
56
67
|
s.homepage = "http://github.com/chetan/bixby-common"
|
57
68
|
s.require_paths = ["lib"]
|
58
|
-
s.rubygems_version = "
|
69
|
+
s.rubygems_version = "2.0.3"
|
59
70
|
s.summary = "Bixby Common"
|
60
71
|
|
61
72
|
if s.respond_to? :specification_version then
|
62
|
-
s.specification_version =
|
73
|
+
s.specification_version = 4
|
63
74
|
|
64
75
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
76
|
+
s.add_runtime_dependency(%q<faye-websocket>, [">= 0"])
|
77
|
+
s.add_runtime_dependency(%q<api-auth>, [">= 0"])
|
65
78
|
s.add_runtime_dependency(%q<multi_json>, [">= 0"])
|
66
79
|
s.add_runtime_dependency(%q<httpi>, [">= 0"])
|
67
80
|
s.add_runtime_dependency(%q<logging>, [">= 0"])
|
@@ -86,6 +99,8 @@ Gem::Specification.new do |s|
|
|
86
99
|
s.add_development_dependency(%q<curb>, [">= 0"])
|
87
100
|
s.add_development_dependency(%q<jruby-openssl>, [">= 0"])
|
88
101
|
else
|
102
|
+
s.add_dependency(%q<faye-websocket>, [">= 0"])
|
103
|
+
s.add_dependency(%q<api-auth>, [">= 0"])
|
89
104
|
s.add_dependency(%q<multi_json>, [">= 0"])
|
90
105
|
s.add_dependency(%q<httpi>, [">= 0"])
|
91
106
|
s.add_dependency(%q<logging>, [">= 0"])
|
@@ -111,6 +126,8 @@ Gem::Specification.new do |s|
|
|
111
126
|
s.add_dependency(%q<jruby-openssl>, [">= 0"])
|
112
127
|
end
|
113
128
|
else
|
129
|
+
s.add_dependency(%q<faye-websocket>, [">= 0"])
|
130
|
+
s.add_dependency(%q<api-auth>, [">= 0"])
|
114
131
|
s.add_dependency(%q<multi_json>, [">= 0"])
|
115
132
|
s.add_dependency(%q<httpi>, [">= 0"])
|
116
133
|
s.add_dependency(%q<logging>, [">= 0"])
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
|
4
|
+
class APIChannel
|
5
|
+
|
6
|
+
include Bixby::Log
|
7
|
+
extend Bixby::Log
|
8
|
+
|
9
|
+
# Execute the given request
|
10
|
+
#
|
11
|
+
# @param [JsonRequest] json_request
|
12
|
+
#
|
13
|
+
# @return [JsonResponse] response
|
14
|
+
def execute(json_request)
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
class EncryptedJsonRequest < JsonRequest
|
4
|
+
|
5
|
+
def initialize(json_request, private_key, public_key, uuid="master")
|
6
|
+
self.operation = json_request.operation
|
7
|
+
self.params = json_request.params
|
8
|
+
|
9
|
+
# encrypt
|
10
|
+
data = json_request.to_json
|
11
|
+
@body = Bixby::CryptoUtil.encrypt(data, uuid, public_key, private_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_wire
|
15
|
+
@body
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
|
4
|
+
class HttpChannel < Bixby::APIChannel
|
5
|
+
|
6
|
+
def initialize(uri)
|
7
|
+
@uri = uri
|
8
|
+
end
|
9
|
+
|
10
|
+
# Execute the given request
|
11
|
+
#
|
12
|
+
# @param [JsonRequest] json_request
|
13
|
+
#
|
14
|
+
# @return [JsonResponse] response
|
15
|
+
def execute(json_request)
|
16
|
+
execute_internal(json_request)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Execute a download request
|
21
|
+
# NOTE: This method is only available on the HTTP Channel.
|
22
|
+
#
|
23
|
+
# @param [JsonRequest] json_request
|
24
|
+
# @param [Block] block
|
25
|
+
#
|
26
|
+
# @return [JsonResponse] response
|
27
|
+
def execute_download(json_request, &block)
|
28
|
+
execute_internal(json_request, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Execute the request, optionally passing a block to handle the response
|
35
|
+
#
|
36
|
+
# @param [JsonRequest] json_request
|
37
|
+
# @param [Block] block
|
38
|
+
#
|
39
|
+
# @return [JsonResponse] response
|
40
|
+
def execute_internal(json_request, &block)
|
41
|
+
|
42
|
+
req = HTTPI::Request.new(:url => @uri, :body => json_request.to_wire)
|
43
|
+
|
44
|
+
# add in extra headers if we have a SignedJsonRequest (or anything which has additional headers)
|
45
|
+
if json_request.respond_to? :headers then
|
46
|
+
req.headers.merge!(json_request.headers)
|
47
|
+
end
|
48
|
+
|
49
|
+
if not req.headers.include? "Content-Type" then
|
50
|
+
# add content-type if not set
|
51
|
+
# may be set when creating a signed request
|
52
|
+
req.headers["Content-Type"] = "application/json"
|
53
|
+
end
|
54
|
+
|
55
|
+
if block then
|
56
|
+
# execute request with block
|
57
|
+
req.on_body(&block)
|
58
|
+
HTTPI.post(req)
|
59
|
+
return JsonResponse.new("success")
|
60
|
+
|
61
|
+
else
|
62
|
+
# execute normal req, and return parsed response
|
63
|
+
res = HTTPI.post(req).body
|
64
|
+
return JsonResponse.from_json(res)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
class RpcHandler
|
4
|
+
|
5
|
+
# Handle a request
|
6
|
+
#
|
7
|
+
# @param [JsonRequest] request
|
8
|
+
#
|
9
|
+
# @return [JsonResponse] response
|
10
|
+
def handle(request)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
# Channel connect event
|
15
|
+
#
|
16
|
+
# NOTE: only used by WebSocket channels and generally only implemented by
|
17
|
+
# the server-side.
|
18
|
+
#
|
19
|
+
# @param [Bixby::JsonRequest] json_req
|
20
|
+
# @param [Bixby::APIChannel] api
|
21
|
+
def connect(json_req, api)
|
22
|
+
# no-op
|
23
|
+
end
|
24
|
+
|
25
|
+
# Channel disconnection event
|
26
|
+
# NOTE: only used by WebSocket channels and generally only implemented by
|
27
|
+
# the server-side.
|
28
|
+
#
|
29
|
+
# @param [Bixby::APIChannel] api
|
30
|
+
def disconnect(api)
|
31
|
+
# no-op
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
class SignedJsonRequest < JsonRequest
|
4
|
+
|
5
|
+
attr_accessor :headers
|
6
|
+
|
7
|
+
def initialize(json_request, access_key=nil, secret_key=nil)
|
8
|
+
@operation = json_request.operation
|
9
|
+
@params = json_request.params
|
10
|
+
@access_key = access_key
|
11
|
+
@secret_key = secret_key
|
12
|
+
@headers = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# api-auth requires a path
|
16
|
+
def path
|
17
|
+
"/api"
|
18
|
+
end
|
19
|
+
|
20
|
+
def body=(str)
|
21
|
+
@body = str
|
22
|
+
end
|
23
|
+
|
24
|
+
def body
|
25
|
+
if @body.nil? then
|
26
|
+
hash = { :operation => operation, :params => params }
|
27
|
+
@body = MultiJson.dump(hash)
|
28
|
+
end
|
29
|
+
return @body
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_wire
|
33
|
+
ApiAuth.sign!(self, @access_key, @secret_key)
|
34
|
+
body
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -14,7 +14,7 @@ class CommandSpec
|
|
14
14
|
|
15
15
|
# Create new CommandSpec
|
16
16
|
#
|
17
|
-
# @
|
17
|
+
# @param [Hash] params Hash of attributes to initialize with
|
18
18
|
def initialize(params = nil)
|
19
19
|
return if params.nil? or params.empty?
|
20
20
|
params.each{ |k,v| self.send("#{k}=", v) if self.respond_to? "#{k}=" }
|
@@ -46,6 +46,27 @@ module Bixby
|
|
46
46
|
opts[:filename] ||= Bixby.path("var", "bixby-agent.log")
|
47
47
|
FileUtils.mkdir_p(File.dirname(opts[:filename]))
|
48
48
|
|
49
|
+
# configure stdout appender (used in debug modes, etc)
|
50
|
+
Logging.color_scheme( 'bright',
|
51
|
+
:levels => {
|
52
|
+
:info => :green,
|
53
|
+
:warn => :yellow,
|
54
|
+
:error => :red,
|
55
|
+
:fatal => [:white, :on_red]
|
56
|
+
},
|
57
|
+
:date => :blue,
|
58
|
+
:logger => :cyan,
|
59
|
+
:message => :magenta
|
60
|
+
)
|
61
|
+
Logging.appenders.stdout( 'stdout',
|
62
|
+
:auto_flushing => true,
|
63
|
+
:layout => Logging.layouts.pattern(
|
64
|
+
:pattern => pattern,
|
65
|
+
:color_scheme => 'bright'
|
66
|
+
)
|
67
|
+
)
|
68
|
+
|
69
|
+
# configure rolling file appender
|
49
70
|
options = {
|
50
71
|
:keep => 7,
|
51
72
|
:roll_by => 'date',
|
@@ -54,7 +75,6 @@ module Bixby
|
|
54
75
|
:auto_flushing => true,
|
55
76
|
:layout => layout
|
56
77
|
}.merge(opts)
|
57
|
-
|
58
78
|
Logging.appenders.rolling_file("file", options)
|
59
79
|
|
60
80
|
Logging::Logger.root.add_appenders("file")
|
@@ -0,0 +1,114 @@
|
|
1
|
+
|
2
|
+
require "bixby-common/websocket/async_response"
|
3
|
+
require "api-auth"
|
4
|
+
|
5
|
+
module Bixby
|
6
|
+
module WebSocket
|
7
|
+
|
8
|
+
# WebSocket API channel
|
9
|
+
#
|
10
|
+
# Implements a simple request/response interface over a WebSocket channel.
|
11
|
+
# Requests can be sent in either direction, in a sync or async manner.
|
12
|
+
class APIChannel < Bixby::APIChannel
|
13
|
+
|
14
|
+
attr_reader :ws
|
15
|
+
|
16
|
+
def initialize(ws, handler)
|
17
|
+
@ws = ws
|
18
|
+
@handler = handler
|
19
|
+
@responses = {}
|
20
|
+
@connected = false
|
21
|
+
end
|
22
|
+
|
23
|
+
# Perform RPC
|
24
|
+
|
25
|
+
# Execute the given request (synchronously)
|
26
|
+
#
|
27
|
+
# @param [JsonRequest] json_request
|
28
|
+
#
|
29
|
+
# @return [JsonResponse] response
|
30
|
+
def execute(json_request)
|
31
|
+
fetch_response( execute_async(json_request) )
|
32
|
+
end
|
33
|
+
|
34
|
+
# Execute the given request (asynchronously)
|
35
|
+
#
|
36
|
+
# @param [JsonRequest] json_request
|
37
|
+
#
|
38
|
+
# @return [String] request id
|
39
|
+
def execute_async(json_request)
|
40
|
+
request = Request.new(json_request)
|
41
|
+
id = request.id
|
42
|
+
@responses[id] = AsyncResponse.new(id)
|
43
|
+
|
44
|
+
EM.next_tick {
|
45
|
+
ws.send(request.to_wire)
|
46
|
+
}
|
47
|
+
id
|
48
|
+
end
|
49
|
+
|
50
|
+
# Fetch the response for the given request
|
51
|
+
#
|
52
|
+
# @param [String] request id
|
53
|
+
#
|
54
|
+
# @return [JsonResponse]
|
55
|
+
def fetch_response(id)
|
56
|
+
res = @responses[id].response
|
57
|
+
@responses.delete(id)
|
58
|
+
res
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Handle channel events
|
63
|
+
|
64
|
+
def connected?
|
65
|
+
@connected
|
66
|
+
end
|
67
|
+
|
68
|
+
# Open
|
69
|
+
def open(event)
|
70
|
+
# TODO extract Agent ID, if Agent
|
71
|
+
logger.debug "new channel opened"
|
72
|
+
@connected = true
|
73
|
+
end
|
74
|
+
|
75
|
+
# Close
|
76
|
+
#
|
77
|
+
# Can be fired either due to disconnection or failure to connect
|
78
|
+
def close(event)
|
79
|
+
if @connected then
|
80
|
+
logger.debug "client disconnected"
|
81
|
+
@connected = false
|
82
|
+
@handler.new(nil).disconnect(self)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Message
|
87
|
+
#
|
88
|
+
# Fired whenever a message is received on the channel
|
89
|
+
def message(event)
|
90
|
+
logger.debug "got a message:\n#{event.data}"
|
91
|
+
req = Message.from_wire(event.data)
|
92
|
+
|
93
|
+
if req.type == "rpc" then
|
94
|
+
# Execute the requested method and return the result
|
95
|
+
json_response = @handler.new(req).handle(req.json_request)
|
96
|
+
|
97
|
+
# result = { :type => "rpc_result", :id => req.id, :data => json_response }
|
98
|
+
# ws.send(MultiJson.dump(result))
|
99
|
+
ws.send(Response.new(json_response, req.id).to_wire)
|
100
|
+
|
101
|
+
elsif req.type == "rpc_result" then
|
102
|
+
# Pass the result back to the caller
|
103
|
+
@responses[req.id].response = JsonResponse.from_json(req.body)
|
104
|
+
|
105
|
+
elsif req.type == "connect" then
|
106
|
+
@handler.new(req).connect(req.json_request, self)
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Bixby
|
5
|
+
module WebSocket
|
6
|
+
|
7
|
+
# Asynchronously receive a response via WebSocket channel
|
8
|
+
class AsyncResponse
|
9
|
+
|
10
|
+
attr_reader :id
|
11
|
+
|
12
|
+
def initialize(id)
|
13
|
+
@id = id
|
14
|
+
@mutex = Mutex.new
|
15
|
+
@cond = ConditionVariable.new
|
16
|
+
@response = nil
|
17
|
+
@completed = false
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set the response and signal any blocking threads
|
21
|
+
#
|
22
|
+
# @param [Object] obj result of request, usually a JsonResponse
|
23
|
+
def response=(obj)
|
24
|
+
@mutex.synchronize {
|
25
|
+
@completed = true
|
26
|
+
@response = obj
|
27
|
+
@cond.signal
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Has the request completed?
|
32
|
+
#
|
33
|
+
# @return [Boolean] true if completed
|
34
|
+
def completed?
|
35
|
+
@completed
|
36
|
+
end
|
37
|
+
|
38
|
+
# Retrieve the response, blocking until it is available
|
39
|
+
#
|
40
|
+
# @return [Object] response data
|
41
|
+
def response
|
42
|
+
return @response if @completed
|
43
|
+
@mutex.synchronize { @cond.wait(@mutex) }
|
44
|
+
return @response
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|