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