Прежде всего, позвольте мне показать вам окончательный вид приложения чата, которое мы завершим к концу этой статьи.
Мы реализуем приложение с Flask , Gunicorn для автономного приложения WSGI и Flask-SocketIO для связи в реальном времени.
1. Сценарий
Давайте рассмотрим пример сценария, который мы можем использовать в этой статье при создании приложения:
- Альберто хочет использовать наше приложение, поэтому он открывает его в браузере.
- Он выбирает ник и входит в чат.
- Он пишет что-то в текстовой области и нажимает Enter
- Введенный текст будет транслироваться пользователям, которые в данный момент вошли в приложение чата.
Как видите, это очень простое приложение, которое охватит все основы веб-приложения. Давайте продолжим с дизайном проекта.
2. Предпосылки
Прежде чем приступить к реализации проекта, нам нужно рассмотреть некоторые необходимые зависимости и библиотеки. Я выполню процесс установки в Ubuntu, чтобы сделать установку намного проще.
2.1. питон
Вы можете просто установить Python, просто выполнив следующую команду:
1
|
sudo apt-get install python-dev build-essential
|
2.2. зернышко
pip — это система управления пакетами, используемая для установки и управления программными пакетами, написанными на Python. Мы будем использовать это для установки пакетов Python для нашего приложения. Вы можете установить pip, выполнив следующую команду:
1
|
sudo apt-get install python-pip
|
2,3. Virtualenv
Этот инструмент позволяет вам создавать изолированную среду Python. Это означает, что вы можете переключить свой контекст в среду, имеющую свойства, связанные с Python, и вернуться в обычную среду, если у вас нет разработки на Python. Вы можете установить Virtualenv, выполнив следующую команду:
1
|
sudo pip install virtualenv
|
2,4. Gunicorn
Gunicorn означает Green Unicorn и является HTTP-сервером Python WSGI (веб-интерфейс) для UNIX. Gunicorn действует как интерфейс между веб-сервером и вашим приложением Python. Мы будем использовать это для запуска нашего приложения Flask как автономного приложения WSGI. Нам нужно использовать [email protected]
потому что у более новых версий есть проблемы, которые необходимо решить.
1
|
sudo pip install gunicorn==18.0
|
Мы закончили с установочной частью. Давайте продолжим с настройкой проекта.
3. Настройка проекта
Создайте каталог проекта, как вы хотите;
1
|
mkdir realtimepythonchat
|
Перейдите во вновь созданный каталог и создайте виртуальную среду для разработки на Python, например:
1
|
virtualenv realtimepythonchat_env
|
Вы можете изменить название среды в соответствии с вашими потребностями. Виртуальная среда создана, но еще не активирована. Если вы выполните следующую команду;
1
|
source realtimepythonchat_env/bin/activate
|
Ваша виртуальная среда Python будет активирована, и мы готовы установить требования в этой виртуальной среде. Чтобы быть уверенным в виртуальной среде, вы можете проверить, что ваша командная строка начинается с имени виртуальной среды в скобках, и вы увидите следующее;
3.1. Установка зависимостей
Нам нужно установить несколько зависимых библиотек для нашего проекта. Создайте файл под названием requirements.txt
в корневом каталоге вашего проекта и поместите в него следующее содержимое:
01
02
03
04
05
06
07
08
09
10
11
|
Flask==0.10.1
Flask-SocketIO
Jinja2==2.7.2
MarkupSafe==0.18
Werkzeug==0.9.4
gevent==1.0
gevent-socketio==0.3.6
gevent-websocket==0.9.2
greenlet==0.4.2
itsdangerous==0.23
ujson==1.33
|
Эти зависимости помогут нам создать веб-приложение в реальном времени. Теперь давайте установим зависимости следующей командой
1
|
pip install -r requirements.txt
|
3.2 Скелет проекта
На данный момент мы создали проект и установили необходимое программное обеспечение. Теперь давайте добавим файлы, специфичные для проекта.
Добавьте файл с именем server.py
и поместите в него следующее содержимое:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
from gevent import monkey
monkey.patch_all()
from flask import Flask, render_template, session, request
from flask.ext.socketio import SocketIO, emit, join_room
app = Flask(__name__)
app.debug = True
app.config[‘SECRET_KEY’] = ‘nuttertools’
socketio = SocketIO(app)
@app.route(‘/’)
def chat():
return render_template(‘chat.html’)
@app.route(‘/login’)
def login():
return render_template(‘login.html’)
@socketio.on(‘message’, namespace=’/chat’)
def chat_message(message):
emit(‘message’, {‘data’: message[‘data’]}, broadcast = True)
@socketio.on(‘connect’, namespace=’/chat’)
def test_connect():
emit(‘my response’, {‘data’: ‘Connected’, ‘count’: 0})
if __name__ == ‘__main__’:
socketio.run(app)
|
Это простое приложение Flask, которое запускается через модуль Flask-SocketIO. Первый и второй маршрут предназначены для рендеринга главной страницы и страницы входа. Третий маршрут — для обработки события message
на канале chat
.
Когда клиент отправляет сообщение этой конечной точке, оно будет транслироваться подключенным клиентам. Это делается командой emit()
. Первый параметр — это полезная нагрузка сообщения, а второй — для установки значения широковещания. Если это правда, сообщение будет передано клиентам. 4-й маршрутизатор предназначен для простого сообщения ACK на стороне клиента, чтобы гарантировать, что клиент подключен к сокету.
3.3 Шаблоны
У нас есть две страницы — chat.html
и login.html.
Вы можете увидеть содержимое login.html
ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
<!DOCTYPE html>
<html>
<head lang=»en»>
<meta charset=»UTF-8″>
<title></title>
<script src=»//code.jquery.com/jquery-1.11.1.js»></script>
<script src=»//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js»></script>
<script src=»//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js»></script>
<script>
$(function(){
if ($.cookie(«realtime-chat-nickname»)) {
window.location = «/»
} else {
$(«#frm-login»).submit(function(event) {
event.preventDefault();
if ($(«#nickname»).val() !== ») {
$.cookie(«realtime-chat-nickname», $(«#nickname»).val());
window.location = «/»;
}
})
}
})
</script>
<link href=»//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css» rel=»stylesheet»>
<link href=»//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css» rel=»stylesheet»>
<style type=»text/css»>
</style>
</head>
<body>
<div class=»container» style=»padding-top: 50px»>
<div class=»row»>
<div class=»col-md-4 col-md-offset-4″>
<div class=»login-panel panel panel-default»>
<div class=»panel-heading»>
<h3 class=»panel-title»>Choose a nickname to enter chat</h3>
</div>
<div class=»panel-body»>
<form role=»form» id=»frm-login»>
<fieldset>
<div class=»form-group»>
<input class=»form-control» placeholder=»Enter Nickname» name=»nickname» id=»nickname» type=»text» autofocus required=»»>
</div>
<button type=»submit» class=»btn btn-lg btn-success btn-block»>Enter Chat</button>
</fieldset>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
|
Это простая система входа в систему, которая включает информацию о пользователе, хранящуюся в cookie. Когда вы выбираете псевдоним и продолжаете, ваш псевдоним будет сохранен в файле cookie, и вы будете перенаправлены на страницу чата. Давайте посмотрим на chat.html
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
<!DOCTYPE html>
<html>
<head lang=»en»>
<meta charset=»UTF-8″>
<title></title>
<script src=»//code.jquery.com/jquery-1.11.1.js»></script>
<script src=»//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js»></script>
<script src=»//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js»></script>
<script src=»//cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.4.0/jquery.timeago.min.js»></script>
<script src=»//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js»></script>
<script>
var channel = «/chat»;
var socket = io.connect(‘http://’ + document.domain + ‘:’ + location.port + channel);
socket.on(‘connect’, function() {
socket.emit(‘my_connection’, {data: ‘I\’m connected!’});
});
socket.on(«message», function (message) {
refreshMessages(message);
});
function refreshMessages(message) {
$(«.media-list»).append(‘<li class=»media»><div class=»media-body»><div class=»media»><div class=»media-body»>’
+ message.message + ‘<br/><small class=»text-muted»>’ + message.author + ‘ |
}
$(function(){
if (typeof $.cookie(«realtime-chat-nickname») === ‘undefined’) {
window.location = «/login»
} else {
$(«#sendMessage»).on(«click», function() {
sendMessage()
});
$(‘#messageText’).keyup(function(e){
if(e.keyCode == 13)
{
sendMessage();
}
});
}
function sendMessage() {
$container = $(‘.media-list’);
$container[0].scrollTop = $container[0].scrollHeight;
var message = $(«#messageText»).val();
var author = $.cookie(«realtime-chat-nickname»);
socket.emit(‘message’, {data: {message: message, author: author}});
$(«#messageText»).val(«»);
$container.animate({ scrollTop: $container[0].scrollHeight }, «slow»);
}
})
</script>
<link href=»//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css» rel=»stylesheet»>
<link href=»//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css» rel=»stylesheet»>
<style type=»text/css»>
.fixed-panel {
min-height: 500px;
max-height: 500px;
}
.media-list {
overflow: auto;
}
</style>
</head>
<body>
<div class=»container»>
<div class=»row » style=»padding-top:40px;»>
<h3 class=»text-center»>Realtime Chat Application with Flask, SocketIO</h3>
<br/><br/>
<div class=»col-md-12″>
<div class=»panel panel-info»>
<div class=»panel-heading»>
<strong><span class=»glyphicon glyphicon-list»>
</div>
<div class=»panel-body fixed-panel»>
<ul class=»media-list»>
</ul>
</div>
<div class=»panel-footer»>
<div class=»input-group»>
<input type=»text» class=»form-control» placeholder=»Enter Message» id=»messageText» autofocus/>
<span class=»input-group-btn»>
<button class=»btn btn-info» type=»button» id=»sendMessage»>SEND <span class=»glyphicon glyphicon-send»>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
|
Как мы уже говорили, клиентская сторона может использовать реализацию JavaScript SocketIO на внешнем интерфейсе. Требуемая клиентская библиотека извлекается из CDN. Фактически, все файлы CSS и JavaSCript извлекаются из CDN, чтобы ускорить работу приложения и уменьшить размер проекта. Вы можете клонировать этот проект и легко запустить его на локальном компьютере.
Когда вы заходите на страницу чата после успешного входа в систему, файл cookie будет проверен, чтобы увидеть, вошел ли пользователь в систему или нет. Если нет, пользователь будет перенаправлен на страницу входа снова. Если вы успешно перейдете на страницу чата, между клиентом и сервером будет установлено сокетное соединение. SocketIO используется на стороне клиента, а сторона сервера уже реализована в предыдущих разделах. Когда пользователь нажимает клавишу « Ввод» или нажимает кнопку « Ввод» , текст, написанный в области сообщений, будет отправляться emit()
на сторону сервера. Сообщение будет обработано на стороне сервера и будет транслироваться подключенным клиентам через канал chat
.
4. Запуск проекта
Мы запустим этот проект как отдельное приложение WSGI. Для этого вы можете использовать следующую команду:
1
|
gunicorn —worker-class socketio.sgunicorn.GeventSocketIOWorker server:app
|
Мы запускаем команду gunicorn
с двумя аргументами. Первый — это рабочий класс, и он происходит от gevent-socketio
. Второе — это имя приложения с его модулем. Здесь модуль — server.py
а имя приложения — app (которое находится на восьмой строке в server.py
). Когда вы выполните вышеуказанную команду, вы увидите вывод, подобный этому:
Когда вы дойдете до http://127.0.0.1:8000
, вы увидите следующий экран:
5. Развертывание
Мы будем использовать модуль для нашей среды развертывания. Прежде всего, создайте учетную запись на модуле и перейдите на панель инструментов, чтобы создать новый проект. Введите имя проекта, выберите поле Python из типов проектов и нажмите кнопку CREATE PROJECT.
После успешного создания учетной записи мы можем приступить к развертыванию. Вы можете выполнить развертывание в модуле двумя способами:
- Заархивируйте ваш проект и загрузите его с панели инструментов Modulus
- Установите клиент Modulus и разверните его из командной строки
Я буду использовать развертывание командной строки для этого проекта. Прежде всего, установите Node.js на свой компьютер.
Когда мы начнем развертывание в модуле, модуль будет выполнять следующую команду на своей стороне:
1
|
pip install -r requirements.txt
|
Мы уже запустили файл зависимостей — requirements.txt
после чего он выполнит следующее, чтобы запустить развернутый проект:
1
|
./manage.py migrate
|
Тем не менее, нам нужно переопределить эту команду, чтобы сделать наше приложение. Создайте файл с именем app.json
и поместите в него следующую команду:
1
2
3
4
5
|
{
«scripts»: {
«start»: «gunicorn -b unix:/mnt/home/app.sock —worker-class socketio.sgunicorn.GeventSocketIOWorker server:app»
}
}
|
Теперь мы готовы загрузить файл в модуль. Откройте консоль командной строки и выполните следующую команду.
1
|
npm install -g modulus
|
Вы готовы использовать CLI модуля, выполните следующую команду для входа в модуль.
1
|
modulus login
|
Вам будет предложено ввести имя пользователя / адрес электронной почты и пароль. Введите необходимые учетные данные, и пришло время для развертывания. Перейдите в каталог вашего проекта и выполните следующую команду.
1
|
modulus deploy -p «your project name»
|
Приведенная выше команда развернет текущий проект в модуле, который вы создали ранее. Не забудьте заменить имя проекта тем, которое вы создали ранее. Если все в порядке, вы увидите сообщение об успешном завершении в консоли и протестируете свое приложение, следуя URL-адресу, указанному в сообщении об успешном выполнении в консоли.
6. Заключение
Основной целью этого урока было показать вам, как создать приложение для чата в реальном времени с Flask и SocketIO. Мы использовали Modulus для провайдера PaaS, и у него есть действительно простые шаги для развертывания вашего приложения в производственной среде.