Make grapevine connect and work

This commit is contained in:
Griatch 2019-06-23 18:59:45 +02:00
parent 59bc475708
commit 8a6ec779da
8 changed files with 102 additions and 71 deletions

View file

@ -15,7 +15,7 @@ _IDLE_TIMEOUT = settings.IDLE_TIMEOUT
_IRC_ENABLED = settings.IRC_ENABLED _IRC_ENABLED = settings.IRC_ENABLED
_RSS_ENABLED = settings.RSS_ENABLED _RSS_ENABLED = settings.RSS_ENABLED
_GRAPEWINE_ENABLED = settings.GRAPEWINE_ENABLED _GRAPEVINE_ENABLED = settings.GRAPEVINE_ENABLED
_SESSIONS = None _SESSIONS = None
@ -270,10 +270,13 @@ class IRCBot(Bot):
""" """
from_obj = kwargs.get("from_obj", None) from_obj = kwargs.get("from_obj", None)
options = kwargs.get("options", None) or {} options = kwargs.get("options", None) or {}
if not self.ndb.ev_channel and self.db.ev_channel: if not self.ndb.ev_channel and self.db.ev_channel:
# cache channel lookup # cache channel lookup
self.ndb.ev_channel = self.db.ev_channel self.ndb.ev_channel = self.db.ev_channel
if "from_channel" in options and text and self.ndb.ev_channel.dbid == options["from_channel"]:
if ("from_channel" in options and text and
self.ndb.ev_channel.dbid == options["from_channel"]):
if not from_obj or from_obj != [self]: if not from_obj or from_obj != [self]:
super().msg(channel=text) super().msg(channel=text)
@ -289,13 +292,16 @@ class IRCBot(Bot):
Kwargs: Kwargs:
user (str): The name of the user who sent the message. user (str): The name of the user who sent the message.
channel (str): The name of channel the message was sent to. channel (str): The name of channel the message was sent to.
type (str): Nature of message. Either 'msg', 'action', 'nicklist' or 'ping'. type (str): Nature of message. Either 'msg', 'action', 'nicklist'
nicklist (list, optional): Set if `type='nicklist'`. This is a list of nicks returned by calling or 'ping'.
the `self.get_nicklist`. It must look for a list `self._nicklist_callers` nicklist (list, optional): Set if `type='nicklist'`. This is a list
which will contain all callers waiting for the nicklist. of nicks returned by calling the `self.get_nicklist`. It must look
timings (float, optional): Set if `type='ping'`. This is the return (in seconds) of a for a list `self._nicklist_callers` which will contain all callers
ping request triggered with `self.ping`. The return must look for a list waiting for the nicklist.
`self._ping_callers` which will contain all callers waiting for the ping return. timings (float, optional): Set if `type='ping'`. This is the return
(in seconds) of a ping request triggered with `self.ping`. The
return must look for a list `self._ping_callers` which will contain
all callers waiting for the ping return.
""" """
if kwargs["type"] == "nicklist": if kwargs["type"] == "nicklist":
@ -354,6 +360,7 @@ class IRCBot(Bot):
if not self.ndb.ev_channel and self.db.ev_channel: if not self.ndb.ev_channel and self.db.ev_channel:
# cache channel lookup # cache channel lookup
self.ndb.ev_channel = self.db.ev_channel self.ndb.ev_channel = self.db.ev_channel
if self.ndb.ev_channel: if self.ndb.ev_channel:
self.ndb.ev_channel.msg(text, senders=self) self.ndb.ev_channel.msg(text, senders=self)
@ -428,22 +435,22 @@ class RSSBot(Bot):
self.ndb.ev_channel.msg(txt, senders=self.id) self.ndb.ev_channel.msg(txt, senders=self.id)
# Grapewine bot # Grapevine bot
class GrapewineBot(Bot): class GrapevineBot(Bot):
""" """
A Grapewine (https://grapewine.haus) relayer. The channel to connect to is the first g Grapevine (https://grapevine.haus) relayer. The channel to connect to is the first
name in the settings.GRAPEWINE_CHANNELS list. name in the settings.GRAPEVINE_CHANNELS list.
""" """
factory_path = "evennia.server.portal.grapewine.RestartingWebsocketServerFactory" factory_path = "evennia.server.portal.grapevine.RestartingWebsocketServerFactory"
def start(self, ev_channel=None, grapewine_channel=None): def start(self, ev_channel=None, grapevine_channel=None):
""" """
Start by telling the portal to connect to the grapewine network. Start by telling the portal to connect to the grapevine network.
""" """
if not _GRAPEWINE_ENABLED: if not _GRAPEVINE_ENABLED:
self.delete() self.delete()
return return
@ -461,12 +468,12 @@ class GrapewineBot(Bot):
channel.connect(self) channel.connect(self)
self.db.ev_channel = channel self.db.ev_channel = channel
if grapewine_channel: if grapevine_channel:
self.db.grapewine_channel = grapewine_channel self.db.grapevine_channel = grapevine_channel
# these will be made available as properties on the protocol factory # these will be made available as properties on the protocol factory
configdict = {"uid": self.dbid, configdict = {"uid": self.dbid,
"grapewine_channel": self.db.grapewine_channel} "grapevine_channel": self.db.grapevine_channel}
_SESSIONS.start_bot_session(self.factory_path, configdict) _SESSIONS.start_bot_session(self.factory_path, configdict)
@ -489,16 +496,25 @@ class GrapewineBot(Bot):
""" """
from_obj = kwargs.get("from_obj", None) from_obj = kwargs.get("from_obj", None)
options = kwargs.get("options", None) or {} options = kwargs.get("options", None) or {}
if not self.ndb.ev_channel and self.db.ev_channel: if not self.ndb.ev_channel and self.db.ev_channel:
# cache channel lookup # cache channel lookup
self.ndb.ev_channel = self.db.ev_channel self.ndb.ev_channel = self.db.ev_channel
if ("from_channel" in options and text and if ("from_channel" in options and text and
self.ndb.ev_channel.dbid == options["from_channel"]): self.ndb.ev_channel.dbid == options["from_channel"]):
if not from_obj or from_obj != [self]: if not from_obj or from_obj != [self]:
# send outputfunc text(msg, chan, sender) # send outputfunc channel(msg, chan, sender)
super().msg(text=(text, self.db.grapewine_channel, from_obj.key))
def execute_cmd(self, txt=None, session=None, event=None, grapewine_channel=None, # TODO we should refactor channel formatting to operate on the
# account/object level instead. For now, remove the channel/name
# prefix since we pass that explicitly anyway
prefix, text = text.split(":", 1)
super().msg(channel=(text.strip(), self.db.grapevine_channel,
", ".join(obj.key for obj in from_obj), {}))
def execute_cmd(self, txt=None, session=None, event=None, grapevine_channel=None,
sender=None, game=None, **kwargs): sender=None, game=None, **kwargs):
""" """
Take incoming data from protocol and send it to connected channel. This is Take incoming data from protocol and send it to connected channel. This is

View file

@ -74,4 +74,4 @@ class AccountCmdSet(CmdSet):
self.add(comms.CmdIRC2Chan()) self.add(comms.CmdIRC2Chan())
self.add(comms.CmdIRCStatus()) self.add(comms.CmdIRCStatus())
self.add(comms.CmdRSS2Chan()) self.add(comms.CmdRSS2Chan())
self.add(comms.CmdGrapewine2Chan()) self.add(comms.CmdGrapevine2Chan())

View file

@ -1094,58 +1094,58 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS):
self.msg("RSS reporter created. Fetching RSS.") self.msg("RSS reporter created. Fetching RSS.")
class CmdGrapewine2Chan(COMMAND_DEFAULT_CLASS): class CmdGrapevine2Chan(COMMAND_DEFAULT_CLASS):
""" """
Link an Evennia channel to an exteral Grapewine channel Link an Evennia channel to an exteral Grapevine channel
Usage: Usage:
grapewine2chan[/switches] <evennia_channel> = <grapewine_channel> grapevine2chan[/switches] <evennia_channel> = <grapevine_channel>
grapewine2chan/disconnect <connection #id> grapevine2chan/disconnect <connection #id>
Switches: Switches:
/list - (or no switch): show existing grapewine <-> Evennia /list - (or no switch): show existing grapevine <-> Evennia
mappings and available grapewine chans mappings and available grapevine chans
/remove - alias to disconnect /remove - alias to disconnect
/delete - alias to disconnect /delete - alias to disconnect
Example: Example:
grapewine2chan mygrapewine = gossip grapevine2chan mygrapevine = gossip
This creates a link between an in-game Evennia channel and an external This creates a link between an in-game Evennia channel and an external
Grapewine channel. The game must be registered with the Grapewine network Grapevine channel. The game must be registered with the Grapevine network
(register at https://grapewine.haus) and the GRAPEWINE_* auth information (register at https://grapevine.haus) and the GRAPEVINE_* auth information
must be added to game settings. must be added to game settings.
""" """
key = "grapewine2chan" key = "grapevine2chan"
switch_options = ("disconnect", "remove", "delete", "list") switch_options = ("disconnect", "remove", "delete", "list")
locks = "cmd:serversetting(GRAPEWINE_ENABLED) and pperm(Developer)" locks = "cmd:serversetting(GRAPEVINE_ENABLED) and pperm(Developer)"
help_category = "Comms" help_category = "Comms"
def func(self): def func(self):
"""Setup the Grapewine channel mapping""" """Setup the Grapevine channel mapping"""
if not settings.GRAPEWINE_ENABLED: if not settings.GRAPEVINE_ENABLED:
self.msg("Set GRAPEWINE_ENABLED=True in settings to enable.") self.msg("Set GRAPEVINE_ENABLED=True in settings to enable.")
return return
if "list" in self.switches: if "list" in self.switches:
# show all connections # show all connections
gwbots = [bot for bot in gwbots = [bot for bot in
AccountDB.objects.filter(db_is_bot=True, AccountDB.objects.filter(db_is_bot=True,
username__startswith="grapewinebot-")] username__startswith="grapevinebot-")]
if gwbots: if gwbots:
table = self.styled_table("|wdbid|n", "|wev-channel", table = self.styled_table("|wdbid|n", "|wev-channel",
"|wgw-channel|n", border="cells", maxwidth=_DEFAULT_WIDTH) "|wgw-channel|n", border="cells", maxwidth=_DEFAULT_WIDTH)
for gwbot in gwbots: for gwbot in gwbots:
table.add_row(gwbot.id, gwbot.db.ev_channel, gwbot.db.grapewine_channel) table.add_row(gwbot.id, gwbot.db.ev_channel, gwbot.db.grapevine_channel)
self.msg(table) self.msg(table)
else: else:
self.msg("No grapewine bots found.") self.msg("No grapevine bots found.")
return return
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches: if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
botname = "grapewinebot-%s" % self.lhs botname = "grapevinebot-%s" % self.lhs
matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname) matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname)
if not matches: if not matches:
@ -1153,20 +1153,20 @@ class CmdGrapewine2Chan(COMMAND_DEFAULT_CLASS):
matches = AccountDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#")) matches = AccountDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#"))
if matches: if matches:
matches[0].delete() matches[0].delete()
self.msg("Grapewine connection destroyed.") self.msg("Grapevine connection destroyed.")
else: else:
self.msg("Grapewine connection/bot could not be removed, does it exist?") self.msg("Grapevine connection/bot could not be removed, does it exist?")
return return
if not self.args or not self.rhs: if not self.args or not self.rhs:
string = "Usage: grapewine2chan[/switches] <evennia_channel> = <grapewine_channel>" string = "Usage: grapevine2chan[/switches] <evennia_channel> = <grapevine_channel>"
self.msg(string) self.msg(string)
return return
channel = self.lhs channel = self.lhs
grapewine_channel = self.rhs grapevine_channel = self.rhs
botname = "grapewinebot-%s-%s" % (channel, grapewine_channel) botname = "grapewinebot-%s-%s" % (channel, grapevine_channel)
bot = AccountDB.objects.filter(username__iexact=botname) bot = AccountDB.objects.filter(username__iexact=botname)
if bot: if bot:
# re-use existing bot # re-use existing bot
@ -1174,9 +1174,11 @@ class CmdGrapewine2Chan(COMMAND_DEFAULT_CLASS):
if not bot.is_bot: if not bot.is_bot:
self.msg("Account '%s' already exists and is not a bot." % botname) self.msg("Account '%s' already exists and is not a bot." % botname)
return return
else:
self.msg("Reusing bot '%s' (%s)" % (botname, bot.dbref))
else: else:
# create a new bot # create a new bot
bot = create.create_account(botname, None, None, typeclass=bots.GrapewineBot) bot = create.create_account(botname, None, None, typeclass=bots.GrapevineBot)
bot.start(ev_channel=channel, grapewine_channel=grapewine_channel) bot.start(ev_channel=channel, grapevine_channel=grapevine_channel)
self.msg(f"Grapewine connection created {channel} <-> {grapewine_channel}.") self.msg(f"Grapevine connection created {channel} <-> {grapevine_channel}.")

