pypsyc/fippos-twisted/pypsyc/objects/server.py

320 lines
12 KiB
Python

from pypsyc.objects import PSYCObject
from pypsyc import parseUNL
from twisted.internet import defer
class GroupMaster(PSYCObject):
"""
@type members: C{dict}
@ivar members: list of members of the group
"""
def __init__(self, netname, center):
PSYCObject.__init__(self, netname, center)
self.members = {}
self.flat = {}
def sizeof(self):
return len(self.flat)
def remove(self, whom, origin = None):
self.flat.pop(whom, None)
if origin is not None:
self.members.get(origin, {}).pop(whom, None)
if not self.members.get(origin, None):
self.members.pop(origin, None)
else:
self.members.pop(whom, None)
def insert(self, whom, origin = None, data = None):
if not data: data = True
self.flat[whom] = data
if origin and not self.netname.startswith(origin):
if not self.members.get(origin):
self.members[origin] = {}
self.members[origin][whom] = True
else:
self.members[whom] = True
def getData(self, whose):
return self.flat[whose]
def setData(self, whose, data):
self.flat[whose] = data
def member(self, who):
return who in self.flat
def castmsg(self, vars, mc, data):
vars['_nick_place'] = 'muh' # IMHO _nick_place is superflous
vars['_context'] = self.netname
for (route, list) in self.members.items():
# TODO: deepcopy needed?
vars['_target'] = route
self.center.sendmsg(vars, mc, data)
class GroupSlave:
def __init__(self, netname, center):
self.center = center
self.context = netname
self.members = {}
def join(self, obj):
url = obj.url()
self.members[url] = obj
# TODO: install a watcher on memberobj?
def leave(self, obj):
url = obj.url()
if url in self.members:
self.members.pop(url)
def castmsg(self, vars, mc, data):
for (target, obj) in self.members.items():
vars['_target'] = target
obj.msg(vars, mc, data)
class Place(GroupMaster):
silent = False
def __init__(self, netname, center):
self.idcallbacks = {}
self.identifications = {}
self.reverseidentifications = {}
GroupMaster.__init__(self, netname, center)
def sendmsg(self, vars, mc, data):
# things like setting vars['_nick_place']
vars['_source'] = self.netname
t = self.reverseidentifications.get(vars['_target'])
if t:
print 'setting target from %s to %s'%(vars['_target'], t)
vars['_target'] = t
GroupMaster.sendmsg(self, vars, mc, data)
def showMembers(self):
return self.flat.keys()
def showTopic(self):
return ''
def msg(self, vars, mc, data):
if '_context' in vars:
print '%s got %s with context %s from %s, bad' % (self.netname, mc,
vars['_context'],
vars['_source'])
return
ident = vars.get('_identification')
source = vars['_source']
if ident and self.identifications.get(source) == ident:
print 'ident of %s is %s'%(source,
self.identifications[vars['_source']])
vars['_source'] = ident
vars.pop('_identification')
GroupMaster.msg(self, vars, mc, data)
def msg_error_invalid_authentication(self, vars, mc, data):
print 'invalid auth'
d = self.idcallbacks.pop((vars['_location'], vars['_source']), None)
if d:
d.errback(1)
def msg_notice_authentication(self, vars, mc, data):
print 'valid auth'
d = self.idcallbacks.pop((vars['_location'], vars['_source']), None)
if d:
self.identifications[vars['_location']] = vars['_source']
self.reverseidentifications[vars['_source']] = vars['_location']
d.callback(1)
def helper(self, res, vars, mc, data):
self.msg(vars, mc, data)
def msg_request_enter(self, vars, mc, data):
source = vars['_source']
if '_identification' in vars:
ident = vars.get('_identification')
print 'looking up identification %s'%(ident,)
self.sendmsg({ '_target' : ident,
'_location' : source },
'_request_authenticate', 'Is that really you?')
d = defer.Deferred()
d.addCallback(self.helper, vars, mc, data)
d.addErrback(self.helper, vars, mc, data)
self.idcallbacks[(source, ident)] = d
return
# TODO: while it is not the final plan to make this via parseUNL
# it is acceptable for now
origin = parseUNL(source)['root']
v = { '_target' : source,
'_source' : self.netname }
if '_tag' in vars:
v['_tag'] = vars['_tag']
else:
pass
if '_nick' in vars:
v['_nick'] = vars['_nick']
else:
pass
if self.silent is True:
v['_control'] = '_silent'
self.sendmsg(v, '_echo_place_enter',
'[_nick] enters')
v.pop('_control', None)
v.pop('_tag', None)
v['_list_members'] = self.showMembers() + [ source ]
self.sendmsg(v, '_status_place_members', '...')
v.pop('_list_members')
if not self.member(source):
v['_source'] = source
self.castmsg(v, '_notice_place_enter', '[_nick] enters')
self.insert(vars['_source'], origin)
def msg_request_leave(self, vars, mc, data):
source = vars['_source']
# TODO again
origin = parseUNL(source)['root']
v = { '_source' : source }
if self.member(source):
self.castmsg({ '_source' : source }, '_notice_place_leave',
'[_nick] leaves')
self.remove(source)
else: # not a member for whatever reason
self.sendmsg({ '_target' : source}, '_echo_place_leave',
'You are not even a member')
pass
if self.sizeof() == 0:
# empty
pass
def msg_message_public(self, vars, mc, data):
if self.silent is False and self.member(vars['_source']):
self.castmsg(vars, mc, data)
class Person(GroupMaster):
def __init__(self, netname, center):
GroupMaster.__init__(self, netname, center)
self.location = None
self.forward = False
self.places = {}
self.tags = {}
def disconnected(self, prot, loc):
"""client has closed connection"""
self.location = None
print 'should leave', places.keys()
self.center.disconnected(prot, loc)
print self.center.remote_connections
def msg(self, vars, mc, data):
if '_context' in vars and not vars['_context'] in self.places:
# context faking, should be impossible as of now
print 'catching fake context!'
return
# dont forward messages from our location to it...
self.forward = vars['_source'] is not self.location
GroupMaster.msg(self, vars, mc, data)
if self.forward is True and self.location is not None:
vars['_target'] = self.location
self.sendmsg(vars, mc, data)
self.forward = False
# user is offline
def sendmsg(self, vars, mc, data):
# TODO: things like tag-creation for joins belong here
# as well as setting vars['_nick']
if not '_source' in vars or vars['_source'] == self.location:
vars['_source'] = self.netname
if vars['_target'] == self.location:
self.center.sendmsg(vars, mc, data)
else:
GroupMaster.sendmsg(self, vars, mc, data)
def sendmsg_request_enter(self, vars, mc, data):
import random
t = str(random.randint(0, 10000))
self.tags[vars['_target']] = t
vars['_tag'] = t
# tobi says, tags become invalid after a certain amount of time
self.center.sendmsg(vars, mc, data)
def sendmsg_request_leave(self, vars, mc, data):
# prepare to leave context after a reasonable amount of time
self.center.sendmsg(vars, mc, data)
def msgUnknownMethod(self, vars, mc, data):
if not self.location:
print 'person:unknown %s for offline user'%mc
def msg_request_link(self, vars, mc, data):
if vars['_password']:
self.msg_set_password(vars, mc, data)
else:
self.sendmsg({ '_target' : vars['_source'] },
'_query_password', 'Is that really you?')
self.forward = False
def msg_set_password(self, vars, mc, data):
"""note that we have NO authorization"""
# TODO: here we have to use origin
if self.location is not None:
self.sendmsg({ '_target' : self.location},
'_notice_unlink',
'You have just lost the magic feeling.')
self.location = vars['_source']
# TODO: we may need to deregister this thing...
self.center.link_unl(self.location, self)
self.sendmsg({ '_target' : self.location},
'_notice_link', 'You are now connected')
self.forward = False
def msg_request_unlink(self, vars, mc, data):
if vars['_source'] == self.netname: # heh, this one is nifty!
self.sendmsg({'_source' : self.netname,
'_target' : self.location },
'_notice_unlink',
'You have just lost the magic feeling.')
self.location = None
self.center.unlink_unl(self.location, self.netname)
for place in self.places.copy():
self.sendmsg({'_source' : self.netname,
'_target' : place },
'_request_leave_logout',
'l8er')
self.forward = False
def msg_echo_place_enter(self, vars, mc, data):
source = vars['_source']
tag = vars.get('_tag')
if not source in self.tags:
self.forward = False
elif self.tags[source] != tag:
self.tags.pop(source) # wrong tag, you get invalid
self.forward = False
else:
self.places[vars['_source']] = 1
self.center.join_context(source, self)
def msg_notice_place_leave(self, vars, mc, data):
if vars['_source'] == self.netname:
mc = '_echo' + mc[7:]
vars['_source'] = vars['_context']
self.msg(vars, mc, data)
def msg_echo_place_leave(self, vars, mc, data):
place = vars.get('_context') or vars['_source']
if place in self.places:
self.places.pop(place)
self.forward = True
def msg_request_roster(self, vars, mc, data):
print 'Roster: %s'%(self.flat)
self.sendmsg({'_source' : self.netname,
'_target' : self.location,
'_list_places' : self.places,
'_list_friends' : self.flat.keys()},
'_notice_roster',
'Your friends are [_friends], you have entered in [_list_places].')
self.forward = False
def msg_request_friendship(self, vars, mc, data):
"""
Friendship states:
known -> 0
asked from -> 1
offered to -> 2
dual accepted -> 3
"""
source = vars['_source']
if self.member(source) and self.getData(source) == 2:
self.setData(source, 3)
mc = '_notice_friendship_establshed'
# TODO
else:
self.insert(source, None, 1)
self.forward = True
def sendmsg_request_friendship(self, vars, mc, data):
target = vars['_target']
if self.member(target) and self.getData(target) == 1:
self.setData(target, 3)
mc = '_notice_friendship_established'
# TODO: echo_notice_friendship_established
else:
self.insert(target, None, 2)
self.center.sendmsg(vars, mc, data)
self.forward = True
def msg_notice_friendship_established(self, vars, mc, data):
source = vars['_source']
if self.member(source) and self.getData(source) == 2:
self.setData(source, 3)