Example #1
0
async def on_command_error(context, exception):
    """ Handle errors that are given from the bot. """
    if settings.DEBUGGING:
        logger.log(exception)
        traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr)

    cmd = context.invoked_with
    channel = context.message.channel

    if isinstance(exception, commands.CommandNotFound):
        await channel.send(f'Command "{cmd}" unknown. Try "?help"', delete_after=settings.DEFAULT_DELETE_DELAY)

    elif isinstance(exception, discord.InvalidArgument):
        await channel.send(f'Invalid argument for command "{cmd}". Try "?help {cmd}"',
                           delete_after=settings.DEFAULT_DELETE_DELAY)

    elif isinstance(exception, commands.MissingRequiredArgument):
        await channel.send(f'Missing argument for command "{cmd}". Try "?help {cmd}"',
                           delete_after=settings.DEFAULT_DELETE_DELAY)

    elif isinstance(exception, commands.CommandInvokeError):
        await channel.send('Oops, looks like something on the back end broke. Please contact @mildmelon#5380.',
                           delete_after=settings.DEFAULT_DELETE_DELAY)

    await asyncio.sleep(settings.DEFAULT_DELETE_DELAY)
    await context.message.delete()
Example #2
0
 def _cleanup_zombie_vpn(self, delay=1, log_lvl=logger.DEBUG):
     time.sleep(delay)
     logger.log(log_lvl, 'Cleanup the VPN zombie processes...')
     SystemHelper.kill_by_process(f'{self.vpn_dir}/vpnclient execsvc',
                                  silent=True,
                                  log_lvl=logger.down_lvl(log_lvl))
     self.device.ip_resolver.cleanup_zombie(f'vpn_')
Example #3
0
    async def _help(self, context, *extra_commands):
        """ Get this message from the bot, and add a mailbox emoji to your help command. """
        author = context.author
        channel = context.message.channel
        dm_channel = author.dm_channel
        message = context.message

        if dm_channel is None:
            dm_channel = await author.create_dm()

        # hacky way to force the help message into a dm instead of guild channel
        context.message.channel = dm_channel
        if len(extra_commands) != 0:
            await _default_help_command(context, *extra_commands)
        else:
            await _default_help_command(context)
        # undo the hacks
        context.message.channel = channel

        if context.guild:
            try:
                # try to add a :mailbox: reaction
                await message.add_reaction(Reaction.MAILBOX.value)
            except (discord.HTTPException, discord.Forbidden, discord.NotFound,
                    discord.InvalidArgument) as e:
                # if the reaction failed, then send a basic message
                logger.log(f'Could not add :mailbox: reaction, {e}')
                await channel.send(
                    f"Sent you a list of the commands, {author.name}")
Example #4
0
 def is_running(self, log_lvl=logger.DEBUG) -> bool:
     logger.log(log_lvl, 'Check if VPN is running...')
     pid = self._find_pid(logger.down_lvl(log_lvl))
     if pid:
         logger.log(log_lvl, f'VPN PID [{pid}]')
         return True
     self.cleanup()
     return False
Example #5
0
def _import_nonexistent(msg):
    """Import an object only if it does not exist in RE already."""
    upa = ':'.join([str(p) for p in [msg['wsid'], msg['objid'], msg['ver']]])
    log('INFO', f'_import_nonexistent on {upa}')  # TODO
    _id = 'wsfull_object_version/' + upa
    exists = check_doc_existence(_id)
    if not exists:
        _import_obj(msg)
Example #6
0
async def on_guild_update(before, after):
    """ When a guild updates, we want to update it's corresponding union. """
    # check to see if there is a union within the database already
    if game.check_union_exists(before):
        game.get_union(before).set_name(after.name)
        logger.log(f'Updated the union named "{before.name}" to "{after.name}"')
    else:
        # theoretically there can't be a case where a union is updated before it's created... except in testing
        await manage.ask_guild_to_join_game(game, bot, after)
