discord.py 中仅适用于一个用户 ID 的变量

问题描述 投票:0回答:1

所以我试图在某人执行“/logstart”和“/logstop”时为他们创建一个秒表,但我希望多个人能够在不受干扰的情况下启动和停止自己的秒表。

@bot.command(name='logstart')
async def logstart(ctx, arg1):
    await ctx.message.delete()
    await ctx.send('Log has Started')
@bot.command(name='logstop')
async def logstop(ctx):
    await ctx.message.delete()
    await ctx.send('FLIGHT LOG\nDuration: stopwatch time\nFlight Plan: argument1')
User does "/logstart EGCC(DEP) EGLL(ARR)":
Bot: Log Started
User does "/logstop"  
Bot: **FLIGHT LOG**  
Duration: %stopwatch time%  
Flight Plan: EGCC(DEP) EGLL(ARR)

我尝试在文档中搜索如何创建局部变量,但没有找到太多

python variables discord.py bots
1个回答
0
投票

我假设问题是您希望这些数据在多次重新启动后保持不变(因为您可以使用常规的旧字典来存储

ctx
的 ID 及其各自的开始时间!)。

假设您能够读取/写入托管机器人的任何位置,我将使用

sqlite3
作为伪字典。创建一个表,其中包含用户 ID、开始时间和
arg1
的列。如果大小/内存使用是数据库或字典的问题,您可以在
logstart()
logstop()
方法内进行清理。也许有最大数量的并发计时器(阻止新计时器启动)或剔除很久以前不合理启动的任何未完成的计时器。


所以基本上是这样的:

import sqlite3
# blah blah blah


MAX_TIMER = 259200                  # 3 day limit
DATABASE_PATH = 'whatever.db'
conn = sqlite3.connect(DATABASE_PATH)
cur = conn.cursor()                 # a cursor to simplify fetching/executing

# create table, ignoring error if it already exists
try:                                # (remove "PRIMARY KEY NOT NULL" if you want multiple timers per user)
    conn.execute('CREATE TABLE timers (user_id TEXT PRIMARY KEY NOT NULL, time_started TEXT, arg1 TEXT);')
except sqlite3.OperationalError:
    pass


@bot.command(name='logstart')
async def logstart(ctx, arg1):
    id = ctx.message.author.id
    await ctx.message.delete()

    # if you only allow one timer per user ("PRIMARY KEY NOT NULL"), you can do the following:
    try:
        cur.execute('INSERT INTO timers (user_id, time_started, arg1) VALUES(?,?,?)', 
                    (id, time.time(), arg1))
        await ctx.send('Log has Started')
    except sqlite3.IntegrityError:
        await ctx.send('You already have a timer started')

    # maybe handle cleanup here? in this example, i delete all rows older than 3 days
    cur.execute('SELECT user_id, time_started FROM timers')
    for id, time_started in cur.fetchall():
        if time.time() - float(time_started) > MAX_TIMER:
            # maybe send a message/whisper to the affected user?
            cur.execute('DELETE FROM timers WHERE user_id=?', (id,))


@bot.command(name='logstop')
async def logstop(ctx):
    id = ctx.message.author.id
    await ctx.message.delete()

    # ---

    # if you only allow one timer per user:
    cur.execute('SELECT time_started, arg1 FROM timers WHERE user_id=?', (id,))
    data = cur.fetchone()
    if data:                        # `fetchone()` returns None if no such row exists
        time_started, arg1 = data   # `time_started` is text, so make sure to cast it to a float
        duration = time.time() - float(time_started)
        await ctx.send(f'FLIGHT LOG\nDuration: {duration}\nFlight Plan: {arg1}')
        cur.execute('DELETE FROM timers WHERE user_id=?', (id,))
    else:                           # ^ delete row once we're done with it
        await ctx.send('You haven\'t started a timer')

    # ---

    # if you allow multiple timers per user (they'd need to pass `arg1` again):
    cur.execute('SELECT time_started FROM timers WHERE user_id=? AND arg1=?', (id, arg1))
    time_started = cur.fetchone()
    if time_started:
        duration = time.time() - float(time_started)
        await ctx.send(f'FLIGHT LOG\nDuration: {duration}\nFlight Plan: {arg1}')
        cur.execute('DELETE FROM timers WHERE user_id=? AND arg1=?', (id, arg1))
    else:
        await ctx.send('You haven\'t started a timer')


一些注意事项:

  • 我的SQLite有点生疏,所以如果有任何错误,我很抱歉。希望这足以让您开始使用。
  • 如果您希望每个用户有多个计时器,您可以使用
    len(cur.execute('SELECT * FROM timers WHERE user_id=?', (id,)).fetchall())
    而不是
    fetchone()
  • 来获取他们启动的计时器数量
  • 您也可以...每次启动计时器时将这些内容写入文本文件。这将同样持久/安全,并且更容易 10 倍(但可扩展性差得多)。
  • 我真的希望我没有完全误解你的问题,但至少我对数据库有了很好的复习。
© www.soinside.com 2019 - 2024. All rights reserved.