django-nativemojo 0.1.10__py3-none-any.whl → 0.1.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_nativemojo-0.1.15.dist-info/METADATA +136 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/RECORD +105 -65
- mojo/__init__.py +1 -1
- mojo/apps/account/management/__init__.py +5 -0
- mojo/apps/account/management/commands/__init__.py +6 -0
- mojo/apps/account/management/commands/serializer_admin.py +531 -0
- mojo/apps/account/migrations/0004_user_avatar.py +20 -0
- mojo/apps/account/migrations/0005_group_last_activity.py +18 -0
- mojo/apps/account/models/group.py +25 -7
- mojo/apps/account/models/member.py +15 -4
- mojo/apps/account/models/user.py +197 -20
- mojo/apps/account/rest/group.py +1 -0
- mojo/apps/account/rest/user.py +6 -2
- mojo/apps/aws/rest/__init__.py +1 -0
- mojo/apps/aws/rest/s3.py +64 -0
- mojo/apps/fileman/README.md +8 -8
- mojo/apps/fileman/backends/base.py +76 -70
- mojo/apps/fileman/backends/filesystem.py +86 -86
- mojo/apps/fileman/backends/s3.py +200 -108
- mojo/apps/fileman/migrations/0001_initial.py +106 -0
- mojo/apps/fileman/migrations/0002_filemanager_parent_alter_filemanager_max_file_size.py +24 -0
- mojo/apps/fileman/migrations/0003_remove_file_fileman_fil_upload__c4bc35_idx_and_more.py +25 -0
- mojo/apps/fileman/migrations/0004_remove_file_original_filename_and_more.py +39 -0
- mojo/apps/fileman/migrations/0005_alter_file_upload_token.py +18 -0
- mojo/apps/fileman/migrations/0006_file_download_url_filemanager_forever_urls.py +23 -0
- mojo/apps/fileman/migrations/0007_remove_filemanager_forever_urls_and_more.py +22 -0
- mojo/apps/fileman/migrations/0008_file_category.py +18 -0
- mojo/apps/fileman/migrations/0009_rename_file_path_file_storage_file_path.py +18 -0
- mojo/apps/fileman/migrations/0010_filerendition.py +33 -0
- mojo/apps/fileman/migrations/0011_alter_filerendition_original_file.py +19 -0
- mojo/apps/fileman/models/__init__.py +1 -5
- mojo/apps/fileman/models/file.py +204 -58
- mojo/apps/fileman/models/manager.py +161 -31
- mojo/apps/fileman/models/rendition.py +118 -0
- mojo/apps/fileman/renderer/__init__.py +111 -0
- mojo/apps/fileman/renderer/audio.py +403 -0
- mojo/apps/fileman/renderer/base.py +205 -0
- mojo/apps/fileman/renderer/document.py +404 -0
- mojo/apps/fileman/renderer/image.py +222 -0
- mojo/apps/fileman/renderer/utils.py +297 -0
- mojo/apps/fileman/renderer/video.py +304 -0
- mojo/apps/fileman/rest/__init__.py +1 -18
- mojo/apps/fileman/rest/upload.py +22 -32
- mojo/apps/fileman/signals.py +58 -0
- mojo/apps/fileman/tasks.py +254 -0
- mojo/apps/fileman/utils/__init__.py +40 -16
- mojo/apps/incident/migrations/0005_incidenthistory.py +39 -0
- mojo/apps/incident/migrations/0006_alter_incident_state.py +18 -0
- mojo/apps/incident/models/__init__.py +1 -0
- mojo/apps/incident/models/history.py +36 -0
- mojo/apps/incident/models/incident.py +1 -1
- mojo/apps/incident/reporter.py +3 -1
- mojo/apps/incident/rest/event.py +7 -1
- mojo/apps/logit/migrations/0004_alter_log_level.py +18 -0
- mojo/apps/logit/models/log.py +4 -1
- mojo/apps/metrics/utils.py +2 -2
- mojo/apps/notify/handlers/ses/message.py +1 -1
- mojo/apps/notify/providers/aws.py +2 -2
- mojo/apps/tasks/__init__.py +34 -1
- mojo/apps/tasks/manager.py +200 -45
- mojo/apps/tasks/rest/tasks.py +24 -10
- mojo/apps/tasks/runner.py +283 -18
- mojo/apps/tasks/task.py +99 -0
- mojo/apps/tasks/tq_handlers.py +118 -0
- mojo/decorators/auth.py +6 -1
- mojo/decorators/http.py +7 -2
- mojo/helpers/aws/__init__.py +41 -0
- mojo/helpers/aws/ec2.py +804 -0
- mojo/helpers/aws/iam.py +748 -0
- mojo/helpers/aws/s3.py +451 -11
- mojo/helpers/aws/ses.py +483 -0
- mojo/helpers/aws/sns.py +461 -0
- mojo/helpers/crypto/__pycache__/hash.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/sign.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/utils.cpython-310.pyc +0 -0
- mojo/helpers/dates.py +18 -0
- mojo/helpers/response.py +6 -2
- mojo/helpers/settings/__init__.py +2 -0
- mojo/helpers/{settings.py → settings/helper.py} +1 -37
- mojo/helpers/settings/parser.py +132 -0
- mojo/middleware/logging.py +1 -1
- mojo/middleware/mojo.py +5 -0
- mojo/models/rest.py +261 -46
- mojo/models/secrets.py +13 -4
- mojo/serializers/__init__.py +100 -0
- mojo/serializers/advanced/README.md +363 -0
- mojo/serializers/advanced/__init__.py +247 -0
- mojo/serializers/advanced/formats/__init__.py +28 -0
- mojo/serializers/advanced/formats/csv.py +416 -0
- mojo/serializers/advanced/formats/excel.py +516 -0
- mojo/serializers/advanced/formats/json.py +239 -0
- mojo/serializers/advanced/formats/localizers.py +509 -0
- mojo/serializers/advanced/formats/response.py +485 -0
- mojo/serializers/advanced/serializer.py +568 -0
- mojo/serializers/manager.py +501 -0
- mojo/serializers/optimized.py +618 -0
- mojo/serializers/settings_example.py +322 -0
- mojo/serializers/{models.py → simple.py} +38 -15
- testit/helpers.py +21 -4
- django_nativemojo-0.1.10.dist-info/METADATA +0 -96
- mojo/apps/metrics/rest/db.py +0 -0
- mojo/helpers/aws/setup_email.py +0 -0
- mojo/ws4redis/README.md +0 -174
- mojo/ws4redis/__init__.py +0 -2
- mojo/ws4redis/client.py +0 -283
- mojo/ws4redis/connection.py +0 -327
- mojo/ws4redis/exceptions.py +0 -32
- mojo/ws4redis/redis.py +0 -183
- mojo/ws4redis/servers/base.py +0 -86
- mojo/ws4redis/servers/django.py +0 -171
- mojo/ws4redis/servers/uwsgi.py +0 -63
- mojo/ws4redis/settings.py +0 -45
- mojo/ws4redis/utf8validator.py +0 -128
- mojo/ws4redis/websocket.py +0 -403
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/LICENSE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/NOTICE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/WHEEL +0 -0
- /mojo/{ws4redis/servers → apps/aws}/__init__.py +0 -0
- /mojo/apps/{fileman/models/render.py → aws/models/__init__.py} +0 -0
- /mojo/apps/fileman/{rest/__init__ → migrations/__init__.py} +0 -0
mojo/ws4redis/README.md
DELETED
@@ -1,174 +0,0 @@
|
|
1
|
-
# Websocket HOWTO
|
2
|
-
|
3
|
-
## Authentication
|
4
|
-
|
5
|
-
### JWT
|
6
|
-
|
7
|
-
Requires an existing JWT token that has gone through authentication process via rest
|
8
|
-
|
9
|
-
```json
|
10
|
-
{
|
11
|
-
"action": "auth",
|
12
|
-
"kind": "jwt",
|
13
|
-
"token": "..."
|
14
|
-
}
|
15
|
-
```
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
### Model Authentication
|
20
|
-
|
21
|
-
You can implement custom authentication flows via a model by using the WS4REDIS_AUTHENTICATORS in your django settings.py.
|
22
|
-
|
23
|
-
##### WS4REDIS_AUTHENTICATORS
|
24
|
-
|
25
|
-
```python
|
26
|
-
WS4REDIS_AUTHENTICATORS = {
|
27
|
-
"mymodel": "myapp.MyModel"
|
28
|
-
}
|
29
|
-
```
|
30
|
-
|
31
|
-
In your Model you will need to add the following class methods.
|
32
|
-
|
33
|
-
This method is used by the async/websocket service to authenticate.
|
34
|
-
If the model can authenticate the connection it should return dict with kind and pk of the model that is authenticaed.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
##### authWS4RedisConnection
|
39
|
-
|
40
|
-
This method will authenticate the model, or return None if authentication failed.
|
41
|
-
|
42
|
-
```python
|
43
|
-
@classmethod
|
44
|
-
def authWS4RedisConnection(cls, auth_data):
|
45
|
-
if auth_data and auth_data.token:
|
46
|
-
terminal = cls.objects.filter(token=auth_data.token).last()
|
47
|
-
if terminal is not None:
|
48
|
-
# we now return the terminal credentials to the framework
|
49
|
-
return UberDict(
|
50
|
-
kind="terminal",
|
51
|
-
pk=terminal.id,
|
52
|
-
uuid=terminal.tid,
|
53
|
-
token=auth_data.token,
|
54
|
-
only_one=True, # only allows one connection at a time
|
55
|
-
instance=terminal)
|
56
|
-
return None
|
57
|
-
```
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
##### canPublishTo
|
62
|
-
|
63
|
-
Add this to your Model to validate messages from this connection to be sent to this channel.
|
64
|
-
|
65
|
-
```python
|
66
|
-
@classmethod
|
67
|
-
def canPublishTo(cls, credentials, msg):
|
68
|
-
if credentials:
|
69
|
-
return True
|
70
|
-
return False
|
71
|
-
```
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
##### WS4REDIS_CHANNELS
|
76
|
-
|
77
|
-
Map channels to models
|
78
|
-
|
79
|
-
```python
|
80
|
-
WS4REDIS_CHANNELS = {
|
81
|
-
"group": "account.Group",
|
82
|
-
"chat": "chat.Room",
|
83
|
-
}
|
84
|
-
```
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
##### onWS4RedisMessage
|
89
|
-
|
90
|
-
Add this to your Model to allow for handling of messages sent to this channel.
|
91
|
-
|
92
|
-
```python
|
93
|
-
@classmethod
|
94
|
-
def onWS4RedisMessage(cls, credentials, msg):
|
95
|
-
if msg.action == "status":
|
96
|
-
cls.createStatusRecord(msg)
|
97
|
-
|
98
|
-
```
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
### URL Params
|
103
|
-
|
104
|
-
You can also use params in the url of the websocket.
|
105
|
-
|
106
|
-
**THIS IS NOT RECOMMENDED as the url params are not encrypted and can be easily snooped.**
|
107
|
-
|
108
|
-
Include something like the follow in your django settings.py:
|
109
|
-
|
110
|
-
```python
|
111
|
-
def URL_AUTHENTICATOR(ws_con):
|
112
|
-
from objict import objict
|
113
|
-
token = ws_con.request.GET.get("token", None)
|
114
|
-
session_key = ws_con.request.GET.get("session_key", None)
|
115
|
-
if token is not None:
|
116
|
-
# this example assume the token is used for terminal auth
|
117
|
-
# you will still need to implement the Custom Auth flows to handle this
|
118
|
-
ws_con.on_auth(objict(kind="terminal", token=token))
|
119
|
-
elif session_key is not None:
|
120
|
-
# or alternative is a session
|
121
|
-
ws_con.on_auth(objict(kind="session", token=session_key))
|
122
|
-
|
123
|
-
```
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
## Subscribe
|
128
|
-
|
129
|
-
```json
|
130
|
-
{
|
131
|
-
"action": "subscribe",
|
132
|
-
"channel": "group",
|
133
|
-
"pk": 3,
|
134
|
-
}
|
135
|
-
```
|
136
|
-
|
137
|
-
### Security
|
138
|
-
|
139
|
-
In settins WS4REDIS_CHANNELS, map your channel to a model.
|
140
|
-
The model should have a classmethod for canSubscribeTo that returns a list of pk they can subscribe to.
|
141
|
-
|
142
|
-
|
143
|
-
## UnSubscribe
|
144
|
-
|
145
|
-
```json
|
146
|
-
{
|
147
|
-
"action": "unsubscribe",
|
148
|
-
"channel": "group",
|
149
|
-
"pk": 3,
|
150
|
-
}
|
151
|
-
```
|
152
|
-
|
153
|
-
|
154
|
-
## Publish / Send To
|
155
|
-
|
156
|
-
```json
|
157
|
-
{
|
158
|
-
"action": "publish",
|
159
|
-
"channel": "group",
|
160
|
-
"pk": 3,
|
161
|
-
"message": "..."
|
162
|
-
}
|
163
|
-
```
|
164
|
-
|
165
|
-
### Security
|
166
|
-
|
167
|
-
In settins WS4REDIS_CHANNELS, map your channel to a model.
|
168
|
-
The model should have a classmethod for canPublishTo that returns a list of pk they can publish to.
|
169
|
-
|
170
|
-
|
171
|
-
## Custom Messages
|
172
|
-
|
173
|
-
If an unknown action is sent with a channel then the framework will call onWS4RedisMessage on the channel model.
|
174
|
-
|
mojo/ws4redis/__init__.py
DELETED
mojo/ws4redis/client.py
DELETED
@@ -1,283 +0,0 @@
|
|
1
|
-
import time
|
2
|
-
|
3
|
-
from objict import objict
|
4
|
-
|
5
|
-
from mojo.ws4redis.redis import RedisMessage, RedisStore, getRedisClient, getPoolStatus
|
6
|
-
|
7
|
-
|
8
|
-
def buildEventMessage(name=None, message=None, priority=0, model=None, model_pk=None, custom=None):
|
9
|
-
msg = objict(priority=priority)
|
10
|
-
if name:
|
11
|
-
msg["name"] = name
|
12
|
-
|
13
|
-
if message:
|
14
|
-
msg["message"] = message
|
15
|
-
|
16
|
-
if model:
|
17
|
-
msg["component"] = objict(pk=model_pk, model=model)
|
18
|
-
|
19
|
-
if custom:
|
20
|
-
msg.update(custom)
|
21
|
-
return msg.toJSON(as_string=True)
|
22
|
-
|
23
|
-
|
24
|
-
def ping():
|
25
|
-
return getRedisClient().ping()
|
26
|
-
|
27
|
-
|
28
|
-
def exists(key, default=None):
|
29
|
-
c = getRedisClient()
|
30
|
-
return c.exists(key)
|
31
|
-
|
32
|
-
|
33
|
-
def keys(keys):
|
34
|
-
c = getRedisClient()
|
35
|
-
return [v.decode() for v in c.keys(keys)]
|
36
|
-
|
37
|
-
|
38
|
-
def get(key, default=None, field_type=None):
|
39
|
-
c = getRedisClient()
|
40
|
-
v = c.get(key)
|
41
|
-
if v is None:
|
42
|
-
return default
|
43
|
-
if field_type is not None:
|
44
|
-
if field_type == "json":
|
45
|
-
return objict.fromJSON(v, ignore_errors=True)
|
46
|
-
if field_type in [str, "str"]:
|
47
|
-
v = v.decode()
|
48
|
-
return field_type(v)
|
49
|
-
return v
|
50
|
-
|
51
|
-
|
52
|
-
def set(key, value, expire=None):
|
53
|
-
c = getRedisClient()
|
54
|
-
v = c.set(key, value)
|
55
|
-
if expire:
|
56
|
-
c.expire(key, expire)
|
57
|
-
return v
|
58
|
-
|
59
|
-
|
60
|
-
def incr(key, amount=1, expire=None):
|
61
|
-
c = getRedisClient()
|
62
|
-
v = c.incr(key, amount)
|
63
|
-
if expire:
|
64
|
-
c.expire(key, expire)
|
65
|
-
return v
|
66
|
-
|
67
|
-
|
68
|
-
def expire(key, expire):
|
69
|
-
c = getRedisClient()
|
70
|
-
return c.expire(key, expire)
|
71
|
-
|
72
|
-
|
73
|
-
def decr(key, amount=1):
|
74
|
-
c = getRedisClient()
|
75
|
-
return c.decr(key, amount)
|
76
|
-
|
77
|
-
|
78
|
-
def delete(key):
|
79
|
-
c = getRedisClient()
|
80
|
-
return c.delete(key)
|
81
|
-
|
82
|
-
|
83
|
-
# SET FUNCTIONS
|
84
|
-
def sadd(name, *values):
|
85
|
-
# add value to set
|
86
|
-
c = getRedisClient()
|
87
|
-
return c.sadd(name, *values)
|
88
|
-
|
89
|
-
|
90
|
-
def srem(name, *values):
|
91
|
-
# remove value from set
|
92
|
-
c = getRedisClient()
|
93
|
-
return c.srem(name, *values)
|
94
|
-
|
95
|
-
|
96
|
-
def sismember(name, value):
|
97
|
-
# return items in set
|
98
|
-
c = getRedisClient()
|
99
|
-
return c.sismember(name, value)
|
100
|
-
|
101
|
-
|
102
|
-
def scard(name):
|
103
|
-
# count items in set
|
104
|
-
c = getRedisClient()
|
105
|
-
return c.scard(name)
|
106
|
-
|
107
|
-
|
108
|
-
def smembers(name):
|
109
|
-
# return items in set
|
110
|
-
c = getRedisClient()
|
111
|
-
return c.smembers(name)
|
112
|
-
|
113
|
-
|
114
|
-
# HASH FUNCTIONS
|
115
|
-
def hget(name, field, default=None):
|
116
|
-
c = getRedisClient()
|
117
|
-
v = c.hget(name, field)
|
118
|
-
if v is None:
|
119
|
-
return default
|
120
|
-
return v
|
121
|
-
|
122
|
-
|
123
|
-
def hgetall(name):
|
124
|
-
c = getRedisClient()
|
125
|
-
return c.hgetall(name)
|
126
|
-
|
127
|
-
|
128
|
-
def hset(name, field, value):
|
129
|
-
c = getRedisClient()
|
130
|
-
return c.hset(name, field, value)
|
131
|
-
|
132
|
-
|
133
|
-
def hdel(name, field):
|
134
|
-
c = getRedisClient()
|
135
|
-
return c.hdel(name, field)
|
136
|
-
|
137
|
-
|
138
|
-
def hincrby(name, field, inc=1):
|
139
|
-
c = getRedisClient()
|
140
|
-
return c.hincrby(name, field, inc)
|
141
|
-
|
142
|
-
|
143
|
-
def lpush(name, value, unique=False):
|
144
|
-
c = getRedisClient()
|
145
|
-
if isinstance(value, list):
|
146
|
-
for v in value:
|
147
|
-
if unique and value.encode() in c.lrange(name, 0, -1):
|
148
|
-
return 0
|
149
|
-
c.lpush(name, v)
|
150
|
-
return len(value)
|
151
|
-
if unique and value.encode() in c.lrange(name, 0, -1):
|
152
|
-
return 0
|
153
|
-
return c.lpush(name, value)
|
154
|
-
|
155
|
-
|
156
|
-
def rpush(name, value, unique=False):
|
157
|
-
c = getRedisClient()
|
158
|
-
if isinstance(value, list):
|
159
|
-
for v in value:
|
160
|
-
if unique and value.encode() in c.lrange(name, 0, -1):
|
161
|
-
return 0
|
162
|
-
c.rpush(name, v)
|
163
|
-
return len(value)
|
164
|
-
if unique and value.encode() in c.lrange(name, 0, -1):
|
165
|
-
return 0
|
166
|
-
return c.rpush(name, value)
|
167
|
-
|
168
|
-
|
169
|
-
def lpop(name, timeout=None):
|
170
|
-
c = getRedisClient()
|
171
|
-
if timeout is None:
|
172
|
-
return c.lpop(name)
|
173
|
-
r = c.blpop(name, timeout=timeout)
|
174
|
-
if isinstance(r, tuple):
|
175
|
-
return r[1].decode()
|
176
|
-
|
177
|
-
|
178
|
-
def rpop(name, timeout=None):
|
179
|
-
c = getRedisClient()
|
180
|
-
if timeout is None:
|
181
|
-
return c.rpop(name)
|
182
|
-
r = c.brpop(name, timeout=timeout)
|
183
|
-
if isinstance(r, tuple):
|
184
|
-
return r[1].decode()
|
185
|
-
|
186
|
-
|
187
|
-
def lrem(name, value, occurences=1):
|
188
|
-
c = getRedisClient()
|
189
|
-
return c.lrem(name, occurences, value.encode())
|
190
|
-
|
191
|
-
|
192
|
-
def vpop(name, value, timeout=None):
|
193
|
-
c = getRedisClient()
|
194
|
-
start = time.time()
|
195
|
-
while c.lrem(name, 1, value) == 0:
|
196
|
-
if timeout is None:
|
197
|
-
return 0
|
198
|
-
time.sleep(1.0)
|
199
|
-
elapsed = time.time() - start
|
200
|
-
if elapsed > timeout:
|
201
|
-
return 0
|
202
|
-
return 1
|
203
|
-
|
204
|
-
|
205
|
-
def lrange(name, start, end):
|
206
|
-
c = getRedisClient()
|
207
|
-
return [v.decode() for v in c.lrange(name, start, end)]
|
208
|
-
|
209
|
-
|
210
|
-
def sendToUser(user, name, message=None, priority=0, model=None, model_pk=None, custom=None):
|
211
|
-
return sendMessageToUsers([user], buildEventMessage(name, message, priority, model, model_pk, custom))
|
212
|
-
|
213
|
-
|
214
|
-
def sendToUsers(users, name, message=None, priority=0, model=None, model_pk=None, custom=None):
|
215
|
-
return sendMessageToUsers(users, buildEventMessage(name, message, priority, model, model_pk, custom))
|
216
|
-
|
217
|
-
|
218
|
-
def sendMessageToUsers(users, msg):
|
219
|
-
return RedisStore().publish(RedisMessage(msg), channel="user", pk=[u.username for u in users])
|
220
|
-
|
221
|
-
|
222
|
-
def sendToGroup(group, name, message=None, priority=0, model=None, model_pk=None, custom=None):
|
223
|
-
return sendMessageToModels("group", [group], buildEventMessage(name, message, priority, model, model_pk, custom))
|
224
|
-
|
225
|
-
|
226
|
-
def sendToGroups(groups, name, message=None, priority=0, model=None, model_pk=None, custom=None):
|
227
|
-
return sendMessageToModels("group", groups, buildEventMessage(name, message, priority, model, model_pk, custom))
|
228
|
-
|
229
|
-
|
230
|
-
def sendToModels(channel, models, name, message=None, priority=0, model=None, model_pk=None, custom=None):
|
231
|
-
return sendMessageToModels(channel, models, buildEventMessage(name, message, priority, model, model_pk, custom))
|
232
|
-
|
233
|
-
|
234
|
-
def sendMessageToModels(channel, models, msg):
|
235
|
-
return RedisStore().publish(RedisMessage(msg), channel=channel, pk=[g.pk for g in models])
|
236
|
-
|
237
|
-
|
238
|
-
def sendMessageToPK(channel, pk, msg):
|
239
|
-
return RedisStore().publish(RedisMessage(msg), channel=channel, pk=pk)
|
240
|
-
|
241
|
-
|
242
|
-
def broadcast(name, message=None, priority=0, model=None, model_pk=None, custom=None):
|
243
|
-
return broadcastMessage(buildEventMessage(name, message, priority, model, model_pk, custom))
|
244
|
-
|
245
|
-
|
246
|
-
def broadcastMessage(msg):
|
247
|
-
return RedisStore().publish(RedisMessage(msg), channel="broadcast")
|
248
|
-
|
249
|
-
|
250
|
-
def publish(key, data, c=None):
|
251
|
-
if c is None:
|
252
|
-
c = getRedisClient()
|
253
|
-
if isinstance(data, dict):
|
254
|
-
if not isinstance(data, objict):
|
255
|
-
data = objict(data)
|
256
|
-
data = data.toJSON(as_string=True)
|
257
|
-
return c.publish(key, data)
|
258
|
-
|
259
|
-
|
260
|
-
def subscribe(channel):
|
261
|
-
c = getRedisClient()
|
262
|
-
pubsub = c.pubsub()
|
263
|
-
pubsub.subscribe(channel)
|
264
|
-
return pubsub
|
265
|
-
|
266
|
-
|
267
|
-
def waitForMessage(pubsub, msg_filter, timeout=55):
|
268
|
-
timeout_at = time.time() + timeout
|
269
|
-
while time.time() < timeout_at:
|
270
|
-
message = pubsub.get_message()
|
271
|
-
if message is not None:
|
272
|
-
if message.get("type") == "message":
|
273
|
-
msg = objict.fromJSON(message.get("data"))
|
274
|
-
if msg_filter(msg):
|
275
|
-
pubsub.unsubscribe()
|
276
|
-
return msg
|
277
|
-
time.sleep(1.0)
|
278
|
-
pubsub.unsubscribe()
|
279
|
-
return None
|
280
|
-
|
281
|
-
|
282
|
-
def isOnline(name, pk):
|
283
|
-
return sismember(f"{name}:online", pk)
|