1
0
Fork 0
mirror of git://git.psyced.org/git/pypsyc synced 2024-08-15 03:20:04 +00:00

last state we had in cvs

This commit is contained in:
psyc://psyced.org/~lynX 2010-02-24 09:50:45 +01:00
commit 0f02e9cd76
128 changed files with 9224 additions and 0 deletions

24
fippos-twisted/README Normal file
View file

@ -0,0 +1,24 @@
pyPSYC - asyncore based library for PSYC
The application programming interface (API) of this library is stable,
says fippo. But he left it unmaintained since 2005.
News at http://about.psyc.eu/pypsyc
Download by anonCVS from the same server as psyced.
:pserver:anonymous@cvs.psyced.org:/CVS/anoCVS
QUESTIONS?
/tell psyc://psyced.org/~fippo or come to psyc://psyced.org/@welcome
AUTHORS
Philipp Hancke
<psyc://psyced.org/~fippo>
Tim Head
<psyc://psyced.org/~betatim>
Andreas Neue
<psyc://psyced.org/~an>

View file

@ -0,0 +1,230 @@
# usage: twistd -noy ircd.py
import sys
from twisted.application import service, internet
from pypsyc.center import ServerCenter
from pypsyc.net import PSYCServerFactory
from pypsyc.objects import PSYCReceiver
from pypsyc.objects.server import Person, Place, GroupSlave
from pypsyc import parseURL
from twisted.protocols import irc
from twisted.internet.protocol import ServerFactory
"""
watch out, the main purpose of this thing is to debug the context slave
system
"""
class IRCD(irc.IRC, PSYCReceiver):
center = None
password = ''
nick = ''
url = ''
source = None
def __init__(self, center, hostname):
self.center = center
self.hostname = hostname
def connectionMade(self):
peer = self.transport.getPeer()
self.source = 'object:%s:%d'%(peer.host, peer.port)
self.center.register_object(self.source, self)
def connectionLost(self, reason):
if self.url:
self.irc_QUIT(None, None)
elif self.nick is '':
print 'closing unknown connection'
def sendNumeric(self, numeric, msg):
self.sendLine(':%s %s %s :%s'%(self.hostname, numeric, self.nick, msg))
# def sendLine(self, line):
# irc.IRC.sendLine(self, line.encode('iso-8859-1'))
def sendMessage(self, source, target, cmd, data = None):
s = ':%s %s %s'%(self.url2prefix(source), target, cmd)
if data:
s += ' :%s'%data
self.sendLine(s)
def sNotice(self, data):
self.sendLine(':%s NOTICE %s :%s'%(self.hostname, self.nick, data))
"""helper functions"""
def expandUrl(self, target):
"""quick and dirty is_uniform check"""
if target.find(':') is -1:
if target[0] == '#':
return self.hostname + '/@%s'%target[1:]
return self.hostname + '/~%s'%target
if target[0] == '#':
return target[1:]
return target
def minimizeUrl(self, source):
if source.startswith(self.hostname):
# remark: +2 to skip trailing /@
return source[len(self.hostname) + 2:]
return source
def url2prefix(self, url):
if url.find(':') != -1:
u = parseURL(url)
if u['resource'][0] == '~':
ident = u['resource'][1:]
else:
ident = '*'
host = u['host']
else:
ident = url # its a local nick
host = 'localuser'
return '%s!%s@%s'%(url, ident, host)
"""irc_ command hooks"""
def irc_USER(self, prefix, params):
pass
def irc_PASS(self, prefix, params):
self.password = params[0]
def irc_NICK(self, prefix, params):
self.nick = params[0]
self.center.msg({'_source' : self.source,
'_target' : self.expandUrl(self.nick),
'_password' : self.password},
'_request_link', '')
def irc_PRIVMSG(self, prefix, params):
target = params[0]
mc = '_message_private'
if target[0] == '#':
mc = '_message_public'
self.center.msg({ '_source' : self.source,
'_target' : self.expandUrl(target),
'_nick' : self.nick},
mc, params[-1])
def irc_JOIN(self, prefix, params):
chan = params[0]
self.center.msg({ '_source' : self.source,
'_target' : self.expandUrl(chan),
'_nick' : self.nick},
'_request_enter', '')
def irc_PART(self, prefix, params):
chan = params[0]
self.center.msg({ '_source' : self.source,
'_target' : self.expandUrl(chan),
'_nick' : self.nick},
'_request_leave', '')
def irc_QUIT(self, prefix, params):
self.center.msg({ '_source' : self.source,
'_target' : self.url },
'_request_unlink', '')
def irc_unknown(self, prefix, command, params):
if command == 'ROSTER':
self.center.msg({ '_source' : self.source,
'_target' : self.url },
'_request_roster', '')
elif command == 'FRIEND':
self.center.msg({ '_source' : self.source,
'_target' : self.expandUrl(params[0]) },
'_request_friendship', 'Lass uns Freunde sein')
else:
print 'unknown irc cmd %s'%command
"""pypsyc msg API"""
def msgUnknownMethod(self, vars, mc, data):
print 'unsupported %s from %s'%(mc, vars['_source'])
def msg_notice_link(self, vars, mc, data):
self.url = vars['_source']
self.sendNumeric(irc.RPL_WELCOME, 'Hello, %s'%self.nick)
self.sendNumeric(irc.RPL_YOURHOST, 'Welcome to %s'%self.hostname)
self.sendNumeric(irc.RPL_MYINFO, '%s is a pyPSYC daemon IRC interface'%self.hostname)
def msg_message_private(self, vars, mc, data):
if vars['_target'] is self.source:
t = self.nick
else: # should not happen
raise
# TODO: might be appropriate to use self.privmsg()
# self.privmsg(vars['_source'], self.nick, None, data)
s = self.minimizeUrl(vars['_source'])
self.sendMessage(s, 'PRIVMSG', t, data)
def msg_message_echo_private(self, vars, mc, data):
pass # echo is not common in irc
def msg_message_public(self, vars, mc, data):
if vars['_source'] != self.url: # skip echo
if vars.has_key('_context'):
t = '#' + self.minimizeUrl(vars['_context'])
else:
t = '#' + self.minimizeUrl(vars['_source'])
s = self.minimizeUrl(vars['_source'])
# TODO: might be appropriate to use self.privmsg()
# self.privmsg(vars['_source'], None, t, data)
self.sendMessage(s, 'PRIVMSG', t, data)
else:
pass # echo is not common in IRC
def msg_echo_place_enter(self, vars, mc, data):
t = '#' + self.minimizeUrl(vars['_source'])
self.sendMessage(self.nick, 'JOIN', t)
def msg_echo_place_leave(self, vars, mc, data):
t = '#' + self.minimizeUrl(vars['_source'])
self.sendMessage(self.nick, 'PART', t)
def msg_status_place_members(self, vars, mc, data):
t = '#' + self.minimizeUrl(vars['_source'])
self.names(self.nick, t, map(self.minimizeUrl, vars['_list_members']))
def msg_notice_unlink(self, vars, mc, data):
if vars['_source'] == self.url:
self.url = None
self.transport.loseConnection()
def msg_notice_place_enter(self, vars, mc, data):
s = vars['_source']
c = '#' + self.minimizeUrl(vars['_context'])
if s == self.url:
return # we dont like being joined via notice!
self.join(self.url2prefix(self.minimizeUrl(s)), c)
def msg_notice_place_leave(self, vars, mc, data):
s = vars['_source']
c = '#' + self.minimizeUrl(vars['_context'])
self.part(self.url2prefix(self.minimizeUrl(s)), c)
def msg_notice_roster(self, vars, mc, data):
friends = vars['_list_friends']
places = vars['_list_places']
if friends:
self.sNotice('Friends')
for friend in vars['_list_friends']:
self.sNotice('~ %s'%friend)
if places:
self.sNotice('Places')
for place in places:
self.sNotice('@ %s'%place)
def msg_request_friendship(self, vars, mc, data):
sni = self.minimizeUrl(vars['_source'])
self.notice(sni, self.nick,
'%s wants to be your friend'%(sni))
def msg_notice_friendship_established(self, vars, mc, data):
sni = self.minimizeUrl(vars['_source'])
self.notice(sni, self.nick,
'%s is now your friend'%(sni))
class IRCDFactory(ServerFactory):
center = None
def __init__(self, center, location):
self.center = center
self.location = location
def buildProtocol(self, addr):
p = IRCD(self.center, self.location)
p.factory = self
return p
class MyServerCenter(ServerCenter):
def create_user(self, netname):
return Person(netname, self)
def create_place(self, netname):
return Place(netname, self)
def create_context(self, netname):
return GroupSlave(netname, self)
root = 'psyc://ente' # TODO: this does belong into a config file!
application = service.Application('psycserver')
center = MyServerCenter(root)
factory = PSYCServerFactory(center, None, root)
psycServer = internet.TCPServer(4404, factory)
ircfactory = IRCDFactory(center, root)
ircServer = internet.TCPServer(6667, ircfactory)
myService = service.IServiceCollection(application)
psycServer.setServiceParent(myService)
ircServer.setServiceParent(myService)

