diff --git a/src/channels/admin.py b/src/channels/admin.py index 44a9551777..edd2e2acb0 100644 --- a/src/channels/admin.py +++ b/src/channels/admin.py @@ -6,5 +6,5 @@ class CommChannelAdmin(admin.ModelAdmin): admin.site.register(CommChannel, CommChannelAdmin) class CommChannelMessageAdmin(admin.ModelAdmin): - list_display = ('channel', 'message') + list_display = ('channel', 'date_sent', 'message') admin.site.register(CommChannelMessage, CommChannelMessageAdmin) \ No newline at end of file diff --git a/src/channels/models.py b/src/channels/models.py index 9c91c4a457..b7be4db4e5 100644 --- a/src/channels/models.py +++ b/src/channels/models.py @@ -101,7 +101,7 @@ class CommChannelMessage(models.Model): date_sent = models.DateTimeField(editable=False, auto_now_add=True) def __str__(self): - return "%s: %s" % (self.sender.name, self.message) + return "%s: %s" % (self.channel.name, self.message) class Meta: ordering = ['-date_sent'] \ No newline at end of file diff --git a/src/comsys.py b/src/comsys.py index a47d43c520..20079565f2 100644 --- a/src/comsys.py +++ b/src/comsys.py @@ -7,6 +7,7 @@ from django.utils import simplejson from src.channels.models import CommChannel, CommChannelMessage from src import session_mgr from src import ansi +from src import logger def plr_get_cdict(session): """ @@ -165,13 +166,25 @@ def msg_chan_hist(target_obj, channel_name): channel_name: (str) The channel's full name. """ cobj = get_cobj_from_name(channel_name) - hist_list = CommChannelMessage.objects.filter(channel=cobj).order_by('date_sent')[0:20] - for entry in hist_list: + hist_list = CommChannelMessage.objects.filter(channel=cobj).order_by('date_sent') + + # Negative indexing is not currently supported with QuerySet objects. + # Figure out what the first CommChannelMessage is to return and grab the + # next 20. + first_msg = hist_list.count() - 20 + # Prevent a negative index from being called on. + if first_msg < 0: + first_msg = 0 + + # Slice and dice, display last 20 messages. + for entry in hist_list[first_msg:]: delta_days = datetime.datetime.now() - entry.date_sent days_elapsed = delta_days.days if days_elapsed > 0: + # Message happened more than a day ago, show the date. time_str = entry.date_sent.strftime("%m.%d / %H:%M") else: + # Recent message (within last 24 hours), show hour:minute. time_str = entry.date_sent.strftime("%H:%M") target_obj.emit_to("[%s] %s" % (time_str, entry.message)) @@ -207,22 +220,30 @@ def load_object_channels(pobject): for session in sessions: session.channels_subscribed = simplejson.loads(chan_list) -def send_cmessage(channel_name, message): +def send_cmessage(channel_name, message, noheader=True): """ Sends a message to all players on the specified channel. channel_name: (string) The name of the channel. - message: (string) Message to send. + message: (string) Message to send. + noheader: (bool) If False, prefix the message with the channel's name. """ + try: + channel_obj = get_cobj_from_name(channel_name) + except: + logger.log_errmsg("send_cmessage(): Can't find channel: %s" % (channel_name,)) + return + + if noheader == False: + message = "%s %s" % (channel_obj.ansi_name, message) + for user in get_cwho_list(channel_name, return_muted=False): user.msg(message) - try: - chan_message = CommChannelMessage() - chan_message.channel = get_cobj_from_name(channel_name) - chan_message.message = message - chan_message.save() - except: - print "send_cmessage(): Can't find channel: %s" % (channel_name,) + + chan_message = CommChannelMessage() + chan_message.channel = channel_obj + chan_message.message = message + chan_message.save() def get_all_channels(): """ diff --git a/src/config_defaults.py b/src/config_defaults.py index 752e0326b1..4b86ebd8fb 100644 --- a/src/config_defaults.py +++ b/src/config_defaults.py @@ -97,6 +97,13 @@ IMC2_SERVER_PW = None # This isn't something you should generally change. IMC2_PROTOCOL_VERSION = '2' +""" +Various comm channels for emitting debug or informative messages. +""" +COMMCHAN_IMC2_INFO = 'MUDInfo' +COMMCHAN_MUD_INFO = 'MUDInfo' +COMMCHAN_MUD_CONNECTIONS = 'MUDConnections' + # Local time zone for this installation. All choices can be found here: # http://www.postgresql.org/docs/8.0/interactive/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE TIME_ZONE = 'America/New_York' diff --git a/src/imc2/connection.py b/src/imc2/connection.py index 9eba9c6a3c..e7c3649ada 100644 --- a/src/imc2/connection.py +++ b/src/imc2/connection.py @@ -19,15 +19,25 @@ from src import comsys # The active instance of IMC2Protocol. Set at server startup. IMC2_PROTOCOL_INSTANCE = None +def cemit_info(message): + """ + Channel emits info to the appropriate info channel. By default, this + is MUDInfo. + """ + comsys.send_cmessage(settings.COMMCHAN_IMC2_INFO, 'IMC: %s' % message, + noheader=False) + class IMC2Protocol(StatefulTelnetProtocol): """ Provides the abstraction for the IMC2 protocol. Handles connection, authentication, and all necessary packets. """ def __init__(self): - logger.log_infomsg("IMC2: Client connecting to %s:%s..." % ( + message = "Client connecting to %s:%s..." % ( settings.IMC2_SERVER_ADDRESS, - settings.IMC2_SERVER_PORT)) + settings.IMC2_SERVER_PORT) + logger.log_infomsg('IMC2: %s' % message) + cemit_info(message) global IMC2_PROTOCOL_INSTANCE IMC2_PROTOCOL_INSTANCE = self self.is_authenticated = False @@ -80,7 +90,12 @@ class IMC2Protocol(StatefulTelnetProtocol): self.network_name = line_split[3] self.is_authenticated = True self.sequence = int(time()) - logger.log_infomsg("IMC2: Successfully authenticated to the '%s' network." % self.network_name) + + # Log to stdout and notify over MUDInfo. + auth_message = "Successfully authenticated to the '%s' network." % self.network_name + logger.log_infomsg('IMC2: %s' % auth_message) + cemit_info(auth_message) + # Ask to see what other MUDs are connected. self.send_packet(IMC2PacketKeepAliveRequest()) # IMC2 protocol states that KeepAliveRequests should be followed @@ -151,7 +166,11 @@ class IMC2ClientFactory(ClientFactory): protocol = IMC2Protocol def clientConnectionFailed(self, connector, reason): - logger.log_errmsg('connection failed: %s' % reason.getErrorMessage()) + message = 'Connection failed: %s' % reason.getErrorMessage() + cemit_info(message) + logger.log_errmsg('IMC2: %s' % message) def clientConnectionLost(self, connector, reason): - logger.log_errmsg('connection lost: %s' % reason.getErrorMessage()) + message = 'Connection lost: %s' % reason.getErrorMessage() + cemit_info(message) + logger.log_errmsg('IMC2: %s' % message) diff --git a/src/initial_setup.py b/src/initial_setup.py index 1f721d0590..40193f45a0 100644 --- a/src/initial_setup.py +++ b/src/initial_setup.py @@ -7,6 +7,7 @@ Everything starts at handle_setup() """ from django.contrib.auth.models import User, Group from django.core import management +from django.conf import settings from src.objects.models import Object from src.config.models import ConfigValue, CommandAlias, ConnectScreen from src import comsys, defines_global @@ -65,8 +66,10 @@ def create_channels(): chan_pub = comsys.create_channel("Public", god_user_obj, description="Public Discussion") chan_pub.is_joined_by_default = True chan_pub.save() - comsys.create_channel("Errors", god_user_obj, description="Error log") - comsys.create_channel("Info", god_user_obj, description="Informative messages") + comsys.create_channel(settings.COMMCHAN_MUD_INFO, god_user_obj, + description="Informative messages") + comsys.create_channel(settings.COMMCHAN_MUD_CONNECTIONS, god_user_obj, + description="Connection log") def create_config_values(): """ diff --git a/src/session.py b/src/session.py index 769e7d03a6..d1aee5bc6b 100755 --- a/src/session.py +++ b/src/session.py @@ -7,6 +7,7 @@ import sys from datetime import datetime from twisted.conch.telnet import StatefulTelnetProtocol from django.contrib.auth.models import User +from django.conf import settings from src.objects.models import Object from src.channels.models import CommChannel from src.config.models import ConnectScreen, ConfigValue @@ -28,7 +29,8 @@ class SessionProtocol(StatefulTelnetProtocol): What to do when we get a connection. """ self.prep_session() - logger.log_infomsg('Connection: %s' % (self,)) + logger.log_infomsg('New connection: %s' % self) + self.cemit_info('New connection: %s' % self) session_mgr.add_session(self) self.game_connect_screen() @@ -66,7 +68,8 @@ class SessionProtocol(StatefulTelnetProtocol): """ Execute this when a client abruplty loses their connection. """ - logger.log_infomsg('Disconnect: %s' % (self,)) + logger.log_infomsg('Disconnected: %s' % self) + self.cemit_info('Disconnected: %s.' % self) self.handle_close() def lineReceived(self, data): @@ -170,7 +173,8 @@ class SessionProtocol(StatefulTelnetProtocol): self.pobject.scriptlink.at_pre_login(self) self.pobject.scriptlink.at_post_login(self) - logger.log_infomsg("Login: %s" % (self,)) + logger.log_infomsg("Loged in: %s" % self) + self.cemit_info('Logged in: %s' % self) # Update their account's last login time. user.last_login = datetime.now() @@ -208,3 +212,12 @@ class SessionProtocol(StatefulTelnetProtocol): else: symbol = '?' return "<%s> %s@%s" % (symbol, self.name, self.address,) + + def cemit_info(self, message): + """ + Channel emits info to the appropriate info channel. By default, this + is MUDConnections. + """ + src.comsys.send_cmessage(settings.COMMCHAN_MUD_CONNECTIONS, + 'Session: %s' % message, + noheader=False)