schleyfox-ernie 2.2.1

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.
@@ -0,0 +1,326 @@
1
+ -module(ernie_server).
2
+ -behaviour(gen_server).
3
+ -include_lib("ernie.hrl").
4
+
5
+ %% api
6
+ -export([start_link/1, start/1, process/1, kick/0]).
7
+
8
+ %% gen_server callbacks
9
+ -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
10
+ terminate/2, code_change/3]).
11
+
12
+ %%====================================================================
13
+ %% API
14
+ %%====================================================================
15
+
16
+ start_link(Args) ->
17
+ gen_server:start_link({global, ?MODULE}, ?MODULE, Args, []).
18
+
19
+ start(Args) ->
20
+ gen_server:start({global, ?MODULE}, ?MODULE, Args, []).
21
+
22
+ process(Sock) ->
23
+ gen_server:cast({global, ?MODULE}, {process, Sock}).
24
+
25
+ kick() ->
26
+ gen_server:cast({global, ?MODULE}, kick).
27
+
28
+ %%====================================================================
29
+ %% gen_server callbacks
30
+ %%====================================================================
31
+
32
+ %%--------------------------------------------------------------------
33
+ %% Function: init(Args) -> {ok, State} |
34
+ %% {ok, State, Timeout} |
35
+ %% ignore |
36
+ %% {stop, Reason}
37
+ %% Description: Initiates the server
38
+ %%--------------------------------------------------------------------
39
+ init([Port, Configs]) ->
40
+ process_flag(trap_exit, true),
41
+ error_logger:info_msg("~p starting~n", [?MODULE]),
42
+ {ok, LSock} = try_listen(Port, 500),
43
+ spawn(fun() -> loop(LSock) end),
44
+ Map = init_map(Configs),
45
+ run_init_functions(Configs),
46
+ io:format("pidmap = ~p~n", [Map]),
47
+ {ok, #state{lsock = LSock, map = Map}}.
48
+
49
+ %%--------------------------------------------------------------------
50
+ %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
51
+ %% {reply, Reply, State, Timeout} |
52
+ %% {noreply, State} |
53
+ %% {noreply, State, Timeout} |
54
+ %% {stop, Reason, Reply, State} |
55
+ %% {stop, Reason, State}
56
+ %% Description: Handling call messages
57
+ %%--------------------------------------------------------------------
58
+ handle_call(_Request, _From, State) ->
59
+ {reply, ok, State}.
60
+
61
+ %%--------------------------------------------------------------------
62
+ %% Function: handle_cast(Msg, State) -> {noreply, State} |
63
+ %% {noreply, State, Timeout} |
64
+ %% {stop, Reason, State}
65
+ %% Description: Handling cast messages
66
+ %%--------------------------------------------------------------------
67
+ handle_cast({process, Sock}, State) ->
68
+ Log = #log{hq = queue:len(State#state.hq),
69
+ lq = queue:len(State#state.lq),
70
+ taccept = erlang:now()},
71
+ Request = #request{sock = Sock, log = Log},
72
+ State2 = receive_term(Request, State),
73
+ {noreply, State2};
74
+ handle_cast(kick, State) ->
75
+ case queue:out(State#state.hq) of
76
+ {{value, Request}, Hq2} ->
77
+ State2 = process_request(Request, hq, Hq2, State),
78
+ {noreply, State2};
79
+ {empty, _Hq} ->
80
+ case queue:out(State#state.lq) of
81
+ {{value, Request}, Lq2} ->
82
+ State2 = process_request(Request, lq, Lq2, State),
83
+ {noreply, State2};
84
+ {empty, _Lq} ->
85
+ {noreply, State}
86
+ end
87
+ end;
88
+ handle_cast(_Msg, State) -> {noreply, State}.
89
+
90
+ handle_info(Msg, State) ->
91
+ error_logger:error_msg("Unexpected message: ~p~n", [Msg]),
92
+ {noreply, State}.
93
+
94
+ terminate(_Reason, _State) -> ok.
95
+ code_change(_OldVersion, State, _Extra) -> {ok, State}.
96
+
97
+ %%====================================================================
98
+ %% Internal
99
+ %%====================================================================
100
+
101
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102
+ % Module mapping
103
+
104
+ init_map(Configs) ->
105
+ lists:map((fun extract_mapping/1), Configs).
106
+
107
+ extract_mapping(Config) ->
108
+ Id = proplists:get_value(id, Config),
109
+ Mod = proplists:get_value(module, Config),
110
+ {Mod, Id}.
111
+
112
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113
+ % Init Function
114
+
115
+ run_init_functions(Configs) ->
116
+ lists:foreach(fun(Config) ->
117
+ case proplists:get_value(init, Config) of
118
+ undefined -> undefined;
119
+ {Mod, Func, Args} -> apply(Mod, Func, Args)
120
+ end
121
+ end,
122
+ Configs).
123
+
124
+
125
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126
+ % Listen and loop
127
+
128
+ try_listen(Port, 0) ->
129
+ error_logger:error_msg("Could not listen on port ~p~n", [Port]),
130
+ {error, "Could not listen on port"};
131
+ try_listen(Port, Times) ->
132
+ Res = gen_tcp:listen(Port, [binary, {packet, 4}, {active, false}, {reuseaddr, true}]),
133
+ case Res of
134
+ {ok, LSock} ->
135
+ error_logger:info_msg("Listening on port ~p~n", [Port]),
136
+ {ok, LSock};
137
+ {error, Reason} ->
138
+ error_logger:info_msg("Could not listen on port ~p: ~p~n", [Port, Reason]),
139
+ timer:sleep(5000),
140
+ try_listen(Port, Times - 1)
141
+ end.
142
+
143
+ loop(LSock) ->
144
+ {ok, Sock} = gen_tcp:accept(LSock),
145
+ logger:debug("Accepted socket: ~p~n", [Sock]),
146
+ ernie_server:process(Sock),
147
+ loop(LSock).
148
+
149
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150
+ % Receive and process
151
+
152
+ receive_term(Request, State) ->
153
+ Sock = Request#request.sock,
154
+ case gen_tcp:recv(Sock, 0) of
155
+ {ok, BinaryTerm} ->
156
+ logger:debug("Got binary term: ~p~n", [BinaryTerm]),
157
+ Term = binary_to_term(BinaryTerm),
158
+ logger:info("Got term: ~p~n", [Term]),
159
+ case Term of
160
+ {call, '__admin__', Fun, Args} ->
161
+ ernie_admin:process(Sock, Fun, Args, State);
162
+ {info, Command, Args} ->
163
+ Infos = Request#request.infos,
164
+ Infos2 = [BinaryTerm | Infos],
165
+ Request2 = Request#request{infos = Infos2},
166
+ Request3 = process_info(Request2, Command, Args),
167
+ receive_term(Request3, State);
168
+ _Any ->
169
+ Request2 = Request#request{action = BinaryTerm},
170
+ close_if_cast(Term, Request2),
171
+ case Request2#request.priority of
172
+ high ->
173
+ Hq2 = queue:in(Request2, State#state.hq),
174
+ Lq2 = State#state.lq;
175
+ low ->
176
+ Hq2 = State#state.hq,
177
+ Lq2 = queue:in(Request2, State#state.lq)
178
+ end,
179
+ ernie_server:kick(),
180
+ State#state{hq = Hq2, lq = Lq2}
181
+ end;
182
+ {error, closed} ->
183
+ ok = gen_tcp:close(Sock),
184
+ State
185
+ end.
186
+
187
+ process_info(Request, priority, [Priority]) ->
188
+ Request#request{priority = Priority};
189
+ process_info(Request, _Command, _Args) ->
190
+ Request.
191
+
192
+ process_request(Request, Priority, Q2, State) ->
193
+ ActionTerm = bert:decode(Request#request.action),
194
+ {_Type, Mod, _Fun, _Args} = ActionTerm,
195
+ Specs = lists:filter(fun({X, _Id}) -> Mod =:= X end, State#state.map),
196
+ process_module(ActionTerm, Specs, Request, Priority, Q2, State).
197
+
198
+ process_module(ActionTerm, [], Request, Priority, Q2, State) ->
199
+ {_Type, Mod, _Fun, _Args} = ActionTerm,
200
+ logger:debug("No such module ~p~n", [Mod]),
201
+ Sock = Request#request.sock,
202
+ Class = <<"ServerError">>,
203
+ Message = list_to_binary(io_lib:format("No such module '~p'", [Mod])),
204
+ gen_tcp:send(Sock, term_to_binary({error, [server, 0, Class, Message, []]})),
205
+ ok = gen_tcp:close(Sock),
206
+ finish(Priority, Q2, State);
207
+ process_module(ActionTerm, Specs, Request, Priority, Q2, State) ->
208
+ [{_Mod, Id} | OtherSpecs] = Specs,
209
+ case Id of
210
+ native ->
211
+ logger:debug("Dispatching to native module~n", []),
212
+ {_Type, Mod, Fun, Args} = ActionTerm,
213
+ case erlang:function_exported(Mod, Fun, length(Args)) of
214
+ false ->
215
+ logger:debug("Not found in native module ~p~n", [Mod]),
216
+ process_module(ActionTerm, OtherSpecs, Request, Priority, Q2, State);
217
+ true ->
218
+ PredFun = list_to_atom(atom_to_list(Fun) ++ "_pred"),
219
+ logger:debug("Checking ~p:~p(~p) for selection.~n", [Mod, PredFun, Args]),
220
+ case erlang:function_exported(Mod, PredFun, length(Args)) of
221
+ false ->
222
+ logger:debug("No such predicate function ~p:~p(~p).~n", [Mod, PredFun, Args]),
223
+ process_native_request(ActionTerm, Request, Priority, Q2, State);
224
+ true ->
225
+ case apply(Mod, PredFun, Args) of
226
+ false ->
227
+ logger:debug("Predicate ~p:~p(~p) returned false.~n", [Mod, PredFun, Args]),
228
+ process_module(ActionTerm, OtherSpecs, Request, Priority, Q2, State);
229
+ true ->
230
+ logger:debug("Predicate ~p:~p(~p) returned true.~n", [Mod, PredFun, Args]),
231
+ process_native_request(ActionTerm, Request, Priority, Q2, State)
232
+ end
233
+ end
234
+ end;
235
+ ValidPid when is_pid(ValidPid) ->
236
+ logger:debug("Found external pid ~p~n", [ValidPid]),
237
+ process_external_request(ValidPid, Request, Priority, Q2, State)
238
+ end.
239
+
240
+ close_if_cast(ActionTerm, Request) ->
241
+ case ActionTerm of
242
+ {cast, _Mod, _Fun, _Args} ->
243
+ Sock = Request#request.sock,
244
+ gen_tcp:send(Sock, term_to_binary({noreply})),
245
+ ok = gen_tcp:close(Sock),
246
+ logger:debug("Closed cast.~n", []);
247
+ _Any ->
248
+ ok
249
+ end.
250
+
251
+ finish(Priority, Q2, State) ->
252
+ case Priority of
253
+ hq -> State#state{hq = Q2};
254
+ lq -> State#state{lq = Q2}
255
+ end.
256
+
257
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258
+ % Native
259
+
260
+ process_native_request(ActionTerm, Request, Priority, Q2, State) ->
261
+ Count = State#state.count,
262
+ State2 = State#state{count = Count + 1},
263
+ logger:debug("Count = ~p~n", [Count + 1]),
264
+ Log = Request#request.log,
265
+ Log2 = Log#log{type = native, tprocess = erlang:now()},
266
+ Request2 = Request#request{log = Log2},
267
+ spawn(fun() -> ernie_native:process(ActionTerm, Request2) end),
268
+ finish(Priority, Q2, State2).
269
+
270
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271
+ % External
272
+
273
+ process_external_request(Pid, Request, Priority, Q2, State) ->
274
+ Count = State#state.count,
275
+ State2 = State#state{count = Count + 1},
276
+ logger:debug("Count = ~p~n", [Count + 1]),
277
+ case asset_pool:lease(Pid) of
278
+ {ok, Asset} ->
279
+ logger:debug("Leased asset for pool ~p~n", [Pid]),
280
+ Log = Request#request.log,
281
+ Log2 = Log#log{type = external, tprocess = erlang:now()},
282
+ Request2 = Request#request{log = Log2},
283
+ spawn(fun() -> process_now(Pid, Request2, Asset) end),
284
+ finish(Priority, Q2, State2);
285
+ empty ->
286
+ State
287
+ end.
288
+
289
+ process_now(Pid, Request, Asset) ->
290
+ try unsafe_process_now(Request, Asset) of
291
+ _AnyResponse ->
292
+ Log = Request#request.log,
293
+ Log2 = Log#log{tdone = erlang:now()},
294
+ Request2 = Request#request{log = Log2},
295
+ ernie_access_logger:acc(Request2)
296
+ catch
297
+ AnyClass:AnyError ->
298
+ Log = Request#request.log,
299
+ Log2 = Log#log{tdone = erlang:now()},
300
+ Request2 = Request#request{log = Log2},
301
+ ernie_access_logger:err(Request2, "External process error ~w: ~w", [AnyClass, AnyError])
302
+ after
303
+ asset_pool:return(Pid, Asset),
304
+ ernie_server:kick(),
305
+ logger:debug("Returned asset ~p~n", [Asset]),
306
+ gen_tcp:close(Request#request.sock),
307
+ logger:debug("Closed socket ~p~n", [Request#request.sock])
308
+ end.
309
+
310
+ unsafe_process_now(Request, Asset) ->
311
+ BinaryTerm = Request#request.action,
312
+ Term = binary_to_term(BinaryTerm),
313
+ case Term of
314
+ {call, Mod, Fun, Args} ->
315
+ logger:debug("Calling ~p:~p(~p)~n", [Mod, Fun, Args]),
316
+ Sock = Request#request.sock,
317
+ {asset, Port, Token} = Asset,
318
+ logger:debug("Asset: ~p ~p~n", [Port, Token]),
319
+ {ok, Data} = port_wrapper:rpc(Port, BinaryTerm),
320
+ ok = gen_tcp:send(Sock, Data);
321
+ {cast, Mod, Fun, Args} ->
322
+ logger:debug("Casting ~p:~p(~p)~n", [Mod, Fun, Args]),
323
+ {asset, Port, Token} = Asset,
324
+ logger:debug("Asset: ~p ~p~n", [Port, Token]),
325
+ {ok, _Data} = port_wrapper:rpc(Port, BinaryTerm)
326
+ end.
@@ -0,0 +1,20 @@
1
+ -module(ernie_server_app).
2
+ -behaviour(application).
3
+
4
+ -export([boot/0, start/2, stop/1]).
5
+
6
+ boot() ->
7
+ application:start(ernie_server_app).
8
+
9
+ start(_Type, _Args) ->
10
+ case application:get_env(ernie_server_app, access_log) of
11
+ {ok, AccessFile} ->
12
+ ernie_access_logger_sup:start_link(AccessFile);
13
+ undefined ->
14
+ ernie_access_logger_sup:start_link(undefined)
15
+ end,
16
+ logger_sup:start_link(),
17
+ ernie_server_sup:start_link().
18
+
19
+ stop(_State) ->
20
+ ok.
@@ -0,0 +1,22 @@
1
+ -module(ernie_server_sup).
2
+ -behaviour(supervisor).
3
+ -export([start_link/0, init/1]).
4
+
5
+ start_link() ->
6
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
7
+
8
+ init([]) ->
9
+ {ok, Port} = application:get_env(ernie_server_app, port),
10
+ io:format("Using port ~p~n", [Port]),
11
+ case application:get_env(ernie_server_app, pidfile) of
12
+ {ok, Location} ->
13
+ Pid = os:getpid(),
14
+ ok = file:write_file(Location, list_to_binary(Pid));
15
+ undefined -> ok
16
+ end,
17
+ {ok, Config} = application:get_env(ernie_server_app, config),
18
+ {ok, Configs} = ernie_config:load(Config),
19
+ io:format("~p~n", [Configs]),
20
+ {ok, {{one_for_one, 1, 60},
21
+ [{ernie_server, {ernie_server, start_link, [[Port, Configs]]},
22
+ permanent, brutal_kill, worker, [ernie_server]}]}}.
data/elib/logger.erl ADDED
@@ -0,0 +1,108 @@
1
+ -module(logger).
2
+ -behaviour(gen_server).
3
+
4
+ %% api
5
+ -export([start_link/1, start/1, set_log_level/1, debug/2, info/2, warn/2, error/2, fatal/2]).
6
+
7
+ %% gen_server callbacks
8
+ -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
9
+ terminate/2, code_change/3]).
10
+
11
+ -record(state, {log_level = undefined}).
12
+
13
+ %%====================================================================
14
+ %% API
15
+ %%====================================================================
16
+
17
+ start_link(Args) ->
18
+ gen_server:start_link({global, ?MODULE}, ?MODULE, Args, []).
19
+
20
+ start(Args) ->
21
+ gen_server:start({global, ?MODULE}, ?MODULE, Args, []).
22
+
23
+ set_log_level(Level) ->
24
+ gen_server:call({global, ?MODULE}, {set_log_level, Level}).
25
+
26
+ debug(Msg, Args) ->
27
+ gen_server:cast({global, ?MODULE}, {debug, Msg, Args}).
28
+
29
+ info(Msg, Args) ->
30
+ gen_server:cast({global, ?MODULE}, {info, Msg, Args}).
31
+
32
+ warn(Msg, Args) ->
33
+ gen_server:cast({global, ?MODULE}, {warn, Msg, Args}).
34
+
35
+ error(Msg, Args) ->
36
+ gen_server:cast({global, ?MODULE}, {error, Msg, Args}).
37
+
38
+ fatal(Msg, Args) ->
39
+ gen_server:cast({global, ?MODULE}, {fatal, Msg, Args}).
40
+
41
+ %%====================================================================
42
+ %% gen_server callbacks
43
+ %%====================================================================
44
+
45
+ %%--------------------------------------------------------------------
46
+ %% Function: init(Args) -> {ok, State} |
47
+ %% {ok, State, Timeout} |
48
+ %% ignore |
49
+ %% {stop, Reason}
50
+ %% Description: Initiates the server
51
+ %%--------------------------------------------------------------------
52
+ init([LogLevel]) ->
53
+ error_logger:info_msg("~p starting~n", [?MODULE]),
54
+ {ok, #state{log_level = LogLevel}}.
55
+
56
+ %%--------------------------------------------------------------------
57
+ %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
58
+ %% {reply, Reply, State, Timeout} |
59
+ %% {noreply, State} |
60
+ %% {noreply, State, Timeout} |
61
+ %% {stop, Reason, Reply, State} |
62
+ %% {stop, Reason, State}
63
+ %% Description: Handling call messages
64
+ %%--------------------------------------------------------------------
65
+ handle_call({set_log_level, Level}, _From, State) ->
66
+ {reply, ok, State#state{log_level = Level}};
67
+ handle_call(_Request, _From, State) ->
68
+ {reply, ok, State}.
69
+
70
+ %%--------------------------------------------------------------------
71
+ %% Function: handle_cast(Msg, State) -> {noreply, State} |
72
+ %% {noreply, State, Timeout} |
73
+ %% {stop, Reason, State}
74
+ %% Description: Handling cast messages
75
+ %%--------------------------------------------------------------------
76
+ handle_cast({debug, Msg, Args}, State) ->
77
+ log(State#state.log_level, 4, Msg, Args),
78
+ {noreply, State};
79
+ handle_cast({info, Msg, Args}, State) ->
80
+ log(State#state.log_level, 3, Msg, Args),
81
+ {noreply, State};
82
+ handle_cast({warn, Msg, Args}, State) ->
83
+ log(State#state.log_level, 2, Msg, Args),
84
+ {noreply, State};
85
+ handle_cast({error, Msg, Args}, State) ->
86
+ log(State#state.log_level, 1, Msg, Args),
87
+ {noreply, State};
88
+ handle_cast({fatal, Msg, Args}, State) ->
89
+ log(State#state.log_level, 0, Msg, Args),
90
+ {noreply, State};
91
+ handle_cast(_Msg, State) -> {noreply, State}.
92
+
93
+ handle_info(Msg, State) ->
94
+ error_logger:error_msg("Unexpected message: ~p~n", [Msg]),
95
+ {noreply, State}.
96
+
97
+ terminate(_Reason, _State) -> ok.
98
+ code_change(_OldVersion, State, _Extra) -> {ok, State}.
99
+
100
+ %%====================================================================
101
+ %% Internal
102
+ %%====================================================================
103
+
104
+ log(SystemLogLevel, MessageLogLevel, Message, Args) ->
105
+ case SystemLogLevel >= MessageLogLevel of
106
+ false -> ok;
107
+ true -> io:format(Message, Args)
108
+ end.
@@ -0,0 +1,13 @@
1
+ -module(logger_sup).
2
+ -behaviour(supervisor).
3
+ -export([start_link/0, init/1]).
4
+
5
+ start_link() ->
6
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
7
+
8
+ init([]) ->
9
+ {ok, LogLevel} = application:get_env(ernie_server_app, log_level),
10
+ io:format("Using log level ~p~n", [LogLevel]),
11
+ {ok, {{one_for_one, 1, 60},
12
+ [{logger, {logger, start_link, [[LogLevel]]},
13
+ permanent, brutal_kill, worker, [logger]}]}}.
@@ -0,0 +1,65 @@
1
+ -module(port_wrapper).
2
+ -export([wrap/1, wrap/2, wrap_link/1, wrap_link/2, send/2, shutdown/1, close/1, rpc/2]).
3
+
4
+ wrap(Command) ->
5
+ spawn(fun() -> process_flag(trap_exit, true), Port = create_port(Command), loop(Port, infinity, Command) end).
6
+ wrap(Command, Timeout) ->
7
+ spawn(fun() -> process_flag(trap_exit, true), Port = create_port(Command), loop(Port, Timeout, Command) end).
8
+
9
+ wrap_link(Command) ->
10
+ spawn_link(fun() -> process_flag(trap_exit, true), Port = create_port(Command), link(Port), loop(Port, infinity, Command) end).
11
+ wrap_link(Command, Timeout) ->
12
+ spawn_link(fun() -> process_flag(trap_exit, true), Port = create_port(Command), link(Port), loop(Port, Timeout, Command) end).
13
+
14
+ rpc(WrappedPort, Message) ->
15
+ send(WrappedPort, Message),
16
+ receive
17
+ {WrappedPort, Result} -> {ok, Result}
18
+ end.
19
+
20
+ send(WrappedPort, Message) ->
21
+ WrappedPort ! {self(), {command, Message}},
22
+ WrappedPort.
23
+
24
+ shutdown(WrappedPort) ->
25
+ WrappedPort ! shutdown,
26
+ true.
27
+
28
+ close(WrappedPort) ->
29
+ WrappedPort ! noose,
30
+ true.
31
+
32
+ create_port(Command) ->
33
+ open_port({spawn, Command}, [{packet, 4}, nouse_stdio, exit_status, binary]).
34
+
35
+ loop(Port, Timeout, Command) ->
36
+ receive
37
+ noose ->
38
+ port_close(Port),
39
+ noose;
40
+ shutdown ->
41
+ port_close(Port),
42
+ exit(shutdown);
43
+ {Source, {command, Message}} ->
44
+ Port ! {self(), {command, Message}},
45
+ receive
46
+ {Port, {data, Result}} ->
47
+ Source ! {self(), Result}
48
+ after Timeout ->
49
+ error_logger:error_msg("Port Wrapper ~p timed out in mid operation (~p)!~n", [self(),Message]),
50
+ % We timed out, which means we need to close and then restart the port
51
+ port_close(Port), % Should SIGPIPE the child.
52
+ exit(timed_out)
53
+ end,
54
+ loop(Port,Timeout,Command);
55
+ {Port, {exit_status, _Code}} ->
56
+ % Hard and Unanticipated Crash
57
+ error_logger:error_msg( "Port closed! ~p~n", [Port] ),
58
+ exit({error, _Code});
59
+ {'EXIT',_Pid,shutdown} ->
60
+ port_close(Port),
61
+ exit(shutdown);
62
+ Any ->
63
+ error_logger:warning_msg("PortWrapper ~p got unexpected message: ~p~n", [self(), Any]),
64
+ loop(Port, Timeout, Command)
65
+ end.
data/ernie.gemspec ADDED
@@ -0,0 +1,94 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{schleyfox-ernie}
8
+ s.version = "2.2.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tom Preston-Werner"]
12
+ s.date = %q{2010-03-12}
13
+ s.default_executable = %q{ernie}
14
+ s.description = %q{Ernie is an Erlang/Ruby hybrid BERT-RPC server implementation packaged as a gem.}
15
+ s.email = %q{tom@mojombo.com}
16
+ s.executables = ["ernie"]
17
+ s.extensions = ["ext/extconf.rb", "ext/extconf.rb"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE",
20
+ "README.md"
21
+ ]
22
+ s.files = [
23
+ ".document",
24
+ ".gitignore",
25
+ "History.txt",
26
+ "LICENSE",
27
+ "README.md",
28
+ "Rakefile",
29
+ "VERSION.yml",
30
+ "bin/ernie",
31
+ "contrib/ebench.erl",
32
+ "ebin/ernie_server_app.app",
33
+ "elib/asset_pool.erl",
34
+ "elib/asset_pool_sup.erl",
35
+ "elib/bert.erl",
36
+ "elib/ernie.hrl",
37
+ "elib/ernie_access_logger.erl",
38
+ "elib/ernie_access_logger_sup.erl",
39
+ "elib/ernie_admin.erl",
40
+ "elib/ernie_config.erl",
41
+ "elib/ernie_native.erl",
42
+ "elib/ernie_server.erl",
43
+ "elib/ernie_server_app.erl",
44
+ "elib/ernie_server_sup.erl",
45
+ "elib/logger.erl",
46
+ "elib/logger_sup.erl",
47
+ "elib/port_wrapper.erl",
48
+ "ernie.gemspec",
49
+ "examples/example.cfg",
50
+ "examples/ext.erl",
51
+ "examples/ext.rb",
52
+ "examples/nat.erl",
53
+ "ext/Makefile",
54
+ "ext/extconf.rb",
55
+ "lib/ernie.rb",
56
+ "test/ernie_server_test.rb",
57
+ "test/ernie_test.rb",
58
+ "test/helper.rb",
59
+ "test/load.rb",
60
+ "test/sample/ext.rb",
61
+ "test/sample/sample.cfg"
62
+ ]
63
+ s.homepage = %q{http://github.com/mojombo/ernie}
64
+ s.rdoc_options = ["--charset=UTF-8"]
65
+ s.require_paths = ["lib"]
66
+ s.rubyforge_project = %q{ernie}
67
+ s.rubygems_version = %q{1.3.5}
68
+ s.summary = %q{Ernie is a BERT-RPC server implementation.}
69
+ s.test_files = [
70
+ "test/ernie_server_test.rb",
71
+ "test/ernie_test.rb",
72
+ "test/helper.rb",
73
+ "test/load.rb",
74
+ "test/sample/ext.rb",
75
+ "examples/ext.rb"
76
+ ]
77
+
78
+ if s.respond_to? :specification_version then
79
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
80
+ s.specification_version = 3
81
+
82
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
83
+ s.add_runtime_dependency(%q<bert>, [">= 1.1.0"])
84
+ s.add_runtime_dependency(%q<bertrpc>, [">= 1.0.0"])
85
+ else
86
+ s.add_dependency(%q<bert>, [">= 1.1.0"])
87
+ s.add_dependency(%q<bertrpc>, [">= 1.0.0"])
88
+ end
89
+ else
90
+ s.add_dependency(%q<bert>, [">= 1.1.0"])
91
+ s.add_dependency(%q<bertrpc>, [">= 1.0.0"])
92
+ end
93
+ end
94
+
@@ -0,0 +1,12 @@
1
+ [{module, ext},
2
+ {type, native},
3
+ {codepaths, ["examples"]}].
4
+
5
+ [{module, ext},
6
+ {type, external},
7
+ {command, "ruby examples/ext.rb"},
8
+ {count, 2}].
9
+
10
+ [{module, nat},
11
+ {type, native},
12
+ {codepaths, ["examples"]}].
data/examples/ext.erl ADDED
@@ -0,0 +1,8 @@
1
+ -module(ext).
2
+ -export([shadow_pred/1, shadow/1]).
3
+
4
+ shadow_pred(X) ->
5
+ X > 10.
6
+
7
+ shadow(_X) ->
8
+ <<"erlang">>.