View file

@ -0,0 +1,9 @@
Purpose:
this is designed to be a news distributing server only. It fetches RSS feeds
Running:
twistd -noy rss_server.py
This code depends on
- rss.py from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277099
- feedparser.py from http://diveintomark.org/projects/feed_parser/
- twisted python (python is less fun without)

View file

@ -0,0 +1,131 @@
# usage: twistd -noy rss_server.py
from twisted.application import service, internet
from twisted.internet import reactor
from pypsyc.center import ServerCenter
from pypsyc.net import PSYCServerFactory
from pypsyc.objects.server import Place
from pypsyc import parseUNL
try:
from rss import FeederFactory
except ImportError:
print 'error while importing rss.py'
print 'make sure you have rss.py from ',
print 'from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277099'
print 'and feedparser.py from ',
print 'http://diveintomark.org/projects/feed_parser/'
class PlaceFeeder(FeederFactory):
def getFeeds(self):
return []
class Feedplace(Place):
channel = None
silent = True
def __init__(self, netname, center, feed):
Place.__init__(self, netname, center)
self.feed = feed
self.error = 0 # number of times that we didnt succeed
self.fetched = 0 # number of times we fetched sucessfully
self.fetched_items = 0 # the average number of new items per fetch
self.fetch_interval = 15 * 60 # initial feed interval
self.feeder = PlaceFeeder(False)
self.news = []
reactor.callLater(5, self.fetchFeed)
def fetchFeed(self):
d = self.feeder.start([(self.feed, '')])
d.addCallback(self.gotFeed)
d.addErrback(self.gotError)
def gotError(self, error):
self.error += 1
# TODO: react on feeds that are temp/perm unreachable
reactor.callLater(self.fetch_interval, self.fetchFeed)
print 'looks as if feed %s is unreachable'%self.feed
print error
def gotFeed(self, data):
self.fetched += 1
new = []
items = {}
if self.channel is None:
self.channel = data['channel']
self.castmsg({ '_nick' : self.netname,
'_topic' : self.showTopic()},
'_status_place_topic',
'Topic by [_nick]: [_topic]')
for item in data['items']:
# diff by url
href = item['link']
new.append(href)
items[href] = item
diff = filter(lambda x: x not in self.news, new)
for href in diff:
item = items[href]
v = {'_news_headline' : item['title_detail']['value'],
'_page_news' : href,
'_channel_title' : data['channel']['title'] }
self.castmsg(v, '_notice_news_headline_rss',
'([_channel_title]) [_news_headline]\n[_page_news]')
self.news = new
# feeds whose average number of new items is < x
# can be polled with less frequency
self.fetched_items += len(diff)
avg = float(self.fetched_items) / self.fetched
print 'avg no of new items per fetch for %s is %f'%(self.feed, avg)
if avg < 1.5: # x
# lower frequency
self.fetch_interval *= avg
elif avg > 4.5 and self.fetched > 10: # y
# increase frequenzy
self.fetch_interval /= 2
print 'callLater in %d'%(self.fetch_interval)
reactor.callLater(self.fetch_interval, self.fetchFeed)
def showMembers(self):
return []
def showTopic(self):
if self.channel is not None:
return 'feed \'%s\' available from %s'%(self.channel['title'],
self.feed)
else:
return 'stand by while fetching feed %s'%self.feed
def msg_message_public(self, vars, mc, data):
pass # they're not for talking
class MyServerCenter(ServerCenter):
feeds = {}
def create_user(self, netname):
return False
def create_place(self, netname):
u = parseUNL(netname)
res = u['resource'][1:]
if self.feeds.has_key(res):
return Feedplace(netname, center, self.feeds[res])
return False
def create_context(self, netname):
return False
def setFeeds(self, feeds):
self.feeds = feeds
def getFeeds(self):
return self.feeds
root = 'psyc://ente'
application = service.Application('psyc news distributor')
center = MyServerCenter(root)
factory = PSYCServerFactory(center, None, root)
psycServer = internet.TCPServer(4404, factory)
center.setFeeds({ 'heise' : 'http://www.heise.de/newsticker/heise.rdf' })
myService = service.IServiceCollection(application)
psycServer.setServiceParent(myService)

