Here's some erlang.
-module(mini_chat).
-compile(export_all).
-define(ACTIVE_OPTIONS, [{reuseaddr, true}]).
% Commands start with "/", char 47
is_command(Str) -> hd(Str) =:= 47.
chatroom(Users) ->
receive
{users, Requester} ->
io:format("~p~n", [Users]),
Requester ! Users,
chatroom(Users);
{join, Username, Pid} ->
chatroom([{Username, Pid} | Users]);
{remove, User} ->
chatroom(Users -- [User]);
{dispatch_msg, From, Msg} ->
case lists:keyfind(From, 1, Users) of
{FromName, _FromPid} = User ->
FormatMsg = io_lib:format(string:join(["~s: ", Msg], ""),
[FromName]),
F = fun({_,Pid}) -> Pid ! {message, FormatMsg} end,
Rest = lists:delete(User, Users),
lists:foreach(F, Rest);
false ->
ok
end,
chatroom(Users);
stop ->
ok
end.
user(Username) ->
chat ! {join, Username, self()},
user(Username, chat).
user(Username, Chatroom) ->
receive
{send, Msg} ->
Chatroom ! {dispatch_msg, Username, Msg},
user(Username, Chatroom);
{message, Msg} ->
io:fwrite(Msg),
user(Username, Chatroom)
end.
tcp_user(Socket) ->
receive
{tcp, Socket, "/nick " ++ Username} ->
tcp_user(Socket, string:strip(Username, right, $\n));
{tcp, Socket, _Data} ->
gen_tcp:send(Socket, "Set a nickname with /nick.\n"),
tcp_user(Socket)
end.
tcp_user(Socket, Username) ->
chat ! {join, Username, self()},
tcp_user(Socket, Username, chat).
tcp_user(Socket, Username, Chatroom) ->
receive
{tcp, Socket, Data} ->
Chatroom ! {dispatch_msg, Username, Data},
tcp_user(Socket, Username, Chatroom);
{message, Msg} ->
io:format(Msg),
gen_tcp:send(Socket, lists:flatten(Msg)),
tcp_user(Socket, Username, Chatroom)
end.
listen() ->
{ok, LSock} = gen_tcp:listen(6667, ?ACTIVE_OPTIONS),
listen(LSock).
listen(LSock) ->
{ok, Socket} = gen_tcp:accept(LSock),
TcpUser = spawn(?MODULE, tcp_user, [Socket]),
gen_tcp:controlling_process(Socket, TcpUser),
listen(LSock).
start() ->
register(tcp, spawn(?MODULE, listen, [])),
register(chat, spawn(?MODULE, chatroom, [[]])).
stop() ->
exit(whereis(chat), kill),
exit(whereis(tcp), kill).