Commits

Alvaro Videla  committed b9f6e13

initial commit

  • Participants

Comments (0)

Files changed (8)

+ebin/*
+% -*- mode: erlang -*-
+{["src/*"], 
+ [{i, "include"},
+  {outdir, "ebin"},
+  debug_info]
+}.
+ERL          ?= erl
+EBIN_DIRS    := $(wildcard deps/*/ebin)
+
+all: erl
+
+erl:
+	@$(ERL) -pa $(EBIN_DIRS) -noinput +B \
+	  -eval 'case make:all() of up_to_date -> halt(0); error -> halt(1) end.'
+
+docs:
+	@erl -noshell -run edoc_run application '$(APP)' '"."' '[]'
+
+clean: 
+	@echo "removing:"
+	@rm -fv ebin/*.beam ebin/*.app

File send_growl_notification.scpt

Binary file added.

File src/pubsub_client.erl

+-module(pubsub_client).
+
+-behaviour(gen_server).
+
+-export([start/4, start_link/4, stop/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+  terminate/2, code_change/3]).
+  
+% API
+-export([subscribe/2, use_growl/0]).
+
+-include_lib("exmpp/include/exmpp.hrl").
+-include_lib("exmpp/include/exmpp_client.hrl").
+
+-record(state, {session, jid, on_message}).
+
+subscribe(Service, Node) ->
+  gen_server:call(?MODULE, {subscribe, Service, Node}).
+use_growl() ->
+  gen_server:call(?MODULE, use_growl).
+
+start(Host, Port, User, Password) ->
+  gen_server:start({local, ?MODULE}, ?MODULE, {Host, Port, User, Password}, []).
+
+start_link(Host, Port, User, Password) -> 
+  gen_server:start_link({local, ?MODULE}, ?MODULE, {Host, Port, User, Password}, []).
+  
+stop() ->
+  gen_server:cast(?MODULE, stop).
+  
+init({Host, Port, User, Password}) ->
+    {ok, {MySession, MyJID}} = pubsub_utils:connect(Host, Port, User, Password),
+    Fun = fun(_XML_Element, Child) -> 
+      case exmpp_xml:get_element(Child, 'log') of
+        undefined -> not_a_notification;
+        Log -> 
+          io:format("Notification: ~s~n", [exmpp_xml:get_cdata_as_list(Log)])
+      end
+    end,
+    {ok, #state{session=MySession, jid=MyJID, on_message=Fun}}.
+  
+handle_call(use_growl, _From, State) ->
+  Fun = fun(_XML_Element, Child) -> 
+    case exmpp_xml:get_element(Child, 'log') of
+      undefined -> not_a_notification;
+      Log -> 
+        os:cmd(io_lib:format("osascript ./send_growl_notification.scpt \"~s\"", [exmpp_xml:get_cdata_as_list(Log)]))
+    end
+  end,
+  {reply, ok, State#state{on_message=Fun}};
+
+handle_call({subscribe, Service, Node}, _From, #state{session=MySession, jid=MyJID}=State) ->
+  IQ = exmpp_client_pubsub:subscribe(exmpp_jid:to_list(MyJID), Service, Node),
+  PacketId = exmpp_session:send_packet(MySession, exmpp_stanza:set_sender(IQ, MyJID)),
+  PacketId2 = erlang:binary_to_list(PacketId),
+  Reply = 
+  receive
+    #received_packet{id=PacketId2, raw_packet=Raw} ->
+      case exmpp_iq:is_error(Raw) of
+        true -> error;
+        _ -> ok
+      end
+  end,
+  {reply, Reply, State};
+  
+handle_call(_Request, _From, State) -> 
+  {reply, ok, State}.
+
+handle_cast(stop, State) -> {stop, normal, State};
+handle_cast(_Msg, State) -> {noreply, State}.
+
+handle_info(#received_packet{packet_type='message'}=Packet, #state{on_message=Fun}=State) ->
+  process_received_packet(Packet, Fun),
+  {noreply, State};
+handle_info(_Info, State) -> 
+  {noreply, State}.
+terminate(_Reason, #state{session=MySession}) -> 
+  pubsub_utils:disconnect(MySession),
+  ok.
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+process_received_packet(#received_packet{raw_packet=Raw}, Fun) ->
+  Event = exmpp_xml:get_element(Raw, ?NS_PUBSUB_EVENT, 'event'),
+  Items = exmpp_xml:get_element(Event, 'items'),
+  exmpp_xml:foreach(Fun, Items),
+  ok.

File src/pubsub_publisher.erl

+-module(pubsub_publisher).
+
+-behaviour(gen_server).
+
+-export([start/4, start_link/4, stop/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+  terminate/2, code_change/3]).
+-export([create_node/2, send_message/1, send_message/2, send_message/3]).
+
+-include_lib("exmpp/include/exmpp.hrl").
+-include_lib("exmpp/include/exmpp_client.hrl").
+
+-record(state, {session, jid}).
+
+start(Host, Port, User, Password) ->
+  gen_server:start({local, ?MODULE}, ?MODULE, {Host, Port, User, Password}, []).
+
+start_link(Host, Port, User, Password) -> 
+  gen_server:start_link({local, ?MODULE}, ?MODULE, {Host, Port, User, Password}, []).
+  
+stop() ->
+  gen_server:cast(?MODULE, stop).
+  
+init({Host, Port, User, Password}) ->
+    {ok, {MySession, MyJID}} = pubsub_utils:connect(Host, Port, User, Password),
+    {ok, #state{session=MySession, jid=MyJID}}.
+
+create_node(Service, Node) ->
+  gen_server:call(?MODULE, {create_node, Service, Node}).
+send_message(Message) ->
+  send_message("pubsub.localhost", Message, "logs").
+send_message(Message, Node) ->
+  send_message("pubsub.localhost", Message, Node).
+send_message(Service, Message, Node) ->
+  gen_server:call(?MODULE, {send_message, Service, Message, Node}).
+  
+handle_call({send_message, Service, Message, Node}, _From, #state{session=MySession, jid=MyJID}=State) ->
+  M = exmpp_xml:element('log'),
+  IQ = exmpp_client_pubsub:publish(Service, Node, exmpp_xml:append_cdata(M, Message)),
+  PacketId = exmpp_session:send_packet(MySession, exmpp_stanza:set_sender(IQ, MyJID)),
+  PacketId2 = erlang:binary_to_list(PacketId),
+  Reply = receive
+    #received_packet{id=PacketId2, raw_packet=Raw} ->
+      io:format("Got Packet: ~s~n", [exmpp_xml:document_to_iolist(Raw)]),
+      case exmpp_iq:is_error(Raw) of
+        true -> error;
+        _ -> ok
+      end
+  end,
+  {reply, Reply, State};
+  
+handle_call({create_node, Service, Name }, _From, #state{session=MySession, jid=MyJID}=State) -> 
+  IQ = exmpp_client_pubsub:create_node(Service, Name),
+  PacketId = exmpp_session:send_packet(MySession, exmpp_stanza:set_sender(IQ, MyJID)),
+  PacketId2 = erlang:binary_to_list(PacketId),
+  Reply = 
+  receive
+    #received_packet{id=PacketId2, raw_packet=Raw} ->
+      case exmpp_iq:is_error(Raw) of
+        true -> error;
+        _ -> ok
+      end
+  end,
+  {reply, Reply, State};
+  
+handle_call(_Request, _From, State) ->
+  {reply, ok, State}.
+  
+handle_cast(stop, State) -> {stop, normal, State};
+handle_cast(_Msg, State) -> {noreply, State}.
+
+handle_info(#received_packet{raw_packet=Raw}, State) ->
+  io:format("Got Packet: ~s~n", [exmpp_xml:document_to_iolist(Raw)]),
+  {noreply, State};
+handle_info(_Info, State) -> 
+  {noreply, State}.
+terminate(_Reason, #state{session=MySession}) -> 
+  pubsub_utils:disconnect(MySession),
+  ok.
+code_change(_OldVsn, State, _Extra) -> {ok, State}.

File src/pubsub_utils.erl

+-module(pubsub_utils).
+
+-export([init_session/2, connect/4, disconnect/1]).
+
+connect(Host, Port, User, Password) ->
+    %% Start XMPP session: Needed to start service (Like exmpp_stringprep):
+    MySession = exmpp_session:start(),
+    %% Create XMPP ID (Session Key):
+    MyJID = exmpp_jid:make(User, Host, random),
+    %% Create a new session with basic (digest) authentication:
+    exmpp_session:auth_basic_digest(MySession, MyJID, Password),
+    %% Connect in standard TCP:
+    _StreamId = exmpp_session:connect_TCP(MySession, Host, Port),
+    try pubsub_utils:init_session(MySession, Password)
+    catch
+      _:Error -> io:format("got error: ~p~n", [Error]),
+		 {error, Error}
+    end,
+    {ok, {MySession, MyJID}}.
+
+init_session(MySession, Password) ->
+  %% Login with defined JID / Authentication:
+  try exmpp_session:login(MySession)
+  catch
+    throw:{auth_error, 'not-authorized'} ->
+    %% Try creating a new user:
+    io:format("Register~n",[]),
+    %% In a real life client, we should trap error case here
+    %% and print the correct message.
+    exmpp_session:register_account(MySession, Password),
+    %% After registration, retry to login:
+    exmpp_session:login(MySession)
+  end,
+  %% We explicitely send presence:
+  exmpp_session:send_packet(MySession, exmpp_presence:set_status(exmpp_presence:available(), "Pubsubber Ready")),
+  ok.
+
+disconnect(MySession) ->
+  exmpp_session:stop(MySession).

File start-dev.sh

+#!/bin/sh
+cd `dirname $0`
+exec erl -pa $PWD/ebin -boot start_sasl -s exmpp