Example #7
0
 def get_vpn_ip(self, nic: str, lenient=True):
     try:
         logger.log(self.log_lvl, f'Query VPN IPv4 on {nic}...')
         return netifaces.ifaddresses(nic)[netifaces.AF_INET]
     except Exception as err:
         if lenient:
             logger.debug(f'Not found VPN IP {nic}. Error: {err}')
             return None
         raise err
Example #8
0
 def create_config(self, vpn_acc: str, replacements: dict):
     config_file = self._to_config_file(vpn_acc)
     logger.log(self.log_lvl,
                f'Create DHCP client VPN config[{config_file}]...')
     FileHelper.copy(self.resource_dir.joinpath(self.DHCLIENT_CONFIG_TMPL),
                     config_file,
                     force=True)
     FileHelper.replace_in_file(config_file, replacements, backup='')
     FileHelper.chmod(config_file, mode=0o0644)
Example #9
0
 def add_hook(self, service_name: str, replacements: dict):
     exit_hook_file = self._to_hook_file(service_name)
     logger.log(self.log_lvl,
                f'Create DHCP client VPN hook[{exit_hook_file}]...')
     FileHelper.copy(self.resource_dir.joinpath(
         self.DHCLIENT_EXIT_HOOK_TMPL),
                     exit_hook_file,
                     force=True)
     FileHelper.replace_in_file(exit_hook_file, replacements, backup='')
     FileHelper.chmod(exit_hook_file, mode=0o0744)
Example #10
0
 def _check_pid(pid_file: str, log_lvl=logger.TRACE) -> int:
     try:
         logger.log(log_lvl, f'Read PID file {pid_file}')
         pid = FileHelper.read_file_by_line(pid_file)
         pid = int(pid)
         if pid and pid > 0 and SystemHelper.is_pid_exists(pid):
             return pid
     except Exception as _:
         FileHelper.rm(pid_file)
     return 0
Example #11
0
 def setUpClass(cls):
     # Initialize specs
     log('INFO', 'Initializing specs for the RE API..')
     resp = requests.put(
         _CONFIG['re_api_url'] + '/api/v1/specs',
         headers={'Authorization': _CONFIG['ws_token']},
         params={'init_collections': '1'}
     )
     resp.raise_for_status()
     log('INFO', 'Done initializing RE specs.')
Example #12
0
    async def logout(self, context):
        """ Command only available to developers.

        Have IsleBot logout and close all connections.
        """
        is_admin(context.author)

        logger.log('Logging out...')
        logger.write_logs(logout=True)
        await context.send('Logging out...')
        await self.bot.logout()
Example #13
0
 def do_disconnect_current(self,
                           must_disable_service=False,
                           log_lvl: int = logger.INFO,
                           silent: bool = True):
     account = self.storage.get_current()
     if not account:
         logger.log(logger.down_lvl(log_lvl), 'Not found any VPN account')
         return
     self.do_disconnect([account],
                        must_disable_service=must_disable_service,
                        log_lvl=log_lvl,
                        silent=silent)
Example #14
0
 def kill_by_pid(pid: list,
                 _signal=signal.SIGTERM,
                 silent=True,
                 log_lvl=logger.DEBUG):
     for p in pid or []:
         try:
             logger.log(log_lvl, f'Kill PID [{p}::{_signal}]...')
             os.kill(int(p), _signal)
         except OSError as err:
             SystemHelper.handle_kill_error(err, silent)
         except ValueError as err:
             logger.decrease(log_lvl, f'Error PID [{p}]. Error: {err}')
Example #15
0
 def lease_ip(self,
              vpn_acc: str,
              vpn_nic: str,
              daemon=False,
              is_execute=True):
     logger.log(self.log_lvl, 'Lease a new VPN IP...')
     command = f'{self.ip_tool} {self._lease_ip_opt(vpn_acc, vpn_nic, daemon)}'
     if is_execute:
         SystemHelper.exec_command(command,
                                   silent=self.silent,
                                   log_lvl=logger.down_lvl(self.log_lvl))
     return command
