Торнадо сервер на джанге. undefined Торнадо сервер на джанге.

Торнадо сервер на джанге.

Open in new window

Торнадо сокет-сервер на Tornado c Django моделью.

Ставим редис.

sudo apt-get install redis-server

Установим зависимости.

django-redis-sessions
django-redis
tornado==6.0.3
tornado-redis
python-socketio
eventlet
aiohttp
aioredis

Настроим редис для сессий.

Установим в качестве бекенда для сессий редис.

SESSION_ENGINE = 'redis_sessions.session'

SESSION_REDIS = {
    'host': 'localhost',
    'port': 6379,
    'db': 3,
    'prefix': 'session',
    'socket_timeout': 1
}

Мы уменьшили количество запросов к базе данных при отправке запросов к сайту на 1 (Redis отвечает на запросы почти мгновенно). :)

Создаем простой сервер, обслуживающий websocket tornado_server.py.

#!/usr/bin/env python
import tornado.ioloop
import tornado.web
from tornado import autoreload
import socketio


sio = socketio.AsyncServer(async_mode='tornado', cors_allowed_origins=['http://localhost:4200'])


@sio.event
def connect(sid, environ):
    print("connect ", sid)


@sio.on('ng-action:set_online')
async def chat_message(sid, data):
    print("message ", data)



@sio.event
def disconnect(sid):
    print('disconnect ', sid)


def make_app():
    return tornado.web.Application([
        (r"/websocket/", socketio.get_tornado_handler(sio)),
    ])

if __name__ == "__main__":
    print('Starting server on 8888 port')
    autoreload.start()
    autoreload.watch('socketserver/server.py')
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

Запуск сервера.

python tornado_server.py

Angular socketio.

Установка.

npm i ngx-socket-io --save

Включение в корневой модуль.

import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io';

const config: SocketIoConfig = { url: 'http://localhost:8888', options: {path:'/websocket'} };

...

  imports: [
    ...
    SocketIoModule.forRoot(config)
  ],

Создание сервиса.

import { Injectable } from '@angular/core';
import { Socket } from 'ngx-socket-io';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SocketService {
  user_online$: Observable<any> = this.socket.fromEvent<string>('server-action:user_online');
  constructor(private socket: Socket) { }

  connect_me(username: string) {
    console.log('emmiting event to server');
    this.socket.emit('ng-action:set_online',{'username': username});
  }

}

Использование сервиса в компоненте.

import { Component, OnInit } from '@angular/core';
import { SocketService } from '../service/socket.service';

@Component({
  selector: 'app-index',
  templateUrl: './index.component.html',
  styleUrls: ['./index.component.css']
})
export class IndexComponent implements OnInit {

  constructor(private socket_service: SocketService) { }

  ngOnInit() {
    this.socket_service.connect_me('admin');

    this.socket_service.user_online$.subscribe(data => {
      console.log(data);
    })
  }

  onClick() {
    this.socket_service.connect_me('admin');
  }
}

Передача данных с сервера на клиент.

@sio.on('ng-action:set_online')
async def chat_message(sid, data):
    print("message ", data)
    # server-action:user_online emitting
    await sio.emit('server-action:user_online', {'users': [1,2,3]})

sio.emit(‘evt_name’, {data}) - всем

sio.emit(‘evt_name’, {data}, sid) - одному по sid

init

Подвязывем Django.

import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
django.setup()
from django.contrib.auth.models import User

Пример модели сохранения пользователей онлайн.

from django.db import models

# Create your models here.
from django.contrib.auth.models import User

class UserOnline(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    username = models.CharField(max_length=250, db_index=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    @staticmethod
    def set_online(login):
        try:
            UserOnline.objects.get(username=login)
        except:
            user = User.objects.get(username=login)
            uo = UserOnline()
            uo.username = login
            uo.user = user
            uo.save()

Использование.

@sio.on('ng-action:set_online')
async def chat_message(sid, data):
    UserOnline.set_online(data['username'])

Other topics