From d486c9c84ac7ca8eb9c8a322ddf7af3bd637e39c Mon Sep 17 00:00:00 2001 From: Matt Mullins Date: Mon, 21 Jan 2013 20:00:16 -0800 Subject: [PATCH] Send !-commands to AMQP for other programs --- irc/irc_amqp_listener.erl | 21 ++++++++++++++++++++- irc/irc_command.erl | 23 ++++++++++++++++++++++- irc/irc_conn.erl | 16 +++++++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/irc/irc_amqp_listener.erl b/irc/irc_amqp_listener.erl index a5accc7..ceca5aa 100644 --- a/irc/irc_amqp_listener.erl +++ b/irc/irc_amqp_listener.erl @@ -4,10 +4,13 @@ -behavior(gen_server). -vsn(2). +-define(EXCHANGE, <<"irc">>). + -export([ start_link/2, encode_routing_key/1, - decode_routing_key/1 + decode_routing_key/1, + send_message/3 ]). -export([ @@ -44,6 +47,22 @@ handle_info( irc_conn:send_command(ConnectionPid, Command), {noreply, State}. +%% @doc Sends a message with the given routing key and body to the proper +%% exchange +send_message(RoutingKey, ReplyTo, Body) -> + BinKey = list_to_binary(RoutingKey), + BinReplyKey = list_to_binary(ReplyTo), + BinBody = list_to_binary(Body), + {ok, Channel} = amqp_bot_connection:open_channel(), + amqp_channel:call(Channel, #'basic.publish'{ routing_key = BinKey, + exchange = ?EXCHANGE }, + #amqp_msg{ payload = BinBody, + props = #'P_basic' { + reply_to = BinReplyKey + } + }), + amqp_channel:close(Channel). + %% @doc Encode an IRC-domain string as an AMQP-compatible routing key -- that %% is, in the set [A-Za-z0-9}. We encode them as follows: %% * lower-case letters are unchanged. diff --git a/irc/irc_command.erl b/irc/irc_command.erl index 87463eb..4f37cc7 100644 --- a/irc/irc_command.erl +++ b/irc/irc_command.erl @@ -22,9 +22,30 @@ do_privmsg_command(Text, From) -> middles = [From], trailing = Response}, irc_conn:send_command(self(), NewCommand); - _ -> ok + _ -> + Source = extract_source(From), + {Command, SpaceThenBody} = lists:splitwith( + fun(X) -> X /= $ end, + Text), + Body = case SpaceThenBody of + [] -> []; + [_|T] -> T + end, + + irc_conn:send_amqp_command(self(), Command, Body, Source) end. +%% Extracts the logical source of the message from the string received from the +%% IRC server's PRIVMSG commands. +%% +%% This is used to determine what to PRIVMSG to send a reply. +%% +%% Example: +%% "mokomull!mmullins@mmlx.us" -> "mokomull" +%% "#tamulug" -> "#tamulug" +extract_source(From) -> + hd(string:tokens(From, "!")). + random_choice([SplitChar | ChoicesText]) -> Choices = string:tokens(ChoicesText, [SplitChar]), Count = length(Choices), diff --git a/irc/irc_conn.erl b/irc/irc_conn.erl index 3628fc1..3d4ba62 100644 --- a/irc/irc_conn.erl +++ b/irc/irc_conn.erl @@ -6,7 +6,8 @@ -export([ start_link/3, - send_command/2 + send_command/2, + send_amqp_command/4 ]). -export([ @@ -37,6 +38,9 @@ start_link(Instance, Supervisor, TableId) -> send_command(Pid, Command) -> gen_server:cast(Pid, {send_command, Command}). +send_amqp_command(Pid, Command, Body, Source) -> + gen_server:cast(Pid, {send_amqp_command, Command, Body, Source}). + init({Instance, Supervisor, TableId}) -> ets:insert(TableId, {irc_conn_pid, self()}), % record the connection PID in the table @@ -87,6 +91,16 @@ handle_cast({send_command, Command}, State) -> ), {noreply, State}; +handle_cast({send_amqp_command, Command, Body, Source}, State) -> + #irc_state{ instance = Instance } = State, + InstanceKey = irc_amqp_listener:encode_routing_key(atom_to_list(Instance)), + SourceKey = irc_amqp_listener:encode_routing_key(Source), + CommandKey = irc_amqp_listener:encode_routing_key(Command), + Key = InstanceKey ++ ".command." ++ CommandKey, + ReplyKey = InstanceKey ++ ".output." ++ SourceKey, + irc_amqp_listener:send_message(Key, ReplyKey, Body), + {noreply, State}; + handle_cast(create_object_sup, State) -> #irc_state{ instance = Instance, supervisor = Supervisor, -- 2.11.0