|
tonyg@24
|
1 |
-module(execdaemon). |
|
tonyg@24
|
2 |
|
|
tonyg@24
|
3 |
-export([open/0, terminate/1, command/3, read_from/1, wait_for_event/1, run/2]). |
|
tonyg@24
|
4 |
|
|
tonyg@24
|
5 |
open() -> |
|
tonyg@24
|
6 |
Pid = spawn(fun startup/0), |
|
tonyg@24
|
7 |
Pid ! {subscribe, self()}, |
|
tonyg@24
|
8 |
receive |
|
tonyg@24
|
9 |
{subscribed, Pid2} when Pid == Pid2 -> Pid |
|
tonyg@24
|
10 |
end. |
|
tonyg@24
|
11 |
|
|
tonyg@24
|
12 |
startup() -> |
|
simon@160
|
13 |
Port = open_port({spawn, jukebox:priv_dir() ++ "/execdaemon/execdaemon"}, [stream, use_stdio, eof]), |
|
tonyg@24
|
14 |
mainloop(Port, 1, [], [], ""). |
|
tonyg@24
|
15 |
|
|
tonyg@24
|
16 |
mainloop(Port, ReqNum, Requests, Subscribers, Acc) -> |
|
tonyg@24
|
17 |
receive |
|
tonyg@24
|
18 |
{subscribe, Pid} -> |
|
tonyg@24
|
19 |
Pid ! {subscribed, self()}, |
|
tonyg@24
|
20 |
mainloop(Port, ReqNum, Requests, [Pid | Subscribers], Acc); |
|
tonyg@24
|
21 |
execdaemon_terminate -> |
|
tonyg@24
|
22 |
port_command(Port, [0]), |
|
tonyg@24
|
23 |
mainloop(Port, ReqNum, Requests, Subscribers, Acc); |
|
tonyg@24
|
24 |
{execdaemon_command, Pid, Command, Arg} -> |
|
tonyg@24
|
25 |
port_command(Port, lists:flatten([integer_to_list(ReqNum), ":", |
|
tonyg@24
|
26 |
atom_to_list(Command), ",", Arg, [0]])), |
|
tonyg@24
|
27 |
mainloop(Port, ReqNum + 1, [{ReqNum, Pid} | Requests], Subscribers, Acc); |
|
tonyg@24
|
28 |
{_Port1, eof} -> |
|
tonyg@24
|
29 |
{_, Pids} = lists:unzip(Requests), |
|
tonyg@24
|
30 |
send_to_subs(Pids ++ Subscribers, {execdaemon_eof, self()}), |
|
tonyg@24
|
31 |
port_close(Port); |
|
tonyg@24
|
32 |
{_Port1, {data, Data}} -> |
|
tonyg@24
|
33 |
{NewRequests, NewAcc} = process_received(Subscribers, Requests, Acc, Data), |
|
tonyg@24
|
34 |
mainloop(Port, ReqNum, NewRequests, Subscribers, NewAcc) |
|
tonyg@24
|
35 |
end. |
|
tonyg@24
|
36 |
|
|
tonyg@24
|
37 |
send_to_subs(Subscribers, Msg) -> |
|
tonyg@24
|
38 |
lists:foreach(fun (Subscriber) -> Subscriber ! Msg end, Subscribers). |
|
tonyg@24
|
39 |
|
|
tonyg@24
|
40 |
process_received(_Subscribers, Requests, Acc, []) -> |
|
tonyg@24
|
41 |
{Requests, Acc}; |
|
tonyg@24
|
42 |
process_received(Subscribers, Requests, Acc, [0 | Rest]) -> |
|
tonyg@24
|
43 |
{ReqNum, Code, Aux} = split_response(lists:reverse(Acc)), |
|
tonyg@24
|
44 |
if |
|
tonyg@24
|
45 |
ReqNum == 0 -> |
|
tonyg@24
|
46 |
send_to_subs(Subscribers, {execdaemon_event, self(), Code, Aux}), |
|
tonyg@24
|
47 |
process_received(Subscribers, Requests, [], Rest); |
|
tonyg@24
|
48 |
true -> |
|
tonyg@24
|
49 |
case proplists:get_value(ReqNum, Requests, none) of |
|
tonyg@24
|
50 |
none -> process_received(Subscribers, Requests, [], Rest); |
|
tonyg@24
|
51 |
Pid -> |
|
tonyg@24
|
52 |
Pid ! {execdaemon_response, self(), Code, Aux}, |
|
tonyg@24
|
53 |
process_received(Subscribers, proplists:delete(ReqNum, Requests), [], Rest) |
|
tonyg@24
|
54 |
end |
|
tonyg@24
|
55 |
end; |
|
tonyg@24
|
56 |
process_received(Subscribers, Requests, Acc, [Ch | Rest]) -> |
|
tonyg@24
|
57 |
process_received(Subscribers, Requests, [Ch | Acc], Rest). |
|
tonyg@24
|
58 |
|
|
tonyg@24
|
59 |
split_response(Str) -> |
|
tonyg@24
|
60 |
{ReqNum, ":" ++ CmdArg} = lists:split(string:chr(Str, $:) - 1, Str), |
|
tonyg@24
|
61 |
{Cmd, "," ++ Arg} = lists:split(string:chr(CmdArg, $,) - 1, CmdArg), |
|
tonyg@24
|
62 |
{list_to_integer(ReqNum), list_to_atom(Cmd), Arg}. |
|
tonyg@24
|
63 |
|
|
tonyg@24
|
64 |
terminate(Pid) -> |
|
tonyg@24
|
65 |
Pid ! execdaemon_terminate. |
|
tonyg@24
|
66 |
|
|
tonyg@24
|
67 |
command(Pid, Command, Arg) -> |
|
tonyg@24
|
68 |
Pid ! {execdaemon_command, self(), Command, Arg}, |
|
tonyg@24
|
69 |
read_from(Pid). |
|
tonyg@24
|
70 |
|
|
tonyg@24
|
71 |
read_from(Pid) -> |
|
tonyg@24
|
72 |
receive |
|
tonyg@24
|
73 |
{execdaemon_response, Pid1, Code, Aux} when Pid == Pid1 -> |
|
tonyg@24
|
74 |
{Code, Aux}; |
|
tonyg@24
|
75 |
{execdaemon_eof, Pid1} when Pid == Pid1 -> |
|
tonyg@24
|
76 |
eof |
|
tonyg@24
|
77 |
end. |
|
tonyg@24
|
78 |
|
|
tonyg@24
|
79 |
wait_for_event(Pid) -> |
|
tonyg@24
|
80 |
receive |
|
tonyg@24
|
81 |
{execdaemon_event, Pid1, Code, Aux} when Pid == Pid1 -> |
|
tonyg@24
|
82 |
{Code, Aux}; |
|
tonyg@24
|
83 |
{execdaemon_eof, Pid1} when Pid == Pid1 -> |
|
tonyg@24
|
84 |
eof |
|
tonyg@24
|
85 |
end. |
|
tonyg@24
|
86 |
|
|
tonyg@24
|
87 |
run(Program, Argvec) -> |
|
tonyg@24
|
88 |
Pid = open(), |
|
tonyg@24
|
89 |
command(Pid, program, Program), |
|
tonyg@24
|
90 |
command(Pid, argc, integer_to_list(length(Argvec))), |
|
tonyg@24
|
91 |
lists:foldl(fun (Arg, Count) -> |
|
tonyg@24
|
92 |
command(Pid, arg, [integer_to_list(Count), ",", Arg]), |
|
tonyg@24
|
93 |
Count + 1 |
|
tonyg@24
|
94 |
end, 0, Argvec), |
|
tonyg@24
|
95 |
command(Pid, execv, ""), |
|
tonyg@24
|
96 |
Pid. |