2019年1月10日 星期四

[Flask] Socket.IO integration - Vue-Socket.io


 Python   Flask    WebSocket    Socket.IO  



Introduction


In previous article, [Flask] Socket.IO integration : Flask-SocketIO, we had successfully create Websocket by Flask-SocketIO on our Flask application.

If you are a Vue.js developer like me, you may want to implement the client side with Socket.IO client in Vue way.
Fortunately Metin Seylan has implemented the open-source project: Vue-Socket.io, to make it simple and clean.

We are going to use Vue.js and to integrate Socket.IO on client-side.


Environment

Python 3.6.5
Flask 1.0.2
Flask-SocketIO 3.1.2
Socket.IO 2.2.0
Vue.js 2.5.21
Vue-Socket.io 3.0.4


Implement



Server-side

If you followed the previous article’s steps, the project file’s hierarchy currently is



Now create these files:

app/static/js/index.js
app/templates/index_vue.html




Before we start implementing the them, there are a few issues here:

1.  Flask use “{{“ and “}}” to indicate a server-side variable on template which will be conflicted with Vue.js  
2.  How client side (javascript) knows which server url to connect?


To solve the first issue, we will need to modify the default Jinja2 options on variable_start_string and variable_end_string.
For the second issue, we can assign the value of Flask’s template variable to Vue’s global variable.


Update Jinja2 ‘s options

main.py

class CustomFlask(Flask):
    jinja_options = Flask.jinja_options.copy()
    jinja_options.update(dict(
        variable_start_string='%%',  # Default is '{{' but Vue.js uses '{{' / '}}'
        variable_end_string='%%', # Default is '}}' but Vue.js uses '{{' / '}}'
    ))

app = CustomFlask(__name__, template_folder='./templates')

Now the template variable must be inside “%%” and “%%”


Pass template variable to Vue

main.py

When rendering template, pass a template variable: server_addr.

from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO, emit

# Global variables
SERVER_ADDR = "http://localhost:5000" # default Server ip/port (local)
app = Flask(__name__, template_folder='./templates')

# Websocket setting
app.config['SECRET_KEY'] = '12qwaszx'
socketio = SocketIO(app)

@app.route('/')
def index():
return render_template('index_vue.html', async_mode=socketio.async_mode, server_addr=SERVER_ADDR)       



On index_vue.html, keep the server_addr’s value to Vue’s global variable

index_vue.html

<script lang="javascript">
        Vue.prototype.$serverAddr = "%% server_addr %%";
 </script>



Integrate Vue-Socket.io

First implement the HTML as following,

index_vue.html

<script lang="javascript">
        Vue.prototype.$serverAddr = "%% server_addr %%";
  </script>
    <div id="app">
        <div>
            <input class="form-control" type="text" v-model="clientMsg" @keyup.enter="emitMsg"/>
            <button class="btn btn-success" id="emitMsg" @click="emitMsg">Send</button>
        </div>
        <br />
        <pre>{{ log }}</pre>
    </div>
  <script src="%% url_for('static', filename="js/index.js") %%"> </script>




Then we can enable Vue-Socket.io and register the event handler:
1.  Connect
2.  Server_response

index.js


Vue.use(new VueSocketIO({
    debug: true,
    connection: Vue.prototype.$serverAddr //'http://localhost:5000'
}))



var app = new Vue({
    el: "#app",
    sockets: {
       connectfunction () {
            this.appendLog("Start connect...");
            this.$socket.emit('connected_event', { data: 'WebSocket connected successfully.' });
       },
        server_response: function (msg) {
            this.appendLog(msg.data);
        }
    },
    data: {
        clientMsg: "",
        log: "",
    },
    methods: {
        emitMsg: function () {
            this.$socket.emit('broadcast_event', { data: this.clientMsg });
        },
        appendLog: function (newLog) {
            this.log += newLog + "\n";
        }
    },
    created: function () {
    }
})


Demo





Sample code





Reference





沒有留言:

張貼留言