def increment(table, column_value, where): if not column_value: return False sets = '' for i in column_value: if where.startswith(i): continue if type(column_value[i]) is str: sets += f'''{i}='{column_value[i]}',''' else: sets += f'''{i}={i}+{column_value[i]},''' sql = f'''UPDATE {table} SET {sets[:-1]} WHERE {where}''' cursor = _conn.cursor() cursor.execute("BEGIN") try: cursor.execute(sql) except OperationalError: FileLogger.exception(f'Exception at {__file__} {__name__}\nSQL: {sql}') _conn.rollback() return False cursor.execute("COMMIT") _conn.commit() return True
def fill_sheet(player_discord_id, description, play_number, boss_tag, damage, play_option, play_miss): global _undo, _sheet_lock if player_discord_id not in _player_list: FileLogger.warn(f'Discord ID: {player_discord_id} not found in sheet') return False player_nickname = _player_list[player_discord_id] today = get_settlement_time_object() play_tag = f"{play_number}{'B' if play_option == '補' else 'A'}" missing_tag = '閃' if play_miss > 0 else '' body = { 'values': [[ today.strftime("%Y/%m/%d %H:%M:%S"), player_nickname, play_tag, damage, boss_tag, missing_tag ]] } play_day_offset = today - _start_date range_name = f'Day {play_day_offset.days + 1}-Log!A2:F' _sheet_lock.acquire() result = append_sheet(range_name, body) _sheet_lock.release() checkResult = True try: updates = result.get('updates') updated_range = updates.get('updatedRange') _undo['undostack'].append([updated_range, body, description]) _undo['redostack'] = [] except Exception as e: FileLogger.error(f'Fail to get result: {description}\n' + str(e)) checkResult = False return checkResult
def setup_guild_member_list(guild, override=False): global timer_member, _guild_member_list if bool(_guild_member_list): elapsed_time = time() - timer_member if elapsed_time < 86400 and not override: return FileLogger.info(f'Setting up members in {guild.name}') _guild_member_list = {} for i in range(0, len(guild.members)): valid = False for role in guild.members[i].roles: if role.name == '隊員': valid = True break if not valid: continue nick = guild.members[i].nick display_name = guild.members[i].display_name if nick: _guild_member_list[guild.members[i].id] = nick elif display_name: _guild_member_list[guild.members[i].id] = display_name else: _guild_member_list[guild.members[i].id] = guild.members[i].name timer_member = time()
def setup_guild_channel_list(guild, override=False): global timer_channel, _guild_channel_list, _guild_channel_board if bool(_guild_channel_list): elapsed_time = time() - timer_channel if elapsed_time < 86400 and not override: return FileLogger.info(f'Setting up channels in {guild.name}') _guild_channel_list = {} for channel in guild.channels: if channel.type.name == 'text' and channel.category.name.endswith( '公會戰討論區'): if channel.name.startswith('一王'): _guild_channel_list[1] = channel.id _guild_channel_list[channel.id] = 1 elif channel.name.startswith('二王'): _guild_channel_list[2] = channel.id _guild_channel_list[channel.id] = 2 elif channel.name.startswith('三王'): _guild_channel_list[3] = channel.id _guild_channel_list[channel.id] = 3 elif channel.name.startswith('四王'): _guild_channel_list[4] = channel.id _guild_channel_list[channel.id] = 4 elif channel.name.startswith('五王'): _guild_channel_list[5] = channel.id _guild_channel_list[channel.id] = 5 if channel.type.name == 'text' and channel.name.endswith('刀傷登記區'): _guild_channel_board = channel.id timer_channel = time()
def insert(table, column_value): if not column_value: return False columns = '' values = '' for i in column_value: columns += f'{i},' if type(column_value[i]) is str: values += f'\'{column_value[i]}\',' else: values += f'{column_value[i]},' play_date = get_settlement_time() sql = f'''INSERT INTO {table} ({columns}play_date) VALUES ({values}'{play_date}')''' cursor = _conn.cursor() cursor.execute("BEGIN") try: cursor.execute(sql) except OperationalError: FileLogger.exception(f'Exception at {__file__} {__name__}\nSQL: {sql}') _conn.rollback() return False cursor.execute("COMMIT") _conn.commit() return True
def backup(self): result = False with self._lock: with open(self._store_path, 'w', encoding="utf-8") as f: try: f.write(repr(self._store)) result = True except Exception as e: FileLogger.error(f'Fail to write dictionary: {str(e)}') return result
def read_sheet(range_name): try: sheets = _service.spreadsheets() result = sheets.values().get(spreadsheetId=_spreadsheet_id, range=range_name).execute() except Exception as e: FileLogger.error( f'Fail to read sheet: ID={_spreadsheet_id}, range={range_name}\n' + str(e)) return return result.get('values', [])
def clear_line(boss_id: int) -> bool: global _guild_lines if boss_id in _guild_lines: _guild_lines[boss_id]["player_ids"] = {} elif boss_id == 0: for key in _guild_lines: _guild_lines[key]["player_ids"] = {} else: return False backup() FileLogger.info('clear_line executed') return True
def get_player_list(): global _player_list values = read_sheet('隊員列表!B2:C') if not values: FileLogger.error('No player list found.') return None else: _player_list = {} for row in values: _player_list[int(row[1])] = row[0] return _player_list
def append_sheet(range_name, body, option='RAW'): try: sheets = _service.spreadsheets() result = sheets.values().append(spreadsheetId=_spreadsheet_id, range=range_name, body=body, valueInputOption=option).execute() except Exception as e: FileLogger.error( f'Fail to append sheet: ID={_spreadsheet_id}, range={range_name}\n' + str(e)) return return result
def setpath(self, path: str) -> bool: result = False self._store_path = path if exists(path): with open(path, 'r', encoding="utf-8") as f: spam_setting_str = f.read() if spam_setting_str: try: self._store = eval(spam_setting_str) result = True except Exception as e: FileLogger.error(f'Fail to read dictionary: {str(e)}') self._store = dict() return result
def get_start_date(): global _start_date values = read_sheet('隊員列表!A1:A1') if not values: FileLogger.error('No start date found.') return None else: date_tokens = values[0][0].split('/') settlement_time = get_settlement_time_object() _start_date = datetime( year=int(date_tokens[0]), month=int(date_tokens[1]), day=int(date_tokens[2])).replace(tzinfo=settlement_time.tzinfo) return _start_date
def query(table, where): cursor = _conn.cursor() sql = f'''SELECT * FROM {table} WHERE {where}''' result = [] try: cursor.execute(sql) row = cursor.fetchone() while row: column_value = {} for i in range(len(cursor.description)): column_value[str(cursor.description[i][0])] = row[i] result.append(column_value) row = cursor.fetchone() except OperationalError: FileLogger.exception(f'Exception at {__file__} {__name__}\nSQL: {sql}') return result
async def on_message(message): if message.content == '!stop' and message.author.guild_permissions.administrator: FileLogger.info('User requested shutdown') execute() await client.logout() return # we do not want the bot to reply to itself if message.author.bot: return if message.content.startswith('!') or message.content.startswith('!'): setup_guild_channel_list(message.author.guild) setup_guild_member_list(message.author.guild) user_auth = { 'guild_id': message.author.guild.id, 'user_id': message.author.id, 'user_admin': message.author.guild_permissions.administrator, 'channel_id': message.channel.id } content = message.content[1:] if message.attachments: content += f' {message.attachments[0].url}' msg = parse_args(user_auth, content) if msg: if isinstance(msg, Mapping): # it's a dict embed = get_embed(message.author, msg) await message.channel.send(embed=embed) elif isinstance(msg, list): # it's a list embed = embed_template(message.author) for i in range(len(msg)): embed.add_field(name=i, value=msg[i], inline=False) await message.channel.send(embed=embed) elif is_url(msg): # it's an url embed = Embed(color=0xffa200) embed.set_image(url=msg) await message.channel.send(embed=embed) else: await message.channel.send(msg)
def redo(): global _undo, _sheet_lock op = _undo['redostack'][-1] _undo['redostack'] = _undo['redostack'][0:-1] (range_name, body, description) = op _sheet_lock.acquire() result = write_sheet(range_name, body) _sheet_lock.release() try: updated_range = result.get('updatedRange') except Exception as e: FileLogger.error(f'Fail to get redo result: {description}\n' + str(e)) if updated_range and range_name == updated_range: _undo['undostack'].append([updated_range, body, description]) return description else: FileLogger.error(f'Inconsistent redo result: {description}') return None
def parse_args(user_auth, string): args = strQ2B(string).split() response = '' if not args: return response # Find command, otherwise consider it as spam cmd = get_cmd(args[0]) if cmd: args = args[1:] else: cmd = "spam" # Create the instance try: inst = getattr(globals()[cmd], cmd)() except KeyError: FileLogger.warn(f'No command found') except Exception: FileLogger.exception(f'Exception at {__file__} {__name__}') # Execute the function FileLogger.info(f"{user_auth['user_id']} call {cmd} with {args}") try: if len(args) == 1 and args[0] == 'help': response = inst.usage elif not inst.check_param(args): response = inst.usage elif not inst.check_auth(user_auth): response = inst.auth_warning else: response = inst.run(user_auth, args) except Exception: FileLogger.exception(f'Exception at {__file__} {__name__}') return response
# -*- coding: utf-8 -*- import json import functools import traceback from utils.log import FileLogger, Logger DEBUG = True if not DEBUG: logger = FileLogger('wshandler.txt') else: logger = Logger() def on_redis(func): @functools.wraps(func) def _wrap(*args, **kwargs): func(*args, **kwargs) return _wrap def on_ws(func): @functools.wraps(func) def _wrap(*args, **kwargs): func(*args, **kwargs) return _wrap
monkey.patch_all() from gevent import Greenlet import redis from utils.redissub import RedisSub from utils.redisvalue import RemoteRedis import utils.exprv from components.autohost import AutoHost from utils.log import FileLogger, Logger import components.hub as hub import components.hosthandler as hosthandler DEBUG = True if not DEBUG: logger = FileLogger('expserver.txt') else: logger = Logger() exp_list = {} rc = redis.Redis() db = torndb.Connection("localhost", 'exp', user='******', password='******') class Server(Greenlet): def __init__(self, channel='experiment'): super(Server, self).__init__() self.redis = rc self.sub = RedisSub(channel, self.on_message)
async def on_ready(): FileLogger.info(f'Logged in as {client.user.name}({client.user.id})') for guild in client.guilds: setup_guild_channel_list(guild, True) setup_guild_member_list(guild, True)
def get_guild_member_nickname(user_id): if user_id not in _guild_member_list: FileLogger.warn('Unknown user id') return return _guild_member_list[user_id]
def get_guild_channel_index(channel_id): if channel_id not in _guild_channel_list: FileLogger.warn('Unknown channel id') return return _guild_channel_list[channel_id]
def get_guild_channel_id(boss_index): if boss_index not in _guild_channel_list: FileLogger.warn('Unknown boss index') return return _guild_channel_list[boss_index]
def get_settlement_time_object(): return datetime.now(_eu_moscow) def get_settlement_time(): return datetime.now(_eu_moscow).strftime('%Y-%m-%d') _transition_point = get_settlement_time_object().replace(hour=0, minute=0, second=0, microsecond=0) _local_transition_point = _transition_point.astimezone() FileLogger.info(f"Schedule daily task clear_line at {_local_transition_point}") schedule.every().day.at(_local_transition_point.strftime('%H:%M:%S')).do( clear_line, boss_id=0) cease_continuous_run = threading.Event() class ScheduleThread(threading.Thread): @classmethod def run(cls): while not cease_continuous_run.is_set(): schedule.run_pending() time.sleep(1) continuous_thread = ScheduleThread()