View file

@ -0,0 +1,28 @@
"""p2p manager and client as described in the old PSYC whitepaper at
http://psyc.pages.de/whitepaper/
probably broken currently"""
from pypsyc.center import ServerCenter, ClientCenter
from pypsyc.objects.PSYCObject import PSYCClient
from pypsyc.objects.Advanced import AdvancedManager, AdvancedPlace
import sys
import asyncore
location = 'psyc://adamantine.aquarium'
type = sys.argv[1]
if type == 'manager':
center = ServerCenter([location + ':4405/', location + ':4406',
location + ':4407', location + ':4408'])
center2 = ServerCenter([location])
AdvancedManager(location + '/@advanced', center2)
if type == 'client':
center = ClientCenter()
me = PSYCClient(location + '/~fippo', center)
me.online()
AdvancedPlace(location + "/@advanced", center)
me.sendmsg({'_target' : location + '/@advanced',
'_source' : location + '/~fippo'},
'_request_enter', '')
while center:
asyncore.poll(timeout=0.5)

10
fippos-twisted/doc/DESIGN Normal file
View file

@ -0,0 +1,10 @@
Design of the pyPSYC library
Asynchronus programming
The role of the center object
Writing a client
- GUI event loop Integration
Writing a server

View file

@ -0,0 +1 @@
onesided zlib compression

View file

@ -0,0 +1,70 @@
from pypsyc.State import State
from twisted.protocols.basic import LineReceiver
class PSYCProtocol(LineReceiver):
statemachine = None
state = 'vars'
mc = None
text = None
delimiter = '\n'
initialized = False
def connectionMade(self):
self.statemachine = State()
self.reset()
self.transport.write('.\n')
def msg(self, vars, mc, text):
"""serialize a packet and send to the other side
@type vars: C{dict}
@param vars: Dictionary of variables to be serialized.
Variables should be strings or lists, variable names start
with an underscore
@type mc: C{str}
@param mc: Methodname of the packet, starts with an underscore
@type text: C{str}
@param text: Data part of the packet"""
packet = self.statemachine.serialize(vars) # this has a newline already!
packet += mc + '\n'
packet += text + '\n'
packet += '.\n'
self.transport.write(packet.encode('iso-8859-1'))
def reset(self):
self.statemachine.reset()
self.state = 'vars'
self.mc = ''
self.text = ''
def lineReceived(self, line):
"""this does not yet handle binary mode and fragments"""
line = line.strip()
if self.initialized is False:
if line != '.':
self.msg({}, '_error_syntax_protocol_initialization',
'The protocol begins with a dot on a line of by itself')
self.transport.loseConnection()
return
else:
self.initialized = True
return
if line == '.':
self.packetReceived()
elif self.state is 'vars' and line.startswith('_'):
self.statemachine.eat(None)
self.mc = line
self.state = 'text'
elif self.state == 'vars':
self.statemachine.eat(line)
else:
self.text += line + '\n'
def packetReceived(self):
vars = self.statemachine.copy()
peer = self.transport.getPeer()
if not vars.has_key('_source'):
vars['_source'] = 'psyc://%s:-%d'%(peer.host, peer.port)
mc = self.mc[:]
data = self.text[:].strip().decode('iso-8859-1')
self.reset()
self.factory.packetReceived(vars, mc, data, self, peer)

View file

@ -0,0 +1,156 @@
# TODO: write tests
from pypsyc import MMPVARS
from copy import deepcopy
class SenderState:
def __init__(self):
self.laststate = {}
self.persistent_out = {}
def serializeList(self, varname, value):
t = []
old = self.persistent_out.get(varname)
# that is far to experimental
if True: # not old: # no previous list sent
self.persistent_out[varname] = value
t.append(':%s\t%s\n'%(varname, value[0].replace('\n', '\n\t')))
for item in value[1:]:
t.append(':\t%s\n'%(item.replace('\n', '\n\t')))
return '\n'.join(t)
if False:
augmented = filter(lambda x: x not in old, value)
if augmented:
packet += '+%s\t%s\n'%(varname, augmented[0].replace('\n',
'\n\t'))
for item in augmented[1:]:
packet += '+\t%s\n'%(item.replace('\n', '\n\t'))
diminished = filter(lambda x: x not in value, old)
if diminished:
packet += '-%s\t%s\n'%(varname, diminished[0].replace('\n',
'\n\t'))
for item in diminished[1:]:
packet += '-\t%s\n'%(item.replace('\n', '\n\t'))
self.persistent_out[varname] = value
def serialize(self, state):
"""
serializes a set of variables into a string
@type state: C{dict}
@param state: Dictionary of variables to be serialized
"""
L = []
# beware of the lambdas!
L.append(self.varencode(filter(lambda x: x[0] in MMPVARS and x[1],
state.items())))
if L != []:
L.append('\n')
L.append(self.varencode(filter(lambda x: x[0] not in MMPVARS and x[1],
state.items())))
self.laststate = state
bytes = '\n'.join(L)
return bytes
def varencode(self, v):
"""
encodes a set of variables, setting the state persistent according to
some strategy
@type v: C{dict}
@param v: Dictionary of variables to be serialized
"""
t = []
for (varname, value) in v:
if self.persistent_out.get(varname) == value:
pass
elif varname.startswith('_list') or type(value) == type([]):
t.append(self.serializeList(varname, value))
elif self.laststate.get(varname) == value and varname != '_context':
self.persistent_out[varname] = value
t.append('=%s\t%s\n'%(varname, value.replace('\n', '\n\t')))
else:
t.append(':%s\t%s\n'%(varname, value.replace('\n', '\n\t')))
return '\n'.join(t)
class ReceiverState:
glyph = ''
varname = ''
listFlag = False
value = ''
def __init__(self):
self.state = {}
self.persistent = {}
def reset(self):
self.state = {}
self.glyph = ''
self.varname = ''
self.listFlag= False
self.value = ''
def copy(self):
# do we actually need those deep copys? TODO
t = deepcopy(self.persistent)
t.update(deepcopy(self.state))
return t
def eat(self, line):
"""
this one is tricky... first it handles the previous line,
and then it prepares the current line.
This is needed to implement multiline-continuations in lists
@type line: C{str} or C{None}
@param line: line to be parsed, a None signals that variable
parsing for current packet is finished
"""
if line: line = line.decode('iso-8859-1') # we use unicode internally
if line and (line[0] == ' ' or line[0] == '\t'): # multiline support
self.value += '\n' + line[1:]
return
# glyph handling
if self.glyph == ':':
if self.listFlag:
if not type(self.state[self.varname]) == list:
self.state[self.varname] = [self.state[self.varname]]
self.state[self.varname].append(self.value)
else:
if self.varname.startswith('_list'):
self.value = [self.value]
self.state[self.varname] = self.value
elif self.glyph == '=':
if self.listFlag:
if not type(self.persistent[self.varname]) == list:
self.persistent[self.varname] = [self.self.persistent[self.varname]]
self.persistent[self.varname].append(self.value)
else:
self.persistent[self.varname] = self.value
elif self.glyph == '+':
self.persistent.get(self.varname, []).append(self.value)
elif self.glyph == '-':
raise NotImplementedError
elif self.glyph == '?':
raise NotImplementedError
if not line: # feeding done
return
# here we parse the current line
self.glyph = line[0]
if line[1] == '\t':
# lastvarname-optimization: varname remains the same
self.listFlag = True
self.value = line[2:]
else:
self.listFlag = False
if line.find('\t') == -1:
self.varname = line[1:]
self.value = ''
else:
self.varname, self.value = line[1:].split('\t', 1)
self.value = self.value
class State(SenderState, ReceiverState):
"""combination of sender and receiver state"""
def __init__(self):
SenderState.__init__(self)
ReceiverState.__init__(self)

