问题描述
我用Python构建了一个国际象棋应用程序,并使用Flask创建了一个供用户玩的网站。我使用Heroku部署了该应用程序()。我是Web开发的新手,想知道如何处理网站上运行该应用程序的多个用户(分别在笔记本电脑或标签上)?每个用户都有一个唯一的游戏ID,可以根据不同的请求提供不同的游戏。以下是我的一些路线和初始化游戏代码。我基本上是初始化一个处理移动并跟踪板状态的Board对象。我使用js将移动信息发送到服务器以进行移动。我也想在用户退出网站后结束游戏。没有人有任何想法吗?
I built a chess app with Python and used Flask to create a site for users to play on. I used Heroku to deploy the app (http://pythonchessapp.herokuapp.com/). I am new to web development and was wondering how I can handle multiple users (on separate laptops or tabs) going on the site to play the app? Something like having a unique game id per user to serve a different game to different requests. Below is some of my code for routes and initializing games. I basically initialize a Board object that handles moves and tracks board states. I use js to send info on moves to the server to make moves. I would also like to end a game after a user exits the site. Does anyone have any ideas?
我只包括了创建木板和渲染初始页面的初始路线以及处理执行动作的路线。
I've only included the initial route that creates the board and renders the initial page, and the route that deals with executing moves.
from logic.chess_board import Board
from logic.chess_pieces import *
b = Board()
@app.route('/', methods=["GET", "POST"])
@app.route('/chess', methods=["GET", "POST"])
def chess():
flipped = b.flipped
img_dict = b.board_html()
return render_template('base.html', img_dict=img_dict, flipped=flipped)
@app.route('/execute', methods=['GET', 'POST'])
def execute():
if request.method == "POST":
castle = None
error = False
outcome = False
empty = None
sq_one = eval(request.get_json()['sq_one'])
sq_two = eval(request.get_json()['sq_two'])
piece = b.board[sq_one]
if type(piece) == King and (piece.castle['king_side'] == sq_two or piece.castle['queen_side'] == sq_two):
y = sq_one[1]
if piece.castle['king_side'] == sq_two:
r_one = str((8, y))
r_two = str((6, y))
elif piece.castle['queen_side'] == sq_two:
r_one = str((1, y))
r_two = str((4, y))
castle = [r_one, r_two]
try:
b.move(sq_one, sq_two)
if b.game_over():
outcome = b.outcome
empty = b.js_remove()
except Exception as e:
error = str(e)
response = {'error': error, 'castle': castle, 'empty': empty, 'outcome': outcome}
return make_response(jsonify(response))
推荐答案
这可以通过库 cachelib
使用Flask的会话$ c $以腌制格式存储
Board
的实例c>对象,以在cookie中存储唯一键。
This could be achieved with the library cachelib
to store your instance of Board
in pickled format, using Flask's session
object to store a unique key in the cookie.
使用 pip安装cachelib
进行安装或添加 cachelib
到 requirements.txt
。
Install with pip install cachelib
or add cachelib
to your requirements.txt
.
首先导入所需的库并初始化缓存:
Start by importing the required libs and initialising the cache:
from flask import Flask, session
import pickle
from uuid import uuid4
from cachelib.simple import SimpleCache
c = SimpleCache(default_timeout=0)
app.config['SECRET_KEY'] = 'somesupersecretkey'
app = Flask(__name__)
返回唯一ID的快速功能:
A quick function to return a unique ID:
def generate_id():
return uuid4().__str__()
代替设置 b = Board()
在全局级别上,我们将在函数内部执行此操作并将其返回。
Instead of setting b = Board()
at the global level, we will do this inside a function and return it.
因此我们可以定义一个函数来加载板。这看起来是要查看 session
对象(cookie存储)中是否存在键 game_id
。如果是这样,我们将从缓存中加载电路板。如果没有,此功能将仅创建一个新板。您还可以在此块的 else
子句中执行其他板子初始化步骤:
So we could define a function which loads a board. This looks to see if the key game_id
exists in the session
object (cookie storage). If it does, we load the board from our cache. If not, this function will just create a new board. You could also do other board initialization steps in the else
clause of this block:
def load_board():
if 'game_id' in session:
pb = c.get(session['game_id'])
board = pickle.loads(pb)
else:
# Initialize new board
board = Board()
return board
现在我们创建一个保存板子的函数。这会立即使我们作为参数传递的板
腌制,然后将其保存在缓存中。根据 session
对象(cookie存储)中是否存在 game_id
,它将使用该ID或生成一个
Now we create a function which saves the board. This immediately pickles the board
we pass as an argument, then saves it in the cache. Depending on whether a game_id
exists in the session
object (cookie storage) it will either use that ID, or generate a new one.
def save_board(board):
pb = pickle.dumps(board)
if 'game_id' in session:
c.set(session['game_id'], pb)
else:
unique_id = generate_id()
session['game_id'] = unique_id
c.set(unique_id, pb)
使用这些实用程序功能,您现在可以在所有请求中保留董事会:
With these utility functions, you can now persist a board across requests:
@app.route('/chess', methods=["GET", "POST"])
def chess():
b = load_board()
flipped = b.flipped
img_dict = b.board_html()
save_board(b)
return render_template('base.html', img_dict=img_dict, flipped=flipped)
然后选择另一条路线:
@app.route('/execute', methods=['GET', 'POST'])
def execute():
if request.method == "POST":
b = load_board()
# All of your logic
# Finally save the board
save_board(b)
return make_response(jsonify(response))
可以使用不同的方法来设计此功能。 SimpleCache
可以将所有内容存储在内存中,这应该很好,假设您只与一名Gunicorn工人一起跑步。
There's probably different ways you could design this functionality in. SimpleCache
stores everything in memory, which should be fine, assuming you only run with 1 gunicorn worker.
最终,如果您超出了一个工人的负担,或者发现您的Web dyno的内存占用量太大,则可以切换 SimpleCache
可以轻松实现 RedisCache
,而无需更改太多逻辑。
Eventually if you outgrew a single worker, or found the memory footprint of your web dyno was too high, you could switch SimpleCache
out for RedisCache
easily without changing much logic. This would also be needed to persist the data across dyno restarts.
cachelib
库很小,因此您可以以查看其他可用的后端和方法。
The cachelib
library is tiny so you can read the code to see the other available backends and methods.
这篇关于在Flask应用中将唯一的游戏ID绑定给用户,以处理对服务器的多个请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!