pvl/irker/irk.py
changeset 224 ed410776effd
parent 223 6842794c20e8
child 225 3c2d0dd42045
equal deleted inserted replaced
223:6842794c20e8 224:ed410776effd
     1 """
       
     2     Irker protocol implementation.
       
     3 """
       
     4 
       
     5 from twisted.internet import protocol, defer
       
     6 from twisted.protocols import basic
       
     7 from twisted.python import log
       
     8 
       
     9 import json, urlparse
       
    10 
       
    11 class Irk (basic.LineOnlyReceiver) :
       
    12     """
       
    13         A connected Irk client.
       
    14     """
       
    15 
       
    16     delimiter = '\n'
       
    17     
       
    18     def connectionMade (self) :
       
    19         self.transport.logPrefix = self.logPrefix
       
    20         
       
    21         log.msg("connected", self)
       
    22     
       
    23     def connectionLost (self, reason) :
       
    24         log.err("connection lost", reason)
       
    25     
       
    26     def error (self, *args) :
       
    27         log.err(*args)
       
    28         self.transport.loseConnection()
       
    29 
       
    30     def lineReceived (self, line) :
       
    31         """
       
    32             JSON -> in
       
    33         """
       
    34 
       
    35         try :
       
    36             irk = json.loads(line)
       
    37 
       
    38         except ValueError as ex :
       
    39             # invalid
       
    40             return self.error(ex, line)
       
    41         
       
    42         # dispatch
       
    43         self.factory.irkReceived(irk).addErrback(self.error, line)
       
    44 
       
    45     def __str__ (self) :
       
    46         if not self.transport : return 'Irk'
       
    47 
       
    48         host = self.transport.getHost()
       
    49         peer = self.transport.getPeer()
       
    50 
       
    51         return "{host.host}:{host.port}:{peer.host}".format(host=host, peer=peer)
       
    52 
       
    53     logPrefix = __str__
       
    54 
       
    55 class IrkFactory (protocol.ServerFactory) :
       
    56     """
       
    57         Manage connected Irk clients.
       
    58     """
       
    59 
       
    60     MAXATTR = 16
       
    61 
       
    62     protocol = Irk
       
    63 
       
    64     def __init__ (self, irc) :
       
    65         self.irc = irc
       
    66     
       
    67     @defer.inlineCallbacks
       
    68     def irkReceived (self, irk) :
       
    69         """
       
    70             Deffered to handle lookup of target, and then sending message.
       
    71 
       
    72             Errbacks on failures.
       
    73         """
       
    74 
       
    75         log.msg(str(irk))
       
    76 
       
    77         if not 'to' in irk :
       
    78             raise ValueError("missing target: to")
       
    79         
       
    80         # MUST NOT be unicode
       
    81         # XXX: ValueError?
       
    82         url = urlparse.urlparse(str(irk.pop('to')))
       
    83         
       
    84         # connect, register, join
       
    85         target = yield self.irc.target(url)
       
    86         
       
    87         # dispatch attrs
       
    88         for attr, value in irk.iteritems() :
       
    89             if len(attr) >= self.MAXATTR or not attr.islower() :
       
    90                 raise ValueError("invalid attr: %s" % (attr, ))
       
    91     
       
    92             method = getattr(self, 'irk_' + attr, None)
       
    93 
       
    94             if not method :
       
    95                 raise ValueError("unknown attr: %s" % (attr, ))
       
    96 
       
    97             if value :
       
    98                 value = unicode(value)
       
    99             else :
       
   100                 value = None
       
   101 
       
   102             method(target, value)
       
   103     
       
   104     # XXX: explicitly enable?
       
   105     def irk_privmsg (self, target, value) :
       
   106         """
       
   107             Send PRIVMSG to target.
       
   108         """
       
   109         
       
   110         if not value :
       
   111             # legacy
       
   112             return
       
   113 
       
   114         target.privmsg(value)
       
   115 
       
   116     def irk_notice (self, target, value) :
       
   117         """
       
   118             Send NOTICE to target.
       
   119         """
       
   120 
       
   121         if not value :
       
   122             raise ValueError("empty notice")
       
   123 
       
   124         target.notice(value)
       
   125 
       
   126     # TODO: refcounting vs join!
       
   127     def irk_part (self, target, value) :
       
   128         """
       
   129             PART target.
       
   130         """
       
   131         
       
   132         # value is optional
       
   133         target.part(value)