ernie 0.3.1 → 0.3.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 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