Beispiel #1
0
def clear():
    global usrs, gone
    log.I('CLEAR people tables')
    usrs = {}
    gone = {}
    rewrite()
    log.I('CLEAR done')
Beispiel #2
0
async def get_bans():
    log.I('- get bans')
    global bans, bans_id
    try:
        bans = await C.client.get_bans(C.vtm_server)
        bans_id = set(ban.id for ban in bans)
        log.I('+ get bans done')
    except Exception as e:
        bans_id = set()
        log.jW("- can't get bans")
Beispiel #3
0
def on_final_exit():
    log.I('\n', 'People online data:')
    log.p('\n'.join(people.print_online_people()))
    ram.t_finish = other.get_now()
    ram.t_work = (ram.t_finish - ram.t_start)
    if C.was_Ready:
        save()
    log.I('Finally exit at ', ram.t_finish.strftime('[%D %T]'),
          ', working for ', other.delta2s(ram.t_work))
    log.p('====== ' * 10)
Beispiel #4
0
def prepare_const():
    log.I('- prepare_const')

    st = os__environ.get('Server_Test')
    C.is_test = bool(st) and st not in ('0', 'False', 'false', '')

    C.DISCORD_TOKEN = os__environ.get('DISCORD_TOKEN')

    if not C.DISCORD_TOKEN:
        log.E('Config var DISCORD_TOKEN is not defined.')
        ev.force_exit()

    if C.is_test:
        log.jI('Bot work with Test Server')
    else:
        C.ignore_channels.update(C.test_channels)

    tst_server_key = 'TEST_SERVER_ID'
    tst_channel_key = 'TEST_CHANNEL_ID'
    vtm_server_key = 'VTM_SERVER_ID'
    vtm_channel_key = 'WELCOME_CHANNEL_ID'

    C.VTM_SERVER_ID = os__environ.get(vtm_server_key)
    C.TST_SERVER_ID = os__environ.get(tst_server_key)

    if not C.VTM_SERVER_ID:
        log.E('Config var VTM_SERVER_ID is not defined.')
        ev.force_exit()

    if not C.TST_SERVER_ID:
        log.E('Config var TST_SERVER_ID is not defined.')
        ev.force_exit()

    C.WELCOME_CHANNEL_ID = os__environ.get(vtm_channel_key)
    C.TEST_CHANNEL_ID = os__environ.get(tst_channel_key)

    if not C.WELCOME_CHANNEL_ID:
        log.E('Config var WELCOME_CHANNEL_ID is not defined.')
        ev.force_exit()

    if not C.TEST_CHANNEL_ID:
        log.E('Config var TEST_CHANNEL_ID is not defined.')
        ev.force_exit()

    C.DATABASE_URL = os__environ.get('DATABASE_URL')
    if not C.DATABASE_URL:
        log.E('Config var DATABASE_URL is not defined.')
        ev.force_exit()

    C.DROPBOX_ID = os__environ.get('DROPBOX_ID')

    ram.t_start = other.get_now()
    log.I('+ prepare_const done')
Beispiel #5
0
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))
Beispiel #6
0
async def _load_messages():
    # Load messages in the cache
    log.I('Start load messages from channels')
    load_channels = other.get_channels((C.channels['sabbat-charsheets'], ),
                                       True)
    for ch in load_channels:  #type: C.Types.Channel
        if not ch:
            continue
        log.I('- load messages from {0.name}'.format(ch))
        async for message in C.client.logs_from(
                ch, limit=10000):  #type: C.Types.Message
            C.client.messages.append(message)
    log.I('End load messages from channels')
Beispiel #7
0
def main_loop():
    for sig_name in ('SIGINT', 'SIGTERM'):
        C.loop.add_signal_handler(getattr(signal, sig_name),
                                  functools__partial(ev.on_exit, sig_name))
    try:
        log.I("Start ClientRun.")
        C.client.run(C.DISCORD_TOKEN)
    except Exception as e:
        other.pr_error(e, 'ClientRun', 'Unexpected error')
    else:
        log.I("ClientRun is completed without errors.")
    finally:
        ev.on_final_exit()
Beispiel #8
0
async def on_voice_state_update_o(server, before, after):
    v_old = before.voice_channel
    v_new = after.voice_channel

    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))
