Changeset 138
- Timestamp:
- 05/05/02 14:02:58 (6 years ago)
- Files:
-
- trunk/RBFoundation/RBFoundation/SmartSelect.py (modified) (2 diffs)
- trunk/RBJabber/RBJabber/Conference.py (modified) (5 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/Subject.py (modified) (6 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/__init__.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/RBFoundation/RBFoundation/SmartSelect.py
r132 r138 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 32 33 """Simple select.select handle management. 34 35 A set of classes wrapping select.select, making the management of N handles as 36 simple as managing a single handle. In order to implement SmartSelect for your 37 socket or other handle(s), simply derive from SmartSelectBase, and implement the 38 abstract methods from ClientBase. 39 40 Well read pythoneers will note that is module is very similar to asyncore, and are 41 probably wondering why. Well, my reason is interface. Asyncore was great inspiration, 42 but I wanted to have less assumption that the objects were sockets; simply objects 43 compatable with select.select. Secondly, objects derived from SmartSelectBase should 44 be as easily run as if they were collected into a larger group. Finally, I wanted the 45 collections to feel like just that: collections of selectable objects. (dict, list, or single) 46 """ 47 33 48 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 49 #~ Imports … … 60 75 61 76 def Process(self, timeout=None): 62 """Uses select.select to wait on several file (proxy) handles in an object-oriented way.""" 77 """Uses select.select to wait on several file (proxy) handles in an object-oriented way. 78 ProcessState contains the state and, if applicable, the handle being processed, 79 allowing for interogation in the case of an exception.""" 63 80 if not self: 64 81 self.ProcessState = "Idle", None trunk/RBJabber/RBJabber/Conference.py
r137 r138 38 38 from Foundation.Jabber.JabberSubject import JabberSubjectBase 39 39 from Foundation.Jabber import JID 40 from Foundation import SubjectObserver40 from Foundation.SubjectObserver.Observer import Observer 41 41 42 42 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 47 47 def __init__(self, JC, ConferenceJID): 48 48 JabberSubjectBase.__init__(self) 49 # Save the conference JID 50 self.ConferenceJID = JID.JID(ConferenceJID).nominal() 51 52 # Save the Jabber Client 53 self.JC = weakref.ref(JC) 54 55 # Pretend like we are a Jabber.Client 49 56 self.stream = weakref.proxy(self) 50 self.ConferenceJID = JID.JID(ConferenceJID).nominal()51 self.JC = weakref.ref(JC)52 JC.stream.AddObserver('message', self)53 JC.stream.AddObserver('presence', self)54 JC.stream.AddObserver('iq', self)57 # Insert our greedy little meathooks... 58 obs = Observer(self._CallConference, self._BidConference) 59 JC.stream.AddObserver('message', obs) 60 JC.stream.AddObserver('presence', obs) 61 JC.stream.AddObserver('iq', obs) 55 62 56 def Bid(self, subject, **UpdateDict): 63 def __del__(self): 64 if self.JC(): 65 self.Presence(type='unavailable') 66 67 def _CallConference(self, subject, **UpdateDict): 68 pass 69 70 def _BidConference(self, subject, **UpdateDict): 57 71 for each in UpdateDict.itervalues(): 58 72 if each.from_ not in self.ConferenceJID: … … 64 78 self.JC().Query('jabber:iq:conference', toJID=self.ConferenceJID, type='get', callback=callback) 65 79 66 def Join (self, NickName, Secret='', callback=None):80 def JoinAs(self, NickName, Secret='', callback=None): 67 81 if not isinstance(NickName, (list, tuple)): NickName = (NickName,) 68 82 xmlNickName = ''.join(['<nick>%s</nick>' % x for x in NickName]) … … 88 102 print "Testing..." 89 103 import Client 90 import pprint91 104 def PrintStuff(stream, **kw): 92 105 for each in kw.itervalues(): … … 94 107 jc = Client.Client('www.runeblade.com') 95 108 jc.Authenticate('shane.test1', 'testing', 'PyConferenceTest') 96 jc.ProcessPending(1.0)97 109 conf = Conference(jc, 'shane.conf@private.www.runeblade.com') 98 110 conf.AddObserver('message', PrintStuff) 99 111 conf.AddObserver('presence', PrintStuff) 100 112 conf.AddObserver('iq', PrintStuff) 101 conf.Join ('RuneBlade.Development')113 conf.JoinAs('RuneBlade.Development') 102 114 conf.Message('Hello from RB development!!!') 103 115 jc.ProcessPending(1.0) 116 try: 117 while 1: jc.Process(1.0) 118 except KeyboardInterrupt: 119 pass 120 #del conf 121 #try: 122 # while 1: jc.Process(1.0) 123 #except KeyboardInterrupt: 124 # pass 104 125 print "Test complete." 105 126 trunk/RBJabber/RBJabber/SubjectObserver/Subject.py
r137 r138 42 42 43 43 class Subject(object): 44 """Maintains a list of montioring observers that get updated when 45 UpdateObservers or UpdateObserversEx get called, unless the subject is Locked. 46 A lock can be obtained by calling Lock, and it maintained until the lock object 47 no longer exisits or is explicitly released.""" 48 49 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 50 #~ Special 51 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 52 44 53 def __init__(self): 45 54 self._observers = [] … … 52 61 53 62 def AddObserver(self, observer): 63 """Adds observer to the internal collection monitoring this subject 64 Observer is assumed to be a callable object.""" 54 65 result = WeakBind.BindCallable(observer) 55 66 self._observers.append(result) … … 57 68 58 69 def RemoveObserver(self, observer): 70 """Removes observer from the internal collection monitoring this subject. 71 Observer should be the same object that was passed to AddObserver.""" 59 72 result = WeakBind.BindCallable(observer) 60 73 try: … … 68 81 69 82 def _ObserverList(self): 83 """Returns the internal observer collection pruned of invalid weakref objects as a list""" 70 84 self._observers = filter(None, self._observers) 71 85 return self._observers … … 73 87 74 88 def UpdateObservers(self, **kw): 89 """Updates all observers of this subject with data in **kw. See also UpdateObserversEx.""" 75 90 return self.UpdateObserversEx(kw) 76 91 77 92 def UpdateObserversEx(self, kw): 93 """Updates all observers of this subject with data in kw. (kw is assumed to be a dictonary.) See also UpdateObservers.""" 78 94 self._cachedUpdates.update(kw) 79 95 if self._cachedUpdates and not self._locked: … … 87 103 88 104 def UpdateObserver(self, observer, UpdateDict): 105 """Updates observer with UpdateDict. (UpdateDict is assumed to be a dictonary.)""" 89 106 if observer: apply(observer, (self,), UpdateDict) 90 107 108 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 109 #~ Subject Locking 110 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 111 112 class _SubjectLock: 113 """Maintains a lock on subject while instance exists""" 114 subject = None 115 def __init__(self, lockedsubject): 116 self.SetLock(lockedsubject) 117 def __del__(self): 118 try: 119 self.SetLock(None) 120 except: 121 # XXX: Is there a good way to pass the exception along, and not have it 122 # be absorbed by the python __del__ exception condition? 123 import traceback 124 traceback.print_exc() 125 def SetLock(self, lockedsubject): 126 """Obtains a lock on lockedsubject. If lockedsubject is different than the 127 current subject, then the current subject is unlocked as well.""" 128 if self.subject and id(self) in self.subject._locked: 129 self.subject._locked.remove(id(self)) 130 if self.subject._cachedUpdates: 131 self.subject.UpdateObservers() 132 self.subject = lockedsubject 133 if self.subject: 134 self.subject._locked.append(id(self)) 135 91 136 def Lock(self): 92 class lock: 93 subject = None 94 def __init__(self, lockedsubject): 95 self.SetLock(lockedsubject) 96 def __del__(self): 97 self.SetLock(None) 98 def SetLock(self, lockedsubject): 99 if self.subject and id(self) in self.subject._locked: 100 self.subject._locked.remove(id(self)) 101 if self.subject._cachedUpdates: 102 self.subject.UpdateObservers() 103 self.subject = lockedsubject 104 if self.subject: 105 self.subject._locked.append(id(self)) 106 return lock(self) 137 """Prevents observers of subject from being updated while a lock is held on the subject.""" 138 return self._SubjectLock(self) 107 139 140 def Locked(self): 141 """Returns 1 if the subject is locked, and 0 otherwise""" 142 return self._locked and 1 or 0 trunk/RBJabber/RBJabber/SubjectObserver/__init__.py
r137 r138 37 37 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 38 39 import Observer 40 import AssociativeObserver 39 import Observer as _Observer 40 import AssociativeObserver as _AssociativeObserver 41 41 42 import Subject 43 import CategorySubject 44 import AttributedSubject 45 import BidableSubject 42 import Subject as _Subject 43 import CategorySubject as _CategorySubject 44 import AttributedSubject as _AttributedSubject 45 import BidableSubject as _BidableSubject 46 46 47 class AttributedCategorySubject(AttributedSubject.AttributedSubjectMixin, CategorySubject.CategorySubjectMixin, Subject.Subject): 47 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 48 #~ Definitions 49 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 50 51 class AttributedCategorySubject(_AttributedSubject.AttributedSubjectMixin, _CategorySubject.CategorySubjectMixin, _Subject.Subject): 48 52 pass 49 class AttributedBidableSubject( AttributedSubject.AttributedSubjectMixin, BidableSubject.BidableSubjectMixin,Subject.Subject):53 class AttributedBidableSubject(_AttributedSubject.AttributedSubjectMixin, _BidableSubject.BidableSubjectMixin, _Subject.Subject): 50 54 pass 51 class AttributedBidableCategorySubject( AttributedSubject.AttributedSubjectMixin, BidableSubject.BidableSubjectMixin, CategorySubject.CategorySubjectMixin,Subject.Subject):55 class AttributedBidableCategorySubject(_AttributedSubject.AttributedSubjectMixin, _BidableSubject.BidableSubjectMixin, _CategorySubject.CategorySubjectMixin, _Subject.Subject): 52 56 pass 53 57 54 class BidableCategorySubject( BidableSubject.BidableSubjectMixin, CategorySubject.CategorySubjectMixin,Subject.Subject):58 class BidableCategorySubject(_BidableSubject.BidableSubjectMixin, _CategorySubject.CategorySubjectMixin, _Subject.Subject): 55 59 pass 56 class BidableAttributedSubject( AttributedSubject.AttributedSubjectMixin, BidableSubject.BidableSubjectMixin,Subject.Subject):60 class BidableAttributedSubject(_AttributedSubject.AttributedSubjectMixin, _BidableSubject.BidableSubjectMixin, _Subject.Subject): 57 61 pass 58 class BidableAttributedCategorySubject( AttributedSubject.AttributedSubjectMixin, BidableSubject.BidableSubjectMixin, CategorySubject.CategorySubjectMixin,Subject.Subject):62 class BidableAttributedCategorySubject(_AttributedSubject.AttributedSubjectMixin, _BidableSubject.BidableSubjectMixin, _CategorySubject.CategorySubjectMixin, _Subject.Subject): 59 63 pass 60 64 … … 97 101 def printo3(subject, **UpdateDict): 98 102 print "O3: ", UpdateDict 99 s1 = Subject.Subject()100 s2 = AttributedSubject.AttributedSubject()103 s1 = _Subject.Subject() 104 s2 = _AttributedSubject.AttributedSubject() 101 105 s3 = AttributedCategorySubject() 102 106 … … 114 118 s1.UpdateObservers(Locked='Update') 115 119 print "Post-lock" 116 lock = None120 del lock 117 121 print "Unlocked" 118 122 119 o3 = Observer.Observer(printo3)120 s3.AddObserver('CategoryA', o1)121 s3.AddObserver('CategoryB', o2)123 o3 = _Observer.Observer(printo3) 124 s3.AddObserver('CategoryA', printo1) 125 s3.AddObserver('CategoryB', printo2) 122 126 s3.AddObserver('CategoryC', o3) 123 127
