From: Brian Warner Date: Wed, 26 Mar 2008 23:09:34 +0000 (-0700) Subject: misc/boodlegrid.tac: tool to monitor a grid through its flogports X-Git-Url: https://git.rkrishnan.org/bar.txt?a=commitdiff_plain;h=ccce37bb4a6e91da91f060a1d45518eac857c2c1;p=tahoe-lafs%2Ftahoe-lafs.git misc/boodlegrid.tac: tool to monitor a grid through its flogports --- diff --git a/misc/boodlegrid.tac b/misc/boodlegrid.tac new file mode 100644 index 00000000..3c79b4f8 --- /dev/null +++ b/misc/boodlegrid.tac @@ -0,0 +1,142 @@ +# -*- python -*- + +"""Monitor a Tahoe grid, by playing sounds in response to remote events. + +To install: + 1: install Boodler, from http://www.eblong.com/zarf/boodler/ + 2: run "boodler.py -l listen.Sounds". This will run a daemon + that listens on a network socket (31863 by default) and + accepts commands in the form of "sound bird/crow1.aiff\n" + 3: copy this file into a new directory, which we'll call $BASEDIR + 4: write one or more logport FURLs into files named *.furl or *.furls, one + per line. All logports from all such files will be used. + 5: launch this daemon with 'cd $BASEDIR && twistd -y boodlegrid.tac' + +""" + +import os, time +from zope.interface import implements +from twisted.application import service +from twisted.internet import protocol, reactor, defer +from foolscap import Tub, Referenceable +from foolscap.logging.interfaces import RILogObserver +from twisted.python import log + +class Listener: + + def __init__(self): + self.boodler = None # filled in when we connect to boodler + self.last = {} + + def sound(self, name, slot=None, max=0.100): + if not self.boodler: + return + now = time.time() + if slot is None: + slot = name + if now < self.last.get(slot, 0) + max: + return # too soon + self.last[slot] = now + self.boodler.write("sound %s\n" % name) + + def msg(self, m, furl): + #print "got it", m + message = m.get("message", m.get("format", "")) + + # messages emitted by the Introducer: client join/leave + if message.startswith("introducer: subscription[storage] request"): + self.sound("voice/hooray.aiff") + if message.startswith("introducer: unsubscribing"): + self.sound("electro/zaptrill-fade.aiff") + + # messages from the helper + if message == "file already found in grid": + print "already found" + self.sound("mech/ziplash-high.aiff") + #if message == "upload done": + if m.get("format") == "plaintext_hash=%(plaintext_hash)s, SI=%(SI)s, size=%(size)d": + size = m.get("size") + print "upload done, size", size + self.sound("mech/ziplash-low.aiff") + if "fetching " in message: + # helper grabbing ciphertext from client + self.sound("voice/phoneme/sh.aiff", max=0.5) + + # messages from storage servers + if message.startswith("storage: slot_readv"): + #self.sound("voice/phoneme/r.aiff") + self.sound("percussion/wood-tap-hollow.aiff") + + # messages from webapi + if message.startswith("Retrieve") and "starting" in message: + self.sound("mech/metal-clack.aiff") + if message.startswith("Publish") and "starting" in message: + #self.sound("mech/metal-clash.aiff") + self.sound("mech/clock-clang.aiff") + if "web" in message and "POST" in message and "t=set_children" in message: + self.sound("mech/door-slam.aiff") + + # generic messages + #if m['level'] < 20: + # self.sound("mech/keyboard-1.aiff") + if m['level'] > 30: # SCARY or BAD + #self.sound("mech/alarm-bell.aiff") + self.sound("environ/thunder-tense.aiff") + print m, furl + elif m['level'] == 30: # WEIRD + self.sound("mech/glass-breaking.aiff") + print m, furl + elif m['level'] > 20: # UNUSUAL or INFREQUENT or CURIOUS + if "_check_for_done but we're not running" in message: + pass + else: + self.sound("mech/telephone-ring-old.aiff") + print m, furl + +class BoodleSender(protocol.Protocol): + def connectionMade(self): + print "connected to boodler" + self.factory.listener.boodler = self.transport + +class Bridge(Referenceable): + implements(RILogObserver) + + def __init__(self, furl, listener): + self.furl = furl + self.listener = listener + + def remote_msg(self, m): + d = defer.maybeDeferred(self.listener.msg, m, self.furl) + d.addErrback(log.err) + # never send errors to the remote side + +class Monitor(service.MultiService): + def __init__(self): + service.MultiService.__init__(self) + self.tub = Tub() + self.tub.setServiceParent(self) + self.listener = Listener() + self.targets = [] + for fn in os.listdir("."): + if fn.endswith(".furl") or fn.endswith(".furls"): + for i,line in enumerate(open(fn, "r").readlines()): + target = line.strip() + if target: + self.tub.connectTo(target, self._got_logpublisher, + fn, i, target) + + cf = protocol.ClientFactory() + cf.listener = self.listener + cf.protocol = BoodleSender + reactor.connectTCP("localhost", 31863, cf) + + def _got_logpublisher(self, publisher, fn, i, target): + print "connected to %s:%d, %s" % (fn, i, target) + b = Bridge(target, self.listener) + publisher.callRemote("subscribe_to_all", b) + + +m = Monitor() +application = service.Application("boodlegrid") +m.setServiceParent(application) +