Beispiel #9
0
def prepare_const2():
    log.I('- prepare_const2')
    ev.upd_server()

    C.vtm_news_ch = other.get_channel(C.channels['vtm_news'])
    C.vtm_avs_ch = other.get_channel(C.channels['vtm_avs'])
    C.other_news_ch = other.get_channel(C.channels['other_news'])
    C.vtm_links_ch = other.get_channel(C.channels['vtm_links'])
    C.other_links_ch = other.get_channel(C.channels['other_links'])

    if not (C.vtm_news_ch and C.other_news_ch and C.vtm_links_ch
            and C.other_links_ch):
        log.W("Can't find some of helps channels!.")

    log.I('+ prepare_const2 done')
Beispiel #10
0
async def silence_on(name, t=1.0, force=False):
    """
    :param name: string
    :param t: float
    :param force: bool
    :rtype: C.Types.Member
    """
    s = C.prm_server
    user = other.find_member(s, name)
    if not user:
        return None

    if user.top_role >= s.me.top_role and not force:
        return 'top_role'

    if other.has_roles(user, C.roles['protege']):
        return 'protege'

    t = max(t, 0.02)
    if user.id in ram.silence_users:
        check = ram.silence_users[user.id]['check']
    else:
        check = await turn_silence(user, turn=True, force=force)
    ram.silence_users[user.id] = {'time': other.get_sec_total() + t * 3600 - 1, 'check': tuple(check)}
    if not C.is_test:
        add_roles = [other.find(s.roles, id=C.roles['Silence'])]
        other.add_roles(user, add_roles, 'silence_on')
    log.I('Silence on for ', user, ' at ', other.t2s(), ' on ', t, 'h.')
    return user
Beispiel #11
0
def _check_once_in_day():
    if not C.is_test:
        check_t = 7776000  # 90 * 24 * 3600
        for uid, usr in people.usrs.items():
            t_off = usr.offtime()
            if t_off > check_t:
                m = other.find_member(C.vtm_server, uid)
                if not other.has_roles(
                        m, C.roles_not_for_mortals) and not m.bot and len(
                            m.roles) > 1:
                    other.add_roles(m,
                                    C.roles['Mortal'],
                                    '_check_once_in_day',
                                    by_id=True,
                                    server_roles=C.vtm_server.roles)
                    log.I("{} go to Mortal (food)!".format(m))
    else:
        log.I("It's test mode, pass _check_once_in_day")
Beispiel #12
0
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))))
Beispiel #13
0
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')
Beispiel #14
0
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))
Beispiel #15
0
def load_mem():
    log.I('+ load data from memory')
    not_load = {'t_start', 't_finish', 't_work'}
    module = sys.modules[ram.__name__]
    module_attrs = dir(module)
    variables = set(key for key in module_attrs
                    if key[0] != '_' and not callable(getattr(module, key))
                    and not hasattr(getattr(module, key), '__dict__'))
    conn = None
    try:
        conn = psycopg2.connect(C.DATABASE_URL, sslmode='require')
        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
        cur.execute("SELECT * FROM memory")
        rows = cur.fetchall()
        for row in rows:
            #print("%s %s %s" % (row["id"], row["var"], row["val"]))
            if row['var'] in variables and not row['var'] in not_load:
                try:
                    if row['val'] == 'set()':
                        v = set()
                    else:
                        v = ast__literal_eval(row['val'])
                except Exception as e:
                    other.pr_error(e, 'load_mem')
                    log.jW("ast.literal_eval can't eval [%s] = '%s'" %
                           (row['var'], row['val']))
                else:
                    setattr(module, row['var'], v)
    except psycopg2.DatabaseError as e:
        log.E('<ev.load_mem> DatabaseError %s' % e)
        sys.exit(1)
    else:
        log.I('+ memory loaded successfully')
    finally:
        if conn:
            conn.close()
Beispiel #16
0
async def on_ready():
    ram.debug = C.is_test
    await other.busy()
    log.I(
        f'Logged in as {C.client.user} (id: {C.client.user.id}, Test: {C.is_test})'
    )
    prepare_const2()
    emj.prepare()
    await ev.load()
    ram.debug = ram.debug or C.is_test
    if not discord__opus.is_loaded():
        lb = find_library("opus")
        log.jD('opus lib: ', lb)  # i can't find it on heroku
        if lb:
            discord__opus.load_opus(lb)
        else:
            log.jI('opus lib not load!')
    ev.start_timers()
    log.I('Beckett ready for work now, after starting at ',
          ram.t_start.strftime('[%d/%m/%y %T]'))
    log.p('======= ' * 10)
    await test_fun()  # for debugging an testing
    C.Ready = True
    await other.test_status(ram.game)
