Changeset 97

Show
Ignore:
Timestamp:
11/13/07 12:28:30 (1 year ago)
Author:
edsuom
Message:

Adding pybywire with parameterized objects and perspective factory formerly in misc subpackage

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • projects/Twisted-Goodies/trunk/twisted_goodies/pybywire/pfactory.py

    r80 r97  
    2020 
    2121""" 
    22 Miscellaneous goodies 
     22Perspective factory 
    2323""" 
    2424 
    25 import struct, socket, new, sys 
    26 from twisted.internet import interfaces, defer 
     25import new 
     26from twisted.internet import interfaces 
    2727from twisted.spread import pb 
    28  
    29  
    30 class DeferredTracker(object): 
    31     """ 
    32     I allow you to track and wait for deferreds without actually having 
    33     received a reference to them. 
    34     """ 
    35     def __init__(self): 
    36         self.list = [] 
    37      
    38     def put(self, d): 
    39         """ 
    40         Put another deferred in the tracker. 
    41         """ 
    42         if not isinstance(d, defer.Deferred): 
    43             raise TypeError("Object '%s' is not a deferred" % d) 
    44         self.list.append(d) 
    45  
    46     def deferToAll(self): 
    47         """ 
    48         Return a deferred that tracks all active deferreds that aren't yet 
    49         being tracked. When the tracked deferreds fire, the returned deferred 
    50         fires, too. 
    51         """ 
    52         if self.list: 
    53             d = defer.DeferredList(self.list) 
    54             self.list = [] 
    55         elif hasattr(self, 'd_WFA') and not self.d_WFA.called(): 
    56             d = defer.Deferred() 
    57             self.d_WFA.chainDeferred(d) 
    58         else: 
    59             d = defer.succeed(None) 
    60         return d 
    61  
    62     def deferToLast(self): 
    63         """ 
    64         Return a deferred that tracks the deferred that was most recently put 
    65         in the tracker. When the tracked deferred fires, the returned deferred 
    66         fires, too. 
    67         """ 
    68         if self.list: 
    69             d = defer.Deferred() 
    70             self.list.pop().chainDeferred(d) 
    71         elif hasattr(self, 'd_WFL') and not self.d_WFL.called(): 
    72             d = defer.Deferred() 
    73             self.d_WFL.chainDeferred(d) 
    74         else: 
    75             d = defer.succeed(None) 
    76         return d 
    77  
    78  
    79 class AddressRestrictorMixin: 
    80     """ 
    81     Mix me in with your normal L{twisted.internet.interfaces.IProtocolFactory} 
    82     implementer to restrict the client addresses that are permitted to connect 
    83     to your server. 
    84     """ 
    85     def addSubnet(self, subnet): 
    86         """ 
    87         Adds a subnet for permitted client connection addresses, e.g., 
    88         '192.168.1.1/24'. 
    89         """ 
    90         subnetSequence = subnet.split("/") 
    91         base = self._quadToInt(subnetSequence[0]) 
    92         if len(subnetSequence) == 1: 
    93             bits = 32 
    94         else: 
    95             bits = subnetSequence[1] 
    96         subnets = getattr(self, '_subnets', []) 
    97         subnets.append((base, int(bits))) 
    98         self._subnets = subnets 
    99      
    100     def _quadToInt(self, quad): 
    101         """ 
    102         Converts the dotted-quad address string supplied as I{quad} into an 
    103         integer. 
    104         """ 
    105         return struct.unpack(">L", socket.inet_aton(quad))[0] 
    106  
    107     def testAddress(self, quad): 
    108         """ 
    109         Tests the supplied IP address for a match with the subnet(s) defined 
    110         for acceptance. 
    111  
    112         @param quad: A string representing an IPv4 address in dotted-quad 
    113             format. 
    114          
    115         """ 
    116         addrInt = self._quadToInt(quad) 
    117         for base, bits in self._subnets: 
    118             maskString = '1'*bits + '0'*(32-bits) 
    119             mask = int(maskString, 2) 
    120             if (addrInt & mask) == (base & mask): 
    121                 return True 
    122         return False 
    123  
    124     def buildProtocol(self, addr): 
    125         """ 
    126         A protocol is only returned if the address matches my IP subnet. 
    127         Otherwise, the connection immediately closes. 
    128         """ 
    129         if self.testAddress(addr.host): 
    130             for BaseClass in self.__class__.__bases__: 
    131                 if interfaces.IProtocolFactory.implementedBy(BaseClass): 
    132                     return BaseClass.buildProtocol(self, addr) 
    13328 
    13429 
     
    19893 
    19994 
    200 class TracerMixin(object): 
    201     """ 
    202     Mix me in to trace problems 
    203     """ 
    204     isTracing = False 
    205     traceFrame = None 
    206     traceStack = [ 
    207         # Bottom frame on up, just like a stack. The following items just 
    208         # represent an example that was used in Trac/WSGI debugging. 
    209         ('cache.py', 'get_changes'), 
    210         ('changeset.py', 'get_changes'), 
    211         ('changeset.py', '_render_html') 
    212         ] 
    213     traceLevels = 5 
    214      
    215     def settrace(self): 
    216         """ 
    217         Call this method to start tracing. If you're using threads, you must 
    218         call it within the same thread whose execution you want to trace. 
    219         """ 
    220         sys.settrace(self.trace) 
    221         self.isTracing = True 
    222  
    223     def trace(self, frame, event, arg): 
    224         """ 
    225         This is the actual trace function. 
    226         """ 
    227         def msg(level): 
    228             values = ["." * level] 
    229             values.extend([ 
    230                 getattr(frame.f_code, "co_%s" % x) 
    231                 for x in ('filename', 'firstlineno', 'name')]) 
    232             if values != getattr(self, '_prevMsgValues', None): 
    233                 self._prevMsgValues = values 
    234                 print "%s %s (%04d): %s" % tuple(values) 
    235  
    236         def isTraceEntry(k, thisFrame): 
    237             if thisFrame.f_code.co_name == self.traceStack[k][1]: 
    238                 tail = "/%s" % self.traceStack[k][0] 
    239                 if thisFrame.f_code.co_filename.endswith(tail): 
    240                     return True 
    241  
    242         def frameGenerator(N): 
    243             nextFrame = frame 
    244             for k in xrange(N): 
    245                 yield k, nextFrame 
    246                 nextFrame = nextFrame.f_back 
    247  
    248         if not self.isTracing: 
    249             return 
    250         if event == 'call': 
    251             level = 1 
    252             if self.traceFrame is None: 
    253                 N = len(self.traceStack) 
    254                 for k, thisFrame in frameGenerator(N): 
    255                     if not isTraceEntry(k, thisFrame): 
    256                         return 
    257                 else: 
    258                     print "-" * 40 
    259                     self.traceFrame = frame 
    260             else: 
    261                 for k, thisFrame in frameGenerator(self.traceLevels): 
    262                     level += 1 
    263                     if thisFrame in (None, self.traceFrame): 
    264                         break 
    265                 else: 
    266                     return 
    267             msg(level) 
    268             return self.trace 
    269         elif event == 'return' and frame == self.traceFrame: 
    270             self.traceFrame = None 
    271             print "->", arg 
  • projects/Twisted-Goodies/trunk/twisted_goodies/pybywire/__init__.py

    r80 r97  
    2020 
    2121""" 
    22 Miscellaneous goodies 
     22Py[thon] by Wire: Miscellaneous PB Improvements  
    2323""" 
    24  
    25 import struct, socket, new, sys 
    26 from twisted.internet import interfaces, defer 
    27 from twisted.spread import pb 
    28  
    29  
    30 class DeferredTracker(object): 
    31     """ 
    32     I allow you to track and wait for deferreds without actually having 
    33     received a reference to them. 
    34     """ 
    35     def __init__(self): 
    36         self.list = [] 
    37      
    38     def put(self, d): 
    39         """ 
    40         Put another deferred in the tracker. 
    41         """ 
    42         if not isinstance(d, defer.Deferred): 
    43             raise TypeError("Object '%s' is not a deferred" % d) 
    44         self.list.append(d) 
    45  
    46     def deferToAll(self): 
    47         """ 
    48         Return a deferred that tracks all active deferreds that aren't yet 
    49         being tracked. When the tracked deferreds fire, the returned deferred 
    50         fires, too. 
    51         """ 
    52         if self.list: 
    53             d = defer.DeferredList(self.list) 
    54             self.list = [] 
    55         elif hasattr(self, 'd_WFA') and not self.d_WFA.called(): 
    56             d = defer.Deferred() 
    57             self.d_WFA.chainDeferred(d) 
    58         else: 
    59             d = defer.succeed(None) 
    60         return d 
    61  
    62     def deferToLast(self): 
    63         """ 
    64         Return a deferred that tracks the deferred that was most recently put 
    65         in the tracker. When the tracked deferred fires, the returned deferred 
    66         fires, too. 
    67         """ 
    68         if self.list: 
    69             d = defer.Deferred() 
    70             self.list.pop().chainDeferred(d) 
    71         elif hasattr(self, 'd_WFL') and not self.d_WFL.called(): 
    72             d = defer.Deferred() 
    73             self.d_WFL.chainDeferred(d) 
    74         else: 
    75             d = defer.succeed(None) 
    76         return d 
    77  
    78  
    79 class AddressRestrictorMixin: 
    80     """ 
    81     Mix me in with your normal L{twisted.internet.interfaces.IProtocolFactory} 
    82     implementer to restrict the client addresses that are permitted to connect 
    83     to your server. 
    84     """ 
    85     def addSubnet(self, subnet): 
    86         """ 
    87         Adds a subnet for permitted client connection addresses, e.g., 
    88         '192.168.1.1/24'. 
    89         """ 
    90         subnetSequence = subnet.split("/") 
    91         base = self._quadToInt(subnetSequence[0]) 
    92         if len(subnetSequence) == 1: 
    93             bits = 32 
    94         else: 
    95             bits = subnetSequence[1] 
    96         subnets = getattr(self, '_subnets', []) 
    97         subnets.append((base, int(bits))) 
    98         self._subnets = subnets 
    99      
    100     def _quadToInt(self, quad): 
    101         """ 
    102         Converts the dotted-quad address string supplied as I{quad} into an 
    103         integer. 
    104         """ 
    105         return struct.unpack(">L", socket.inet_aton(quad))[0] 
    106  
    107     def testAddress(self, quad): 
    108         """ 
    109         Tests the supplied IP address for a match with the subnet(s) defined 
    110         for acceptance. 
    111  
    112         @param quad: A string representing an IPv4 address in dotted-quad 
    113             format. 
    114          
    115         """ 
    116         addrInt = self._quadToInt(quad) 
    117         for base, bits in self._subnets: 
    118             maskString = '1'*bits + '0'*(32-bits) 
    119             mask = int(maskString, 2) 
    120             if (addrInt & mask) == (base & mask): 
    121                 return True 
    122         return False 
    123  
    124     def buildProtocol(self, addr): 
    125         """ 
    126         A protocol is only returned if the address matches my IP subnet. 
    127         Otherwise, the connection immediately closes. 
    128         """ 
    129         if self.testAddress(addr.host): 
    130             for BaseClass in self.__class__.__bases__: 
    131                 if interfaces.IProtocolFactory.implementedBy(BaseClass): 
    132                     return BaseClass.buildProtocol(self, addr) 
    133  
    134  
    135 class PerspectiveFactory(object): 
    136     """ 
    137     I generate perspectives for clients with varying access 
    138     privileges. Construct me with an I{interfaceMap} dict and a 
    139     I{perspectiveList} sequence. 
    140  
    141     Each entry of the interface map is keyed by the name of an access privilege 
    142     and has as its value a sequence of one or more interfaces that must be 
    143     provided by the perspective object in order to grant the client such 
    144     access. 
    145  
    146     The perspective list contains all of the perspective classes that implement 
    147     the interfaces in the interface map. Each perspective that I generate will 
    148     be an instance of a composite of those classes that implement a required 
    149     interfaces. 
    150     """ 
    151     def __init__(self, interfaceMap, perspectiveList): 
    152         self.interfaceMap = interfaceMap 
    153         self.perspectiveList = perspectiveList 
    154         self.implementorMap = {} 
    155      
    156     def implementor(self, interface): 
    157         """ 
    158         Returns the first perspective class in my C{perspectiveList} sequence 
    159         that implements the supplied I{interface}, raising an exception if none 
    160         do so. 
    161         """ 
    162         result = self.implementorMap.get(interface, None) 
    163         if result is None: 
    164             for candidate in self.perspectiveList: 
    165                 if interface.implementedBy(candidate): 
    166                     result = self.implementorMap[interface] = candidate 
    167                     break 
    168             else: 
    169                 raise NotImplementedError( 
    170                     "No perspective class implements '%s'" % repr(interface)) 
    171         return result 
    172      
    173     def perspective(self, privileges, **kw): 
    174         """ 
    175         Returns to the client a perspective instance that provides interfaces 
    176         in accordance with the supplied list of I{privileges}. Any keywords 
    177         supplied define the names and values of attributes that the instance is 
    178         assigned. 
    179  
    180         The interfaces provided by the perspective are mapped out in my 
    181         I{interfaceMap} dict. 
    182         """ 
    183         baseClasses = [pb.Avatar] 
    184         for thisPrivilege in privileges: 
    185             requiredInterfaces = self.interfaceMap.get(thisPrivilege, []) 
    186             for thisInterface in requiredInterfaces: 
    187                 implementor = self.implementor(thisInterface) 
    188                 if implementor is not None and implementor not in baseClasses: 
    189                     baseClasses.append(implementor) 
    190         # Create and instantiate the user's custom perspective class 
    191         Perspective = new.classobj('Perspective', tuple(baseClasses), {}) 
    192         thisPerspective = Perspective() 
    193         # Set the perspective's instance attributes 
    194         for name, value in kw.iteritems(): 
    195             setattr(thisPerspective, name, value) 
    196         # The perspective is ready to give to the client 
    197         return thisPerspective 
    198  
    199  
    200 class TracerMixin(object): 
    201     """ 
    202     Mix me in to trace problems 
    203     """ 
    204     isTracing = False 
    205     traceFrame = None 
    206     traceStack = [ 
    207         # Bottom frame on up, just like a stack. The following items just 
    208         # represent an example that was used in Trac/WSGI debugging. 
    209         ('cache.py', 'get_changes'), 
    210         ('changeset.py', 'get_changes'), 
    211         ('changeset.py', '_render_html') 
    212         ] 
    213     traceLevels = 5 
    214      
    215     def settrace(self): 
    216         """ 
    217         Call this method to start tracing. If you're using threads, you must 
    218         call it within the same thread whose execution you want to trace. 
    219         """ 
    220         sys.settrace(self.trace) 
    221         self.isTracing = True 
    222  
    223     def trace(self, frame, event, arg): 
    224         """ 
    225         This is the actual trace function. 
    226         """ 
    227         def msg(level): 
    228             values = ["." * level] 
    229             values.extend([ 
    230                 getattr(frame.f_code, "co_%s" % x) 
    231                 for x in ('filename', 'firstlineno', 'name')]) 
    232             if values != getattr(self, '_prevMsgValues', None): 
    233                 self._prevMsgValues = values 
    234                 print "%s %s (%04d): %s" % tuple(values) 
    235  
    236         def isTraceEntry(k, thisFrame): 
    237             if thisFrame.f_code.co_name == self.traceStack[k][1]: 
    238                 tail = "/%s" % self.traceStack[k][0] 
    239                 if thisFrame.f_code.co_filename.endswith(tail): 
    240                     return True 
    241  
    242         def frameGenerator(N): 
    243             nextFrame = frame 
    244             for k in xrange(N): 
    245                 yield k, nextFrame 
    246                 nextFrame = nextFrame.f_back 
    247  
    248         if not self.isTracing: 
    249             return 
    250         if event == 'call': 
    251             level = 1 
    252             if self.traceFrame is None: 
    253                 N = len(self.traceStack) 
    254                 for k, thisFrame in frameGenerator(N): 
    255                     if not isTraceEntry(k, thisFrame): 
    256                         return 
    257                 else: 
    258                     print "-" * 40 
    259                     self.traceFrame = frame 
    260             else: 
    261                 for k, thisFrame in frameGenerator(self.traceLevels): 
    262                     level += 1 
    263                     if thisFrame in (None, self.traceFrame): 
    264                         break 
    265                 else: 
    266                     return 
    267             msg(level) 
    268             return self.trace 
    269         elif event == 'return' and frame == self.traceFrame: 
    270             self.traceFrame = None 
    271             print "->", arg