-
Notifications
You must be signed in to change notification settings - Fork 288
/
get-poetry
executable file
·104 lines (76 loc) · 2.46 KB
/
get-poetry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable
-mode(compile).
usage() ->
io:format("usage: get-poetry [hostname]:port ...
This is the Get Poetry Now! client, Erlang Edition.
Run it like this:
get-poetry port1 port2 port3 ...
If you are in the base directory of the twisted-intro package,
you could run it like this:
erlang-client/get-poetry 10001 10002 10003
to grab poetry from servers on ports 10001, 10002, and 10003.
Of course, there need to be servers listening on those ports
for that to work.
"),
halt(1).
parse_args(Args) ->
try
[parse_addr(Arg) || Arg <- Args]
catch
_:_ ->
usage()
end.
parse_addr(Addr) ->
parse_addr(Addr, []).
parse_addr([], Accum) ->
{"localhost", erlang:list_to_integer(lists:reverse(Accum))};
parse_addr([$:|Addr], Accum) ->
{lists:reverse(Accum), erlang:list_to_integer(Addr)};
parse_addr([Ch|Addr], Accum) ->
parse_addr(Addr, [Ch|Accum]).
enumerate(L) ->
enumerate(L, 1).
enumerate([], _) ->
[];
enumerate([X|Xs], N) ->
[{N, X} | enumerate(Xs, N+1)].
collect_poems(0, Poems) ->
[io:format("~s\n", [P]) || P <- Poems];
collect_poems(N, Poems) ->
receive
{'DOWN', _, _, _, _} ->
collect_poems(N-1, Poems);
{poem, Poem} ->
collect_poems(N, [Poem|Poems])
end.
peername(Socket) ->
{ok, {IP, Port}} = inet:peername(Socket),
format_ip(IP) ++ ":" ++ erlang:integer_to_list(Port).
format_ip(IP) when is_tuple(IP) ->
format_ip(erlang:tuple_to_list(IP));
format_ip(IP) ->
string:join([erlang:integer_to_list(N) || N <- IP], ":").
get_poetry(Tasknum, Addr, Main) ->
{Host, Port} = Addr,
{ok, Socket} = gen_tcp:connect(Host, Port,
[binary, {active, false}, {packet, 0}]),
get_poetry(Tasknum, Socket, Main, []).
get_poetry(Tasknum, Socket, Main, Packets) ->
case gen_tcp:recv(Socket, 0) of
{ok, Packet} ->
io:format("Task ~w: got ~w bytes of poetry from ~s\n",
[Tasknum, size(Packet), peername(Socket)]),
get_poetry(Tasknum, Socket, Main, [Packet|Packets]);
{error, _} ->
Main ! {poem, list_to_binary(lists:reverse(Packets))}
end.
main([]) ->
usage();
main(Args) ->
Addresses = parse_args(Args),
Main = self(),
[erlang:spawn_monitor(fun () -> get_poetry(TaskNum, Addr, Main) end)
|| {TaskNum, Addr} <- enumerate(Addresses)],
collect_poems(length(Addresses), []).