def Reply(self, channel: types.Target, msg: MessageType, default_channel: Optional[Channel] = None, limit_lines: bool = False, max_public_lines: int = 6, user: Optional[types.User] = None, log: bool = False, log_level: int = logging.INFO) -> None: """Sends a message to the channel. Leaving Reply on the HypeCore allows replacing the interface to process nested commands. However, some change will be needed in order to actually create an OutputUtil for HBDS without a HypeCore. Args: channel: Who/where to send the message. msg: The message to send. default_channel: Who/where to send the message if no channel is specified. limit_lines: Whether to limit lines or not. max_public_lines: Maximum number of lines to send to a public channel. user: If specified, where to send the message if its too long. log: Whether to also log the message. log_level: How important the log is. """ if not msg: return if log: text_msg = msg logging.log(log_level, text_msg, exc_info=log_level == logging.ERROR) channel = channel or default_channel if not channel: logging.info('Attempted to send message with no channel: %s', msg) return # Support legacy Reply to users as a string. if not isinstance(channel, Channel): # Send messages for sub-accounts to the real user. channel = Channel(id=channel.split(':')[0], visibility=Channel.PRIVATE, name=channel) if (limit_lines and channel.visibility == Channel.PUBLIC and isinstance(msg, list) and len(msg) > max_public_lines): if user: self.interface.SendMessage( channel, _MakeMessage('It\'s long so I sent it privately.')) self.interface.SendMessage( Channel(id=user, visibility=Channel.PRIVATE, name=user), _MakeMessage(msg)) else: # If there is no user, just truncate and send to channel. self.interface.SendMessage( channel, _MakeMessage(msg[:max_public_lines] + ['...'])) else: self.interface.SendMessage(channel, _MakeMessage(msg))
def __init__( self, params: Any, # HypeParams interface: interface_lib.BaseChatInterface) -> None: """Constructs core of hypebot. Args: params: Bot parameters. interface: This will always be the original interface that the bot was created with, and never the CaptureInterface during nested calls. For this reason, you should only call Join/Part and potentially Notice/Topic on this interface. Don't call SendMessage or else it can send messages never intended for human consumption. hypeletter_callback: brcooley get rid of this when migrating hypeletter to its own command. """ self.params = params self.nick = self.params.name.lower() self.interface = interface self.output_util = OutputUtil(self.Reply) self.store = storage_factory.CreateFromParams(self.params.storage) cached_type = self.params.storage.get(self.params.storage.type, {}).get('cached_type') if cached_type: self.cached_store = storage_factory.Create( cached_type, self.params.storage.get(self.params.storage.type)) else: logging.info( 'No cached_type found for storage, using default store.') self.cached_store = self.store self.user_tracker = util_lib.UserTracker() self.timezone = self.params.time_zone self.scheduler = schedule_lib.HypeScheduler(self.timezone) self.executor = futures.ThreadPoolExecutor(max_workers=8) self.runner = async_lib.AsyncRunner(self.executor) self.inventory = inventory_lib.InventoryManager(self.store) self.proxy = proxy_lib.Proxy(self.store) self.zombie_manager = zombie_lib.ZombieManager(self.Reply) self.request_tracker = RequestTracker(self.Reply) self.bank = coin_lib.Bank(self.store, self.nick) self.bets = coin_lib.Bookie(self.store, self.bank, self.inventory) self.stocks = stock_factory.CreateFromParams(self.params.stocks, self.proxy) self.deployment_manager = deploy_lib.DeploymentManager( self.nick, self.bets, self.output_util, self.executor) self.hypestacks = hypestack_lib.HypeStacks(self.store, self.bank, self.Reply) self.betting_games = [] self.last_command = None self.default_channel = Channel(visibility=Channel.PUBLIC, **self.params.default_channel.AsDict())
async def on_message(message): # Discord doesn't protect us from responding to ourself. if message.author == self._client.user: return logging.info('Message from: %s - %s#%s - %s', message.author.name, message.author.display_name, message.author.discriminator, message.author.id) channel = Channel( id=message.channel.id, visibility=(Channel.PRIVATE if message.channel.is_private else Channel.PUBLIC), name=message.channel.name) self._on_message_fn(channel, message.author.name, self._CleanContent(message))
def __init__(self, params): super(HypeBot, self).__init__(params) api_key = (self._params.riot.api_key or self._core.store.GetValue('api_key', 'key')) if not api_key: logging.fatal('api_key failed to load') self._core.rito = rito_lib.RitoLib(self._core.proxy, self._params.riot.api_address) self._core.rito.api_key = api_key self._core.game = game_lib.GameLib(self._core.rito) self._core.summoner = summoner_lib.SummonerLib(self._core.rito, self._core.game) self._core.summoner_tracker = summoner_lib.SummonerTracker( self._core.rito) self._core.esports = esports_lib.EsportsLib(self._core.proxy, self._core.executor, self._core.game, self._core.timezone) self._core.items = items_lib.ItemsLib(self._core.rito) # Trivia can probably be self contained once multiple parsers exist. self._core.trivia = trivia_lib.TriviaMaster(self._core.game, self._OnNewTriviaQuestion, self._OnTriviaQuestionDone, self._OnTriviaLeaderboard) for chan in self._params.trivia_channels: channel = Channel(visibility=Channel.PUBLIC, **chan) self._core.trivia.MakeNewChannel(channel) self._core.lcs_channel = Channel(visibility=Channel.PUBLIC, **self._params.lcs_channel.AsDict()) # Place LCS gambling first, so it beats Stock to taking the game. self._lcs_game = vegas_game_lib.LCSGame(self._core.esports) self._core.betting_games.insert(0, self._lcs_game) # Give _esports a chance at loading before trying to resolve LCS bets self._core.scheduler.FixedRate(5 * 60, 30 * 60, self._LCSGameCallback)
def _ProcessNestedCalls(self, channel, user, msg): """Evaluate nested commands within $(...).""" m = self.NESTED_PATTERN.search(msg) while m: backup_interface = self._core.interface self._core.interface = interface_factory.Create( 'CaptureInterface', {}) # Pretend it's Private to avoid ratelimit. nested_channel = Channel(id=channel.id, visibility=Channel.PRIVATE, name=channel.name) self.HandleMessage(nested_channel, user, m.group(1)) response = self._core.interface.MessageLog() msg = msg[:m.start()] + response + msg[m.end():] self._core.interface = backup_interface m = self.NESTED_PATTERN.search(msg) return msg
def _Handle(self, channel, user, channel_name): self._core.interface.Leave( Channel(id=channel_name, visibility=Channel.PUBLIC, name=channel_name))