source: trunk/misc/awesome_weird_stuff/boodlegrid.tac

Last change on this file was b856238, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-15T15:53:34Z

remove old Python2 future statements

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