Example #16
0
 def pre_exec(self, silent=False, log_lvl=logger.DEBUG, **kwargs):
     logger.log(log_lvl, 'Start VPN Client if not yet running...')
     if not self.is_installed(silent, log_lvl):
         return
     if self.pid_handler.is_running():
         self._prev_is_run = True
         return
     SystemHelper.exec_command(f'{self.opts.vpnclient} start',
                               log_lvl=logger.down_lvl(log_lvl))
     time.sleep(1)
     if not self.pid_handler.is_running(log_lvl=logger.down_lvl(log_lvl)):
         logger.error('Unable start VPN Client')
         sys.exit(ErrorCode.VPN_START_FAILED)
Example #17
0
 def create_symlink(source: Union[str, Path], link: Union[str, Path], force=False, log_lvl=logger.DEBUG):
     src = Path(source)
     lk = Path(link)
     logger.log(log_lvl, f'Create symlink from [{src}] to [{lk}]...')
     if not FileHelper.is_exists(src):
         raise RuntimeError(f'Given file[{src}] is not existed')
     if FileHelper.is_exists(lk):
         if FileHelper.is_dir(lk):
             raise RuntimeError(f'Given target link[{lk}] is directory')
         if not force:
             raise RuntimeError(f'Given target link[{lk}] is existed')
         os.remove(lk)
     os.symlink(src, lk, target_is_directory=FileHelper.is_dir(src))
def wait_for_services():
    """Wait for dependency services such as the RE API."""
    timeout = int(time.time()) + 60
    while True:
        try:
            requests.get(_CONFIG['re_api_url'] + '/').raise_for_status()
            break
        except Exception as err:
            log('INFO', f'Service not yet online: {err}')
            if int(time.time()) >= timeout:
                raise RuntimeError("Timed out waiting for other services to come online.")
            time.sleep(3)
    log('INFO', 'Services started!')
Example #19
0
 def post_exec(self, silent=False, log_lvl=logger.DEBUG, **kwargs):
     logger.log(log_lvl, 'Stop VPN Client if applicable...')
     if not self.is_installed(True, log_lvl):
         return
     if (self._prev_is_run or
             not self.adhoc_task) and not kwargs.get('_force_stop', False):
         return
     lvl = logger.down_lvl(log_lvl)
     if self.pid_handler.is_running(log_lvl=lvl):
         SystemHelper.exec_command(f'{self.opts.vpnclient} stop',
                                   silent=silent,
                                   log_lvl=lvl)
         self._cleanup_zombie_vpn(1, log_lvl=lvl)
         self.pid_handler.cleanup()
Example #20
0
 def do_connect(self, account: str, log_lvl: int = logger.INFO):
     if not account:
         logger.error(f'VPN account is not correct')
         sys.exit(ErrorCode.INVALID_ARGUMENT)
     acc = self.storage.find(account)
     if not acc:
         logger.error(f'Not found VPN account')
         sys.exit(ErrorCode.VPN_ACCOUNT_NOT_FOUND)
     logger.log(log_lvl, f'Connect VPN account [{account}]...')
     self.storage.create_or_update(acc, _connect=True)
     self.exec_command(['AccountConnect'], params=account)
     self.lease_vpn_service(is_enable=acc.is_default,
                            is_restart=acc.is_default,
                            is_lease_ip=not acc.is_default,
                            account=acc.account)
Example #21
0
 def do_uninstall(self,
                  keep_vpn: bool = True,
                  keep_dnsmasq: bool = True,
                  service_opts: UnixServiceOpts = None,
                  log_lvl: int = logger.INFO):
     vpn_service = self._standard_service_opt(service_opts).service_name
     logger.info(f'Uninstall VPN service [{vpn_service}]...')
     self.do_delete([a.account for a in self.storage.list()],
                    force_stop=True,
                    log_lvl=log_lvl)
     if not keep_vpn:
         logger.log(log_lvl, f'Remove VPN Client [{self.opts.vpn_dir}]...')
         self.device.ip_resolver.remove_hook(vpn_service)
         self.opts.remove_env()
         FileHelper.rm(self.opts.vpn_dir)
     self.device.dns_resolver.cleanup_config(vpn_service,
                                             keep_dnsmasq=keep_dnsmasq)
