Further updates to the IMC2 system, making it a bit easier to use.
This commit is contained in:
parent
c70d59045a
commit
23462c626c
5 changed files with 147 additions and 183 deletions
|
|
@ -921,19 +921,20 @@ class CmdIMC2Chan(MuxCommand):
|
||||||
imc2chan - link an evennia channel to imc2
|
imc2chan - link an evennia channel to imc2
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@imc2chan[/switches] <evennia_channel> = <imc2network> <port> <imc2channel> <imc2_client_pwd> <imc2_server_pwd>
|
@imc2chan[/switches] <evennia_channel> = <imc2_channel>
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
/disconnect - this will delete the bot and remove the imc2 connection to the channel.
|
/disconnect - this clear the imc2 connection to the channel.
|
||||||
/remove - "
|
/remove - "
|
||||||
/list - show all imc2<->evennia mappings
|
/list - show all imc2<->evennia mappings
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@imc2chan myimcchan = server02.mudbytes.net 9000 ievennia Gjds8372 LAKdf84e
|
@imc2chan myimcchan = ievennia
|
||||||
|
|
||||||
Connect an existing evennia channel to an IMC2 network and channel. You must have registered with the network
|
Connect an existing evennia channel to a channel on an IMC2
|
||||||
beforehand and obtained valid server- and client passwords. You will always connect using the name of your
|
network. The network contact information is defined in settings and
|
||||||
mud, as defined by settings.SERVERNAME, so make sure this was the name you registered to the imc2 network.
|
should already be accessed at this point. Use @imcchanlist to see
|
||||||
|
available IMC channels.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -953,10 +954,11 @@ class CmdIMC2Chan(MuxCommand):
|
||||||
# show all connections
|
# show all connections
|
||||||
connections = ExternalChannelConnection.objects.filter(db_external_key__startswith='imc2_')
|
connections = ExternalChannelConnection.objects.filter(db_external_key__startswith='imc2_')
|
||||||
if connections:
|
if connections:
|
||||||
cols = [["Evennia channel"], ["IMC channel"]]
|
cols = [["Evennia channel"], ["<->"], ["IMC channel"]]
|
||||||
for conn in connections:
|
for conn in connections:
|
||||||
cols[0].append(conn.channel.key)
|
cols[0].append(conn.channel.key)
|
||||||
cols[1].append(" ".join(conn.external_config.split('|')[:-3]))
|
cols[1].append("")
|
||||||
|
cols[2].append(conn.external_config)
|
||||||
ftable = utils.format_table(cols)
|
ftable = utils.format_table(cols)
|
||||||
string = ""
|
string = ""
|
||||||
for ir, row in enumerate(ftable):
|
for ir, row in enumerate(ftable):
|
||||||
|
|
@ -969,44 +971,34 @@ class CmdIMC2Chan(MuxCommand):
|
||||||
self.caller.msg("No connections found.")
|
self.caller.msg("No connections found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not settings.IMC2_ENABLED:
|
|
||||||
string = """IMC2 is not enabled. You need to activate it in game/settings.py."""
|
|
||||||
self.caller.msg(string)
|
|
||||||
return
|
|
||||||
if not self.args or not self.rhs:
|
if not self.args or not self.rhs:
|
||||||
string = "Usage: @imc2chan[/switches] <evennia_channel> = <imc2network> <port> <imc2channel> <client_pwd> <server_pwd>"
|
string = "Usage: @imc2chan[/switches] <evennia_channel> = <imc2_channel>"
|
||||||
self.caller.msg(string)
|
|
||||||
return
|
|
||||||
channel = self.lhs
|
|
||||||
try:
|
|
||||||
imc2_network, imc2_port, imc2_channel, imc2_client_pwd, imc2_server_pwd = [part.strip() for part in self.rhs.split(None, 4)]
|
|
||||||
except Exception:
|
|
||||||
string = "Usage: @imc2chan[/switches] <evennia_channel> = <imc2network> <port> <imc2channel> <client_pwd> <server_pwd>"
|
|
||||||
string += "\nYou must supply a value in every position to define the IMC2 connnection.\nFor deletion, the tree last arguments (imc2channel and the two passwords) may be dummy values."
|
|
||||||
self.caller.msg(string)
|
self.caller.msg(string)
|
||||||
return
|
return
|
||||||
|
|
||||||
# get the name to use for connecting
|
channel = self.lhs
|
||||||
mudname = settings.SERVERNAME
|
imc2_channel = self.rhs
|
||||||
|
|
||||||
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:
|
||||||
|
# we don't search for channels before this since we want to clear the link
|
||||||
ok = imc2.delete_connection(imc2_network, imc2_port, mudname)
|
# also if the channel no longer exists.
|
||||||
|
ok = imc2.delete_connection(channel, imc2_channel)
|
||||||
if not ok:
|
if not ok:
|
||||||
self.caller.msg("IMC2 connection could not be removed, does it exist?")
|
self.caller.msg("IMC2 connection could not be removed, does it exist?")
|
||||||
else:
|
else:
|
||||||
self.caller.msg("IMC2 connection destroyed.")
|
self.caller.msg("IMC2 connection destroyed.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# actually get the channel object
|
||||||
channel = find_channel(self.caller, channel)
|
channel = find_channel(self.caller, channel)
|
||||||
if not channel:
|
if not channel:
|
||||||
return
|
return
|
||||||
|
|
||||||
ok = imc2.create_connection(channel, imc2_network, imc2_port, imc2_channel, mudname, imc2_client_pwd, imc2_server_pwd)
|
ok = imc2.create_connection(channel, imc2_channel)
|
||||||
if not ok:
|
if not ok:
|
||||||
self.caller.msg("This IMC2 connection already exists.")
|
self.caller.msg("The connection %s <-> %s already exists." % (channel.key, imc2_channel))
|
||||||
return
|
return
|
||||||
self.caller.msg("Connection created. Connecting to IMC2 server.")
|
self.caller.msg("Created connection channel %s <-> IMC channel %s." % (channel.key, imc2_channel))
|
||||||
|
|
||||||
|
|
||||||
class CmdIMCInfo(MuxCommand):
|
class CmdIMCInfo(MuxCommand):
|
||||||
|
|
@ -1025,7 +1017,6 @@ class CmdIMCInfo(MuxCommand):
|
||||||
whois - as @imcwhois (requires an additional argument)
|
whois - as @imcwhois (requires an additional argument)
|
||||||
update - force an update of all lists
|
update - force an update of all lists
|
||||||
|
|
||||||
|
|
||||||
Shows lists of games or channels on the IMC2 network.
|
Shows lists of games or channels on the IMC2 network.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -1046,21 +1037,15 @@ class CmdIMCInfo(MuxCommand):
|
||||||
# update the lists
|
# update the lists
|
||||||
import time
|
import time
|
||||||
from src.comms.imc2lib import imc2_packets as pck
|
from src.comms.imc2lib import imc2_packets as pck
|
||||||
from src.comms.imc2 import IMC2_MUDLIST, IMC2_CHANLIST, IMC2_CONNECTIONS
|
from src.comms.imc2 import IMC2_MUDLIST, IMC2_CHANLIST, IMC2_CLIENT
|
||||||
# update connected muds
|
# update connected muds
|
||||||
for conn in IMC2_CONNECTIONS:
|
IMC2_CLIENT.send_packet(pck.IMC2PacketKeepAliveRequest())
|
||||||
conn.send_packet(pck.IMC2PacketKeepAliveRequest())
|
|
||||||
# prune inactive muds
|
# prune inactive muds
|
||||||
for name, mudinfo in IMC2_MUDLIST.mud_list.items():
|
for name, mudinfo in IMC2_MUDLIST.mud_list.items():
|
||||||
if time.time() - mudinfo.last_updated > 3599:
|
if time.time() - mudinfo.last_updated > 3599:
|
||||||
del IMC2_MUDLIST.mud_list[name]
|
del IMC2_MUDLIST.mud_list[name]
|
||||||
# update channel list
|
# update channel list
|
||||||
checked_networks = []
|
IMC2_CLIENT.send_packet(pck.IMC2PacketIceRefresh())
|
||||||
for conn in IMC2_CONNECTIONS:
|
|
||||||
network = conn.factory.network
|
|
||||||
if not network in checked_networks:
|
|
||||||
conn.send_packet(pck.IMC2PacketIceRefresh())
|
|
||||||
checked_networks.append(network)
|
|
||||||
self.caller.msg("IMC2 lists were re-synced.")
|
self.caller.msg("IMC2 lists were re-synced.")
|
||||||
|
|
||||||
elif "games" in self.switches or "muds" in self.switches or self.cmdstring == "@imclist":
|
elif "games" in self.switches or "muds" in self.switches or self.cmdstring == "@imclist":
|
||||||
|
|
@ -1094,19 +1079,18 @@ class CmdIMCInfo(MuxCommand):
|
||||||
if not self.args:
|
if not self.args:
|
||||||
self.caller.msg("Usage: @imcwhois <playername>")
|
self.caller.msg("Usage: @imcwhois <playername>")
|
||||||
return
|
return
|
||||||
from src.comms.imc2 import IMC2_CONNECTIONS
|
from src.comms.imc2 import IMC2_CLIENT
|
||||||
self.caller.msg("Sending IMC whois request. If you receive no response, no matches were found.")
|
self.caller.msg("Sending IMC whois request. If you receive no response, no matches were found.")
|
||||||
for comm in IMC2_CONNECTIONS:
|
IMC2_CLIENT.msg_imc2(None, from_obj=self.caller.player, packet_type="imcwhois", data={"target":self.args})
|
||||||
comm.msg_imc2(None, from_obj=self.caller.player, packet_type="imcwhois", data={"target":self.args})
|
|
||||||
|
|
||||||
elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist":
|
elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist":
|
||||||
# show channels
|
# show channels
|
||||||
from src.comms.imc2 import IMC2_CHANLIST, IMC2_CONNECTIONS
|
from src.comms.imc2 import IMC2_CHANLIST, IMC2_CLIENT
|
||||||
|
|
||||||
channels = IMC2_CHANLIST.get_channel_list()
|
channels = IMC2_CHANLIST.get_channel_list()
|
||||||
string = ""
|
string = ""
|
||||||
nchans = 0
|
nchans = 0
|
||||||
string += "\n {GChannels on %s:{n" % (", ".join(conn.factory.network for conn in IMC2_CONNECTIONS))
|
string += "\n {GChannels on %s:{n" % IMC2_CLIENT.factory.network
|
||||||
cols = [["Full name"], ["Name"], ["Owner"], ["Perm"], ["Policy"]]
|
cols = [["Full name"], ["Name"], ["Owner"], ["Perm"], ["Policy"]]
|
||||||
for channel in channels:
|
for channel in channels:
|
||||||
nchans += 1
|
nchans += 1
|
||||||
|
|
@ -1155,7 +1139,7 @@ class CmdIMCTell(MuxCommand):
|
||||||
self.caller.msg(string)
|
self.caller.msg(string)
|
||||||
return
|
return
|
||||||
|
|
||||||
from src.comms.imc2 import IMC2_CONNECTIONS
|
from src.comms.imc2 import IMC2_CLIENT
|
||||||
|
|
||||||
if not self.args or not '@' in self.lhs or not self.rhs:
|
if not self.args or not '@' in self.lhs or not self.rhs:
|
||||||
string = "Usage: imctell User@Mud = <msg>"
|
string = "Usage: imctell User@Mud = <msg>"
|
||||||
|
|
@ -1165,8 +1149,7 @@ class CmdIMCTell(MuxCommand):
|
||||||
message = self.rhs.strip()
|
message = self.rhs.strip()
|
||||||
data = {"target":target, "destination":destination}
|
data = {"target":target, "destination":destination}
|
||||||
|
|
||||||
for comm in IMC2_CONNECTIONS:
|
# send to imc2
|
||||||
# we don't know which connection we aim for, so we send to all.
|
IMC2_CLIENT.msg_imc2(message, from_obj=self.caller.player, packet_type="imctell", data=data)
|
||||||
comm.msg_imc2(message, from_obj=self.caller.player, packet_type="imctell", data=data)
|
|
||||||
|
|
||||||
self.caller.msg("You paged {c%s@%s{n (over IMC): '%s'." % (target, destination, message))
|
self.caller.msg("You paged {c%s@%s{n (over IMC): '%s'." % (target, destination, message))
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,17 @@ from src.comms.imc2lib import imc2_packets as pck
|
||||||
from src.comms.imc2lib.imc2_trackers import IMC2MudList, IMC2ChanList
|
from src.comms.imc2lib.imc2_trackers import IMC2MudList, IMC2ChanList
|
||||||
from src.comms.imc2lib.imc2_listeners import handle_whois_reply
|
from src.comms.imc2lib.imc2_listeners import handle_whois_reply
|
||||||
|
|
||||||
|
# IMC2 network setup
|
||||||
|
IMC2_MUDNAME = settings.SERVERNAME
|
||||||
|
IMC2_NETWORK = settings.IMC2_NETWORK
|
||||||
|
IMC2_PORT = settings.IMC2_PORT
|
||||||
|
IMC2_CLIENT_PWD = settings.IMC2_CLIENT_PWD
|
||||||
|
IMC2_SERVER_PWD = settings.IMC2_SERVER_PWD
|
||||||
|
|
||||||
# channel to send info to
|
# channel to send info to
|
||||||
INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0])
|
INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0])
|
||||||
# all linked channel connections
|
# all linked channel connections
|
||||||
IMC2_CONNECTIONS = []
|
IMC2_CLIENT = None
|
||||||
# IMC2 debug mode
|
# IMC2 debug mode
|
||||||
IMC2_DEBUG = False
|
IMC2_DEBUG = False
|
||||||
# Use this instance to keep track of the other games on the network.
|
# Use this instance to keep track of the other games on the network.
|
||||||
|
|
@ -58,11 +64,10 @@ class Send_IsAlive(Script):
|
||||||
self.desc = "Send an IMC2 is-alive packet"
|
self.desc = "Send an IMC2 is-alive packet"
|
||||||
self.persistent = True
|
self.persistent = True
|
||||||
def at_repeat(self):
|
def at_repeat(self):
|
||||||
for channel in IMC2_CONNECTIONS:
|
IMC2_CLIENT.send_packet(pck.IMC2PacketIsAlive())
|
||||||
channel.send_packet(pck.IMC2PacketIsAlive())
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
"Is only valid as long as there are channels to update"
|
"Is only valid as long as there are channels to update"
|
||||||
return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:"))
|
return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_"))
|
||||||
|
|
||||||
class Send_Keepalive_Request(Script):
|
class Send_Keepalive_Request(Script):
|
||||||
"""
|
"""
|
||||||
|
|
@ -75,11 +80,10 @@ class Send_Keepalive_Request(Script):
|
||||||
self.desc = "Send an IMC2 keepalive-request packet"
|
self.desc = "Send an IMC2 keepalive-request packet"
|
||||||
self.persistent = True
|
self.persistent = True
|
||||||
def at_repeat(self):
|
def at_repeat(self):
|
||||||
for channel in IMC2_CONNECTIONS:
|
IMC2_CLIENT.channel.send_packet(pck.IMC2PacketKeepAliveRequest())
|
||||||
channel.send_packet(pck.IMC2PacketKeepAliveRequest())
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
"Is only valid as long as there are channels to update"
|
"Is only valid as long as there are channels to update"
|
||||||
return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:"))
|
return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_"))
|
||||||
|
|
||||||
class Prune_Inactive_Muds(Script):
|
class Prune_Inactive_Muds(Script):
|
||||||
"""
|
"""
|
||||||
|
|
@ -99,7 +103,7 @@ class Prune_Inactive_Muds(Script):
|
||||||
del IMC2_MUDLIST.mud_list[name]
|
del IMC2_MUDLIST.mud_list[name]
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
"Is only valid as long as there are channels to update"
|
"Is only valid as long as there are channels to update"
|
||||||
return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:"))
|
return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_"))
|
||||||
|
|
||||||
class Sync_Server_Channel_List(Script):
|
class Sync_Server_Channel_List(Script):
|
||||||
"""
|
"""
|
||||||
|
|
@ -115,13 +119,12 @@ class Sync_Server_Channel_List(Script):
|
||||||
self.persistent = True
|
self.persistent = True
|
||||||
def at_repeat(self):
|
def at_repeat(self):
|
||||||
checked_networks = []
|
checked_networks = []
|
||||||
for channel in self.IMC2_CONNECTIONS:
|
network = IMC2_CLIENT.factory.network
|
||||||
network = channel.factory.network
|
if not network in checked_networks:
|
||||||
if not network in checked_networks:
|
channel.send_packet(pkg.IMC2PacketIceRefresh())
|
||||||
channel.send_packet(pkg.IMC2PacketIceRefresh())
|
checked_networks.append(network)
|
||||||
checked_networks.append(network)
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:"))
|
return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_"))
|
||||||
#
|
#
|
||||||
# IMC2 protocol
|
# IMC2 protocol
|
||||||
#
|
#
|
||||||
|
|
@ -132,8 +135,8 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
authentication, and all necessary packets.
|
authentication, and all necessary packets.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
global IMC2_CONNECTIONS
|
global IMC2_CLIENT
|
||||||
IMC2_CONNECTIONS.append(self)
|
IMC2_CLIENT = self
|
||||||
self.is_authenticated = False
|
self.is_authenticated = False
|
||||||
self.auth_type = None
|
self.auth_type = None
|
||||||
self.server_name = None
|
self.server_name = None
|
||||||
|
|
@ -146,8 +149,9 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
Triggered after connecting to the IMC2 network.
|
Triggered after connecting to the IMC2 network.
|
||||||
"""
|
"""
|
||||||
self.auth_type = "plaintext"
|
self.auth_type = "plaintext"
|
||||||
logger.log_infomsg("IMC2: Connected to network server.")
|
if IMC2_DEBUG:
|
||||||
logger.log_infomsg("IMC2: Sending authentication packet.")
|
logger.log_infomsg("IMC2: Connected to network server.")
|
||||||
|
logger.log_infomsg("IMC2: Sending authentication packet.")
|
||||||
self.send_packet(pck.IMC2PacketAuthPlaintext())
|
self.send_packet(pck.IMC2PacketAuthPlaintext())
|
||||||
|
|
||||||
def connectionLost(self, reason=None):
|
def connectionLost(self, reason=None):
|
||||||
|
|
@ -155,7 +159,12 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
This is executed when the connection is lost for
|
This is executed when the connection is lost for
|
||||||
whatever reason.
|
whatever reason.
|
||||||
"""
|
"""
|
||||||
pass # we don't need to do anything, it's cleaned up automatically.
|
try:
|
||||||
|
service = SESSIONS.server.services.getServiceNamed("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME))
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
if service.running:
|
||||||
|
service.stopService()
|
||||||
|
|
||||||
def send_packet(self, packet):
|
def send_packet(self, packet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -206,7 +215,7 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
self.sequence = int(time())
|
self.sequence = int(time())
|
||||||
|
|
||||||
# Log to stdout and notify over MUDInfo.
|
# Log to stdout and notify over MUDInfo.
|
||||||
auth_message = "Successfully authenticated to the '%s' network." % self.network_name
|
auth_message = "Successfully authenticated to the '%s' network." % self.factory.network
|
||||||
logger.log_infomsg('IMC2: %s' % auth_message)
|
logger.log_infomsg('IMC2: %s' % auth_message)
|
||||||
msg_info(auth_message)
|
msg_info(auth_message)
|
||||||
|
|
||||||
|
|
@ -228,23 +237,18 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
# If the packet lacks the 'echo' key, don't bother with it.
|
# If the packet lacks the 'echo' key, don't bother with it.
|
||||||
if not conn_name or not packet.optional_data.get('echo', None):
|
if not conn_name or not packet.optional_data.get('echo', None):
|
||||||
return
|
return
|
||||||
chan_name = conn_name.split(':', 1)[1]
|
imc2_channel = conn_name.split(':', 1)[1]
|
||||||
|
|
||||||
key = "imc2_%s" % conn_name
|
# Look for matching IMC2 channel maps mapping to this imc2 channel.
|
||||||
# Look for matching IMC2 channel maps.
|
conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_")
|
||||||
conns = ExternalChannelConnection.objects.filter(db_external_key=self.factory.key)
|
conns = [conn for conn in conns if imc2_channel in conn.db_external_config.split(",")]
|
||||||
if not conns:
|
if not conns:
|
||||||
|
# we are not listening to this imc2 channel.
|
||||||
return
|
return
|
||||||
|
|
||||||
# get channel subscriptions
|
# Format the message to send to local channel(s).
|
||||||
chansubs = conns[0].db_external_config.split("|")[2].split(",")
|
for conn in conns:
|
||||||
if not chan_name in chansubs:
|
message = '[%s] %s@%s: %s' % (conn.channel.key, packet.sender, packet.origin, packet.optional_data.get('text'))
|
||||||
# we are not listening to this channel.
|
|
||||||
return
|
|
||||||
|
|
||||||
# Format the message to send to local channel.
|
|
||||||
message = '[%s] %s@%s: %s' % (self.factory.evennia_channel, packet.sender, packet.origin, packet.optional_data.get('text'))
|
|
||||||
for conn in (conn for conn in conns if conn.channel):
|
|
||||||
conn.to_channel(message)
|
conn.to_channel(message)
|
||||||
|
|
||||||
def _format_tell(self, packet):
|
def _format_tell(self, packet):
|
||||||
|
|
@ -252,7 +256,7 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
Handle tells over IMC2 by formatting the text properly
|
Handle tells over IMC2 by formatting the text properly
|
||||||
"""
|
"""
|
||||||
return "{c%s@%s{n {wpages (over IMC):{n %s" % (packet.sender, packet.origin,
|
return "{c%s@%s{n {wpages (over IMC):{n %s" % (packet.sender, packet.origin,
|
||||||
packet.optional_data.get('text', 'ERROR: No text provided.'))
|
packet.optional_data.get('text', 'ERROR: No text provided.'))
|
||||||
|
|
||||||
def lineReceived(self, line):
|
def lineReceived(self, line):
|
||||||
"""
|
"""
|
||||||
|
|
@ -308,9 +312,6 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
"""
|
"""
|
||||||
Called by Evennia to send a message through the imc2 connection
|
Called by Evennia to send a message through the imc2 connection
|
||||||
"""
|
"""
|
||||||
conns = ExternalChannelConnection.objects.filter(db_external_key=self.factory.key)
|
|
||||||
if not conns:
|
|
||||||
return
|
|
||||||
if from_obj:
|
if from_obj:
|
||||||
if hasattr(from_obj, 'key'):
|
if hasattr(from_obj, 'key'):
|
||||||
from_name = from_obj.key
|
from_name = from_obj.key
|
||||||
|
|
@ -320,9 +321,18 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
from_name = self.factory.mudname
|
from_name = self.factory.mudname
|
||||||
|
|
||||||
if packet_type == "imcbroadcast":
|
if packet_type == "imcbroadcast":
|
||||||
# send the packet
|
if type(data) == dict:
|
||||||
self.send_packet(pck.IMC2PacketIceMsgBroadcasted(self.factory.servername, self.factory.channel[0],
|
conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_",
|
||||||
from_name, message))
|
db_channel=data.get("channel", "Unknown"))
|
||||||
|
if not conns:
|
||||||
|
return
|
||||||
|
# we remove the extra channel info since imc2 supplies this anyway
|
||||||
|
if ":" in message:
|
||||||
|
header, message = [part.strip() for part in message.split(":", 1)]
|
||||||
|
# send the packet
|
||||||
|
imc2_channel = conns[0].db_external_config.split(',')[0] # only send to the first channel
|
||||||
|
self.send_packet(pck.IMC2PacketIceMsgBroadcasted(self.factory.servername, imc2_channel,
|
||||||
|
from_name, message))
|
||||||
elif packet_type == "imctell":
|
elif packet_type == "imctell":
|
||||||
# send a tell
|
# send a tell
|
||||||
if type(data) == dict:
|
if type(data) == dict:
|
||||||
|
|
@ -338,24 +348,21 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol):
|
||||||
|
|
||||||
class IMC2Factory(protocol.ClientFactory):
|
class IMC2Factory(protocol.ClientFactory):
|
||||||
"""
|
"""
|
||||||
Creates instances of the IMC2Protocol. Should really only ever create one
|
Creates instances of the IMC2Protocol. Should really only ever
|
||||||
in our particular instance. Tied in via src/server.py.
|
need to create one connection. Tied in via src/server.py.
|
||||||
"""
|
"""
|
||||||
protocol = IMC2Protocol
|
protocol = IMC2Protocol
|
||||||
|
|
||||||
def __init__(self, key, channel, network, port, mudname, client_pwd, server_pwd, evennia_channel):
|
def __init__(self, network, port, mudname, client_pwd, server_pwd):
|
||||||
self.key = key
|
self.pretty_key = "%s:%s(%s)" % (network, port, mudname)
|
||||||
self.mudname = mudname
|
|
||||||
self.channel = channel # this is a list!
|
|
||||||
self.pretty_key = "%s:%s/%s (%s)" % (network, port, channel, mudname)
|
|
||||||
self.network = network
|
self.network = network
|
||||||
sname, host = network.split(".", 1)
|
sname, host = network.split(".", 1)
|
||||||
self.servername = sname.strip()
|
self.servername = sname.strip()
|
||||||
|
self.port = port
|
||||||
|
self.mudname = mudname
|
||||||
self.protocol_version = '2'
|
self.protocol_version = '2'
|
||||||
self.client_pwd = client_pwd
|
self.client_pwd = client_pwd
|
||||||
self.server_pwd = server_pwd
|
self.server_pwd = server_pwd
|
||||||
self.evennia_channel = evennia_channel
|
|
||||||
|
|
||||||
|
|
||||||
def clientConnectionFailed(self, connector, reason):
|
def clientConnectionFailed(self, connector, reason):
|
||||||
message = 'Connection failed: %s' % reason.getErrorMessage()
|
message = 'Connection failed: %s' % reason.getErrorMessage()
|
||||||
|
|
@ -368,12 +375,11 @@ class IMC2Factory(protocol.ClientFactory):
|
||||||
logger.log_errmsg('IMC2: %s' % message)
|
logger.log_errmsg('IMC2: %s' % message)
|
||||||
|
|
||||||
|
|
||||||
def build_connection_key(imc2_network, imc2_port, imc2_mudname):
|
def build_connection_key(channel, imc2_channel):
|
||||||
"Build an id hash for the connection"
|
"Build an id hash for the connection"
|
||||||
return "imc2_%s:%s(%s)<>Evennia" % (imc2_network, imc2_port, imc2_mudname)
|
if hasattr(channel, "key"):
|
||||||
|
channel = channel.key
|
||||||
def build_service_key(key):
|
return "imc2_%s:%s(%s)%s<>%s" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME, imc2_channel, channel)
|
||||||
return "IMC2:%s" % key
|
|
||||||
|
|
||||||
def start_scripts(validate=False):
|
def start_scripts(validate=False):
|
||||||
"""
|
"""
|
||||||
|
|
@ -393,97 +399,69 @@ def start_scripts(validate=False):
|
||||||
if not search.scripts("IMC2_Sync_Server_Channel_List"):
|
if not search.scripts("IMC2_Sync_Server_Channel_List"):
|
||||||
create.create_script(Sync_Server_Channel_List)
|
create.create_script(Sync_Server_Channel_List)
|
||||||
|
|
||||||
def create_connection(channel, imc2_network, imc2_port, imc2_channel, imc2_mudname, imc2_client_pwd, imc2_server_pwd):
|
def create_connection(channel, imc2_channel):
|
||||||
"""
|
"""
|
||||||
This will create a new IMC2<->channel connection.
|
This will create a new IMC2<->channel connection.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = build_connection_key(imc2_network, imc2_port, imc2_mudname)
|
|
||||||
|
|
||||||
if not type(channel) == Channel:
|
if not type(channel) == Channel:
|
||||||
new_channel = Channel.objects.filter(db_key=channel)
|
new_channel = Channel.objects.filter(db_key=channel)
|
||||||
if not new_channel:
|
if not new_channel:
|
||||||
logger.log_errmsg("Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found" % channel)
|
logger.log_errmsg("Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found" % channel)
|
||||||
return False
|
return False
|
||||||
channel = new_channel[0]
|
channel = new_channel[0]
|
||||||
|
key = build_connection_key(channel, imc2_channel)
|
||||||
|
|
||||||
old_conns = ExternalChannelConnection.objects.filter(db_external_key=key)
|
old_conns = ExternalChannelConnection.objects.filter(db_external_key=key)
|
||||||
if old_conns:
|
if old_conns:
|
||||||
|
# this evennia channel is already connected to imc. Check if imc2_channel is different.
|
||||||
# connection already exists. We try to only connect a new channel
|
# connection already exists. We try to only connect a new channel
|
||||||
old_config = old_conns[0].db_external_config.split('|',5)
|
old_config = old_conns[0].db_external_config.split(",")
|
||||||
old_chan_subs = old_config[2].split(',')
|
if imc2_channel in old_config:
|
||||||
if imc2_channel in old_chan_subs:
|
|
||||||
return False # we already listen to this channel
|
return False # we already listen to this channel
|
||||||
else:
|
else:
|
||||||
# We add thew new channel to the connection instead of creating a new connection.
|
# We add a new imc2_channel to listen to
|
||||||
old_chan_subs.append(imc2_channel)
|
old_config.append(imc2_channel)
|
||||||
old_chan_subs = ",".join(old_chan_subs)
|
old_conns[0].db_external_config = ",".join(old_config)
|
||||||
old_config[2] = old_chan_subs # add a channel subscription to old config
|
|
||||||
old_conns[0].db_external_config = "|".join(old_config)
|
|
||||||
old_conns[0].save()
|
old_conns[0].save()
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
# no old connection found; create a new one.
|
||||||
|
config = imc2_channel
|
||||||
|
# how the evennia channel will be able to contact this protocol in reverse
|
||||||
|
send_code = "from src.comms.imc2 import IMC2_CLIENT\n"
|
||||||
|
send_code += "data={'channel':from_channel}\n"
|
||||||
|
send_code += "IMC2_CLIENT.msg_imc2(message, from_obj=from_obj, data=data)\n"
|
||||||
|
conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code,
|
||||||
|
db_external_config=config)
|
||||||
|
conn.save()
|
||||||
|
return True
|
||||||
|
|
||||||
# new connection
|
def delete_connection(channel, imc2_channel):
|
||||||
config = "%s|%s|%s|%s|%s|%s" % (imc2_network, imc2_port, imc2_channel, imc2_mudname, imc2_client_pwd, imc2_server_pwd)
|
|
||||||
# how the channel will be able to contact this protocol
|
|
||||||
send_code = "from src.comms.imc2 import IMC2_CONNECTIONS\n"
|
|
||||||
send_code += "matched_imc2s = [imc2 for imc2 in IMC2_CONNECTIONS if imc2.factory.key == '%s']\n" % key
|
|
||||||
send_code += "[imc2.msg_imc2(message, from_obj=from_obj) for imc2 in matched_imc2s]\n"
|
|
||||||
conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code,
|
|
||||||
db_external_config=config)
|
|
||||||
conn.save()
|
|
||||||
|
|
||||||
# connect
|
|
||||||
connect_to_imc2(conn)
|
|
||||||
# start scripts (if needed)
|
|
||||||
start_scripts()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def delete_connection(imc2_network, imc2_port, mudname):
|
|
||||||
"Destroy a connection"
|
"Destroy a connection"
|
||||||
|
if hasattr(channel, "key"):
|
||||||
|
channel = channel.key
|
||||||
|
key = build_connection_key(channel, imc2_channel)
|
||||||
|
|
||||||
key = build_connection_key(imc2_network, imc2_port, mudname)
|
|
||||||
service_key = build_service_key(key)
|
|
||||||
try:
|
try:
|
||||||
conn = ExternalChannelConnection.objects.get(db_external_key=key)
|
conn = ExternalChannelConnection.objects.get(db_external_key=key)
|
||||||
except Exception:
|
except ExternalChannelConnection.DoesNotExist:
|
||||||
return False
|
return False
|
||||||
conn.delete()
|
conn.delete()
|
||||||
|
|
||||||
try:
|
|
||||||
service = SESSIONS.server.services.getServiceNamed(service_key)
|
|
||||||
except Exception:
|
|
||||||
return True
|
|
||||||
if service.running:
|
|
||||||
SESSIONS.server.services.removeService(service)
|
|
||||||
# validate scripts
|
|
||||||
start_scripts(validate=True)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def connect_to_imc2(connection):
|
def connect_to_imc2():
|
||||||
"Create the imc instance and connect to the IMC2 network and channel."
|
"Create the imc instance and connect to the IMC2 network."
|
||||||
|
|
||||||
# get config
|
|
||||||
key = utils.to_str(connection.external_key)
|
|
||||||
service_key = build_service_key(key)
|
|
||||||
imc2_network, imc2_port, imc2_channel, imc2_mudname, imc2_client_pwd, imc2_server_pwd = \
|
|
||||||
[utils.to_str(conf) for conf in connection.external_config.split('|')]
|
|
||||||
imc2_channel = imc2_channel.split(",")
|
|
||||||
# connect
|
# connect
|
||||||
imc = internet.TCPClient(imc2_network, int(imc2_port), IMC2Factory(key, imc2_channel, imc2_network, imc2_port, imc2_mudname,
|
imc = internet.TCPClient(IMC2_NETWORK, int(IMC2_PORT), IMC2Factory(IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME,
|
||||||
imc2_client_pwd, imc2_server_pwd, connection.channel.key))
|
IMC2_CLIENT_PWD, IMC2_SERVER_PWD))
|
||||||
imc.setName(service_key)
|
imc.setName("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME))
|
||||||
SESSIONS.server.services.addService(imc)
|
SESSIONS.server.services.addService(imc)
|
||||||
|
|
||||||
def connect_all():
|
def connect_all():
|
||||||
"""
|
"""
|
||||||
Activate all imc2 bots.
|
Activates the imc2 system. Called by the server if IMC2_ENABLED=True.
|
||||||
|
|
||||||
Returns a list of (key, TCPClient) tuples for server to properly set services.
|
|
||||||
"""
|
"""
|
||||||
connections = ExternalChannelConnection.objects.filter(db_external_key__startswith='imc2_')
|
connect_to_imc2()
|
||||||
for connection in connections:
|
start_scripts()
|
||||||
connect_to_imc2(connection)
|
|
||||||
if connections:
|
|
||||||
start_scripts()
|
|
||||||
|
|
|
||||||
|
|
@ -561,7 +561,7 @@ class Channel(SharedMemoryModel):
|
||||||
conn.player.msg(msg, from_obj)
|
conn.player.msg(msg, from_obj)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
try:
|
try:
|
||||||
conn.to_external(msg, from_obj)
|
conn.to_external(msg, from_obj, from_channel=self)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.log_trace("Cannot send msg to connection '%s'" % conn)
|
logger.log_trace("Cannot send msg to connection '%s'" % conn)
|
||||||
return True
|
return True
|
||||||
|
|
@ -780,7 +780,7 @@ class ExternalChannelConnection(SharedMemoryModel):
|
||||||
from_obj = self.external_key
|
from_obj = self.external_key
|
||||||
self.channel.msg(message, from_obj=from_obj)
|
self.channel.msg(message, from_obj=from_obj)
|
||||||
|
|
||||||
def to_external(self, message, from_obj=None):
|
def to_external(self, message, from_obj=None, from_channel=None):
|
||||||
"Send channel -> external"
|
"Send channel -> external"
|
||||||
|
|
||||||
# make sure we are not echoing back our own message to ourselves
|
# make sure we are not echoing back our own message to ourselves
|
||||||
|
|
@ -792,7 +792,7 @@ class ExternalChannelConnection(SharedMemoryModel):
|
||||||
# we execute the code snippet that should make it possible for the
|
# we execute the code snippet that should make it possible for the
|
||||||
# connection to contact the protocol correctly (as set by the protocol).
|
# connection to contact the protocol correctly (as set by the protocol).
|
||||||
# Note that the code block has access to the variables here, such
|
# Note that the code block has access to the variables here, such
|
||||||
# as message and from_obj.
|
# as message, from_obj and from_channel.
|
||||||
exec(to_str(self.external_send_code))
|
exec(to_str(self.external_send_code))
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.log_trace("Channel %s could not send to External %s" % (self.channel, self.external_key))
|
logger.log_trace("Channel %s could not send to External %s" % (self.channel, self.external_key))
|
||||||
|
|
|
||||||
|
|
@ -281,13 +281,16 @@ IRC_ENABLED = False
|
||||||
# use it, go to http://www.mudbytes.net/imc2-intermud-join-network.
|
# use it, go to http://www.mudbytes.net/imc2-intermud-join-network.
|
||||||
# Choose 'Other unsupported IMC2 version' from the choices and and
|
# Choose 'Other unsupported IMC2 version' from the choices and and
|
||||||
# enter your information there. You should enter the same 'short mud
|
# enter your information there. You should enter the same 'short mud
|
||||||
# name' as your SERVERNAME above. When enabled, the command @imc2chan
|
# name' as your SERVERNAME above, then choose imc network server as
|
||||||
# becomes available in-game. It will take 'client password' and
|
# well as client/server passwords same as below. When enabled, the
|
||||||
# 'server password' as chosen when registering on mudbytes. The
|
# command @imc2chan becomes available in-game and allows you to
|
||||||
# Evennia discussion channel 'ievennia' is on
|
# connect Evennia channels to IMC channels on the network. The Evennia
|
||||||
# server02.mudbytes.net:9000.
|
# discussion channel 'ievennia' is on server01.mudbytes.net:5000.
|
||||||
IMC2_ENABLED = False
|
IMC2_ENABLED = False
|
||||||
|
IMC2_NETWORK = "server01.mudbytes.net"
|
||||||
|
IMC2_PORT = 5000
|
||||||
|
IMC2_CLIENT_PWD = ""
|
||||||
|
IMC2_SERVER_PWD = ""
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
# Config for Django web features
|
# Config for Django web features
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue