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:
commit
0f02e9cd76
128 changed files with 9224 additions and 0 deletions
230
fippos-twisted/contrib/ircd.py
Normal file
230
fippos-twisted/contrib/ircd.py
Normal 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)
|
9
fippos-twisted/contrib/rss/README
Normal file
9
fippos-twisted/contrib/rss/README
Normal 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)
|
131
fippos-twisted/contrib/rss/rss_server.py
Normal file
131
fippos-twisted/contrib/rss/rss_server.py
Normal 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)
|
||||
|
28
fippos-twisted/contrib/whitepaper.py
Normal file
28
fippos-twisted/contrib/whitepaper.py
Normal 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)
|
Loading…
Add table
Add a link
Reference in a new issue