NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

channel_controller.py (12150B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\chat\client\channel_controller.py
      2 import blue
      3 import sys
      4 import signals
      5 import localization
      6 import gametime
      7 import threadutils
      8 import logging
      9 from chat.client.hide_messages import open_hide_message_settings
     10 from collections import deque
     11 from carbon.common.script.util.commonutils import StripTags
     12 from carbon.common.script.util.format import FmtDate
     13 from carbonui.util.stringManip import SanitizeFilename
     14 from eveProto.generated.eve_public.chat.local.local_pb2 import CLASSIFICATION_INVISIBLE
     15 from inventorycommon.const import ownerSystem, ownerNone
     16 from chatutil import CompleteAutoLinks
     17 from chat.common.const import CLASSIFACTION_TO_COLOR, MemberClassification
     18 from chat.client.const import MAX_MESSAGES_IN_HISTORY, CHATLOG_TEMPLATE, MAX_MESSAGES_PER_SEC, MAX_PENDING_MESSAGES
     19 from chat.client.util import parse_chat_message, should_hide_message
     20 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     21 logger = logging.getLogger('chat')
     22 
     23 class BaseChatChannelController(object):
     24     __notifyevents__ = []
     25 
     26     def __init__(self, channel_id, category_id):
     27         self._is_closing = False
     28         self._channel_id = channel_id
     29         self._category_id = category_id
     30         self._window_id = 'chatchannel_%s' % self._channel_id
     31         self._member_ids = set()
     32         self._pending_messages = set()
     33         self._messages = deque(maxlen=MAX_MESSAGES_IN_HISTORY)
     34         self._sent_message_timestamps = deque(maxlen=MAX_MESSAGES_PER_SEC)
     35         self._logfile = None
     36         self._muted = None
     37         self.on_members_set = signals.Signal('on_members_set')
     38         self.on_members_cleared = signals.Signal('on_members_cleared')
     39         self.on_member_added = signals.Signal('on_member_added')
     40         self.on_member_removed = signals.Signal('on_member_removed')
     41         self.on_member_data_changed = signals.Signal('on_member_data_changed')
     42         self.on_message_added = signals.Signal('on_message_added')
     43         self.on_messages_cleared = signals.Signal('on_messages_cleared')
     44         self.on_pending_message_removed = signals.Signal('on_pending_message_removed')
     45         self._register()
     46 
     47     def close(self):
     48         if self._is_closing:
     49             return
     50         self._is_closing = True
     51         self._pending_messages.clear()
     52         self._messages.clear()
     53         self._sent_message_timestamps.clear()
     54         self._unregister()
     55 
     56     def _register(self):
     57         sm.RegisterNotify(self)
     58         self.chat_service.on_member_data_changed.connect(self._on_member_data_changed)
     59 
     60     def _unregister(self):
     61         sm.UnregisterNotify(self)
     62         self.chat_service.on_member_data_changed.disconnect(self._on_member_data_changed)
     63 
     64     @property
     65     def chat_service(self):
     66         return sm.GetService('chat')
     67 
     68     @property
     69     def channel_id(self):
     70         return self._channel_id
     71 
     72     @property
     73     def category_id(self):
     74         return self._category_id
     75 
     76     @property
     77     def window_id(self):
     78         return self._window_id
     79 
     80     @property
     81     def window_display_name(self):
     82         return self.category_id
     83 
     84     @property
     85     def is_closable(self):
     86         return False
     87 
     88     @property
     89     def member_ids(self):
     90         return self._member_ids
     91 
     92     @property
     93     def member_count(self):
     94         return len(self._member_ids)
     95 
     96     @property
     97     def member_count_tooltip(self):
     98         return localization.GetByLabel('UI/Chat/CapsuleerCounterHint')
     99 
    100     @property
    101     def messages(self):
    102         return self._messages
    103 
    104     @property
    105     def message_count(self):
    106         return len(self._messages)
    107 
    108     @property
    109     def motd(self):
    110         return ''
    111 
    112     def close_by_user(self):
    113         self.chat_service.close_channel(self.channel_id)
    114 
    115     def clear_messages(self):
    116         if not self._messages:
    117             return
    118         self._messages.clear()
    119         self._pending_messages.clear()
    120         self._sent_message_timestamps.clear()
    121         self.on_messages_cleared()
    122 
    123     def _clear_members(self):
    124         if not self._member_ids:
    125             return
    126         self._member_ids.clear()
    127         self.on_members_cleared()
    128 
    129     def _on_member_data_changed(self, character_id, data):
    130         if character_id in self._member_ids:
    131             self.on_member_data_changed(character_id, data)
    132 
    133     def message_received(self, sender_id, text, message_id = None):
    134         if sender_id == session.charid:
    135             return
    136         if self.chat_service.is_blocked_character(sender_id, self.get_member_data(sender_id)):
    137             return
    138         if self.chat_service.is_reported_spammer(sender_id):
    139             return
    140         text = parse_chat_message(text)
    141         if not text:
    142             return
    143         if self.should_hide_message(text):
    144             return
    145         self._add_to_messages(sender_id, text)
    146 
    147     def should_hide_message(self, text):
    148         return should_hide_message(self.channel_id, self.category_id, text)
    149 
    150     def open_hide_message_settings(self):
    151         open_hide_message_settings(category_id=self.category_id, channel_id=self.channel_id, channel_name=self.channel_id)
    152 
    153     def add_game_message(self, text, sender_id = None):
    154         self._add_to_messages(sender_id, text)
    155 
    156     def can_send_chat_message(self):
    157         if self._is_at_sent_message_cap():
    158             prompt_player_fsd_dialog('uiwarning03')
    159             return False
    160         if self._muted:
    161             self.add_game_message(self._get_muted_reason(), sender_id=ownerSystem)
    162             return False
    163         return True
    164 
    165     def _is_at_sent_message_cap(self):
    166         if len(self._pending_messages) > MAX_PENDING_MESSAGES:
    167             return True
    168         if len(self._sent_message_timestamps) < MAX_MESSAGES_PER_SEC:
    169             return False
    170         return gametime.GetSecondsSinceWallclockTime(self._sent_message_timestamps[0]) < 1
    171 
    172     def send_chat_message(self, text):
    173         pass
    174 
    175     def _prime_unprimed_members(self, member_ids):
    176         members_to_prime = set()
    177         for member_id in member_ids:
    178             if not cfg.eveowners.GetIfExists(member_id):
    179                 members_to_prime.add(member_id)
    180 
    181         cfg.eveowners.Prime(members_to_prime)
    182 
    183     def set_members(self, members):
    184         if not members:
    185             self._clear_members()
    186             return
    187         members = {member_id:member_data for member_id, member_data in members.iteritems() if member_data['classification'] != CLASSIFICATION_INVISIBLE}
    188         self._member_ids = set(members.keys())
    189         self._prime_unprimed_members(self._member_ids)
    190         self.chat_service.update_members_info(members)
    191         self.on_members_set()
    192 
    193     def add_member(self, character_id, character_info = None):
    194         if character_id in self._member_ids:
    195             return
    196         if character_info and character_info['classification'] == CLASSIFICATION_INVISIBLE:
    197             return
    198         self._member_ids.add(character_id)
    199         if character_info:
    200             self.chat_service.update_members_info({character_id: character_info})
    201         self.on_member_added(character_id)
    202 
    203     def remove_member(self, character_id):
    204         if character_id not in self._member_ids:
    205             return
    206         self._member_ids.remove(character_id)
    207         self.on_member_removed(character_id)
    208 
    209     def can_invite_character(self, character_id):
    210         return False
    211 
    212     def invite_character(self, character_id):
    213         pass
    214 
    215     def get_member_data(self, member_id):
    216         return self.chat_service.get_member_info(member_id)
    217 
    218     def has_member_data(self, member_id):
    219         return self.chat_service.has_member_info(member_id)
    220 
    221     def get_color_for_sender(self, member_id):
    222         if member_id in (ownerSystem, ownerNone):
    223             return '0xb2ee6666'
    224         if self.has_member_data(member_id):
    225             sender_classification = self.get_member_data(member_id).get('classification', None)
    226             return CLASSIFACTION_TO_COLOR.get(sender_classification, '0x99ffffff')
    227         try:
    228             name = cfg.eveowners.Get(member_id).name
    229             if name.startswith('GM'):
    230                 return CLASSIFACTION_TO_COLOR[MemberClassification.GAME_MASTER]
    231             if name.startswith('CCP'):
    232                 return CLASSIFACTION_TO_COLOR[MemberClassification.DEVELOPER]
    233             if name.startswith('ISD'):
    234                 return CLASSIFACTION_TO_COLOR[MemberClassification.VOLUNTEER]
    235             return '0x99ffffff'
    236         except:
    237             return '0x99ffffff'
    238 
    239     def set_muted(self, end_date, reason):
    240         self._muted = {'end_date': end_date,
    241          'reason': reason}
    242 
    243     def clear_muted(self):
    244         self._muted = None
    245 
    246     def mute_player(self, character_id, duration, reason):
    247         pass
    248 
    249     def _get_muted_reason(self):
    250         if not self._muted:
    251             return ''
    252         return self._muted['reason']
    253 
    254     def _add_to_messages(self, sender_id, text, timestamp = None, color = None):
    255         if not timestamp:
    256             timestamp = gametime.GetWallclockTime()
    257         if not color:
    258             color = self.get_color_for_sender(sender_id)
    259         text = CompleteAutoLinks(text)
    260         self._messages.append((sender_id,
    261          text,
    262          timestamp,
    263          color))
    264         self.on_message_added(sender_id, text, timestamp, color)
    265         self._write_to_log_file(sender_id, text, timestamp)
    266 
    267     def _add_pending_message(self, message_id):
    268         self._pending_messages.add(message_id)
    269         self._sent_message_timestamps.append(gametime.GetWallclockTime())
    270 
    271     def _remove_pending_message(self, message_id, was_delivered = True):
    272         if message_id not in self._pending_messages:
    273             return
    274         self._pending_messages.remove(message_id)
    275         self.on_pending_message_removed(message_id, was_delivered)
    276 
    277     def _close_logfile(self):
    278         if self._logfile:
    279             self._logfile.Close()
    280             self._logfile = None
    281 
    282     @threadutils.threaded
    283     def _setup_log_file(self):
    284         if self._logfile or not settings.user.ui.Get('logchat', True):
    285             return
    286         now = gametime.GetWallclockTime()
    287         if session.charid:
    288             character_name = cfg.eveowners.Get(session.charid).name
    289         else:
    290             logger.warning('_SetupLogfile %s: No charid in session. Listener will be unknown character in chatlog' % self.window_display_name)
    291             character_name = 'unknown_character'
    292         chatlog = CHATLOG_TEMPLATE % (self.channel_id,
    293          self.window_display_name,
    294          character_name,
    295          FmtDate(now))
    296         year, month, weekday, day, hour, minute, second, msec = blue.os.GetTimeParts(now)
    297         date_time = '%d%.2d%.2d_%.2d%.2d%.2d' % (year,
    298          month,
    299          day,
    300          hour,
    301          minute,
    302          second)
    303         filename = '%s_%s' % (self.window_display_name, date_time)
    304         filename = SanitizeFilename(filename)
    305         post_fix = '_%s' % session.charid if session.charid else ''
    306         filename = blue.sysinfo.GetUserDocumentsDirectory() + '/EVE/logs/Chatlogs/%s%s.txt' % (filename, post_fix)
    307         try:
    308             self._logfile = blue.classes.CreateInstance('blue.ResFile')
    309             if not self._logfile.Open(filename, 0):
    310                 self._logfile.Create(filename)
    311             self._logfile.Write(chatlog.encode('utf-16'))
    312         except Exception:
    313             self._logfile = None
    314             logger.exception('Failed to instantiate log file')
    315             sys.exc_clear()
    316 
    317     @threadutils.threaded
    318     def _write_to_log_file(self, sender_id, text, timestamp):
    319         if self._logfile is None or self._logfile.size <= 0:
    320             return
    321         text_without_tags = StripTags(text).replace('&lt;', '<').replace('&gt;', '>').replace('&amp;', '&')
    322         try:
    323             if sender_id is None:
    324                 who = localization.GetByLabel('UI/Common/Message')
    325             else:
    326                 who = cfg.eveowners.Get(int(sender_id)).name
    327         except:
    328             who = sender_id
    329 
    330         line = '[%20s ] %s > %s\r\n' % (FmtDate(timestamp), who, text_without_tags)
    331         try:
    332             self._logfile.Write(line.encode('utf-16'))
    333         except:
    334             logger.error('Failed to write chat message to logfile', sender_id, text)