]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - misc/awesome_weird_stuff/boodlegrid.tac
Fix an error handling path that would never have been reached. fixes ticket:2543
[tahoe-lafs/tahoe-lafs.git] / misc / awesome_weird_stuff / boodlegrid.tac
1 # -*- python -*-
2
3 """Monitor a Tahoe grid, by playing sounds in response to remote events.
4
5 To install:
6  1: install Boodler, from http://www.eblong.com/zarf/boodler/
7  2: run "boodler.py -l listen.Sounds". This will run a daemon
8     that listens on a network socket (31863 by default) and
9     accepts commands in the form of "sound bird/crow1.aiff\n"
10  3: copy this file into a new directory, which we'll call $BASEDIR
11  4: write one or more logport FURLs into files named *.furl or *.furls, one
12     per line. All logports from all such files will be used.
13  5: launch this daemon with 'cd $BASEDIR && twistd -y boodlegrid.tac'
14
15 """
16
17 import os, time
18 from zope.interface import implements
19 from twisted.application import service
20 from twisted.internet import protocol, reactor, defer
21 from foolscap import Tub, Referenceable
22 from foolscap.logging.interfaces import RILogObserver
23 from twisted.python import log
24
25 class Listener:
26
27     def __init__(self):
28         self.boodler = None # filled in when we connect to boodler
29         self.last = {}
30
31     def sound(self, name, slot=None, max=0.100):
32         if not self.boodler:
33             return
34         now = time.time()
35         if slot is None:
36             slot = name
37         if now < self.last.get(slot, 0) + max:
38             return # too soon
39         self.last[slot] = now
40         self.boodler.write("sound %s\n" % name)
41
42     def msg(self, m, furl):
43         #print "got it", m
44         message = m.get("message", m.get("format", ""))
45         format = m.get("format", "")
46         facility = m.get("facility", "")
47
48         # messages emitted by the Introducer: client join/leave
49         if message.startswith("introducer: subscription[storage] request"):
50             print "new client"
51             self.sound("voice/hooray.aiff")
52         if message.startswith("introducer: unsubscribing"):
53             print "unsubscribe"
54             self.sound("electro/zaptrill-fade.aiff")
55
56         # messages from the helper
57         if message == "file already found in grid":
58             print "already found"
59             self.sound("mech/ziplash-high.aiff")
60         #if message == "upload done":
61         if format == "plaintext_hash=%(plaintext_hash)s, SI=%(SI)s, size=%(size)d":
62             size = m.get("size")
63             print "upload done, size", size
64             self.sound("mech/ziplash-low.aiff")
65         if "fetching " in message:
66             # helper grabbing ciphertext from client
67             self.sound("voice/phoneme/sh.aiff", max=0.5)
68
69         # messages from storage servers
70         if message.startswith("storage: slot_readv"):
71             #self.sound("voice/phoneme/r.aiff")
72             self.sound("percussion/wood-tap-hollow.aiff")
73
74         # messages from webapi
75         if message.startswith("Retrieve") and "starting" in message:
76             self.sound("mech/metal-clack.aiff")
77         if message.startswith("Publish") and "starting" in message:
78             self.sound("mech/door-slam.aiff")
79             #self.sound("mech/metal-clash.aiff")
80         if ("web: %(clientip)s" in format
81             and m.get("method") == "POST"
82             and ("t=set_children" in m.get("uri", "")       # FIXME: may give false-positives
83                  or "t=set-children" in m.get("uri", ""))):
84             self.sound("mech/clock-clang.aiff")
85
86         # generic messages
87         #if m['level'] < 20:
88         #    self.sound("mech/keyboard-1.aiff")
89         if "_check_for_done but we're not running" in message:
90             pass
91         elif format == "excessive reactor delay (%ss)":
92             self.sound("animal/frog-cheep.aiff")
93             print "excessive delay %s: %s" % (m['args'][0], furl)
94         elif format == "excessive reactor delay (%(delay)ss)":
95             self.sound("animal/frog-cheep.aiff")
96             print "excessive delay %s: %s" % (m['delay'], furl)
97         elif facility == "foolscap.negotiation":
98           if (message == "got offer for an existing connection"
99               or "master told us to use a new connection" in message):
100               print "foolscap: got offer for an existing connection", message, furl
101           else:
102               #print "foolscap:", message
103               pass
104         elif m['level'] > 30: # SCARY or BAD
105             #self.sound("mech/alarm-bell.aiff")
106             self.sound("environ/thunder-tense.aiff")
107             print m, furl
108         elif m['level'] == 30: # WEIRD
109             self.sound("mech/glass-breaking.aiff")
110             print m, furl
111         elif m['level'] > 20: # UNUSUAL or INFREQUENT or CURIOUS
112             self.sound("mech/telephone-ring-old.aiff")
113             print m, furl
114
115 class BoodleSender(protocol.Protocol):
116     def connectionMade(self):
117         print "connected to boodler"
118         self.factory.listener.boodler = self.transport
119
120 class Bridge(Referenceable):
121     implements(RILogObserver)
122
123     def __init__(self, furl, listener):
124         self.furl = furl
125         self.listener = listener
126
127     def remote_msg(self, m):
128         d = defer.maybeDeferred(self.listener.msg, m, self.furl)
129         d.addErrback(log.err)
130         # never send errors to the remote side
131
132 class Monitor(service.MultiService):
133     def __init__(self):
134         service.MultiService.__init__(self)
135         self.tub = Tub()
136         self.tub.setServiceParent(self)
137         self.listener = Listener()
138         self.targets = []
139         for fn in os.listdir("."):
140             if fn.endswith(".furl") or fn.endswith(".furls"):
141                 for i,line in enumerate(open(fn, "r").readlines()):
142                     target = line.strip()
143                     if target:
144                         self.tub.connectTo(target, self._got_logpublisher,
145                                            fn, i, target)
146
147         cf = protocol.ClientFactory()
148         cf.listener = self.listener
149         cf.protocol = BoodleSender
150         reactor.connectTCP("localhost", 31863, cf)
151
152     def _got_logpublisher(self, publisher, fn, i, target):
153         print "connected to %s:%d, %s" % (fn, i, target)
154         b = Bridge(target, self.listener)
155         publisher.callRemote("subscribe_to_all", b)
156
157
158 m = Monitor()
159 application = service.Application("boodlegrid")
160 m.setServiceParent(application)
161