instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / UPnP / upnpserver / upnpeventdispatcher.py
1 # Written by Ingar Arntzen
2 # see LICENSE.txt for license information
3
4 """This module implements a non-blocking event dispatcher for
5 the UPnP server."""
6
7 import urlparse
8 import BaseLib.UPnP.common.asynchHTTPclient as httpclient
9 import BaseLib.UPnP.common.upnpsoap as upnpsoap
10
11 HTTP_NOTIFY_HEADER = u"""NOTIFY %(path)s HTTP/1.1\r
12 HOST: %(host)s:%(port)d\r
13 CONTENT-TYPE: text/xml\r
14 CONTENT-LENGTH: %(length)s\r
15 NT: upnp:event\r
16 NTS: upnp:propchange\r
17 SID: uuid:%(sid)s\r
18 SEQ: %(key)s\r\n\r\n"""
19
20 _LOG_TAG = "HTTPClient"
21
22 ##############################################
23 # EVENT DISPATCHER
24 ##############################################
25
26 class EventDispatcher:
27     """
28     Event Dispatcher wraps non-blocking httpClient to
29     provide a non-blocking event mechanism for the UPnP server.
30     """
31
32     def __init__(self, task_runner, logger=None):
33         self._tr = task_runner
34         self._httpclient = httpclient.AsynchHTTPClient(task_runner)
35
36         # Logging
37         self._logger = logger
38
39     ##############################################
40     # PRIVATE UTILITY
41     ##############################################
42
43     def _log(self, msg):
44         """Logging."""
45         if self._logger:
46             self._logger.log(_LOG_TAG, msg)
47
48     ##############################################
49     # PUBLIC API
50     ##############################################
51         
52     def dispatch(self, sid, event_key, callback_url, variables):
53         """Dispatch a new UPnP event message."""
54         # Generate Soap Body
55         # variables [(name, data)]
56         body = upnpsoap.create_event_message(variables)
57         # Create Notify Header
58         url = urlparse.urlparse(callback_url)
59         dict_ = {
60             'path': url.geturl(),
61             'host': url.hostname,
62             'port': url.port,
63             'sid': sid,
64             'length': len(body),
65             'key': event_key,
66             }
67         header = HTTP_NOTIFY_HEADER % dict_
68         # Dispatch Event Message
69         rid = self._httpclient.get_request_id()
70         self._httpclient.request(rid, url.hostname, url.port, header + body)
71         self._log("NOTIFY %s [%d]" %(url.hostname, event_key))
72
73     def close(self):
74         """Closes Event Dispacter along with its internal HTTP client."""
75         self._log('CLOSE')
76         self._httpclient.close()
77
78 ##############################################
79 # MAIN
80 ##############################################
81
82 if __name__ == '__main__':
83
84     import BaseLib.UPnP.common.taskrunner as taskrunner
85     TASK_RUNNER = taskrunner.TaskRunner()
86     
87     # Parameters
88     import uuid
89     SID = uuid.uuid1()
90     KEY = 1
91     WORK_URL = "http://193.156.106.130:44444/events"
92     HOME_URL = "http://192.168.1.235:44444/events"
93     VARIABLES = [(u'arg1', u'data1'), (u'arg2', u'data2')]
94
95     class MockLogger:
96         """MockLogger."""
97         def log(self, log_tag, msg):
98             """Log to std out."""
99             print log_tag, msg
100
101     # Event Dispatcher
102     EVD = EventDispatcher(TASK_RUNNER, logger=MockLogger())
103     EVD.dispatch(SID, KEY, WORK_URL, VARIABLES)
104     try:
105         TASK_RUNNER.run_forever()
106     except KeyboardInterrupt:
107         print
108     EVD.close()
109