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