View file

@ -35,4 +35,4 @@ CONNECTION_SCREEN = """
If you have spaces in your username, enclose it in quotes. If you have spaces in your username, enclose it in quotes.
Enter |whelp|n for more info. |wlook|n will re-show this screen. Enter |whelp|n for more info. |wlook|n will re-show this screen.
|b==============================================================|n""" \ |b==============================================================|n""" \
.format(settings.SERVERNAME, utils.get_evennia_version()) .format(settings.SERVERNAME, utils.get_evennia_version("short"))

View file

@ -140,7 +140,7 @@ class RSSBotFactory(object):
def start(self): def start(self):
""" """
Called by portalsessionhandler. Starts te bot. Called by portalsessionhandler. Starts the bot.
""" """
def errback(fail): def errback(fail):
logger.log_err(fail.value) logger.log_err(fail.value)

View file

@ -72,7 +72,7 @@ GUEST_ENABLED = settings.GUEST_ENABLED
WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES
IRC_ENABLED = settings.IRC_ENABLED IRC_ENABLED = settings.IRC_ENABLED
RSS_ENABLED = settings.RSS_ENABLED RSS_ENABLED = settings.RSS_ENABLED
GRAPEWINE_ENABLED = settings.GRAPEWINE_ENABLED GRAPEVINE_ENABLED = settings.GRAPEVINE_ENABLED
WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED
INFO_DICT = {"servername": SERVERNAME, "version": VERSION, INFO_DICT = {"servername": SERVERNAME, "version": VERSION,
@ -584,9 +584,9 @@ if RSS_ENABLED:
# RSS feed channel connections # RSS feed channel connections
ENABLED.append('rss') ENABLED.append('rss')
if GRAPEWINE_ENABLED: if GRAPEVINE_ENABLED:
# Grapewine channel connections # Grapevine channel connections
ENABLED.append('grapewine') ENABLED.append('grapevine')
if ENABLED: if ENABLED:
INFO_DICT["irc_rss"] = ", ".join(ENABLED) + " enabled." INFO_DICT["irc_rss"] = ", ".join(ENABLED) + " enabled."

View file

@ -706,21 +706,21 @@ IRC_ENABLED = False
RSS_ENABLED = False RSS_ENABLED = False
RSS_UPDATE_INTERVAL = 60 * 10 # 10 minutes RSS_UPDATE_INTERVAL = 60 * 10 # 10 minutes
# Grapewine (grapewine.haus) is a network for listing MUDs as well as allow # Grapevine (grapevine.haus) is a network for listing MUDs as well as allow
# users of said MUDs to communicate with each other on shared channels. To use, # users of said MUDs to communicate with each other on shared channels. To use,
# your game must first be registered by logging in and creating a game entry at # your game must first be registered by logging in and creating a game entry at
# https://grapewine.haus. Evennia links grapewine channels to in-game channels # https://grapevine.haus. Evennia links grapevine channels to in-game channels
# with the @grapewine2chan command, available once this flag is set # with the @grapevine2chan command, available once this flag is set
# Grapewine requires installing the pyopenssl library (pip install pyopenssl) # Grapevine requires installing the pyopenssl library (pip install pyopenssl)
GRAPEWINE_ENABLED = False GRAPEVINE_ENABLED = False
# Grapewine channels to allow connection to. See https://grapevine.haus/chat # Grapevine channels to allow connection to. See https://grapevine.haus/chat
# for the available channels. Only channels in this list can be linked to in-game # for the available channels. Only channels in this list can be linked to in-game
# channels later. # channels later.
GRAPEWINE_CHANNELS = ["gossip", "testing"] GRAPEVINE_CHANNELS = ["gossip", "testing"]
# Grapewine authentication. Register your game at https://grapewine.haus to get # Grapevine authentication. Register your game at https://grapevine.haus to get
# them. These are secret and should thus be overridden in secret_settings file # them. These are secret and should thus be overridden in secret_settings file
GRAPEWINE_CLIENT_ID = "" GRAPEVINE_CLIENT_ID = ""
GRAPEWINE_CLIENT_SECRET = "" GRAPEVINE_CLIENT_SECRET = ""
###################################################################### ######################################################################
# Django web features # Django web features

View file

@ -603,16 +603,29 @@ def host_os_is(osname):
return os.name == osname return os.name == osname
def get_evennia_version(): def get_evennia_version(mode="long"):
""" """
Helper method for getting the current evennia version. Helper method for getting the current evennia version.
Args:
mode (str, optional): One of:
- long: 0.9.0 rev342453534
- short: 0.9.0
- pretty: Evennia 0.9.0
Returns: Returns:
version (str): The version string. version (str): The version string.
""" """
import evennia import evennia
return evennia.__version__ vers = evennia.__version__
if mode == "short":
return vers.split()[0].strip()
elif mode == "pretty":
vers = vers.split()[0].strip()
return f"Evennia {vers}"
else: # mode "long":
return vers
def pypath_to_realpath(python_path, file_ending='.py', pypath_prefixes=None): def pypath_to_realpath(python_path, file_ending='.py', pypath_prefixes=None):