Beispiel #17
0
def timer_midnight_update(now=None):
    if not now:
        now = other.get_now()

    log.I('[=== New day! ===]')

    try:
        _check_day_ev(now, on_midnight=True)
    except Exception as e:
        other.pr_error(e, '_check_day_ev', 'Unexpected error')

    try:
        _check_once_in_day()
    except Exception as e:
        other.pr_error(e, '_check_once_in_day', 'Unexpected error')
Beispiel #18
0
async def delete_reaction(message):
    """

    :type message: C.Types.Message
    """
    # delete reaction
    typing = data_typings.setdefault(message.channel.id,{}).get(message.id, '')
    resp = data_msgs.get(message.channel.id, {}).get(message.id, {})
    type_ = resp['type'] if resp else ''
    # if resp and type_ and (not type_.startswith('cmd_') or type_ == 'cmd_help'):
    if resp and type_ and not type_.startswith('cmd_'):
        log.I(f'<delete_reaction> [{type_}]')
        com.rem_from_queue(message.channel.id, typing)
        for mess in resp['ans']:
            await com.delete_msg(mess, 'delete_reaction')
        data_msgs[message.channel.id].pop(message.id)
Beispiel #19
0
async def delete_msg(message, reason='-'):
    """

    :param C.Types.Message message:
    :param reason: string
    """
    log.I(
        f"Bot will try delete message in #{message.channel.name}. Reason: {reason}."
    )
    try:
        await C.client.delete_message(message)
    except C.Exceptions.Forbidden:
        log.jW("Bot haven't permissions to delete messages here.")
    except C.Exceptions.NotFound:
        log.jW("Can't find the message to delete.")
    except Exception as e:
        pr_error(e, 'delete_msg', 'Unexpected error')
Beispiel #20
0
async def on_member_join_u(member):
    uid = member.id

    if uid in ram.silence_users:
        t = ram.silence_users[uid]['time'] - other.get_sec_total()
        if t > 0:
            log.I(member, ' come, but Silence is on.')
            await manager.silence_on(uid, t / 3600)
            timer_quarter_h()

    if people.Usr.check_new(member):
        not_embrace.add(uid)
        log.pr_news('{0} ({0.mention}) comeback!'.format(member))
        await C.client.send_message(
            C.main_ch,
            com.comeback_msg(uid, people.time_out(uid), people.clan(uid)))
    else:
        log.pr_news('{0} ({0.mention}) new!'.format(member))
Beispiel #21
0
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()
Beispiel #22
0
def _send_reaction(msg:Msg, m_type, text, edit=False):
    if not m_type or not text:
        return

    log.I(('<reaction.edit>' if edit else '<reaction>') + f'[{m_type}]')

    if text == 'no-response' or m_type == 'no-response':
        return

    if (m_type not in ('rand_tableflip', 'unflip', 'shrug') and ':' not in text
            and msg.roles.intersection((C.roles['Nosferatu'], C.roles['Malkavian'])) and other.rand() < 0.1):
        if C.roles['Malkavian'] in msg.roles:
            text = com.text2malk(text, 1)
        elif C.roles['Nosferatu'] in msg.roles:
            text = com.text2leet(text, 0.25)

    save_obj = _data_msgs_add(msg, m_type)
    if text != 'no-response' and m_type != 'no-response':
        _data_tp_add(msg, com.write_msg(msg.channel, text=text, save_obj=save_obj,
            fun=data_tp_del(msg.channel.id, msg.message.id)))
Beispiel #23
0
async def silence_off(name):
    """
    :param name: string
    :rtype: C.Types.Member
    """
    s = C.prm_server
    user = other.find_member(s, name)
    if not user:
        ram.silence_users.pop(name, 0)
        return None

    s_user = ram.silence_users.pop(user.id, False)
    if s_user:
        await turn_silence(user, turn=False, check=s_user['check'])
        if not C.is_test:
            rem_roles = [other.find(s.roles, id=C.roles['Silence'])]
            other.rem_roles(user, rem_roles, 'silence_off')
        log.I('Silence off for ', user, ' at ', other.t2s())
        return user
    else:
        return False
Beispiel #24
0
def phrase_gt(gt=None, uid=None, add_id=None):
    if not gt:
        return False

    uid = uid or 'here'
    phr = other.choice(d2u.good_time[gt['g_key']][gt['g_type']]['response'])
    str_weather = ''
    if gt['g_key'] == 'g_morn':  # and uid in emj.morn_add:
        smile_ids = other.it2list(uid) + other.it2list(add_id)
        smiles = []
        for sm_id in smile_ids:
            smiles += emj.morn_add.get(sm_id, [])
        if smiles:
            phr += ' ' + other.choice(smiles)
    if uid == C.users['Natali'] and gt['g_key'] in ('g_morn', 'g_day'):
        try:
            log.I('try get_weather for Natali')
            str_weather = '\n:newspaper: ' + get_weather()
        except Exception as e:
            other.pr_error(e, 'get_weather')
    return other.name_phr(uid, phr) + str_weather
Beispiel #25
0
def upd_server():
    log.I('Update Servers data')
    C.vtm_server = C.client.get_server(C.VTM_SERVER_ID)  # type: C.Types.Server
    C.tst_server = C.client.get_server(C.TST_SERVER_ID)  # type: C.Types.Server
    if not C.vtm_server:
        log.E("Can't find server.")
        force_exit()
    if not C.tst_server:
        log.E("Can't find test server.")
        force_exit()

    if C.is_test:
        C.prm_server = C.tst_server
        C.main_ch = C.client.get_channel(C.TEST_CHANNEL_ID)
    else:
        C.prm_server = C.vtm_server
        C.main_ch = C.client.get_channel(C.WELCOME_CHANNEL_ID)

    if not C.main_ch:
        log.E("Can't find welcome_channel.")
        force_exit()
Beispiel #26
0
def rewrite():
    usr_rows = []
    gn_rows = []
    for uid, usr in usrs.items():
        usr_rows.append(usr.row_add())
    for uid, gn in gone.items():
        gn_rows.append(gn.row_add())
    conn = None
    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)

        cur.execute("TRUNCATE TABLE members RESTART IDENTITY")
        if usr_rows:
            query = f'''INSERT INTO members (id, {ch_usrs_par})
                                        VALUES (%s, {ch_usrs_par_s})'''
            cur.executemany(query, usr_rows)
        conn.commit()

        cur.execute("TRUNCATE TABLE users_gone RESTART IDENTITY")
        if gn_rows:
            query = f'''INSERT INTO users_gone (id, {ch_gone_par}) 
                                                    VALUES (%s, {ch_gone_par_s})'''
            cur.executemany(query, gn_rows)
        conn.commit()

    except psycopg2.DatabaseError as e:
        log.E('{{rewrite}} DatabaseError %s' % e)
    else:
        log.I('Members rewrite successfully')
    finally:
        if conn:
            conn.close()
Beispiel #27
0
async def voting(channel, text='', timeout=60, votes=None, count=3):
    votes = votes or set()
    text = text + '\n*(для согласия введите за/y/yes/ok//д/да/+/1/:ok_hand:/:thumbsup:)*'
    yes = {'за', '1', 'y', 'yes', 'д', 'да', 'ок', 'у', '+', 't_d_', 'ok_hand', 'ok', 'thumbsup', '+1', 'thumbup'}
    await C.client.send_message(channel, text)
    time_end = other.get_sec_total() + timeout

    def check(msg):
        return (msg.author.id not in votes.union({C.users['bot']}) and
                    yes.intersection(emj.em2text(msg.content).lower().replace('.', '').replace(':', ' ').split()))

    while len(votes) < count:
        time_left = time_end - other.get_sec_total()
        log.I('<voting> We have {0}/{1} votes, wait more for {2} sec.'.format(len(votes), count, time_left))
        ans = await C.client.wait_for_message(timeout=time_left, channel=channel, check=check)
        if ans:
                votes.add(ans.author.id)
                other.later_coro(0, C.client.add_reaction(ans, emj.e('ok_hand')))
        else:
            break
    else:
        return votes

    return False
Beispiel #28
0
def on_exit(signum):
    log.I(f'Call on_exit by signal {signum}')
    C.loop.create_task(C.client.logout())
    stop_timers()
    C.was_Ready = C.Ready
    C.Ready = False
Beispiel #29
0
def _timer_check_silence_in_chat():
    if ram.last_vtm_msg and (
        (other.get_sec_total() - ram.last_vtm_msg) > 25200):  # 7 hours
        log.I('<timer_quarter_h> silence event!')
        phr = com.get_t('silence', )
        com.write_msg(C.main_ch, phr)
Beispiel #30
0
def start_quarter_h_timer():
    global timer_quarter_h_handle
    t = 900
    stop_quarter_h_timer()
    timer_quarter_h_handle = other.later(t, timer_quarter_h)
    log.I('* Start new timer in {0} seconds.'.format(t))