Статьи

Создайте приложение для чата в реальном времени с модулем и Python

Прежде всего, позвольте мне показать вам окончательный вид приложения чата, которое мы завершим к концу этой статьи.

Демо-страница чата

Мы реализуем приложение с Flask , Gunicorn для автономного приложения WSGI и Flask-SocketIO для связи в реальном времени.

Давайте рассмотрим пример сценария, который мы можем использовать в этой статье при создании приложения:

  1. Альберто хочет использовать наше приложение, поэтому он открывает его в браузере.
  2. Он выбирает ник и входит в чат.
  3. Он пишет что-то в текстовой области и нажимает Enter
  4. Введенный текст будет транслироваться пользователям, которые в данный момент вошли в приложение чата.

Как видите, это очень простое приложение, которое охватит все основы веб-приложения. Давайте продолжим с дизайном проекта.

Прежде чем приступить к реализации проекта, нам нужно рассмотреть некоторые необходимые зависимости и библиотеки. Я выполню процесс установки в Ubuntu, чтобы сделать установку намного проще.

Вы можете просто установить Python, просто выполнив следующую команду:

1
sudo apt-get install python-dev build-essential

pip — это система управления пакетами, используемая для установки и управления программными пакетами, написанными на Python. Мы будем использовать это для установки пакетов Python для нашего приложения. Вы можете установить pip, выполнив следующую команду:

1
sudo apt-get install python-pip

Этот инструмент позволяет вам создавать изолированную среду Python. Это означает, что вы можете переключить свой контекст в среду, имеющую свойства, связанные с Python, и вернуться в обычную среду, если у вас нет разработки на Python. Вы можете установить Virtualenv, выполнив следующую команду:

1
sudo pip install virtualenv

Gunicorn означает Green Unicorn и является HTTP-сервером Python WSGI (веб-интерфейс) для UNIX. Gunicorn действует как интерфейс между веб-сервером и вашим приложением Python. Мы будем использовать это для запуска нашего приложения Flask как автономного приложения WSGI. Нам нужно использовать [email protected] потому что у более новых версий есть проблемы, которые необходимо решить.

1
sudo pip install gunicorn==18.0

Мы закончили с установочной частью. Давайте продолжим с настройкой проекта.

Создайте каталог проекта, как вы хотите;

1
mkdir realtimepythonchat

Перейдите во вновь созданный каталог и создайте виртуальную среду для разработки на Python, например:

1
virtualenv realtimepythonchat_env

Вы можете изменить название среды в соответствии с вашими потребностями. Виртуальная среда создана, но еще не активирована. Если вы выполните следующую команду;

1
source realtimepythonchat_env/bin/activate

Ваша виртуальная среда Python будет активирована, и мы готовы установить требования в этой виртуальной среде. Чтобы быть уверенным в виртуальной среде, вы можете проверить, что ваша командная строка начинается с имени виртуальной среды в скобках, и вы увидите следующее;

Virtualenv активированная консоль

Нам нужно установить несколько зависимых библиотек для нашего проекта. Создайте файл под названием 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

На данный момент мы создали проект и установили необходимое программное обеспечение. Теперь давайте добавим файлы, специфичные для проекта.

Добавьте файл с именем 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 на стороне клиента, чтобы гарантировать, что клиент подключен к сокету.

У нас есть две страницы — 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 .

Мы запустим этот проект как отдельное приложение WSGI. Для этого вы можете использовать следующую команду:

1
gunicorn —worker-class socketio.sgunicorn.GeventSocketIOWorker server:app

Мы запускаем команду gunicorn с двумя аргументами. Первый — это рабочий класс, и он происходит от gevent-socketio . Второе — это имя приложения с его модулем. Здесь модуль — server.py а имя приложения — app (которое находится на восьмой строке в server.py ). Когда вы выполните вышеуказанную команду, вы увидите вывод, подобный этому:

Консольный запуск вывода

Когда вы дойдете до http://127.0.0.1:8000 , вы увидите следующий экран:

Страница чата

Мы будем использовать модуль для нашей среды развертывания. Прежде всего, создайте учетную запись на модуле и перейдите на панель инструментов, чтобы создать новый проект. Введите имя проекта, выберите поле Python из типов проектов и нажмите кнопку CREATE PROJECT.

После успешного создания учетной записи мы можем приступить к развертыванию. Вы можете выполнить развертывание в модуле двумя способами:

  1. Заархивируйте ваш проект и загрузите его с панели инструментов Modulus
  2. Установите клиент 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-адресу, указанному в сообщении об успешном выполнении в консоли.

Основной целью этого урока было показать вам, как создать приложение для чата в реальном времени с Flask и SocketIO. Мы использовали Modulus для провайдера PaaS, и у него есть действительно простые шаги для развертывания вашего приложения в производственной среде.