如何使用Flask Socket-IO的join事件呈现新模板?

huangapple go评论69阅读模式
英文:

How can I render new Template with Flask Socket-IO join event?

问题

I've translated the non-code portions for you:

I'm programming a little multiplayer game with Flask Socket-IO. If the client is on the website, he connects to the websocket. On the start page, the client should type a nickname in the field and press the button. Then the client tries to join a room, if it's possible to join the room, I want to render a new HTML file or redirect to a new site if the join worked.

My index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Start</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
    <script src="{{ url_for('static', filename='js/script.js')}}"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.6.1/socket.io.js" integrity="sha512-xbQU0+iHqhVt7VIXi6vBJKPh3IQBF5B84sSHdjKiSccyX/1ZI7Vnkt2/8y8uruj63/DVmCxfUNohPNruthTEQA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<script type="text/javascript">
  var socket = io.connect('localhost:5000');
  var sessionId = socket.id;

  document.cookie = 'session_id=' + sessionId + '; expires=' + new Date(Date.now() + 3600000);

  socket.on('connect', function() {
    console.log(socket.id)
  });
  socket.on('joined', function(data) {
    console.log(data['nickname'] + " joined the " + data['room']);
  });
  function joinroom(){
    var nickname = document.getElementById("nickname").value;
    socket.emit('join', {nickname: nickname, room : 'room1'})
  }
</script>
  <div id="home">
    <div class ="logo-big">
      <a href="./start">
        <img src="{{ url_for('static', filename='images/logo.png')}}">
      </a>
    </div>
    <div class ="panels">
      <div class="panel-left"></div>
      <div class="panel">
        <form onsubmit="joinroom()">
          <div class="container-name">
            <input class="input-name" id="nickname" type="text" placeholder="Enter your name" maxlength="21" data-translate="placeholder" required>
          </div>
            <button id="playbtn" class="button-play" type="submit">
            <span>Play!</span>
          </button>
        </form>
      </div>
      <div class="panel-right">
      </div>
    </div>
    <div class="bottom"></div>
  </div>
</body>
</html>

In the moment it does not work. After clicking the button and triggering the join event, there is no update of the View.

The full flask app:

from flask import Flask, render_template, request
from flask_socketio import SocketIO, send, emit, join_room, leave_room

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*")

MAX_CLIENTS_PER_ROOM = 4
room_clients = {}
room_states = {}

@app.route("/start")
def start():
    return render_template('index.html')

@app.route("/game")
def game():
    return render_template('game.html')
  
@socketio.on('connect')
def handle_connect():
    print('Client connected!')

@socketio.on('disconnect')
def handle_disconnect():
    print("Client disconnected!")

@socketio.on('join')
def handle_join(data):
    nickname = data['nickname']
    room = data['room']
    if room not in room_clients:
        room_clients[room] = 0
    if room_clients[room] >= MAX_CLIENTS_PER_ROOM:
        print("Raum ist voll:"+ str(room_clients[room]))
        emit('room_full', {'room': room})
    else:
        print("Es sind "+ str(room_clients[room]) +" Leute im Raum!")
        if room in room_states and room_states[room] == 'running':
            print("Das Spiel läuft bereits")
            emit('room_running', {'room': room})
        else:
            print("Du kannst dem Raum beitreten. Mit dir sind "+ str(room_clients[room]+1)+" Leute im Raum.")
            join_room(room)
            room_clients[room] += 1
            emit('joined', {'nickname': nickname, 'room': room}, room=room)
            return render_template('game.html')

@socketio.on('leave')
def handle_leave(data):
    nickname = data['nickname']
    room = data['room']
    leave_room(room)
    room_clients[room] -= 1
    if room_clients[room] == 0:
        del room_clients[room]
        del room_states[room]
    emit('left', {'nickname': nickname, 'room': room}, room=room)
    
if __name__ == '__main__':
    socketio.run(app)

Please note that this is a translation of your provided code and HTML, and I haven't made any modifications to its functionality. If you're experiencing issues, you might want to check for errors or debugging messages in your Flask application's console or browser developer tools.

英文:

I'm programming a litte multiplayer game with Flask Socket-IO. If the client is on the website, he connects to the websocket. On the start page the client should type a nickname in the field and press the button. Then the client tries to join a room, if its possible to join the room, I want to render a new html file or redirect to an new site if the join worked.

Here is my try to programm this join event. Just ignore my prints.