Example #22
0
 def do_delete(self,
               accounts: Sequence[str],
               log_lvl: int = logger.INFO,
               silent: bool = True,
               force_stop=False):
     cur_acc = self.storage.get_current()
     is_disable, is_stop = False, force_stop or cur_acc is None or cur_acc == ''
     for acc in accounts:
         logger.log(log_lvl, f'Delete VPN account [{acc}]...')
         is_default, is_current = self.storage.remove(acc)
         is_stop = is_current or is_stop
         is_disable = is_default or is_disable
         commands = ['AccountDisconnect', 'AccountDelete', 'NicDelete']
         if is_default:
             commands.insert(1, 'AccountStartupRemove')
             self.storage.set_default('')
         self.exec_command(commands, acc, silent, log_lvl)
     self.shutdown_vpn_service(is_stop=is_stop,
                               is_disable=is_disable,
                               log_lvl=log_lvl)
Example #23
0
async def ask_guild_to_join_game(bot, guild, channel=None):
    if channel is None:
        channel = find_open_channel(guild)

    # we don't to pollute our database with random guilds that are inactive, so ask first if they want to join
    confirm_msg = ConfirmMenu(
        bot,
        channel,
        [
            'Welcome, would you like this guild to be registered within the game?',
            'This guild will not be registered.',  # message when dismissed
            'This guild is now registered.'
        ])  # message when confirmed
    await confirm_msg.send()
    logger.log(
        f'Asking guild "{guild.name}" [id:{guild.id}] to join the game.')
    confirmed = await confirm_msg.wait_for_user_reaction()

    if confirmed:
        # create a new guild for the guild
        union = Game.create_union(guild)
        logger.log(f'Created a new Union under the name "{union.name}"')
    else:
        await channel.send(
            'I am leaving this guild, as I am no longer needed. '
            'If you change your mind and would like to register this guild, just add me back.'
        )
        try:
            guild.leave()
        except HTTPException as exception:
            logger.log(exception)
            await channel.send(
                'Sorry to bother you, this is kind of embarrassing. '
                'I am having some trouble leaving, would you mind kicking me please?'
            )
Example #24
0
 def do_disconnect(self,
                   accounts: Sequence[str],
                   must_disable_service=False,
                   log_lvl: int = logger.INFO,
                   silent: bool = True):
     cur_acc = self.storage.get_current()
     is_stop = cur_acc is None or cur_acc == ''
     for acc in accounts:
         logger.log(log_lvl, f'Disconnect VPN account [{acc}]...')
         self.exec_command('AccountDisconnect',
                           params=acc,
                           log_lvl=logger.down_lvl(log_lvl),
                           silent=silent)
         self.device.ip_resolver.release_ip(acc,
                                            self.opts.account_to_nic(acc))
         self.device.ip_resolver.cleanup_zombie(
             f'--no-pid.* {self.opts.account_to_nic(acc)}')
         is_stop = acc == cur_acc or is_stop
     if is_stop:
         self.shutdown_vpn_service(is_stop=True,
                                   is_disable=must_disable_service,
                                   log_lvl=log_lvl)
Example #25
0
def _handle_msg(msg):
    """Receive a kafka message."""
    event_type = msg.get('evtype')
    wsid = msg.get('wsid')
    if not wsid:
        raise RuntimeError(f'Invalid wsid in event: {wsid}')
    if not event_type:
        raise RuntimeError(f"Missing 'evtype' in event: {msg}")
    log('INFO', f'Received {msg["evtype"]} for {wsid}/{msg.get("objid", "?")}')
    if event_type in ['IMPORT', 'NEW_VERSION', 'COPY_OBJECT', 'RENAME_OBJECT']:
        _import_obj(msg)
    elif event_type == 'IMPORT_NONEXISTENT':
        _import_nonexistent(msg)
    elif event_type == 'OBJECT_DELETE_STATE_CHANGE':
        _delete_obj(msg)
    elif event_type == 'WORKSPACE_DELETE_STATE_CHANGE':
        _delete_ws(msg)
    elif event_type in ['CLONE_WORKSPACE', 'IMPORT_WORKSPACE']:
        _import_ws(msg)
    elif event_type == 'SET_GLOBAL_PERMISSION':
        _set_global_perms(msg)
    else:
        raise RuntimeError(f"Unrecognized event {event_type}.")
