ernie 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -2
- data/VERSION.yml +1 -1
- data/bin/ernie +13 -1
- data/elib/ernie_server.erl +77 -36
- data/ernie.gemspec +2 -2
- data/lib/ernie.rb +11 -0
- metadata +2 -2
data/README.md
CHANGED
@@ -13,13 +13,20 @@ Description
|
|
13
13
|
|
14
14
|
Ernie is a BERT-RPC server implementation that uses an Erlang server to accept incoming connections, and then delegates the request to a Ruby handler via Erlectricity.
|
15
15
|
|
16
|
+
Ernie currently supports the following BERT-RPC features:
|
17
|
+
* `call` requests
|
18
|
+
* `cast` requests
|
19
|
+
|
16
20
|
|
17
21
|
Installation
|
18
22
|
------------
|
19
23
|
|
20
|
-
|
24
|
+
You must have Erlang installed before installing Ernie.
|
25
|
+
|
26
|
+
From GitHub:
|
21
27
|
|
22
|
-
gem install mojombo-ernie -s http://gems.github.com
|
28
|
+
gem install mojombo-ernie -s http://gems.github.com \
|
29
|
+
-s http://gemcutter.org
|
23
30
|
|
24
31
|
|
25
32
|
Running
|
data/VERSION.yml
CHANGED
data/bin/ernie
CHANGED
@@ -14,14 +14,25 @@ def code_paths
|
|
14
14
|
DEFAULT_ERLANG_CODEPATHS.map {|n| "-pz #{rel(n)}" }.join(" ") + " \\"
|
15
15
|
end
|
16
16
|
|
17
|
+
def version
|
18
|
+
yml = YAML.load(File.read(File.join(File.dirname(__FILE__), *%w[.. VERSION.yml])))
|
19
|
+
"#{yml[:major]}.#{yml[:minor]}.#{yml[:patch]}"
|
20
|
+
end
|
21
|
+
|
17
22
|
require 'optparse'
|
18
23
|
require 'pp'
|
24
|
+
require 'yaml'
|
19
25
|
|
20
26
|
help = <<HELP
|
21
27
|
Ernie is an Erlang/Ruby BERT-RPC Server.
|
22
28
|
|
23
29
|
Basic Command Line Usage:
|
24
|
-
ernie [options]
|
30
|
+
ernie [command] [options]
|
31
|
+
|
32
|
+
Commands:
|
33
|
+
<none> Start an Ernie server.
|
34
|
+
reload-handlers Gracefully reload all of the the ruby handlers
|
35
|
+
and use the new code for all subsequent requests.
|
25
36
|
|
26
37
|
Options:
|
27
38
|
HELP
|
@@ -29,6 +40,7 @@ HELP
|
|
29
40
|
options = {}
|
30
41
|
OptionParser.new do |opts|
|
31
42
|
opts.banner = help
|
43
|
+
opts.version = version
|
32
44
|
|
33
45
|
opts.on("-h HANDLER", "--handler HANDLER", "Handler ruby file") do |x|
|
34
46
|
options[:handler] = x
|
data/elib/ernie_server.erl
CHANGED
@@ -11,6 +11,10 @@
|
|
11
11
|
-record(state, {lsock = undefined,
|
12
12
|
pending = queue:new()}).
|
13
13
|
|
14
|
+
-record(request, {sock = undefined,
|
15
|
+
info = undefined,
|
16
|
+
action = undefined}).
|
17
|
+
|
14
18
|
%%====================================================================
|
15
19
|
%% API
|
16
20
|
%%====================================================================
|
@@ -64,30 +68,17 @@ handle_call(_Request, _From, State) ->
|
|
64
68
|
%% Description: Handling cast messages
|
65
69
|
%%--------------------------------------------------------------------
|
66
70
|
handle_cast({process, Sock}, State) ->
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
Term = binary_to_term(BinaryTerm),
|
71
|
-
logger:info("Got term: ~p~n", [Term]),
|
72
|
-
case Term of
|
73
|
-
{call, '__admin__', Fun, Args} ->
|
74
|
-
State2 = process_admin(Sock, Fun, Args, State);
|
75
|
-
Any ->
|
76
|
-
State2 = process_normal(BinaryTerm, Sock, State)
|
77
|
-
end,
|
78
|
-
{noreply, State2};
|
79
|
-
{error, closed} ->
|
80
|
-
ok = gen_tcp:close(Sock),
|
81
|
-
{noreply, State}
|
82
|
-
end;
|
71
|
+
Request = #request{sock = Sock},
|
72
|
+
State2 = receive_term(Request, State),
|
73
|
+
{noreply, State2};
|
83
74
|
handle_cast({asset_freed}, State) ->
|
84
75
|
case queue:is_empty(State#state.pending) of
|
85
76
|
false ->
|
86
77
|
case asset_pool:lease() of
|
87
78
|
{ok, Asset} ->
|
88
|
-
{{value,
|
79
|
+
{{value, Request}, Pending2} = queue:out(State#state.pending),
|
89
80
|
% io:format("d", []),
|
90
|
-
spawn(fun() -> process_now(
|
81
|
+
spawn(fun() -> process_now(Request, Asset) end),
|
91
82
|
{noreply, State#state{pending = Pending2}};
|
92
83
|
empty ->
|
93
84
|
% io:format(".", []),
|
@@ -135,41 +126,91 @@ process_admin(Sock, reload_handlers, _Args, State) ->
|
|
135
126
|
gen_tcp:send(Sock, term_to_binary({reply, <<"Handlers reloaded.">>})),
|
136
127
|
ok = gen_tcp:close(Sock),
|
137
128
|
State;
|
138
|
-
process_admin(Sock,
|
129
|
+
process_admin(Sock, _Fun, _Args, State) ->
|
139
130
|
gen_tcp:send(Sock, term_to_binary({reply, <<"Admin function not supported.">>})),
|
140
131
|
ok = gen_tcp:close(Sock),
|
141
132
|
State.
|
142
133
|
|
143
|
-
|
134
|
+
receive_term(Request, State) ->
|
135
|
+
Sock = Request#request.sock,
|
136
|
+
case gen_tcp:recv(Sock, 0) of
|
137
|
+
{ok, BinaryTerm} ->
|
138
|
+
logger:debug("Got binary term: ~p~n", [BinaryTerm]),
|
139
|
+
Term = binary_to_term(BinaryTerm),
|
140
|
+
logger:info("Got term: ~p~n", [Term]),
|
141
|
+
case Term of
|
142
|
+
{call, '__admin__', Fun, Args} ->
|
143
|
+
process_admin(Sock, Fun, Args, State);
|
144
|
+
{info, _Command, _Args} ->
|
145
|
+
Request2 = Request#request{info = BinaryTerm},
|
146
|
+
receive_term(Request2, State);
|
147
|
+
_Any ->
|
148
|
+
Request2 = Request#request{action = BinaryTerm},
|
149
|
+
process_request(Request2, State)
|
150
|
+
end;
|
151
|
+
{error, closed} ->
|
152
|
+
ok = gen_tcp:close(Sock),
|
153
|
+
State
|
154
|
+
end.
|
155
|
+
|
156
|
+
process_request(Request, State) ->
|
157
|
+
ActionTerm = binary_to_term(Request#request.action),
|
158
|
+
case ActionTerm of
|
159
|
+
{cast, _Mod, _Fun, _Args} ->
|
160
|
+
Sock = Request#request.sock,
|
161
|
+
gen_tcp:send(Sock, term_to_binary({noreply})),
|
162
|
+
ok = gen_tcp:close(Sock),
|
163
|
+
logger:debug("Closing cast.~n", []);
|
164
|
+
_Any ->
|
165
|
+
ok
|
166
|
+
end,
|
144
167
|
case queue:is_empty(State#state.pending) of
|
145
168
|
false ->
|
146
|
-
Pending2 = queue:in(
|
169
|
+
Pending2 = queue:in(Request, State#state.pending),
|
147
170
|
% io:format("Q", []),
|
148
171
|
State#state{pending = Pending2};
|
149
172
|
true ->
|
150
|
-
try_process_now(
|
173
|
+
try_process_now(Request, State)
|
151
174
|
end.
|
152
175
|
|
153
|
-
try_process_now(
|
176
|
+
try_process_now(Request, State) ->
|
154
177
|
case asset_pool:lease() of
|
155
178
|
{ok, Asset} ->
|
156
179
|
% io:format("i", []),
|
157
|
-
spawn(fun() -> process_now(
|
180
|
+
spawn(fun() -> process_now(Request, Asset) end),
|
158
181
|
State;
|
159
182
|
empty ->
|
160
183
|
% io:format("q", []),
|
161
|
-
Pending2 = queue:in(
|
184
|
+
Pending2 = queue:in(Request, State#state.pending),
|
162
185
|
State#state{pending = Pending2}
|
163
186
|
end.
|
164
187
|
|
165
|
-
process_now(
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
188
|
+
process_now(Request, Asset) ->
|
189
|
+
try unsafe_process_now(Request, Asset) of
|
190
|
+
_AnyResponse -> ok
|
191
|
+
catch
|
192
|
+
_AnyError -> ok
|
193
|
+
after
|
194
|
+
asset_pool:return(Asset),
|
195
|
+
ernie_server:asset_freed(),
|
196
|
+
gen_tcp:close(Request#request.sock)
|
197
|
+
end.
|
198
|
+
|
199
|
+
unsafe_process_now(Request, Asset) ->
|
200
|
+
BinaryTerm = Request#request.action,
|
201
|
+
Term = binary_to_term(BinaryTerm),
|
202
|
+
case Term of
|
203
|
+
{call, Mod, Fun, Args} ->
|
204
|
+
logger:debug("Calling ~p:~p(~p)~n", [Mod, Fun, Args]),
|
205
|
+
Sock = Request#request.sock,
|
206
|
+
{asset, Port, Token} = Asset,
|
207
|
+
logger:debug("Asset: ~p ~p~n", [Port, Token]),
|
208
|
+
{ok, Data} = port_wrapper:rpc(Port, BinaryTerm),
|
209
|
+
gen_tcp:send(Sock, Data),
|
210
|
+
ok = gen_tcp:close(Sock);
|
211
|
+
{cast, Mod, Fun, Args} ->
|
212
|
+
logger:debug("Casting ~p:~p(~p)~n", [Mod, Fun, Args]),
|
213
|
+
{asset, Port, Token} = Asset,
|
214
|
+
logger:debug("Asset: ~p ~p~n", [Port, Token]),
|
215
|
+
{ok, _Data} = port_wrapper:rpc(Port, BinaryTerm)
|
216
|
+
end.
|
data/ernie.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{ernie}
|
5
|
-
s.version = "0.3.
|
5
|
+
s.version = "0.3.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Tom Preston-Werner"]
|
9
|
-
s.date = %q{2009-08-
|
9
|
+
s.date = %q{2009-08-20}
|
10
10
|
s.default_executable = %q{ernie}
|
11
11
|
s.email = %q{tom@mojombo.com}
|
12
12
|
s.executables = ["ernie"]
|
data/lib/ernie.rb
CHANGED
@@ -83,6 +83,17 @@ class Ernie
|
|
83
83
|
f.receive_loop
|
84
84
|
end
|
85
85
|
|
86
|
+
f.when([:cast, Symbol, Symbol, Array]) do |mod, fun, args|
|
87
|
+
self.log("-> " + [:cast, mod, fun, args].inspect)
|
88
|
+
begin
|
89
|
+
self.dispatch(mod, fun, args)
|
90
|
+
rescue Object => e
|
91
|
+
# ignore
|
92
|
+
end
|
93
|
+
f.send!([:noreply])
|
94
|
+
f.receive_loop
|
95
|
+
end
|
96
|
+
|
86
97
|
f.when(Any) do |any|
|
87
98
|
self.log("-> " + any.inspect)
|
88
99
|
xres = [:error, [:server, 0, "Invalid request: #{any.inspect}"]]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ernie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Preston-Werner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-20 00:00:00 -07:00
|
13
13
|
default_executable: ernie
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|