Implemented RSS feed reader along with updated rss2chan command.
This commit is contained in:
parent
c0417def6d
commit
97991a2238
8 changed files with 327 additions and 252 deletions
|
|
@ -68,7 +68,7 @@ class PlayerCmdSet(CmdSet):
|
|||
self.add(comms.CmdCdesc())
|
||||
self.add(comms.CmdPage())
|
||||
self.add(comms.CmdIRC2Chan())
|
||||
self.add(comms.CmdRSS2Chan())
|
||||
#self.add(comms.CmdIMC2Chan())
|
||||
#self.add(comms.CmdIMCInfo())
|
||||
#self.add(comms.CmdIMCTell())
|
||||
#self.add(comms.CmdRSS2Chan())
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ from src.commands.default.muxcommand import MuxCommand, MuxPlayerCommand
|
|||
__all__ = ("CmdAddCom", "CmdDelCom", "CmdAllCom",
|
||||
"CmdChannels", "CmdCdestroy", "CmdCBoot", "CmdCemit",
|
||||
"CmdCWho", "CmdChannelCreate", "CmdClock", "CmdCdesc",
|
||||
"CmdPage", "CmdIRC2Chan")#, "CmdIMC2Chan", "CmdIMCInfo",
|
||||
#"CmdIMCTell", "CmdRSS2Chan")
|
||||
"CmdPage", "CmdIRC2Chan", "CmdRSS2Chan")#, "CmdIMC2Chan", "CmdIMCInfo",
|
||||
#"CmdIMCTell")
|
||||
|
||||
|
||||
def find_channel(caller, channelname, silent=False, noaliases=False):
|
||||
|
|
@ -798,7 +798,7 @@ class CmdIRC2Chan(MuxCommand):
|
|||
|
||||
if 'list' in self.switches:
|
||||
# show all connections
|
||||
ircbots = [bot.typeclass for bot in PlayerDB.objects.filter(db_is_bot=True)]
|
||||
ircbots = [bot.typeclass for bot in PlayerDB.objects.filter(db_is_bot=True, username__startswith="ircbot-")]
|
||||
if ircbots:
|
||||
from src.utils.evtable import EvTable
|
||||
table = EvTable("{wdbid{n", "{wbotname{n", "{wev-channel{n", "{wirc-channel{n", border="cells", maxwidth=78)
|
||||
|
|
@ -849,7 +849,7 @@ class CmdIRC2Chan(MuxCommand):
|
|||
# re-use an existing bot
|
||||
bot = bot[0].typeclass
|
||||
if not bot.is_bot:
|
||||
self.msg("Player '%s', which is not a bot, already exists." % botname)
|
||||
self.msg("Player '%s' already exists and is not a bot." % botname)
|
||||
return
|
||||
else:
|
||||
bot = create.create_player(botname, None, None, typeclass=bots.IRCBot)
|
||||
|
|
@ -857,6 +857,101 @@ class CmdIRC2Chan(MuxCommand):
|
|||
irc_network=irc_network, irc_port=irc_port)
|
||||
self.msg("Connection created. Starting IRC bot.")
|
||||
|
||||
# RSS connection
|
||||
class CmdRSS2Chan(MuxCommand):
|
||||
"""
|
||||
link an evennia channel to an external RSS feed
|
||||
|
||||
Usage:
|
||||
@rss2chan[/switches] <evennia_channel> = <rss_url>
|
||||
|
||||
Switches:
|
||||
/disconnect - this will stop the feed and remove the connection to the
|
||||
channel.
|
||||
/remove - "
|
||||
/list - show all rss->evennia mappings
|
||||
|
||||
Example:
|
||||
@rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic
|
||||
|
||||
This creates an RSS reader that connects to a given RSS feed url. Updates
|
||||
will be echoed as a title and news link to the given channel. The rate of
|
||||
updating is set with the RSS_UPDATE_INTERVAL variable in settings (default
|
||||
is every 10 minutes).
|
||||
|
||||
When disconnecting you need to supply both the channel and url again so as
|
||||
to identify the connection uniquely.
|
||||
"""
|
||||
|
||||
key = "@rss2chan"
|
||||
locks = "cmd:serversetting(RSS_ENABLED) and pperm(Immortals)"
|
||||
help_category = "Comms"
|
||||
|
||||
def func(self):
|
||||
"Setup the rss-channel mapping"
|
||||
|
||||
# checking we have all we need
|
||||
if not settings.RSS_ENABLED:
|
||||
string = """RSS is not enabled. You need to activate it in game/settings.py."""
|
||||
self.msg(string)
|
||||
return
|
||||
try:
|
||||
import feedparser
|
||||
feedparser # to avoid checker error of not being used
|
||||
except ImportError:
|
||||
string = ("RSS requires python-feedparser (https://pypi.python.org/pypi/feedparser). "
|
||||
"Install before continuing.")
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
if 'list' in self.switches:
|
||||
# show all connections
|
||||
rssbots = [bot.typeclass for bot in PlayerDB.objects.filter(db_is_bot=True, username__startswith="rssbot-")]
|
||||
if rssbots:
|
||||
from src.utils.evtable import EvTable
|
||||
table = EvTable("{wdbid{n", "{wupdate rate{n", "{wev-channel", "{wRSS feed URL{n", border="cells", maxwidth=78)
|
||||
for rssbot in rssbots:
|
||||
table.add_row(rssbot.id, rssbot.db.rss_rate, rssbot.db.ev_channel, rssbot.db.rss_url)
|
||||
self.caller.msg(table)
|
||||
else:
|
||||
self.msg("No rss bots found.")
|
||||
return
|
||||
|
||||
if('disconnect' in self.switches or 'remove' in self.switches or
|
||||
'delete' in self.switches):
|
||||
botname = "rssbot-%s" % self.lhs
|
||||
matches = PlayerDB.objects.filter(db_is_bot=True, db_key=botname)
|
||||
if not matches:
|
||||
# try dbref match
|
||||
matches = PlayerDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#"))
|
||||
if matches:
|
||||
matches[0].delete()
|
||||
self.msg("RSS connection destroyed.")
|
||||
else:
|
||||
self.msg("RSS connection/bot could not be removed, does it exist?")
|
||||
return
|
||||
|
||||
if not self.args or not self.rhs:
|
||||
string = "Usage: @rss2chan[/switches] <evennia_channel> = <rss url>"
|
||||
self.msg(string)
|
||||
return
|
||||
channel = self.lhs
|
||||
url = self.rhs
|
||||
|
||||
botname = "rssbot-%s" % url
|
||||
# create a new bot
|
||||
bot = PlayerDB.objects.filter(username__iexact=botname)
|
||||
if bot:
|
||||
# re-use existing bot
|
||||
bot = bot[0].typeclass
|
||||
if not bot.is_bot:
|
||||
self.msg("Player '%s' already exists and is not a bot." % botname)
|
||||
return
|
||||
else:
|
||||
bot = create.create_player(botname, None, None, typeclass=bots.RSSBot)
|
||||
bot.start(ev_channel=channel, rss_url=url, rss_rate=10)
|
||||
self.msg("RSS reporter created. Fetching RSS.")
|
||||
|
||||
|
||||
#class CmdIMC2Chan(MuxCommand):
|
||||
# """
|
||||
|
|
@ -1077,85 +1172,3 @@ class CmdIRC2Chan(MuxCommand):
|
|||
# self.msg("You paged {c%s@%s{n (over IMC): '%s'." % (target, destination, message))
|
||||
#
|
||||
#
|
||||
## RSS connection
|
||||
#class CmdRSS2Chan(MuxCommand):
|
||||
# """
|
||||
# link an evennia channel to an external RSS feed
|
||||
#
|
||||
# Usage:
|
||||
# @rss2chan[/switches] <evennia_channel> = <rss_url>
|
||||
#
|
||||
# Switches:
|
||||
# /disconnect - this will stop the feed and remove the connection to the
|
||||
# channel.
|
||||
# /remove - "
|
||||
# /list - show all rss->evennia mappings
|
||||
#
|
||||
# Example:
|
||||
# @rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic
|
||||
#
|
||||
# This creates an RSS reader that connects to a given RSS feed url. Updates
|
||||
# will be echoed as a title and news link to the given channel. The rate of
|
||||
# updating is set with the RSS_UPDATE_INTERVAL variable in settings (default
|
||||
# is every 10 minutes).
|
||||
#
|
||||
# When disconnecting you need to supply both the channel and url again so as
|
||||
# to identify the connection uniquely.
|
||||
# """
|
||||
#
|
||||
# key = "@rss2chan"
|
||||
# locks = "cmd:serversetting(RSS_ENABLED) and pperm(Immortals)"
|
||||
# help_category = "Comms"
|
||||
#
|
||||
# def func(self):
|
||||
# "Setup the rss-channel mapping"
|
||||
#
|
||||
# if not settings.RSS_ENABLED:
|
||||
# string = """RSS is not enabled. You need to activate it in game/settings.py."""
|
||||
# self.msg(string)
|
||||
# return
|
||||
#
|
||||
# if 'list' in self.switches:
|
||||
# # show all connections
|
||||
# connections = ExternalChannelConnection.objects.filter(db_external_key__startswith='rss_')
|
||||
# if connections:
|
||||
# table = prettytable.PrettyTable(["Evennia channel", "RSS url"])
|
||||
# for conn in connections:
|
||||
# table.add_row([conn.channel.key, conn.external_config.split('|')[0]])
|
||||
# string = "{wConnections to RSS:{n\n%s" % table
|
||||
# self.msg(string)
|
||||
# else:
|
||||
# self.msg("No connections found.")
|
||||
# return
|
||||
#
|
||||
# if not self.args or not self.rhs:
|
||||
# string = "Usage: @rss2chan[/switches] <evennia_channel> = <rss url>"
|
||||
# self.msg(string)
|
||||
# return
|
||||
# channel = self.lhs
|
||||
# url = self.rhs
|
||||
#
|
||||
# if('disconnect' in self.switches or 'remove' in self.switches or
|
||||
# 'delete' in self.switches):
|
||||
# chanmatch = find_channel(self.caller, channel, silent=True)
|
||||
# if chanmatch:
|
||||
# channel = chanmatch.key
|
||||
#
|
||||
# ok = rss.delete_connection(channel, url)
|
||||
# if not ok:
|
||||
# self.msg("RSS connection/reader could not be removed, does it exist?")
|
||||
# else:
|
||||
# self.msg("RSS connection destroyed.")
|
||||
# return
|
||||
#
|
||||
# channel = find_channel(self.caller, channel)
|
||||
# if not channel:
|
||||
# return
|
||||
# interval = settings.RSS_UPDATE_INTERVAL
|
||||
# if not interval:
|
||||
# interval = 10*60
|
||||
# ok = rss.create_connection(channel, url, interval)
|
||||
# if not ok:
|
||||
# self.msg("This RSS connection already exists.")
|
||||
# return
|
||||
# self.msg("Connection created. Starting RSS reader.")
|
||||
|
|
|
|||
|
|
@ -59,10 +59,10 @@ class BotStarter(Script):
|
|||
|
||||
class CmdBotListen(Command):
|
||||
"""
|
||||
This is a catch-all command that absorbs
|
||||
all input coming into the bot through its
|
||||
session and pipes it into its execute_cmd
|
||||
method.
|
||||
This is a command that absorbs input
|
||||
aimed specifically at the bot. The session
|
||||
must prepend its data with bot_data_in for
|
||||
this to trigger.
|
||||
"""
|
||||
key = "bot_data_in"
|
||||
def func(self):
|
||||
|
|
@ -199,7 +199,7 @@ class RSSBot(Bot):
|
|||
An RSS relayer. The RSS protocol itself runs a ticker to update its feed at regular
|
||||
intervals.
|
||||
"""
|
||||
def start(self, ev_channel=None, rss_url=None, rss_update_rate=None):
|
||||
def start(self, ev_channel=None, rss_url=None, rss_rate=None):
|
||||
"""
|
||||
Start by telling the portal to start a new RSS session
|
||||
|
||||
|
|
@ -220,19 +220,20 @@ class RSSBot(Bot):
|
|||
self.db.ev_channel = channel
|
||||
if rss_url:
|
||||
self.db.rss_url = rss_url
|
||||
if rss_update_rate:
|
||||
self.db.rss_update_rate = rss_update_rate
|
||||
if rss_rate:
|
||||
self.db.rss_rate = rss_rate
|
||||
# instruct the server and portal to create a new session with
|
||||
# the stored configuration
|
||||
configdict = {"uid": self.dbid,
|
||||
"url": self.db.rss_url,
|
||||
"rate": self.db.rss_update_rate}
|
||||
"rate": self.db.rss_rate}
|
||||
_SESSIONS.start_bot_session("src.server.portal.rss.RSSBotFactory", configdict)
|
||||
|
||||
def execute_cmd(self, text=None, sessid=None):
|
||||
"""
|
||||
Echo RSS input to connected channel
|
||||
"""
|
||||
print "execute_cmd rss:", text
|
||||
if not self.ndb.ev_channel and self.db.ev_channel:
|
||||
# cache channel lookup
|
||||
self.ndb.ev_channel = self.db.ev_channel
|
||||
|
|
|
|||
|
|
@ -36,9 +36,10 @@ class IRCBot(irc.IRCClient, Session):
|
|||
self.join(self.channel)
|
||||
self.stopping = False
|
||||
self.factory.bot = self
|
||||
self.init_session("ircbot", self.network, self.factory.sessionhandler)
|
||||
address = "%s@%s" % (self.channel, self.network)
|
||||
self.init_session("ircbot", address, self.factory.sessionhandler)
|
||||
# we link back to our bot and log in
|
||||
self.uid = self.factory.uid
|
||||
self.uid = int(self.factory.uid)
|
||||
self.logged_in = True
|
||||
self.factory.sessionhandler.connect(self)
|
||||
logger.log_infomsg("IRC bot '%s' connected to %s at %s:%s." % (self.nickname, self.channel,
|
||||
|
|
@ -86,13 +87,14 @@ class IRCBotFactory(protocol.ReconnectingClientFactory):
|
|||
factor = 1.5
|
||||
maxDelay = 60
|
||||
|
||||
def __init__(self, uid=None, botname=None, channel=None, network=None, port=None):
|
||||
def __init__(self, sessionhandler, uid=None, botname=None, channel=None, network=None, port=None):
|
||||
"Storing some important protocol properties"
|
||||
self.uid = int(uid)
|
||||
self.sessionhandler = sessionhandler
|
||||
self.uid = uid
|
||||
self.nickname = str(botname)
|
||||
self.channel = str(channel)
|
||||
self.network = str(network)
|
||||
self.port = int(port)
|
||||
self.port = port
|
||||
self.bot = None
|
||||
|
||||
def buildProtocol(self, addr):
|
||||
|
|
@ -118,8 +120,9 @@ class IRCBotFactory(protocol.ReconnectingClientFactory):
|
|||
|
||||
def start(self):
|
||||
"Connect session to sessionhandler"
|
||||
service = internet.TCPClient(self.network, self.port, self)
|
||||
self.sessionhandler.portal.services.addService(service)
|
||||
if self.port:
|
||||
service = internet.TCPClient(self.network, int(self.port), self)
|
||||
self.sessionhandler.portal.services.addService(service)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -92,8 +92,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
cls = _MOD_IMPORT(path, clsname)
|
||||
if not cls:
|
||||
raise RuntimeError("ServerConnect: protocol factory '%s' not found." % protocol_path)
|
||||
protocol = cls(**config)
|
||||
protocol.sessionhandler = self
|
||||
protocol = cls(self, **config)
|
||||
protocol.start()
|
||||
|
||||
def server_disconnect(self, sessid, reason=""):
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ to the channel whenever the feed updates.
|
|||
"""
|
||||
|
||||
import re
|
||||
from twisted.internet import task
|
||||
from twisted.internet import task, threads
|
||||
from django.conf import settings
|
||||
from src.comms.models import ExternalChannelConnection, ChannelDB
|
||||
from src.server.session import Session
|
||||
from src.utils import logger, utils
|
||||
from src.scripts.models import ScriptDB
|
||||
|
||||
RSS_ENABLED = settings.RSS_ENABLED
|
||||
RSS_UPDATE_INTERVAL = settings.RSS_UPDATE_INTERVAL
|
||||
|
|
@ -21,17 +21,6 @@ RETAG = re.compile(r'<[^>]*?>')
|
|||
# holds rss readers they can be shut down at will.
|
||||
RSS_READERS = {}
|
||||
|
||||
|
||||
def msg_info(message):
|
||||
"""
|
||||
Send info to default info channel
|
||||
"""
|
||||
message = '[%s][RSS]: %s' % (INFOCHANNEL[0].key, message)
|
||||
try:
|
||||
INFOCHANNEL[0].msg(message)
|
||||
except AttributeError:
|
||||
logger.log_infomsg("MUDinfo (rss): %s" % message)
|
||||
|
||||
if RSS_ENABLED:
|
||||
try:
|
||||
import feedparser
|
||||
|
|
@ -39,129 +28,208 @@ if RSS_ENABLED:
|
|||
raise ImportError("RSS requires python-feedparser to be installed. Install or set RSS_ENABLED=False.")
|
||||
|
||||
|
||||
class RSSReader(object):
|
||||
class RSSReader(Session):
|
||||
"""
|
||||
Reader script used to connect to each individual RSS feed
|
||||
A simple RSS reader using universal feedparser
|
||||
"""
|
||||
def __init__(self, key, url, interval):
|
||||
"""
|
||||
The reader needs an rss url and It also needs an interval
|
||||
for how often it is to check for new updates (defaults
|
||||
to 10 minutes)
|
||||
"""
|
||||
self.key = key
|
||||
def __init__(self, factory, url, rate):
|
||||
self.url = url
|
||||
self.interval = interval
|
||||
self.entries = {} # stored feeds
|
||||
self.task = None
|
||||
# first we do is to load the feed so we don't resend
|
||||
# old entries whenever the reader starts.
|
||||
self.update_feed()
|
||||
# start runner
|
||||
self.start()
|
||||
self.rate = rate
|
||||
self.factory = factory
|
||||
self.old_entries = {}
|
||||
|
||||
def update_feed(self):
|
||||
"Read the url for new updated data and determine what's new."
|
||||
def get_new(self):
|
||||
"""Returns list of new items."""
|
||||
feed = feedparser.parse(self.url)
|
||||
new = []
|
||||
for entry in (e for e in feed['entries'] if e['id'] not in self.entries):
|
||||
txt = "[RSS] %s: %s" % (RETAG.sub("", entry['title']),
|
||||
entry['link'].replace('\n','').encode('utf-8'))
|
||||
self.entries[entry['id']] = txt
|
||||
new.append(txt)
|
||||
return new
|
||||
new_entries = []
|
||||
for entry in feed['entries']:
|
||||
idval = entry['id'] + entry.get("updated", "")
|
||||
if idval not in self.old_entries:
|
||||
self.old_entries[idval] = entry
|
||||
new_entries.append(entry)
|
||||
return new_entries
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Called every self.interval seconds - tries to get new feed entries,
|
||||
and if so, uses the appropriate ExternalChannelConnection to send the
|
||||
data to subscribing channels.
|
||||
"""
|
||||
new = self.update_feed()
|
||||
if not new:
|
||||
return
|
||||
conns = ExternalChannelConnection.objects.filter(db_external_key=self.key)
|
||||
for conn in (conn for conn in conns if conn.channel):
|
||||
for txt in new:
|
||||
conn.to_channel("%s:%s" % (conn.channel.key, txt))
|
||||
def disconnect(self, reason=None):
|
||||
"Disconnect from feed"
|
||||
if self.factory.task and self.factory.task.running:
|
||||
self.factory.task.stop()
|
||||
self.sessionhandler.disconnect(self)
|
||||
|
||||
def _callback(self, new_entries, init):
|
||||
"Called when RSS returns (threaded)"
|
||||
if not init:
|
||||
# for initialization we just ignore old entries
|
||||
for entry in reversed(new_entries):
|
||||
self.data_in("bot_data_in " + entry)
|
||||
|
||||
def data_in(self, text=None, **kwargs):
|
||||
"Data RSS -> Server"
|
||||
self.sessionhandler.data_in(self, text=text, **kwargs)
|
||||
|
||||
def _errback(self, fail):
|
||||
"Report error"
|
||||
print "RSS feed error: %s" % fail.value
|
||||
|
||||
def update(self, init=False):
|
||||
"Request feed"
|
||||
return threads.deferToThread(self.get_new).addCallback(self._callback, init).addErrback(self._errback)
|
||||
|
||||
class RSSBotFactory(object):
|
||||
"""
|
||||
Initializes new bots
|
||||
"""
|
||||
|
||||
def __init__(self, sessionhandler, uid=None, url=None, rate=None):
|
||||
"Initialize"
|
||||
self.sessionhandler = sessionhandler
|
||||
self.url = url
|
||||
self.rate = rate
|
||||
self.uid = uid
|
||||
self.bot = RSSReader(self, url, rate)
|
||||
self.task = None
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starting the update task and store a reference in the
|
||||
global variable so it can be found and shut down later.
|
||||
Called by portalsessionhandler
|
||||
"""
|
||||
global RSS_READERS
|
||||
self.task = task.LoopingCall(self.update)
|
||||
self.task.start(self.interval, now=False)
|
||||
RSS_READERS[self.key] = self
|
||||
def errback(fail):
|
||||
print fail.value
|
||||
|
||||
# set up session and connect it to sessionhandler
|
||||
self.bot.init_session("rssbot", self.url, self.sessionhandler)
|
||||
self.bot.uid = self.uid
|
||||
self.bot.logged_in = True
|
||||
self.sessionhandler.connect(self.bot)
|
||||
# start repeater task
|
||||
#self.bot.update(init=True)
|
||||
self.bot.update(init=True)
|
||||
self.task = task.LoopingCall(self.bot.update)
|
||||
if self.rate:
|
||||
self.task.start(self.rate, now=False).addErrback(errback)
|
||||
|
||||
def build_connection_key(channel, url):
|
||||
"This is used to id the connection"
|
||||
if hasattr(channel, 'key'):
|
||||
channel = channel.key
|
||||
return "rss_%s>%s" % (url, channel)
|
||||
|
||||
|
||||
def create_connection(channel, url, interval):
|
||||
"""
|
||||
This will create a new RSS->channel connection
|
||||
"""
|
||||
if not type(channel) == ChannelDB:
|
||||
new_channel = ChannelDB.objects.filter(db_key=channel)
|
||||
if not new_channel:
|
||||
logger.log_errmsg("Cannot attach RSS->Evennia: Evennia Channel '%s' not found." % channel)
|
||||
return False
|
||||
channel = new_channel[0]
|
||||
key = build_connection_key(channel, url)
|
||||
old_conns = ExternalChannelConnection.objects.filter(db_external_key=key)
|
||||
if old_conns:
|
||||
return False
|
||||
config = "%s|%i" % (url, interval)
|
||||
# There is no sendback from evennia to the rss, so we need not define
|
||||
# any sendback code.
|
||||
conn = ExternalChannelConnection(db_channel=channel,
|
||||
db_external_key=key,
|
||||
db_external_config=config)
|
||||
conn.save()
|
||||
|
||||
connect_to_rss(conn)
|
||||
return True
|
||||
|
||||
|
||||
def delete_connection(channel, url):
|
||||
"""
|
||||
Delete rss connection between channel and url
|
||||
"""
|
||||
key = build_connection_key(channel, url)
|
||||
try:
|
||||
conn = ExternalChannelConnection.objects.get(db_external_key=key)
|
||||
except Exception:
|
||||
return False
|
||||
conn.delete()
|
||||
reader = RSS_READERS.get(key, None)
|
||||
if reader and reader.task:
|
||||
reader.task.stop()
|
||||
return True
|
||||
|
||||
|
||||
def connect_to_rss(connection):
|
||||
"""
|
||||
Create the parser instance and connect to RSS feed and channel
|
||||
"""
|
||||
global RSS_READERS
|
||||
key = utils.to_str(connection.external_key)
|
||||
url, interval = [utils.to_str(conf) for conf in connection.external_config.split('|')]
|
||||
# Create reader (this starts the running task and stores a reference in RSS_TASKS)
|
||||
RSSReader(key, url, int(interval))
|
||||
|
||||
|
||||
def connect_all():
|
||||
"""
|
||||
Activate all rss feed parsers
|
||||
"""
|
||||
if not RSS_ENABLED:
|
||||
return
|
||||
for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith="rss_"):
|
||||
print "connecting RSS: %s" % connection
|
||||
connect_to_rss(connection)
|
||||
#class RSSReader(object):
|
||||
# """
|
||||
# Reader script used to connect to each individual RSS feed
|
||||
# """
|
||||
# def __init__(self, key, url, interval):
|
||||
# """
|
||||
# The reader needs an rss url and It also needs an interval
|
||||
# for how often it is to check for new updates (defaults
|
||||
# to 10 minutes)
|
||||
# """
|
||||
# self.key = key
|
||||
# self.url = url
|
||||
# self.interval = interval
|
||||
# self.entries = {} # stored feeds
|
||||
# self.task = None
|
||||
# # first we do is to load the feed so we don't resend
|
||||
# # old entries whenever the reader starts.
|
||||
# self.update_feed()
|
||||
# # start runner
|
||||
# self.start()
|
||||
#
|
||||
# def update_feed(self):
|
||||
# "Read the url for new updated data and determine what's new."
|
||||
# feed = feedparser.parse(self.url)
|
||||
# new = []
|
||||
# for entry in (e for e in feed['entries'] if e['id'] not in self.entries):
|
||||
# txt = "[RSS] %s: %s" % (RETAG.sub("", entry['title']),
|
||||
# entry['link'].replace('\n','').encode('utf-8'))
|
||||
# self.entries[entry['id']] = txt
|
||||
# new.append(txt)
|
||||
# return new
|
||||
#
|
||||
# def update(self):
|
||||
# """
|
||||
# Called every self.interval seconds - tries to get new feed entries,
|
||||
# and if so, uses the appropriate ExternalChannelConnection to send the
|
||||
# data to subscribing channels.
|
||||
# """
|
||||
# new = self.update_feed()
|
||||
# if not new:
|
||||
# return
|
||||
# conns = ExternalChannelConnection.objects.filter(db_external_key=self.key)
|
||||
# for conn in (conn for conn in conns if conn.channel):
|
||||
# for txt in new:
|
||||
# conn.to_channel("%s:%s" % (conn.channel.key, txt))
|
||||
#
|
||||
# def start(self):
|
||||
# """
|
||||
# Starting the update task and store a reference in the
|
||||
# global variable so it can be found and shut down later.
|
||||
# """
|
||||
# global RSS_READERS
|
||||
# self.task = task.LoopingCall(self.update)
|
||||
# self.task.start(self.interval, now=False)
|
||||
# RSS_READERS[self.key] = self
|
||||
#
|
||||
#
|
||||
#def build_connection_key(channel, url):
|
||||
# "This is used to id the connection"
|
||||
# if hasattr(channel, 'key'):
|
||||
# channel = channel.key
|
||||
# return "rss_%s>%s" % (url, channel)
|
||||
#
|
||||
#
|
||||
#def create_connection(channel, url, interval):
|
||||
# """
|
||||
# This will create a new RSS->channel connection
|
||||
# """
|
||||
# if not type(channel) == ChannelDB:
|
||||
# new_channel = ChannelDB.objects.filter(db_key=channel)
|
||||
# if not new_channel:
|
||||
# logger.log_errmsg("Cannot attach RSS->Evennia: Evennia Channel '%s' not found." % channel)
|
||||
# return False
|
||||
# channel = new_channel[0]
|
||||
# key = build_connection_key(channel, url)
|
||||
# old_conns = ExternalChannelConnection.objects.filter(db_external_key=key)
|
||||
# if old_conns:
|
||||
# return False
|
||||
# config = "%s|%i" % (url, interval)
|
||||
# # There is no sendback from evennia to the rss, so we need not define
|
||||
# # any sendback code.
|
||||
# conn = ExternalChannelConnection(db_channel=channel,
|
||||
# db_external_key=key,
|
||||
# db_external_config=config)
|
||||
# conn.save()
|
||||
#
|
||||
# connect_to_rss(conn)
|
||||
# return True
|
||||
#
|
||||
#
|
||||
#def delete_connection(channel, url):
|
||||
# """
|
||||
# Delete rss connection between channel and url
|
||||
# """
|
||||
# key = build_connection_key(channel, url)
|
||||
# try:
|
||||
# conn = ExternalChannelConnection.objects.get(db_external_key=key)
|
||||
# except Exception:
|
||||
# return False
|
||||
# conn.delete()
|
||||
# reader = RSS_READERS.get(key, None)
|
||||
# if reader and reader.task:
|
||||
# reader.task.stop()
|
||||
# return True
|
||||
#
|
||||
#
|
||||
#def connect_to_rss(connection):
|
||||
# """
|
||||
# Create the parser instance and connect to RSS feed and channel
|
||||
# """
|
||||
# global RSS_READERS
|
||||
# key = utils.to_str(connection.external_key)
|
||||
# url, interval = [utils.to_str(conf) for conf in connection.external_config.split('|')]
|
||||
# # Create reader (this starts the running task and stores a reference in RSS_TASKS)
|
||||
# RSSReader(key, url, int(interval))
|
||||
#
|
||||
#
|
||||
#def connect_all():
|
||||
# """
|
||||
# Activate all rss feed parsers
|
||||
# """
|
||||
# if not RSS_ENABLED:
|
||||
# return
|
||||
# for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith="rss_"):
|
||||
# print "connecting RSS: %s" % connection
|
||||
# connect_to_rss(connection)
|
||||
|
|
|
|||
|
|
@ -423,32 +423,21 @@ if WEBSERVER_ENABLED:
|
|||
|
||||
print " webserver: %s" % serverport
|
||||
|
||||
ENABLED = []
|
||||
if IRC_ENABLED:
|
||||
|
||||
# IRC channel connections
|
||||
|
||||
print ' irc enabled'
|
||||
|
||||
from src.comms import irc
|
||||
irc.connect_all()
|
||||
ENABLED.append('irc')
|
||||
|
||||
if IMC2_ENABLED:
|
||||
|
||||
# IMC2 channel connections
|
||||
|
||||
print ' imc2 enabled'
|
||||
|
||||
from src.comms import imc2
|
||||
imc2.connect_all()
|
||||
ENABLED.append('imc2')
|
||||
|
||||
if RSS_ENABLED:
|
||||
|
||||
# RSS feed channel connections
|
||||
ENABLED.append('rss')
|
||||
|
||||
print ' rss enabled'
|
||||
|
||||
from src.comms import rss
|
||||
rss.connect_all()
|
||||
if ENABLED:
|
||||
print " " + ", ".join(ENABLED) + " enabled."
|
||||
|
||||
for plugin_module in SERVER_SERVICES_PLUGIN_MODULES:
|
||||
# external plugin protocols
|
||||
|
|
|
|||
|
|
@ -236,14 +236,14 @@ class AttributeHandler(object):
|
|||
|
||||
def get(self, key=None, category=None, default=None, return_obj=False,
|
||||
strattr=False, raise_exception=False, accessing_obj=None,
|
||||
default_access=True):
|
||||
default_access=True, not_found_none=False):
|
||||
"""
|
||||
Returns the value of the given Attribute or list of Attributes.
|
||||
strattr will cause the string-only value field instead of the normal
|
||||
pickled field data. Use to get back values from Attributes added with
|
||||
the strattr keyword.
|
||||
If return_obj=True, return the matching Attribute object
|
||||
instead. Returns None if no matches (or [ ] if key was a list
|
||||
instead. Returns default if no matches (or [ ] if key was a list
|
||||
with no matches). If raise_exception=True, failure to find a
|
||||
match will raise AttributeError instead.
|
||||
|
||||
|
|
@ -278,6 +278,8 @@ class AttributeHandler(object):
|
|||
ret = ret if return_obj else [attr.strvalue for attr in ret if attr]
|
||||
else:
|
||||
ret = ret if return_obj else [attr.value for attr in ret if attr]
|
||||
if not ret:
|
||||
return ret if len(key) > 1 else default
|
||||
return ret[0] if len(ret)==1 else ret
|
||||
|
||||
def add(self, key, value, category=None, lockstring="",
|
||||
|
|
@ -399,10 +401,10 @@ class NickHandler(AttributeHandler):
|
|||
raw_string
|
||||
obj_nicks, player_nicks = [], []
|
||||
for category in make_iter(categories):
|
||||
obj_nicks.extend(make_iter(self.get(category=category, return_obj=True)))
|
||||
obj_nicks.extend([n for n in make_iter(self.get(category=category, return_obj=True)) if n])
|
||||
if include_player and self.obj.has_player:
|
||||
for category in make_iter(categories):
|
||||
player_nicks.extend(make_iter(self.obj.player.nicks.get(category=category, return_obj=True)))
|
||||
player_nicks.extend([n for n in make_iter(self.obj.player.nicks.get(category=category, return_obj=True)) if n])
|
||||
for nick in obj_nicks + player_nicks:
|
||||
# make a case-insensitive match here
|
||||
match = re.match(re.escape(nick.db_key), raw_string, re.IGNORECASE)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue