Я пытаюсь включить чат в моем приложении flask, используя socketio в качестве микросервиса. Прямо сейчас у меня есть файл rout.py:
main_blueprint = Blueprint("main", __name__, template_folder='../templates', static_folder='../templates')
@main.route('/', methods=['GET', 'POST'])
def index():
"""Login form to enter a room."""
form = LoginForm()
if form.validate_on_submit():
session['name'] = form.name.data
session['room'] = form.room.data
return redirect(url_for('.chat'))
elif request.method == 'GET':
form.name.data = session.get('name', '')
form.room.data = session.get('room', '')
return render_template('index.html', form=form)
@main.route('/chat')
def chat():
"""Chat room. The user's name and room must be stored in
the session."""
name = session.get('name', '')
room = session.get('room', '')
if name == '' or room == '':
return redirect(url_for('.index'))
return render_template('chat.html', name=name, room=room)
Этот лог c отображает два html файла, расположенных в файле ../templates. Однако остальная часть моего приложения находится в отдельном клиентском сервисе, написанном на реаги. Я хотел бы использовать компонент реакции, такой как:
import React from "react";
import io from 'socket.io-client';
class ChatRoom extends React.Component {
state = {
socketData: "",
socketStatus:"On"
}
componentWillUnmount() {
this.socket.close()
console.log("component unmounted")
}
componentDidMount() {
var sensorEndpoint = "http://localhost:5002"
this.socket = io.connect(sensorEndpoint, {
reconnection: true,
// transports: ['websocket']
});
console.log("component mounted")
this.socket.on("responseMessage", message => {
this.setState({'socketData': message.temperature})
console.log("responseMessage", message)
})
}
handleEmit=()=>{
if(this.state.socketStatus==="On"){
this.socket.emit("message", {'data':'Stop Sending', 'status':'Off'})
this.setState({'socketStatus':"Off"})
}
else{
this.socket.emit("message", {'data':'Start Sending', 'status':'On'})
this.setState({'socketStatus':"On"})
}
console.log("Emit Clicked")
}
render() {
return (
<React.Fragment>
<div>Data: {this.state.socketData}</div>
<div>Status: {this.state.socketStatus}</div>
<div onClick={this.handleEmit}> Start/Stop</div>
</React.Fragment>
)
}
}
export default ChatRoom;
или этот:
import React, { Component } from 'react'
import ControlBar from './ControlBar'
import Conversations from './Conversations'
import Flash from './Flash'
import io from 'socket.io-client';
import axios from 'axios';
const socket = io('http://localhost:5002')
class Chat extends Component {
constructor (props) {
super(props)
this.state = {
username: '',
activeUsers: [],
rooms: [],
messages: [],
flashNotice: ''
}
this.handleChange = this.handleChange.bind(this)
this.joinRoom = this.joinRoom.bind(this)
this.leaveRoom = this.leaveRoom.bind(this)
this.sendMessage = this.sendMessage.bind(this)
this.setUsername = this.setUsername.bind(this)
this.createFlash = this.createFlash.bind(this)
this.clearFlash = this.clearFlash.bind(this)
}
handleChange (event) {
const {name, value} = event.target
this.setState({ [name]: value })
}
setUsername (username) {
const oldName = this.state.username
if (oldName && oldName !== username) {
socket.emit('deactivate_user', { username: oldName })
}
this.setState({ username }, () => {
socket.emit('activate_user', { username: this.state.username })
})
}
loadMessages () {
const savedMessages = window.localStorage.getItem('messages')
if (savedMessages) {
this.setState({ messages: JSON.parse(savedMessages) || [] })
}
}
setSocketListeners () {
socket.on('message', (data) => {
console.log(data.message)
})
socket.on('message_sent', (message) => {
const room = message['room']
this.setState({ messages: [...this.state.messages, message] }, () => {
window.localStorage.setItem('messages', JSON.stringify(this.state.messages))
if (this.state.rooms.indexOf(room) === -1) {
this.setState({ rooms: [...this.state.rooms, room] })
}
})
})
socket.on('retrieve_active_users', () => {
if (this.state.username) {
socket.emit('activate_user', { username: this.state.username })
}
})
socket.on('user_activated', (data) => {
const user = data['user']
const { activeUsers } = this.state
if (activeUsers.indexOf(user) === -1 && user !== this.state.username) {
this.setState({ activeUsers: [...activeUsers, user] }, () => {
this.createFlash(`${user} is online`)
})
}
})
socket.on('user_deactivated', (data) => {
const deactivatedUser = data['user']
const { activeUsers } = this.state
if (activeUsers.indexOf(deactivatedUser) !== -1) {
this.setState({ activeUsers: activeUsers.filter((user) => {
return user !== deactivatedUser
})})
}
})
socket.on('open_room', (data) => {
const room = data['room']
const openRooms = this.state.rooms
const userInRoom = room.split('|').indexOf(this.state.username) !== -1
const roomNotOpen = openRooms.indexOf(room) === -1
if (userInRoom && roomNotOpen) {
this.joinRoom(room, this.state.username)
}
})
}
joinRoom (room, username, partner) {
room = room || [username, partner].sort().join('|')
if (this.state.rooms.indexOf(room) === -1) {
this.setState({rooms: [...this.state.rooms, room]}, () => {
socket.emit('join_room', { username, room })
})
}
}
leaveRoom (room, username) {
this.setState({ rooms: this.state.rooms.filter((r) => r !== room) })
}
sendMessage (message, room) {
socket.emit(
'send_message',
{
room,
author: this.state.username,
body: message,
timeStamp: Date.now()
}
)
}
createFlash (text) {
this.setState({flashNotice: ''}, () => {
this.setState({flashNotice: text}, () => {
window.setTimeout(this.clearFlash, 2500)
})
})
}
clearFlash () {
this.setState({flashNotice: ''})
}
getChat() {
return axios.get(`${process.env.REACT_APP_CHAT_SERVICE_URL}/chat`)
.then((res) => {
this.setState({
exercises: res.data.data.exercises,
currentExercise: 0,
});
this.renderButtons();
})
.catch((err) => { console.log(err); });
};
componentDidMount () {
this.getChat()
this.loadMessages()
this.setSocketListeners()
}
render () {
const {username, rooms, messages, flashNotice} = this.state
return (
<div className='App'>
<div className='header'>
{/* <img className='logo' src={logo} alt='logo' /> */}
<h1 className='title'>Fat Chat</h1>
</div>
<Flash notice={flashNotice} />
<ControlBar
activeUsers={this.state.activeUsers}
setUsername={this.setUsername}
createFlash={this.createFlash}
joinRoom={this.joinRoom} />
<Conversations
rooms={rooms}
messages={messages}
username={username}
leaveRoom={this.leaveRoom}
sendMessage={this.sendMessage} />
</div>
)
}
}
export default Chat;
, чтобы играть роль чата. html файл:
<head>
<title>Flask-SocketIO-Chat: {{ room }}</title>
<script type="text/javascript" src="//code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
var socket;
$(document).ready(function(){
socket = io.connect('http://' + document.domain + ':' + location.port + '/chat');
socket.on('connect', function() {
socket.emit('joined', {});
});
socket.on('status', function(data) {
$('#chat').val($('#chat').val() + '<' + data.msg + '>\n');
$('#chat').scrollTop($('#chat')[0].scrollHeight);
});
socket.on('message', function(data) {
$('#chat').val($('#chat').val() + data.msg + '\n');
$('#chat').scrollTop($('#chat')[0].scrollHeight);
});
$('#text').keypress(function(e) {
var code = e.keyCode || e.which;
if (code == 13) {
text = $('#text').val();
$('#text').val('');
socket.emit('text', {msg: text});
}
});
});
function leave_room() {
socket.emit('left', {}, function() {
socket.disconnect();
// go back to the login page
window.location.href = "{{ url_for('main.index') }}";
});
}
</script>
</head>
<body>
<h1>Flask-SocketIO-Chat: {{ room }}</h1>
<textarea id="chat" cols="80" rows="20"></textarea><br><br>
<input id="text" size="80" placeholder="Enter your message here"><br><br>
<a href="#" onclick="leave_room();">Leave this room</a>
</body>
</html>
В настоящее время, когда я набираю url localhost: // chat в адресной строке, я получаю html, однако, когда я пытаюсь получить доступ к маршруту, на стороне клиента с помощью ax ios я получаю jsx. Только когда я обновлю sh страницу, я получу обслуживаемый шаблон.
Я хотел бы понять, как буквально и в переносном смысле получить интерфейс и бэкэнд моего приложения на одной странице. Обе стороны не могут «договориться» о том, что должно быть отображено, и я не понимаю, должен ли я указать бэкэнду flask, чтобы он служил шаблону «реакции», или я должен сказать клиенту реакции, что он должен извлекать данные из указанного c маршрута.
Я благодарю всех за их время и отзывы. Я изо всех сил пытаюсь понять, что происходит, и надеюсь, что этот вопрос достаточно хорошо описан. Если вы хотите взглянуть на источник, он расположен по адресу:
https://github.com/smeyerhot/appster