-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy path__init__.py
More file actions
executable file
·150 lines (114 loc) · 4.15 KB
/
Copy path__init__.py
File metadata and controls
executable file
·150 lines (114 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from .channel import Channel
from .connection import Connection
import hashlib
import hmac
import logging
try:
import simplejson as json
except ImportError:
import json
VERSION = "0.2.0"
class Pusher(object):
host = "ws.pusherapp.com"
client_id = 'PythonPusherClient'
protocol = 6
def __init__(self, key, secure=True, secret=None, user_data=None, log_level=logging.INFO, daemon=True, port=None, reconnect_interval=10):
self.key = key
self.secret = secret
self.user_data = user_data or {}
self.channels = {}
self.url = self._build_url(key, secure, port)
self.connection = Connection(self._connection_handler, self.url, log_level=log_level, daemon=daemon, reconnect_interval=reconnect_interval)
def connect(self):
"""Connect to Pusher"""
self.connection.start()
def disconnect(self):
"""Disconnect from Pusher"""
self.connection.disconnect()
self.channels = {}
def subscribe(self, channel_name):
"""Subscribe to a channel
:param channel_name: The name of the channel to subscribe to.
:type channel_name: str
:rtype : Channel
"""
data = {'channel': channel_name}
if channel_name.startswith('presence-'):
data['auth'] = self._generate_presence_key(
self.connection.socket_id,
self.key,
channel_name,
self.secret,
self.user_data
)
data['channel_data'] = json.dumps(self.user_data)
elif channel_name.startswith('private-'):
data['auth'] = self._generate_private_key(
self.connection.socket_id,
self.key,
channel_name,
self.secret
)
self.connection.send_event('pusher:subscribe', data)
self.channels[channel_name] = Channel(channel_name, self.connection)
return self.channels[channel_name]
def unsubscribe(self, channel_name):
"""Unsubscribe from a channel
:param channel_name: The name of the channel to unsubscribe from.
:type channel_name: str
"""
if channel_name in self.channels:
self.connection.send_event(
'pusher:unsubscribe', {
'channel': channel_name,
}
)
del self.channels[channel_name]
def channel(self, channel_name):
"""Get an existing channel object by name
:param channel_name: The name of the channel you want to retrieve
:type channel_name: str
:rtype: Channel or None
"""
return self.channels.get(channel_name)
def _connection_handler(self, event_name, data, channel_name):
if channel_name in self.channels:
self.channels[channel_name]._handle_event(event_name, data)
@staticmethod
def _generate_private_key(socket_id, key, channel_name, secret):
auth_key = ""
if socket_id and key and channel_name and secret:
subject = "%s:%s" % (socket_id, channel_name)
h = hmac.new(secret, subject, hashlib.sha256)
auth_key = "%s:%s" % (key, h.hexdigest())
return auth_key
@staticmethod
def _generate_presence_key(socket_id, key, channel_name, secret, user_data):
auth_key = ""
if socket_id and key and channel_name and secret and user_data:
subject = "%s:%s:%s" % (socket_id, channel_name, json.dumps(user_data))
h = hmac.new(secret, subject, hashlib.sha256)
auth_key = "%s:%s" % (key, h.hexdigest())
return auth_key
@classmethod
def _build_url(cls, key, secure, port=None):
path = "/app/%s?client=%s&version=%s&protocol=%s" % (
key,
cls.client_id,
VERSION,
cls.protocol
)
proto = "ws"
if secure:
proto = "wss"
if port is None:
if secure:
port = 443
else:
port = 80
return "%s://%s:%s%s" % (
proto,
cls.host,
port,
path
)