@socketio.on(&#39;join&#39;)
def handle_join(data):
nickname = data[&#39;nickname&#39;]
room = data[&#39;room&#39;]
if room not in room_clients:
room_clients[room] = 0
if room_clients[room] &gt;= MAX_CLIENTS_PER_ROOM:
print(&quot;Raum ist voll:&quot;+ str(room_clients[room]))
emit(&#39;room_full&#39;, {&#39;room&#39;: room})
else:
print(&quot;Es sind &quot;+ str(room_clients[room]) +&quot; Leute im Raum!&quot;)
if room in room_states and room_states[room] == &#39;running&#39;:
print(&quot;Das Spiel l&#228;uft bereits&quot;)
emit(&#39;room_running&#39;, {&#39;room&#39;: room})
else:
print(&quot;Du kannst dem Raum beitreten. Mit dir sind &quot;+ str(room_clients[room]+1)+&quot; Leute im Raum.&quot;)
join_room(room)
room_clients[room] += 1
emit(&#39;joined&#39;, {&#39;nickname&#39;: nickname, &#39;room&#39;: room}, room=room)
return render_template(&#39;game.html&#39;)

My index.html:

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Start&lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;{{ url_for(&#39;static&#39;, filename=&#39;css/style.css&#39;) }}&quot;&gt;
&lt;script src=&quot;{{ url_for(&#39;static&#39;, filename=&#39;js/script.js&#39;)}}&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.6.1/socket.io.js&quot; integrity=&quot;sha512-xbQU0+iHqhVt7VIXi6vBJKPh3IQBF5B84sSHdjKiSccyX/1ZI7Vnkt2/8y8uruj63/DVmCxfUNohPNruthTEQA==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var socket = io.connect(&#39;localhost:5000&#39;);
var sessionId = socket.id;
document.cookie = &#39;session_id=&#39; + sessionId + &#39;; expires=&#39; + new Date(Date.now() + 3600000);
socket.on(&#39;connect&#39;, function() {
console.log(socket.id)
});
socket.on(&#39;joined&#39;, function(data) {
console.log(data[&#39;nickname&#39;] + &quot; joined the &quot; + data[&#39;room&#39;]);
});
function joinroom(){
var nickname = document.getElementById(&quot;nickname&quot;).value;
socket.emit(&#39;join&#39;, {nickname: nickname, room : &#39;room1&#39;})
}
&lt;/script&gt;
&lt;div id=&quot;home&quot;&gt;
&lt;div class =&quot;logo-big&quot;&gt;
&lt;a href=&quot;./start&quot;&gt;
&lt;img src=&quot;{{ url_for(&#39;static&#39;, filename=&#39;images/logo.png&#39;)}}&quot;&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;div class =&quot;panels&quot;&gt;
&lt;div class=&quot;panel-left&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;panel&quot;&gt;
&lt;form onsubmit=&quot;joinroom()&quot;&gt;
&lt;div class=&quot;container-name&quot;&gt;
&lt;input class=&quot;input-name&quot; id=&quot;nickname&quot; type=&quot;text&quot; placeholder=&quot;Enter your name&quot; maxlength=&quot;21&quot; data-translate=&quot;placeholder&quot; required&gt;
&lt;/div&gt;
&lt;button id=&quot;playbtn&quot; class=&quot;button-play&quot; type=&quot;submit&quot;&gt;
&lt;span&gt;Play!&lt;/span&gt;
&lt;/button&gt;
&lt;/form&gt;
&lt;/div&gt;
&lt;div class=&quot;panel-right&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;bottom&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

In the moment it does not work. After clicking the button and trigger the join event, there is now update of the View.

The full flask app:

from flask import Flask, render_template, request
from flask_socketio import SocketIO, send, emit, join_room, leave_room
app = Flask(__name__)
app.config[&#39;SECRET_KEY&#39;] = &#39;secret!&#39;
socketio = SocketIO(app, cors_allowed_origins=&quot;*&quot;)
MAX_CLIENTS_PER_ROOM = 4
room_clients = {}
room_states = {}
@app.route(&quot;/start&quot;)
def start():
return render_template(&#39;index.html&#39;)
@app.route(&quot;/game&quot;)
def game():
return render_template(&#39;game.html&#39;)
@socketio.on(&#39;connect&#39;)
def handle_connect():
print(&#39;Client connected!&#39;)
@socketio.on(&#39;disconnect&#39;)
def handle_disconnect():
print(&quot;Client disconnected!&quot;)
@socketio.on(&#39;join&#39;)
def handle_join(data):
nickname = data[&#39;nickname&#39;]
room = data[&#39;room&#39;]
if room not in room_clients:
room_clients[room] = 0
if room_clients[room] &gt;= MAX_CLIENTS_PER_ROOM:
print(&quot;Raum ist voll:&quot;+ str(room_clients[room]))
emit(&#39;room_full&#39;, {&#39;room&#39;: room})
else:
print(&quot;Es sind &quot;+ str(room_clients[room]) +&quot; Leute im Raum!&quot;)
if room in room_states and room_states[room] == &#39;running&#39;:
print(&quot;Das Spiel l&#228;uft bereits&quot;)
emit(&#39;room_running&#39;, {&#39;room&#39;: room})
else:
print(&quot;Du kannst dem Raum beitreten. Mit dir sind &quot;+ str(room_clients[room]+1)+&quot; Leute im Raum.&quot;)
join_room(room)
room_clients[room] += 1
emit(&#39;joined&#39;, {&#39;nickname&#39;: nickname, &#39;room&#39;: room}, room=room)
return render_template(&#39;game.html&#39;)
@socketio.on(&#39;leave&#39;)
def handle_leave(data):
nickname = data[&#39;nickname&#39;]
room = data[&#39;room&#39;]
leave_room(room)
room_clients[room] -= 1
if room_clients[room] == 0:
del room_clients[room]
del room_states[room]
emit(&#39;left&#39;, {&#39;nickname&#39;: nickname, &#39;room&#39;: room}, room=room)
if __name__ == &#39;__main__&#39;:
socketio.run(app)

答案1

得分: 0

Socket.IO事件处理程序不是Flask路由,无法从中返回HTML。通常,Socket.IO应用程序是单页应用程序。您应该通过客户端的JavaScript代码实现所需的页面更新。

一种方法是让您的主要Flask模板同时呈现初始视图和游戏视图,但游戏视图最初是隐藏的。然后,一旦游戏开始,您可以隐藏初始视图并显示游戏视图。

英文:

The Socket.IO event handlers are not Flask routes, you cannot return HTML from them. Normally Socket.IO apps are single-page apps. You should implement the page updates that you want through JavaScript code in the client.

One way you can do this is to have your main Flask template render both the initial and game views, but the game view is initially hidden. Then once the game starts you can hide the initial view and display the game view.

huangapple
  • 本文由 发表于 2023年4月13日 19:18:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76004803.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定