View file

@ -0,0 +1,101 @@
"""common methods and constants for pyPSYC"""
# URL parsing functions modelled after psycMUVE parseURL
def parseURL(url):
u = { 'scheme' : '',
'user' : '',
'pass' : '',
'host' : '',
'port' : '4404',
'transport' : '',
'string' : url,
'body' : '',
'userAtHost' : '',
'hostPort' : '',
'root' : '',
'circuit' : '',
'size' : ''
}
if url.find(':') == -1: return u
u['scheme'], t = url.split(':', 1)
if t[0:2] == '//': t = t[2:]
u['body'] = t[:]
if t.find('/') != -1:
t, u['resource'] = t.split('/', 1)
else:
u['resource'] = ''
if u.has_key('resource') and u['resource'].find('#') != -1:
u['resource'], u['fragment'] = u['resource'].split('#', 1)
u['userAtHost'] = t[:]
if t.find('@') != -1:
s, t = t.split('@', 1)
if s.find(':') != -1:
u['user'], u['pass'] = s.split(':', 1)
else:
u['user'] = s
u['hostPort'] = t[:]
u['root'] = u['scheme'] + '://' + u['hostPort']
if t.find(':') != -1:
t, s = t.split(':', 1)
# TODO: split s in Port (numeric), Transport
if s and s[-1] in ['c', 'd', 'm']:
u['transport'] = s[-1]
u['port'] = s[:-1] or '4404'
else:
u['port'] = s or '4404'
u['host'] = t[:]
# print "parseurl(%s)"%url, u
return u
def parseUNL(unl): return parseURL(unl) # alias
def UNL2Location(unl):
# if we did not have the user@host syntax this would
# reduce to a simple splitting in front of #
u = parseUNL(unl)
short = u['scheme'] + '://' + u['host']
if u['port'] != '4404':
short += ':' + u['port']
if u['resource']:
return short + '/' + u['resource']
return short
def netLocation(unl):
u = parseURL(unl)
return u['root']
def parsetext(vars, mc, data, caller=None):
pstring = data
#print '---'
#print type(data)
#print '---'
try:
for (varname, value) in vars.items():
if type(value) == list:
no_list = u''
for x in value:
no_list += x + ', '
pstring = pstring.replace(u'[' + varname + u']', no_list[:-2])
else:
pstring = pstring.replace(u'[' + varname + u']', value)
except:
print 'Error in parsetext() for vars'
return pstring
# debugging helper
def dump_packet(banner, vars, mc, data):
print banner + ' ',
for key in vars.keys():
try:
print key + '=' + vars[key] + ' ',
except:
pass
print mc,
print '[' + parsetext(vars, mc, data) + ']'
# constants
GLYPHS = [':', '=', '+', '-', '?', ' ', '\t' ]
MMPVARS = ["_source", "_target", "_context"]

View file

