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 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
- You must have Erlang installed before installing Ernie.
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
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 1
2
+ :patch: 2
3
3
  :major: 0
4
4
  :minor: 3
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] <path to handler file>
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
@@ -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
- case gen_tcp:recv(Sock, 0) of
68
- {ok, BinaryTerm} ->
69
- logger:debug("Got binary term: ~p~n", [BinaryTerm]),
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, {pending, BinaryTerm, Sock}}, Pending2} = queue:out(State#state.pending),
79
+ {{value, Request}, Pending2} = queue:out(State#state.pending),
89
80
  % io:format("d", []),
90
- spawn(fun() -> process_now(BinaryTerm, Sock, Asset) end),
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, Fun, _Args, State) ->
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
- process_normal(BinaryTerm, Sock, State) ->
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({pending, BinaryTerm, Sock}, State#state.pending),
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(BinaryTerm, Sock, State)
173
+ try_process_now(Request, State)
151
174
  end.
152
175
 
153
- try_process_now(BinaryTerm, Sock, State) ->
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(BinaryTerm, Sock, Asset) end),
180
+ spawn(fun() -> process_now(Request, Asset) end),
158
181
  State;
159
182
  empty ->
160
183
  % io:format("q", []),
161
- Pending2 = queue:in({pending, BinaryTerm, Sock}, State#state.pending),
184
+ Pending2 = queue:in(Request, State#state.pending),
162
185
  State#state{pending = Pending2}
163
186
  end.
164
187
 
165
- process_now(BinaryTerm, Sock, Asset) ->
166
- % io:format(".", []),
167
- % error_logger:info_msg("From Internet: ~p~n", [BinaryTerm]),
168
- {asset, Port, Token} = Asset,
169
- logger:debug("Asset: ~p ~p~n", [Port, Token]),
170
- {ok, Data} = port_wrapper:rpc(Port, BinaryTerm),
171
- % error_logger:info_msg("From Port: ~p~n", [Data]),
172
- asset_pool:return(Asset),
173
- ernie_server:asset_freed(),
174
- gen_tcp:send(Sock, Data),
175
- ok = gen_tcp:close(Sock).
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.1"
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-14}
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.1
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-14 00:00:00 -07:00
12
+ date: 2009-08-20 00:00:00 -07:00
13
13
  default_executable: ernie
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency