跳至主要内容

通过gevent-socketio为TurboGears提供SocketIO支持

项目描述

关于tgext.socketio

https://travis-ci.org/amol-/tgext.socketio.png https://coveralls.io/repos/amol-/tgext.socketio/badge.png https://img.shields.io/pypi/pyversions/tgext.socketio.svg

tgext.socketio提供了一种在TurboGears2中实现SocketIO的简单方法。通过gevent-socketio提供SocketIO支持,并提供了基于gevent的特定SocketIO服务器。

安装

tgextsocketio可以从pypi安装

pip install tgext.socketio

运行

SocketIO支持需要一个自定义的基于GEvent的HTTP服务器才能正确工作,请记得编辑您的development.ini并添加

# SOCKETIO doesn't work with debug mode
debug = false

[server:main]
use = egg:tgext.socketio#socketio
socketio_resource = socketio

host = 127.0.0.1
port = 8080

tgext.socketio#socketio是tgext.socketio提供的服务器,以正确支持SocketIO,而socketio_resource是您的SocketIOController类的路径。

默认情况下使用socketio,因此您可以在RootController下挂载一个SocketIOController子类,或者您可以在任何其他位置挂载它并更改您的socketio_resource选项。

使用SocketIOController

SocketIOController的工作方式类似于任何其他TurboGears控制器,但支持作为子控制器服务SocketIOTGNamespaceSocketIOController还可以像任何其他TG控制器一样表现,并提供普通网页。

SocketIOTGNamespacesocketio.namespace.Basenamespace 的子类,具有额外的 TurboGears 功能,如 @validate@require 支持。请注意,SocketIOTGNamespace 至少需要 TurboGears 2.3.1,如果您想使用之前的 TurboGears 版本,仍然可以使用带有纯 socketio.namespace.Basenamespace 类的 SocketIOController

使用示例

以下是一个非常简单的示例,处理两种类型的事件 pingfireball,并对这些事件进行实时响应

from tgext.socketio import SocketIOTGNamespace, SocketIOController

class PingPong(SocketIOTGNamespace):
    def on_ping(self, attack):
        if attack['type'] == 'fireball':
            for i in range(10):
                self.emit('pong',{'sound':'bang!'})
        else:
            self.emit('pong',{'sound':'pong'})


class SocketIO(SocketIOController):
    pingpong = PingPong

    @expose()
    def page(self, **kw):
        return '''
<html>
<body>
    <div>
        <a class="ping" href="#" data-attack="ping">Ping</a>
        <a class="ping" href="#" data-attack="fireball">Fireball</a>
        <a class="ping" href="#" data-attack="auto">Auto</a>
        <a class="ping" href="#" data-attack="error">Error</a>
    </div>
    <div id="result"></div>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js"></script>
    <script>
    $(function(){
        var socket = io.connect('/pingpong', {'resource':'socketio'});
        socket.on('pong',function(data){
            $('#result').append(data.sound + '<br/>');
        });
        socket.on('error',function(error, info) {
            if (error == 'method_access_denied') { alert(info); }
            else { console.log(info); alert(error); }
        });
        $('.ping').click(function(event){
            event.preventDefault();
            socket.emit('ping',{'type':$(this).data('attack')});
        });
    });
    </script>
</body>
</html>
'''

class RootController(BaseController):
    socketio = SocketIO()

请注意,SocketIOController 必须与配置文件中 socketio_resource 属性指定的相同位置进行挂载。

使用验证器和要求

SocketIOTGNamespace 也支持使用 @validate@require TurboGears 装饰器。

相同的示例可以修改为通过几行代码提供验证和权限检查

from tg import validate, require, predicates
from tg.validation import TGValidationError
import random

class NoFireBallValidator(object):
    def to_python(self, value, *args, **kw):
        type_ = value['type']
        if type_ == 'auto':
            return {'type': random.choice(['ping', 'fireball'])}
        elif type_ == 'error':
            raise TGValidationError('Got an error!')

        return value


class PingPong(SocketIOTGNamespace):
    @require(predicates.not_anonymous())
    @validate({'attack': NoFireBallValidator()})
    def on_ping(self, attack):
        if attack['type'] == 'fireball':
            for i in range(10):
                self.emit('pong',{'sound':'bang!'})
        else:
            self.emit('pong',{'sound':'pong'})

PubSub 支持

tgext.socketio 内置了对基于 anypubsub 库的 PubSub 模式的支持。如果您想使用 PubSub,应通过 pip install anypubsub 安装 anypubsub 或将其添加到您的项目依赖项中。

PubSub 支持通过从 tgext.socketio.pubsub.PubSubTGNamespace 继承来实现。这个特殊的命名空间允许客户端通过从 JavaScript 接口调用 socket.emit('subscribe', 'channel_name') 来订阅频道。

每当用户订阅频道时,PubSubTGNamespace 子类将收到对 subscribe_channelname 方法的调用,该方法可以返回用户是否有权订阅指定的频道(可以使用 @require 装饰器)。subscribe_channelname 方法还可以返回不同的频道名称,如果您想指定子频道。

对于在订阅的频道上发布的每条消息,PubSubTGNamespace 将发出一个 pubblication 事件,该事件可以被 socket.io 客户端捕获以执行所需操作。

通过 PubSubTGNamespace.publish 可以发布消息。

您可以在 examples/chat.py 中看到一个简单的示例,该示例提供了一个在 redis 后端实现的实时聊天。

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面