@ -0,0 +1,269 @@
#!/usr/bin/env python
from pypsyc import parseUNL, UNL2Location, netLocation
from twisted.internet import reactor, defer
from pypsyc.net import PSYCClientConnector, PSYCActiveConnector
from pypsyc import dump_packet
class Center:
object_handlers = {}
remote_connections = {}
def msg(self, vars, mc, data):
raise NotImplementedError
def sendmsg(self, vars, mc, data, target = None):
raise NotImplementedError
def register_object(self, netname, object):
# multiple handlers are not possible
# we only want lower case netnames
self.object_handlers[netname.lower()] = object
def find_object(self, netname):
"""find a local object that corresponds to netname"""
# try "real/local" object"
# we only have lower case netnames
return self.object_handlers.get(netname.lower())
def find_remote(self, netname):
"""find a remote location where netname may be located"""
address = netLocation(netname)
if self.remote_connections.has_key(address):
return self.remote_connections[address]
return None
def register_remote(self, obj, where):
self.remote_connections[where] = obj
def unregister_remote(self, obj, where):
if self.remote_connections.get(where) == obj:
self.remote_connections.pop(where)
def connect(self, location):
raise NotImplementedError
def create_user(self, netname):
raise NotImplementedError
def create_place(self, netname):
raise NotImplementedError
class ClientCenter(Center):
# connection to the homeserver, default return for find_remote
default_connection = None
options = {}
def get_option(self, option):
return self.options.get(option)
def connect(self, location):
# already connected or connecting?
a = self.find_remote(location)
if a:
return a
a = PSYCClientConnector(self, location)
return a.get_queue()
def find_remote(self, netname):
"""clients will send most things via their homeserver
p2p connections are an exception to that, but they will be
created by user objects"""
return Center.find_remote(self, netname) or Center.find_remote(self, self.default_connection)
def msg(self, vars, mc, data):
if not mc:
#print "warning: minor bug in pypsyc: msg() without mc"
return
if self.get_option('debug'):
dump_packet(">>>", vars, mc, data)
source = vars.get('_context') or vars.get('_source')
if not source: return # ignore empty packets?
obj = self.find_object(source)
if obj:
obj.msg(vars, mc, data)
return
print 'unhandled packet from %s'%source
# do something about it... pop up a window, etc
u = parseUNL(source)
if u['resource'] and u['resource'].startswith('~'):
# create a user object
obj = self.create_user(source)
obj.msg(vars, mc, data)
elif u['resource'] and u['resource'].startswith('@'):
# create a place object
obj = self.create_place(source)
obj.msg(vars, mc, data)
else:
print 'no handler for %s object'%(source)
def sendmsg(self, vars, mc, data):
target = vars.get('_target')
if not target: return
obj = self.find_remote(target)
if obj:
obj.msg(vars, mc, data)
else:
raise
# this should not happen!
# TODO this does not belong here
import sha
class Authenticator:
def __init__(self, center, uni, password):
self.center = center
self.uni = uni
self.password = password
def startLink(self):
print 'start link'
self.sendmsg({'_target' : uni }, '_request_link', '')
def msg_query_password(self, vars, mc, data):
if vars['_nonce'] and self.center.get_option('auth_sha'):
digest = sha.sha(vars['_nonce'] + self.password).hexdigest()
self.center.sendmsg({ '_method' : 'sha1',
'_password' : digest },
'_set_password', '')
elif self.center.get_option('auth_plain'):
self.sendmsg({ '_password' : self.password },
'_set_password', '')
else:
print 'no authorization method available!'
return
class Client(ClientCenter):
default_uni = ''
nick = ''
online_callback = None
def __init__(self, config):
self.config = config
self.default_uni = config.get('main', 'uni')
u = parseUNL(self.default_uni)
self.nick = u['resource'][1:]
self.default_connection = netLocation(self.default_uni)
if self.config.has_section('library'):
for option in self.config.options('library'):
self.options[option] = self.config.getboolean('library', option)
def online(self):
self.connect(self.default_connection)
# experimental API using the cool Deferred's
self.online_callback = defer.Deferred()
return self.online_callback
def gotOnline(self):
if self.online_callback:
self.online_callback.callback(None)
print 'connected to host of default location'
def sendmsg(self, vars, mc, data):
if vars.get('_nick') == '':
vars['_nick'] = self.nick
# TODO: I am not sure, it this is correct
if vars.get('_source') == '':
vars['_source'] = self.default_uni
ClientCenter.sendmsg(self, vars, mc, data)
class ServerCenter(Center):
unl2uni = {}
remote_contexts = {}
def __init__(self, location):
self.location = location
def msg(self, vars, mc, data):
if not mc:
return # ignore empty packets
source = vars['_source']
# TODO: auth check 'global' or per-object
if vars.has_key('_identification'):
print 'Identification of %s is %s'%(source, vars['_identification'])
context = vars.get('_context')
if context and not self.is_local_object(context):
target = context
else:
target = vars['_target']
if self.unl2uni.has_key(source):
"""local client who is using us as a proxy"""
self.unl2uni[source].sendmsg(vars, mc, data)
elif target:
obj = self.find_object(target)
if obj:
return obj.msg(vars, mc, data)
# probably object has to be created
if self.is_local_object(target):
u = parseUNL(target)
if (u['resource'] and u['resource'].startswith('@')):
obj = self.create_place(target)
if obj:
return obj.msg(vars, mc, data)
else:
vars['_target'], vars['_source'] = vars['_source'], vars['_target']
self.sendmsg(vars, '_error_unknown_name_place',
'No such place: [_source]')
elif (u['resource'] and u['resource'].startswith('~')):
obj = self.create_user(target)
if obj:
return obj.msg(vars, mc, data)
else:
vars['_target'], vars['_source'] = vars['_source'], vars['_target']
self.sendmsg(vars, '_error_unknown_name_user',
'No such user: [_source]')
elif u['resource']:
vars['_target'] = source
vars['_source'] = target
self.sendmsg(vars, '_error_unknown_name',
'No such object: [_source]')
else: # rootmsg
pass
elif context is not None and self.remote_contexts.has_key(context):
self.remote_contexts[context].castmsg(vars, mc, data)
else: # nonlocal target
print 'rejected relay %s from %s to %s'%(mc, source, target)
return # skip it for now
self.sendmsg({ '_target' : source, '_source' : self.location,
'_destination' : target },
'_error_rejected_relay',
'You are not allowed to send messages to [_destination]')
else:
# no target???
print 'no target in packet???'
def sendmsg(self, vars, mc, data):
target = vars['_target']
if self.is_local_object(target):
self.msg(vars, mc, data)
else:
u = parseUNL(target)
target = (self.find_object(target) or
self.find_remote(target) or
self.find_remote(target))
if not target and u['scheme'] == 'psyc':
q = self.connect(u['root'])
q.msg(vars, mc, data)
elif target:
target.msg(vars, mc, data)
else:
raise 'can not find %s'%(target) # programming error?
def register_object(self, netname, object):
self.object_handlers[netname.lower()] = object
def link_unl(self, unl, uni):
self.unl2uni[unl] = uni
def unlink_unl(self, unl, uni):
if self.unl2uni.has_key(unl) and self.unl2uni[unl] == uni:
self.unl2uni.pop(unl)
def is_local_object(self, location):
return netLocation(location) == netLocation(self.location)
def connect(self, location):
a = PSYCActiveConnector(self, location, self.location)
self.remote_connections[location] = a.get_queue()
return a.get_queue()
def find_remote(self, netname):
address = netLocation(netname)
return self.remote_connections.get(address, None)
def join_context(self, context, obj):
if self.is_local_object(context):
print 'skipping join to local context'
if not self.remote_contexts.has_key(context):
self.remote_contexts[context] = self.create_context(context)
self.remote_contexts[context].join(obj)
def leave_context(self, context, obj):
if self.is_local_object(context):
print 'skipping part of local context'
if self.remote_contexts.has_key(context):
self.remote_contexts[context].leave(obj)
# TODO possibly clean_up that context
def create_context(self, netname):
"""this is how we create context slaves"""
raise NotImplementedError

View file

@ -0,0 +1,186 @@
"""network code for pyPSYC"""
from pypsyc import GLYPHS
from pypsyc.PSYC import PSYCProtocol
from pypsyc import parseUNL, UNL2Location
from twisted.names import client
from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory, ServerFactory
class HostChecker:
"""checks validity of _source/_context in a packet
this could well implement policies like trusted from localhost"""
def __init__(self, center, target, myname):
self.target = target
self.myname = myname
self.center = center
def check(self, vars, mc, data, protocol, peer):
source = vars.get('_context') or vars.get('_source')
if (source and not
source.startswith('psyc://%s'%(peer.host))):
u = parseUNL(source)
d = client.lookupAddress(u['host'])
d.addCallback(self.resolved, peer.host, vars, mc, data, protocol)
elif source:
# numeric address
self.handle(vars, mc, data, protocol)
else:
protocol.msg({ '_source' : self.myname },
'_error_syntax_protocol_missing_source',
'Your implementation is broken')
def handle(self, vars, mc, data, protocol):
method = getattr(self, 'recv%s'%mc, None)
if method is not None:
method(vars, mc, data, protocol)
else:
u = parseUNL(vars['_source'])
self.center.register_remote(protocol, u['root'])
self.center.msg(vars, mc, data)
def resolved(self, record, shouldbe, vars, mc, data, protocol):
v = { '_source' : self.myname,
'_target' : vars['_source'] }
if not record[0]:
print 'name not resolvable'
protocol.msg(v, '_error_rejected_relay',
'[_source] is not resolvable. Goodbye')
protocol.transport.loseConnection()
elif record[0][0].type == 5:
payload = record[0][0].payload
d = client.lookupAddress(payload.name.name)
d.addCallback(self.resolved, shouldbe, vars, mc, data, protocol)
else:
payload = record[0][0].payload
if payload.dottedQuad() == shouldbe:
self.handle(vars, mc, data, protocol)
else:
print 'rejected relay'
protocol.msg(v, '_error_rejected_relay',
'[_source] does not resolve to your ip.')
protocol.transport.loseConnection()
class PSYCConnector:
hostname = ''
port = 4404
factory = None
factory_type = None
real_hostname = ''
def __init__(self, center, target, myname = None):
# TODO: dont try to resolve IP addresses ;)
# must subclass
if not self.factory_type: raise NotImplementedError
try:
self.factory = self.factory_type(center, target, myname)
except:
print self.factory_type
raise
u = parseUNL(target)
self.host = u['host']
d = client.lookupService('_psyc._tcp.' + self.host)
d.addCallback(self.srvResolved)
def get_queue(self):
return self.factory
def resolved(self, record):
if not record[0]:
print 'resolution failed...'
else:
payload = record[0][0].payload
if record[0][0].type == 5: # evil cname
d = client.lookupAddress(payload.name.name)
d.addCallback(self.resolved)
else:
reactor.connectTCP(payload.dottedQuad(), self.port, self.factory)
return True
def srvResolved(self, record):
if not record[0]:
d = client.lookupAddress(self.host)
d.addCallback(self.resolved)
else:
payload = record[0][0].payload
self.port = payload.port
d = client.lookupAddress(payload.target.name)
d.addCallback(self.resolved)
return True
class PSYCClientFactory(ClientFactory):
"""a factory for a client which does not have to check
for validity of host names"""
class PSYCClient(PSYCProtocol):
def connectionMade(self):
PSYCProtocol.connectionMade(self)
self.factory.connectionMade(self)
protocol = PSYCClient
center = None
location = None
def __init__(self, center, location, myname):
self.center = center
self.location = location
def connectionMade(self, proto):
self.center.register_remote(proto, self.location)
self.center.gotOnline()
def packetReceived(self, vars, mc, data, protocol, peer):
self.center.msg(vars, mc, data)
class PSYCClientConnector(PSYCConnector):
factory_type = PSYCClientFactory
class PSYCActiveFactory(ClientFactory, HostChecker):
"""a factory for a client which does hostname checks
maybe this will also become a Q
probably we want to override connectionMade?"""
protocol = PSYCProtocol
queue = []
connected = None
def packetReceived(self, vars, mc, data, protocol, peer):
self.check(vars, mc, data, protocol, peer)
def msg(self, vars, mc, data):
# watch out, if we dont use dict-vars we may need deepcopy
if self.connected is not None:
self.connected.msg(vars, mc, data)
else:
self.queue.append((vars, mc, data))
def run_queue(self, target):
for (vars, mc, data) in self.queue:
target.msg(vars, mc, data)
self.queue = []
self.connected = target
def recv_notice_circuit_established(self, vars, mc, data, protocol):
print 'got _notice_circuit_established'
protocol.msg({'_source' : self.myname,
'_target' : self.target or vars['_source'] },
'_notice_circuit_established',
'hi there')
# TODO: what do we register here? source oder our definition of
# what the source should be (self.target)
self.center.register_remote(protocol, self.target)
self.run_queue(protocol)
class PSYCActiveConnector(PSYCConnector):
factory_type = PSYCActiveFactory
class PSYCServerFactory(ServerFactory, HostChecker):
"""funny question... do we deal all the stuff about
modules, compression, tls etc here?"""
class PSYCServerProtocol(PSYCProtocol):
def connectionMade(self):
peer = self.transport.getPeer()
PSYCProtocol.connectionMade(self)
self.msg({ '_source' : self.factory.myname,
'_target' : 'psyc://%s:-%d'%(peer.host, peer.port)},
'_notice_circuit_established',
'Connection to [_source] established')
protocol = PSYCServerProtocol
def packetReceived(self, vars, mc, data, protocol, peer):
self.check(vars, mc, data, protocol, peer)
def recv_notice_circuit_established(self, vars, mc, data, protocol):
self.center.register_remote(protocol, vars['_source'])

View file

@ -0,0 +1,49 @@
class PSYCReceiver:
def msg(self, vars, mc, data):
'called when a message is received'
# method inheritance
if mc.count('_') > 10:
# considered abusive
return
l = len(mc)
while l > 0:
method = getattr(self, 'msg%s'%(mc[:l]), None)
if method is not None:
# could this method return the next methodname
# to be called? freaky!
# actually, this a much more flexible fallthrough
# than switch/case provides.
# yet it is more expensive to evaluate
method(vars, mc, data)
break
l = mc.rfind('_', 0, l)
else:
self.msgUnknownMethod(vars, mc, data)
def msgUnknownMethod(self, vars, mc, data):
print 'unknown %s'%mc
class PSYCObject(PSYCReceiver):
"""generic PSYC object"""
def __init__(self, netname, center):
self.center = center
self.netname = netname.lower()
self.center.register_object(netname, self)
def url(self):
return self.netname
def str(self):
return self.netname
def sendmsg(self, vars, mc, data):
'called to send a message'
l = len(mc)
while l > 0:
method = getattr(self, 'sendmsg%s'%(mc[:l]), None)
if method is not None:
method(vars, mc, data)
break
l = mc.rfind('_', 0, l)
else:
self.center.sendmsg(vars, mc, data)
def castmsg(self, vars, mc, data):
'called to send a message to a group'

View file

@ -0,0 +1,14 @@
"""Client API for PSYC objects"""
class IPSYCClientObject:
def msg(self, vars, mc, data):
"""receive a message"""
def sendmsg(self, vars, mc, data):
"""send a message to a single person or a group manager
use this make requests to the other side that should not be
distributed in an unchangend fashion"""
def castmsg(self, vars, mc, data):
"""send a message that is destined to be delivered to a group
Note that you should use this for all communication with the
group, as it enables transparent distribution for both centralistic
and peer2peer scenarios"""

View file

@ -0,0 +1,319 @@
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)

54
fippos-twisted/test.py Normal file
View file

@ -0,0 +1,54 @@
#!/usr/bin/env python
from pypsyc import parseUNL, UNL2Location, netLocation
from pypsyc.objects.PSYCObject import PSYCQueueObject, PSYCObject, PSYCUNI, PSYCPlace, PSYCClient, ClientUser, ClientPlace, AdvancedManager, AdvancedPlace
from pypsyc.net import PSYCUDPSender
from pypsyc.center import ServerCenter, ClientCenter
import asyncore
if __name__ == '__main__':
import sys
type = sys.argv[1]
location = 'psyc://adamantine.aquarium'
center = None
if type == "server":
# tcp only server
center = ServerCenter([location + ':c'])
PSYCPlace(location + '/@place', center)
PSYCUNI(location + '/~fippo', center)
if type == "server2":
# tcp and udp server on non-standard port
center = ServerCenter([location + ':4405'])
center.connect(location)
if type == "udpserver":
center = ServerCenter([location + ':4405d'])
PSYCUNI(location + ':4405/~fool', center)
if type == "udpclient":
# this should better be done via a Center which can parse
# URLs and them handle according to their transport
# but for a quick udp sender this is okay...
q = PSYCUDPSender(location + ':4405d')
q.msg({'_target' : 'psyc://adamantine.aquarium:d/~fippo'},
{'_nick' : 'udpclient'},
'_message_private',
'hallo udp welt')
if type == "client":
center = ClientCenter()
PSYCObject('psyc://adamantine.aquarium', center)
# maybe add config information here?
# and let this thing connect as well?
me = PSYCClient('psyc://adamantine.aquarium/~fippo', center)
me.online()
# but thats the fast way to do it
me.sendmsg({'_target' : 'psyc://adamantine.aquarium/~fippo'},
{'_password' : 'xfippox'},
'_request_link',
'')
while center:
asyncore.poll(timeout=0.5)