def save_mem(): log.D('+ save memory to DB') module = sys.modules[ram.__name__] module_attrs = dir(module) variables = { key: getattr(module, key) for key in module_attrs if key[0] != '_' and not callable(getattr(module, key)) } conn = None rows = [] for var, val in variables.items(): if isinstance(val, dict): val = {k: v for k, v in val.items() if v != set()} if isinstance(val, (C.Types.Datetime, C.Types.Timedelta)): val = str(val) rows.append(( var, repr(val), )) try: conn = psycopg2.connect(C.DATABASE_URL, sslmode='require') cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cur.execute("TRUNCATE TABLE memory RESTART IDENTITY") query = "INSERT INTO memory (var, val) VALUES (%s, %s)" cur.executemany(query, rows) conn.commit() except psycopg2.DatabaseError as e: log.E('<ev.save_mem> DatabaseError %s' % e) # sys.exit(1) else: log.D('+ memory saved successfully') finally: if conn: conn.close()
async def on_voice_state_update_u(before, after): """ :type before: C.types.Member :type after: C.types.Member """ global voice_alert_msg v_old = before.voice_channel v_new = after.voice_channel if v_new: on_user_life_signs(after.id) if v_old == v_new: return if v_old and v_new: log.I('<voice> {0} reconnects from #{1} to #{2}.'.format( after, v_old, v_new)) elif v_old: log.I('<voice> {0} disconnects from #{1}.'.format(after, v_old)) elif v_new: log.I('<voice> {0} connects to #{1}.'.format(after, v_new)) note = com.voice_note(after) if note: log.D('<voice> Note event') await other.type2sent(after, note) await _del_voice_alert(after.id) user = None ch = None if (after.id in C.voice_alert and v_new) or (after.top_role > after.server.me.top_role): user = after ch = v_new # type: C.Types.Channel elif v_old and v_old.voice_members and v_old.voice_members[ 0].id in C.voice_alert: user = v_old.voice_members[0] await _del_voice_alert(user.id) ch = v_old # type: C.Types.Channel if user and ch and len(ch.voice_members) == 1 and not other.s_in_s( ('radio', 'радио'), ch.name.lower()): log.D('<voice> Event to @here') every_prm = ch.overwrites_for(ch.server.default_role) if every_prm.connect or (every_prm.connect is None and ch.server.default_role.permissions.connect): va_ids = voice_alert_ids.setdefault(user.id, []) va_msg = voice_alert_msg.setdefault(user.id, []) va_ids.append( com.write_msg(C.main_ch, text=com.voice_event(user, ch), save_obj=va_msg))
def timer_quarter_h(): global timer_quarter_works start_quarter_h_timer() try: log.D('+ Quarter hour timer event!') _timer_check_games() _timer_check_silence_in_chat() timer_quarter_works += 1 save() if timer_quarter_works % TMR_IN_H == 0: # hour_timer # other.later_coro(1, _timer_check_stuff()) mn = 4 else: mn = 1 log.D('+ Timer event finished!') log.p('------------------------------------- ' * mn) except Exception as e: other.pr_error(e, 'timer_quarter_h')
def save_texts_used(): log.D('+ save data_used to DB') conn = None rows = [(i, val) for i, val in enumerate(com.d2u.data_used)] try: conn = psycopg2.connect(C.DATABASE_URL, sslmode='require') cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cur.execute("TRUNCATE TABLE data_used RESTART IDENTITY") query = "INSERT INTO data_used (id, value) VALUES (%s, %s)" cur.executemany(query, rows) conn.commit() except psycopg2.DatabaseError as e: log.E('<ev.save_texts_used> DatabaseError %s' % e) else: log.D('+ data_used saved successfully') finally: if conn: conn.close()
async def time_sync(): # scan chat and get users time of last_message from history log.I('+ Time_sync start') t = {} mems = [mem.id for mem in C.vtm_server.members] for ch in C.vtm_server.channels: if str(ch.type) == 'text': t[ch.position] = ch channels = [t[k] for k in sorted(t)] log.D('- {0} channels prepare to scan:'.format(len(channels))) for i, ch in enumerate(channels): pr = ch.permissions_for(ch.server.me) if pr.read_message_history: log.D('+ {0}) {1} - check'.format(i + 1, ch.name)) mems_i = set(mems) count = 0 messes = [] async for mess in C.client.logs_from(ch, limit=1000000): messes.append(mess) for mess in messes: aid = mess.author.id if aid in mems_i: ts = other.get_sec_total(mess.timestamp) if ts > usrs[aid].last_m: usrs[aid].last_m = ts usrs[aid].status = 'upd' mems_i.remove(aid) if len(mems_i) < 1: break count += 1 if count % 10000 == 0: log.D('- - <time_sync> check messages: ', count, ', mems_i: ', len(mems_i)) log.D('+ {0}) {1} - done'.format(i + 1, ch.name)) else: log.D('-- {0}) {1} - not permissions for reading'.format( i + 1, ch.name)) log.I('+ Time_sync end') log.jD('Test results:') for mem in C.vtm_server.members: log.jD('{0} \t-\t {1}'.format(mem, other.sec2str(offtime(mem.id))))
async def do_check_and_embrace(name, clan_name=None): user = other.find_member(C.vtm_server, name) roles = set(role.id for role in user.roles).difference(C.other_roles) if len(roles) == 1: await just_embrace(user, clan_name=clan_name) # just_embrace_say(user, clan_name) # text = await do_embrace(user, clan_name=clan_name) # com.write_msg(C.main_ch, text) else: log.D('<do_check_and_embrace> Will not embrace, there are other roles.')
async def _rem_roles_coro(member, roles, error_msg='rem_roles'): log.D('Try rem roles ({r}) to @{m.display_name}.'.format( m=member, r=', '.join([r.name for r in roles]))) try: await C.client.remove_roles(member, *roles) return True except C.Exceptions.Forbidden: log.jW("[{}] Bot can't change roles.".format(error_msg)) except Exception as e: pr_error(e, error_msg, 'Error in changing roles') return False
async def sync(): # scan chat and get users array from messages in history log.I('+ Sync Start') count = 0 # print('[{0}] TEST'.format(other.t2s())) for mem in C.client.get_all_members(): distribute(mem) async for message in C.client.logs_from(C.main_ch, limit=1000000): distribute(message.author, other.get_sec_total(message.timestamp)) count += 1 if count % 10000 == 0: log.D('<sync> Check message: ', count) # for i in message.raw_mentions: # distribute(await C.client.get_user_info(i), message.timestamp) for usr in bans: distribute(usr) log.D('<sync> MESS COUNT = {0}'.format(str(count))) rewrite() log.I('+ Sync End')
async def tree_test(): import re embr_txt = ( '<@(?P<sir>\d+)> получает право на становление, и <@(?P<child>\d+)> теперь познает всю боль нежизни.', '<@(?P<sir>\d+)> дарует становление, но было ли получено разрешение, и что теперь ждёт новоявленое дитя <@(' '?P<child>\d+)>?', '<@(?P<child>\d+)> теперь находится под защитой клана и теперь за ним присмотрит его сир, <@(?P<sir>\d+)>', 'Не может быть, <@(?P<sir>\d+)> дарует становление неонату <@(?P<child>\d+)> - но является ли это наградой - ' 'или наказанием?', 'Витэ капнуло тут раз - <@(?P<sir>\d+)> теперь... сир у нас. Что ты об этом думаешь, <@(?P<child>\d+)>?', ) r_txt = [] for txt in embr_txt: r_txt.append(re.compile(txt)) ch = other.get_channel('flood') log.D('- <read> for {0}({1}) start'.format(ch, ch.id)) messages = [] count = 0 async for message in C.client.logs_from( ch, limit=1000000000): #type: C.Types.Message if message.author.id == C.users['bot'] and len(message.mentions) == 2: messages.append(message) count += 1 if count % 100 == 0: log.D('- - <read> save messages: ', count) log.D('- <read> end save with {0} messages'.format(count)) messages.reverse() log.D('- <read> start format messages') tree = {} for msg in messages: for r in r_txt: m = r.match(msg.content) if m: d = m.groupdict() tree[d['child']] = d['sir'] log.D(msg.clean_content) log.I(tree) log.I(len(tree))
def load(res=False): usrs_l = {} gone_l = {} conn = None if not res: log.D('- load people tables') try: conn = psycopg2.connect(C.DATABASE_URL, sslmode='require') cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cur.execute("SELECT * FROM members") rows = cur.fetchall() for row in rows: # type: dict u = Usr.load(row) usrs_l[u.id] = u cur.execute("SELECT * FROM users_gone") rows = cur.fetchall() for row in rows: # type: dict g = Gn.load(row) gone_l[g.id] = g except psycopg2.DatabaseError as e: log.E('DatabaseError %s' % e) sys.exit(1) else: if not res: log.D('+ people tables loaded successfully') finally: if conn: conn.close() if res: return {'usrs': usrs_l, 'gone': gone_l} else: global usrs, gone usrs = usrs_l gone = gone_l
def load_texts_used(): log.D('+ load data_used from DB') conn = None com.d2u.data_used = [] try: conn = psycopg2.connect(C.DATABASE_URL, sslmode='require') cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cur.execute("SELECT * FROM data_used ORDER BY id") rows = cur.fetchall() for row in rows: com.d2u.data_used.append(row['value']) except psycopg2.DatabaseError as e: log.E('<ev.load_texts_used> DatabaseError %s' % e) else: log.I('+ data_used loaded successfully') finally: if conn: conn.close()
def change_roles(callback, member, roles, error_msg='', delay=0, by_id=False, server_roles=None): """ :param callback: :param member: :param roles: :param error_msg: :param delay: float|int in seconds :param by_id: :param server_roles: :return: """ if not roles: return if not isinstance(roles, list): if is_iterable(roles): roles = list(roles) else: roles = [roles] if not error_msg: error_msg = callback if by_id: roles = get_roles(roles, server_roles) log.D('Try {t} to @{m.display_name} roles ({r}) // {msg}'.format( m=member, t=callback.__name__, r=', '.join([r.name for r in roles]), msg=error_msg)) later_coro(delay, callback(member, roles, error_msg))
async def on_member_update_u(before: C.Types.Member, after: C.Types.Member): # it's triggers on changing status, game playing, avatar, nickname or roles # if after.id == C.users['bot']: return smth_happend = False a_n = other.uname(after) + f' [{after.id}]' if before.display_name != after.display_name or before.name != after.name: smth_happend = True b_n = other.uname(before) log.pr_news(f'<on_member_update> {b_n} change nickname to {a_n}.') if before.game != after.game: smth_happend = True if before.game and after.game: log.D( f'<on_member_update> {a_n} go play from {before.game.name} to {after.game.name}.' ) elif before.game: log.D(f'<on_member_update> {a_n} stop play {before.game.name}.') elif after.game: log.D(f'<on_member_update> {a_n} start play {after.game.name}.') else: log.D( f'<on_member_update> {{???}} {a_n} - game change, but there are no games...' ) if after.id == C.users['Natali']: if before.game and C.prm_server.me.game.name == before.game.name: await other.set_game('') if after.game and not C.prm_server.me.game: await other.set_game(after.game.name) user_g = user_games.pop(after.id, {'name': '', 'h': 0}) # degradation if False and other.rand() < 0.5 and ( before.game and before.game.name and after.id not in ram.ignore_users and people.was_writing( after.id, 48) and user_g['h'] >= TMR_IN_H): phr = com.get_t('game', user=f'<@{after.id}>', game=f"«{user_g['name']}»") com.write_msg(C.main_ch, phr) if after.game and after.game.name: user_games[after.id] = {'name': after.game.name, 'h': 0} if before.avatar_url != after.avatar_url: smth_happend = True urls = [] for url in (before.avatar_url, after.avatar_url): urls.append(' ?'.join(url.split('?', maxsplit=1))) b_url, a_url = urls if before.avatar_url and after.avatar_url: await log.pr_avs( f'<on_member_update> {a_n} change avatar from \n{a_url} \nto\n{b_url}' ) elif before.avatar_url: await log.pr_avs( f'<on_member_update> {a_n} delete avatar: \n{b_url}') elif after.avatar_url: await log.pr_avs(f'<on_member_update> {a_n} set avatar: \n{a_url}') else: log.I( f'<on_member_update> {{???}} {a_n} - avatar change, but there are no avatar_urls...' ) # small degradation if (other.rand() < 0.01 and after.avatar_url and after.id not in ram.ignore_users and people.was_writing(after.id, 48)): phr = com.get_t('new_avatar', user=f'<@{after.id}>') com.write_msg(C.main_ch, phr) if before.roles != after.roles: smth_happend = True old_roles = [('@&' + r.name) for r in before.roles if r not in after.roles] new_roles = [('@&' + r.name) for r in after.roles if r not in before.roles] if old_roles: log.pr_news( f'<on_member_update> {a_n} lost role(s): {", ".join(old_roles)}.' ) if new_roles: log.pr_news( f'<on_member_update> {a_n} get role(s): {", ".join(new_roles)}.' ) new_role_ids = {r.id for r in after.roles if r not in before.roles} new_clan_roles = C.clan_ids.intersection(new_role_ids) has_clan_before = other.has_roles(before, C.clan_ids) if after.id not in not_embrace and new_clan_roles and not has_clan_before: clan_id = other.choice(new_clan_roles) clan_name = C.role_by_id[clan_id] log.pr_news( f'<on_member_update> {a_n} get new clan role "{clan_name}" => call do_embrace.' ) manager.just_embrace_say(after, clan_name=clan_name) # if sir_id: # if clan_id in C.clan_channels: # clan_ch = C.clan_channels[clan_id] # phr = com.get_t(all_keys=('clan_welcome', clan_ch), user=f'<@{after.id}>', sir=f'<@{sir_id}>') # com.write_msg(clan_ch, phr) elif has_clan_before and C.roles['Pander'] in new_clan_roles: log.jI( f'<on_member_update> {a_n} go to Pander => delete other clan roles if it\'s exist.' ) del_clans_id = C.clan_ids.difference({C.roles['Pander']}) rem_roles = {r for r in after.roles if r.id in del_clans_id} if rem_roles: other.rem_roles(after, rem_roles, 'on_member_update_u[1]') str_rem_r = f"<@&{'>, <@&'.join(r.id for r in rem_roles)}>" phr = com.get_t('to_Pander', user=f'<@{after.id}>', old_clans=str_rem_r, pander=f"<@&{C.roles['Pander']}>") com.write_msg(C.main_ch, phr) elif C.roles['Mortal'] in new_role_ids: if has_clan_before: # go to food rem_roles = { r for r in after.roles if r.id not in C.mortal_can_have_roles } other.rem_roles(after, rem_roles, 'go to Mortal(food)') log.pr_news(f'<on_member_update> {a_n} go to food') else: # new user await C.client.send_message(C.main_ch, com.welcome_msg(before.id)) log.pr_news(f'<on_member_update> {a_n} welcome') if C.roles['Sabbat'] in new_role_ids: clan_ch = C.clan_channels[C.roles['Sabbat']] phr = com.get_t(all_keys=('clan_welcome', clan_ch), user=f'<@{after.id}>') com.write_msg(clan_ch, phr) if before.status != after.status or not smth_happend: people.online_change(after.id, after.status, force=before.status == after.status) # small degradation _check_status_change(after) if (smth_happend or people.is_online(after.id)) and before.roles == after.roles: on_user_life_signs(after.id)
def upd(): t = load(res=True) log.D('- start upd people tables') log_upd = { 'change_usrs': { 'add': [], 'upd': [], 'del': [] }, 'change_gone': { 'add': [], 'upd': [], 'del': [] } } change_usrs = {'add': [], 'upd': [], 'del': []} for uid in list(usrs.keys()): usr = usrs[uid] if usr.status == 'add' or usr.status == 'upd': if uid in t['usrs']: change_usrs['upd'].append(usr.row_upd()) log_upd['change_usrs']['upd'].append(usr.name) else: change_usrs['add'].append(usr.row_add()) log_upd['change_usrs']['add'].append(usr.name) usr.status = '' elif usr.status == 'del': if uid in t['usrs']: change_usrs['del'].append([uid]) log_upd['change_usrs']['del'].append(usr.name) usrs.pop(uid) change_gone = {'add': [], 'upd': [], 'del': []} for uid in list(gone.keys()): gn = gone[uid] if gn.status == 'add' or gn.status == 'upd': if uid in t['gone']: change_gone['upd'].append(gn.row_upd()) log_upd['change_gone']['upd'].append(gn.name) else: change_gone['add'].append(gn.row_add()) log_upd['change_gone']['add'].append(gn.name) gn.status = '' elif gn.status == 'del': if uid in t['gone']: change_gone['del'].append([uid]) log_upd['change_gone']['del'].append(gn.name) gone.pop(uid) if log.debug(): if C.is_test: log.D("- it's Test mode, print results and return") log_upd = {'change_usrs': change_usrs, 'change_gone': change_gone} log.jD( 'subjects were updated:\n', '\n'.join([ cat + ':\n\t' + '\n'.join([ tp + '[{0}]:\n\t\t'.format(len(u_s)) + ',\n\t\t'.join(str(u) for u in u_s) for tp, u_s in ls.items() if u_s ]) for cat, ls in log_upd.items() if ls ])) # log.p('--------------------------------------------------------') if C.is_test: return conn = None log.D('- update people tables') try: ch_usrs_par = ', '.join(Usr.upd_props) ch_usrs_par_s = ', '.join(('%s', ) * len(Usr.upd_props)) ch_gone_par = ', '.join(Gn.upd_props) ch_gone_par_s = ', '.join(('%s', ) * len(Gn.upd_props)) conn = psycopg2.connect(C.DATABASE_URL, sslmode='require') cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) if change_usrs['add']: query = f'''INSERT INTO members (id, {ch_usrs_par}) VALUES (%s, {ch_usrs_par_s})''' cur.executemany(query, change_usrs['add']) conn.commit() if change_gone['add']: query = f'''INSERT INTO users_gone (id, {ch_gone_par}) VALUES (%s, {ch_gone_par_s})''' cur.executemany(query, change_gone['add']) conn.commit() if change_usrs['upd']: query = f'''UPDATE members SET ({ch_usrs_par}) = ({ch_usrs_par_s}) WHERE id = %s''' cur.executemany(query, change_usrs['upd']) conn.commit() if change_gone['upd']: query = f'''UPDATE users_gone SET ({ch_gone_par}) = ({ch_gone_par_s}) WHERE id = %s''' cur.executemany(query, change_gone['upd']) conn.commit() if change_usrs['del']: query = '''DELETE FROM members WHERE id = %s''' cur.executemany(query, change_usrs['del']) conn.commit() if change_gone['del']: query = '''DELETE FROM users_gone WHERE id = %s''' cur.executemany(query, change_gone['del']) conn.commit() except psycopg2.DatabaseError as e: log.E('DatabaseError %s' % e) sys.exit(1) else: log.D('+ people tables updated successfully') log.jD( 'subjects were updated:\n', '\n'.join([ cat + ':\n\t' + '\n'.join([ tp + '[{0}]:\n\t\t'.format(len(u_s)) + ',\n\t\t'.join(str(u) for u in u_s) for tp, u_s in ls.items() if u_s ]) for cat, ls in log_upd.items() if ls ])) finally: if conn: conn.close()