Example #26
0
 def backup(src: Union[str, Path], dest: Union[str, Path] = None, remove=True, force=True,
            log_lvl=logger.DEBUG) -> str:
     """
     Backup
     :param src: given path
     :param dest: given destination or backup to same given source with suffix '.bak'
     :param remove: remove flag to decide removing source after backup
     :param force: force flag to decide removing dest if exists
     :param log_lvl: log level
     :return: the file destination
     """
     p = Path(src)
     t = Path(dest) if dest else p.parent.joinpath(p.name + '.bak')
     logger.log(log_lvl, f'Backup [{p}] to [{t}]...')
     if FileHelper.is_symlink(p):
         FileHelper.create_symlink(FileHelper.get_target_link(p), t, force)
         to = t
     else:
         to = FileHelper.copy_advanced(p, t, force)
     if remove:
         logger.log(log_lvl, f'Remove [{p}] after backup...')
         os.remove(p)
     return to
Example #27
0
 def exec_command(command: str,
                  shell=False,
                  silent=False,
                  log_lvl=logger.DEBUG) -> str:
     logger.decrease(log_lvl, "Execute command: %s", command)
     list_cmd = command.split(" | ") if not shell else [command]
     length = len(list_cmd)
     prev = None
     for idx, cmd in enumerate(list_cmd, 1):
         logger.trace("\tsub_command::%s::%s", cmd, prev)
         kwargs = {} if EnvHelper.is_py3_5() else {"encoding": "utf-8"}
         complete = subprocess.run(cmd.split() if not shell else cmd,
                                   input=prev,
                                   env=TWEAK_ENV,
                                   shell=shell,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   **kwargs)
         ret = complete.returncode
         lvl = (logger.TRACE if idx < length else
                logger.DEBUG) if ret == 0 or silent else logger.ERROR
         try:
             prev = SystemHelper.__handle_command_result(
                 complete, silent, lvl)
         except RuntimeError as _:
             if not silent:
                 logger.error('Failed when executing command %s', cmd)
                 sys.exit(ret)
         finally:
             ret_val = ("0. Actual: %s" %
                        ret) if silent and ret != 0 else ret
             logger.decrease(log_lvl, "%sReturn code: %s",
                             "\t" if idx < length else "", ret_val)
     if prev:
         logger.log(log_lvl, "\t%s", prev)
     return prev
Example #28
0
 def lease_vpn_ip(self, account: str, log_lvl=logger.DEBUG):
     logger.log(log_lvl, 'Wait a VPN session is established...')
     loop_interval(lambda: self.get_vpn_status(account)['connected'],
                   'Unable connect VPN',
                   max_retries=3,
                   interval=5)
     nic = self.opts.account_to_nic(account)
     if self.device.dns_resolver.is_connman(
     ) and not self.device.dns_resolver.is_enable_connman_dhcp():
         logger.log(
             logger.WARN, f'Please lease VPN IP manually by ' +
             f'[{self.device.ip_resolver.lease_ip(account, nic, daemon=True, is_execute=False)}]'
         )
         return
     logger.log(log_lvl, 'Wait a VPN IP is leased...')
     self.device.ip_resolver.lease_ip(account, nic, daemon=True)
Example #29
0
def _delete_obj(msg):
    """Handle an object deletion event (OBJECT_DELETE_STATE_CHANGE)"""
    log('INFO', '_delete_obj TODO')  # TODO
    raise NotImplementedError()
Example #30
0
def _import_obj(msg):
    log('INFO', 'Downloading obj')
    obj_info = download_info(msg['wsid'], msg['objid'], msg.get('ver'))
    import_object(obj_info)