author | Tero Marttila <terom@paivola.fi> |
Fri, 11 Jan 2013 17:32:35 +0200 | |
changeset 83 | 1cb48f2ba1e9 |
parent 80 | 231d3de7081a |
child 111 | 4b96c153c113 |
permissions | -rw-r--r-- |
80
231d3de7081a
pvl.verkko-syslog: renamed pvl.irk
Tero Marttila <terom@paivola.fi>
parents:
79
diff
changeset
|
1 |
""" |
231d3de7081a
pvl.verkko-syslog: renamed pvl.irk
Tero Marttila <terom@paivola.fi>
parents:
79
diff
changeset
|
2 |
Irker client. |
231d3de7081a
pvl.verkko-syslog: renamed pvl.irk
Tero Marttila <terom@paivola.fi>
parents:
79
diff
changeset
|
3 |
""" |
231d3de7081a
pvl.verkko-syslog: renamed pvl.irk
Tero Marttila <terom@paivola.fi>
parents:
79
diff
changeset
|
4 |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
5 |
import optparse, sys |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
6 |
|
80
231d3de7081a
pvl.verkko-syslog: renamed pvl.irk
Tero Marttila <terom@paivola.fi>
parents:
79
diff
changeset
|
7 |
import logging; log = logging.getLogger('pvl.irk') |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
8 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
9 |
# proto |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
10 |
import socket, json |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
11 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
12 |
def parser (parser, connect='tcp://localhost/', target=None) : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
13 |
""" |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
14 |
Optparse option group. |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
15 |
""" |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
16 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
17 |
irker = optparse.OptionGroup(parser, 'Irker output') |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
18 |
|
72
7bb07131c2b5
pvl.irker: drop --irker-target arg
Tero Marttila <terom@paivola.fi>
parents:
71
diff
changeset
|
19 |
irker.add_option('--irker', metavar='URL', default=connect, |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
20 |
help="Irker daemon URL") |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
21 |
|
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
22 |
irker.add_option('--irker-notice', action='store_true', |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
23 |
help="Use irker NOTICE") |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
24 |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
25 |
return irker |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
26 |
|
72
7bb07131c2b5
pvl.irker: drop --irker-target arg
Tero Marttila <terom@paivola.fi>
parents:
71
diff
changeset
|
27 |
def apply (options) : |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
28 |
""" |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
29 |
Return Irker (XXX: target) from options. |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
30 |
""" |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
31 |
|
79 | 32 |
# None -> stdout |
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
33 |
return Irker(options.irker, options.irker_notice) |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
34 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
35 |
def connect (host=None, port=None, family=socket.AF_UNSPEC, socktype=socket.SOCK_STREAM) : |
79 | 36 |
""" |
37 |
Return a TCP/UDP socket connected to the given host/port using getaddrinfo. |
|
38 |
||
39 |
TODO: timeout? |
|
40 |
""" |
|
41 |
||
42 |
log.debug("%s:%s: %s/%s", host, port, family, socktype) |
|
43 |
||
44 |
if host : |
|
45 |
flags = socket.AI_CANONNAME |
|
46 |
else : |
|
47 |
flags = 0 |
|
48 |
||
49 |
addrinfo = socket.getaddrinfo(host, port, family, socktype, 0, flags) |
|
50 |
||
51 |
if not addrinfo : |
|
52 |
raise Exception("getaddrinfo: %s:%s: no results" % (host, port)) |
|
53 |
||
54 |
for af, st, proto, name, addr in addrinfo : |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
55 |
try : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
56 |
s = socket.socket(af, st, proto) |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
57 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
58 |
except socket.error as error : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
59 |
log.warning("%s:%s: socket: %s", host, port, error) |
79 | 60 |
continue |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
61 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
62 |
try : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
63 |
s.connect(addr) |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
64 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
65 |
except socket.error as error : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
66 |
log.warning("%s:%s: connect: %s", host, port, error) |
79 | 67 |
continue |
68 |
||
69 |
log.info("%s", name) |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
70 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
71 |
return s |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
72 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
73 |
else : |
79 | 74 |
raise Exception("Unable to connect: %s:%s: %s" % (host, port, error)) |
75 |
||
76 |
import urlparse |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
77 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
78 |
class Irk (object) : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
79 |
""" |
79 | 80 |
Irker JSON connection. |
81 |
||
82 |
TODO: timeout? |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
83 |
""" |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
84 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
85 |
PORT = 6659 |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
86 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
87 |
SCHEME = { |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
88 |
'tcp': (socket.AF_INET, socket.SOCK_STREAM), |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
89 |
'udp': (socket.AF_INET, socket.SOCK_DGRAM), |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
90 |
'unix': (socket.AF_UNIX, socket.SOCK_DGRAM), |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
91 |
} |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
92 |
|
79 | 93 |
@classmethod |
94 |
def connect (cls, url) : |
|
95 |
""" |
|
96 |
Connect to given urllib URL, or None -> stdout |
|
97 |
""" |
|
98 |
||
99 |
if not url : |
|
100 |
return cls(sys.stdout) |
|
101 |
||
102 |
family, socktype = cls.SCHEME[url.scheme] |
|
103 |
||
104 |
if family == socket.AF_UNIX : |
|
105 |
raise Exception("unix:// is not supported") |
|
106 |
else : |
|
107 |
# inet |
|
108 |
sock = connect(url.hostname, url.port or cls.PORT, family=family, socktype=socktype) |
|
109 |
||
110 |
return cls(sock.makefile('w')) |
|
111 |
||
112 |
def __init__ (self, file) : |
|
113 |
""" |
|
114 |
Use given file-like object for output. |
|
115 |
""" |
|
116 |
||
117 |
self.file = file |
|
118 |
||
119 |
log.debug("%s", file) |
|
120 |
||
121 |
def send (self, **opts) : |
|
122 |
""" |
|
123 |
Raises IOError on write errors. |
|
124 |
""" |
|
125 |
||
126 |
log.debug("%s", opts) |
|
127 |
||
128 |
# write line + flush |
|
129 |
json.dump(opts, self.file) |
|
130 |
self.file.write('\n') |
|
131 |
self.file.flush() |
|
132 |
||
133 |
class IrkerTarget (object) : |
|
134 |
""" |
|
135 |
A channel on an Irk connection. |
|
136 |
""" |
|
137 |
||
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
138 |
def __init__ (self, irker, target, notice=False) : |
79 | 139 |
self.irker = irker |
140 |
self.target = target |
|
141 |
||
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
142 |
self._notice = notice |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
143 |
|
79 | 144 |
def join (self) : |
145 |
log.info("%s", self) |
|
146 |
self.irker.send(to=str(self), privmsg='') |
|
147 |
||
148 |
def privmsg (self, *args) : |
|
149 |
for arg in args : |
|
150 |
log.info("%s: %s", self, arg) |
|
151 |
self.irker.send(to=str(self), privmsg=arg) |
|
152 |
||
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
153 |
def notice (self, *args) : |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
154 |
for arg in args : |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
155 |
log.info("%s: %s", self, arg) |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
156 |
self.irker.send(to=str(self), notice=arg) |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
157 |
|
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
158 |
def __call__ (self, *args) : |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
159 |
# default msg policy |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
160 |
if self._notice : |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
161 |
return self.notice(*args) |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
162 |
else : |
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
163 |
return self.privmsg(*args) |
79 | 164 |
|
165 |
def __str__ (self) : |
|
166 |
return self.target |
|
167 |
||
168 |
class Irker (object) : |
|
169 |
""" |
|
170 |
Reconnecting irker. |
|
171 |
""" |
|
172 |
||
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
173 |
def __init__ (self, url=None, notice=False) : |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
174 |
if url : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
175 |
self.url = urlparse.urlparse(url) |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
176 |
else : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
177 |
self.url = None |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
178 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
179 |
self.targets = {} |
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
180 |
self.notice = notice |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
181 |
|
79 | 182 |
self.connect() |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
183 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
184 |
def connect (self) : |
79 | 185 |
""" |
186 |
Connect, and fix up our targets. |
|
187 |
""" |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
188 |
|
79 | 189 |
self.irk = Irk.connect(self.url) |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
190 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
191 |
# rejoin |
79 | 192 |
for target in self.targets.itervalues() : |
193 |
target.join() |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
194 |
|
79 | 195 |
def send (self, **opts) : |
196 |
""" |
|
197 |
Send on current irker connection. |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
198 |
|
79 | 199 |
TODO: handle errors and reconnect? |
200 |
""" |
|
201 |
||
202 |
self.irk.send(**opts) |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
203 |
|
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
204 |
def target (self, target) : |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
205 |
""" |
79 | 206 |
Bind to given target URL, returning an IrkerTarget for sending messages. |
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
207 |
""" |
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
208 |
|
79 | 209 |
if target not in self.targets : |
83
1cb48f2ba1e9
pvl.irker/irk: implement support for NOTICE
Tero Marttila <terom@paivola.fi>
parents:
80
diff
changeset
|
210 |
self.targets[target] = IrkerTarget(self, target, notice=self.notice) |
79 | 211 |
self.targets[target].join() |
212 |
||
213 |
return self.targets[target] |
|
48
40ccb8d3c96e
pvl.verkko-syslog: syslog -> irker gateway
Tero Marttila <terom@fixme.fi>
parents:
diff
changeset
|
214 |
|
79 | 215 |
__getitem__ = target |