10
10
SCENE_PUBLIC_WRITE_DEF , SCENE_USERS_DEF ,
11
11
SCENE_VIDEO_CONF_DEF , Scene )
12
12
13
- # topic constants
14
13
PUBLIC_NAMESPACE = "public"
15
14
ANON_REGEX = "anonymous-(?=.*?[a-zA-Z].*?[a-zA-Z])"
16
15
DEF_JWT_DURATION = datetime .timedelta (minutes = 1 )
17
- API_V1 = "v1"
18
- API_V2 = "v2"
16
+
17
+ # version constants
18
+ API_V1 = "v1" # url /user/, first version
19
+ API_V2 = "v2" # url /user/v2/, full topic structure refactor
19
20
TOPIC_SUPPORTED_API_VERSIONS = [API_V1 , API_V2 ] # TODO (mwfarb): remove v1
20
21
21
22
@@ -30,11 +31,10 @@ def all_scenes_read_token(version):
30
31
31
32
realm = config ["mqtt_realm" ]
32
33
username = config ["mqtt_username" ]
33
- duration = datetime .timedelta (minutes = 1 )
34
34
35
35
payload = {}
36
36
payload ["sub" ] = username
37
- payload ["exp" ] = datetime .datetime .utcnow () + duration
37
+ payload ["exp" ] = datetime .datetime .utcnow () + DEF_JWT_DURATION
38
38
39
39
if version == API_V2 :
40
40
payload ["subs" ] = [f"{ realm } /s/+/+/o/#" ] # v2
@@ -49,37 +49,20 @@ def generate_arena_token(
49
49
* ,
50
50
user ,
51
51
username ,
52
- realm = "realm" ,
52
+ realm = None ,
53
53
ns_scene = None ,
54
- device = None ,
55
- camid = None ,
56
- userid = None ,
57
- handleftid = None ,
58
- handrightid = None ,
54
+ ns_device = None ,
55
+ ids = None ,
59
56
duration = DEF_JWT_DURATION
60
57
):
61
- """ MQTT Token Constructor. Topic Notes:
62
- /s/: virtual scene objects
63
- /d/: device inter-process
64
- /env/: physical environment detection
65
-
66
- Args:
67
- user (object): User object
68
- username (str): _description_
69
- realm (str, optional): _description_. Defaults to "realm".
70
- ns_scene (str, optional): _description_. Defaults to None.
71
- device (str, optional): _description_. Defaults to None.
72
- camid (str, optional): _description_. Defaults to None.
73
- userid (str, optional): _description_. Defaults to None.
74
- handleftid (str, optional): _description_. Defaults to None.
75
- handrightid (str, optional): _description_. Defaults to None.
76
- duration (integer, optional): _description_. Defaults to DEF_JWT_DURATION.
58
+ """ MQTT Token Constructor.
77
59
78
60
Returns:
79
61
str: JWT or None
80
62
"""
81
- subs = []
82
- pubs = []
63
+ config = settings .PUBSUB
64
+ if not realm :
65
+ realm = config ["mqtt_realm" ]
83
66
privkeyfile = settings .MQTT_TOKEN_PRIVKEY
84
67
if not os .path .exists (privkeyfile ):
85
68
print ("Error: keyfile not found" )
@@ -91,43 +74,75 @@ def generate_arena_token(
91
74
payload ["exp" ] = datetime .datetime .utcnow () + duration
92
75
headers = None
93
76
94
- p_public_read = SCENE_PUBLIC_READ_DEF
95
- p_public_write = SCENE_PUBLIC_WRITE_DEF
96
- p_anonymous_users = SCENE_ANON_USERS_DEF
97
- p_video = SCENE_VIDEO_CONF_DEF
98
- p_users = SCENE_USERS_DEF
99
-
100
- # create permissions shorthand
77
+ perm = {
78
+ "public_read" : SCENE_PUBLIC_READ_DEF ,
79
+ "public_write" : SCENE_PUBLIC_WRITE_DEF ,
80
+ "anonymous_users" : SCENE_ANON_USERS_DEF ,
81
+ "video" : SCENE_VIDEO_CONF_DEF ,
82
+ "users" : SCENE_USERS_DEF ,
83
+ }
101
84
if ns_scene and Scene .objects .filter (name = ns_scene ).exists ():
102
- scene_perm = Scene .objects .get (name = ns_scene )
103
- p_public_read = scene_perm .public_read
104
- p_public_write = scene_perm .public_write
105
- p_anonymous_users = scene_perm .anonymous_users
106
- p_video = scene_perm .video_conference
107
- p_users = scene_perm .users
85
+ p = Scene .objects .get (name = ns_scene )
86
+ perm [ "public_read" ] = p .public_read
87
+ perm [ "public_write" ] = p .public_write
88
+ perm [ "anonymous_users" ] = p .anonymous_users
89
+ perm [ "video" ] = p .video_conference
90
+ perm [ "users" ] = p .users
108
91
109
92
# add jitsi server params if a/v scene
110
- if ns_scene and camid and p_users and p_video :
93
+ if ns_scene and ids and perm [ "users" ] and perm [ "video" ] :
111
94
host = os .getenv ("HOSTNAME" )
112
95
headers = {"kid" : host }
113
96
payload ["aud" ] = "arena"
114
97
payload ["iss" ] = "arena-account"
115
- # we use the namespace + scene name as the jitsi room name, handle RFC 3986 reserved chars as = '_'
98
+ # we use the scene name as the jitsi room name, handle RFC 3986 reserved chars as = '_'
116
99
roomname = re .sub (r"[!#$&'()*+,\/:;=?@[\]]" , '_' , ns_scene .lower ())
117
100
payload ["room" ] = roomname
118
101
102
+ pubs , subs = get_pubsub_topics_api_v1 (
103
+ user ,
104
+ username ,
105
+ realm ,
106
+ ns_scene ,
107
+ ns_device ,
108
+ ids ,
109
+ perm ,
110
+ )
111
+ if len (subs ) > 0 :
112
+ payload ["subs" ] = clean_topics (subs )
113
+ if len (pubs ) > 0 :
114
+ payload ["publ" ] = clean_topics (pubs )
115
+
116
+ return jwt .encode (payload , private_key , algorithm = "RS256" , headers = headers )
117
+
118
+
119
+ def get_pubsub_topics_api_v1 (
120
+ user ,
121
+ username ,
122
+ realm ,
123
+ ns_scene ,
124
+ ns_device ,
125
+ ids ,
126
+ perm ,
127
+ ):
128
+ """ V1 Topic Notes:
129
+ /s/: virtual scene objects
130
+ /d/: device inter-process
131
+ /env/: physical environment detection
132
+ """
133
+ pubs = []
134
+ subs = []
119
135
# everyone should be able to read all public scenes
120
- if not device : # scene token scenario
136
+ if not ns_device : # scene token scenario
121
137
subs .append (f"{ realm } /s/{ PUBLIC_NAMESPACE } /#" )
122
138
# And transmit env data
123
139
pubs .append (f"{ realm } /env/{ PUBLIC_NAMESPACE } /#" )
124
-
125
140
# user presence objects
126
141
if user .is_authenticated :
127
- if device : # device token scenario
142
+ if ns_device : # device token scenario
128
143
# device owners have rights to their device objects only
129
- subs .append (f"{ realm } /d/{ device } /#" )
130
- pubs .append (f"{ realm } /d/{ device } /#" )
144
+ subs .append (f"{ realm } /d/{ ns_device } /#" )
145
+ pubs .append (f"{ realm } /d/{ ns_device } /#" )
131
146
else : # scene token scenario
132
147
# scene rights default by namespace
133
148
if user .is_staff :
@@ -164,58 +179,47 @@ def generate_arena_token(
164
179
# device owners have rights to their device objects only
165
180
subs .append (f"{ realm } /d/{ username } /#" )
166
181
pubs .append (f"{ realm } /d/{ username } /#" )
167
-
168
182
# anon/non-owners have rights to view scene objects only
169
183
if ns_scene and not user .is_staff :
170
184
# did the user set specific public read or public write?
171
- if not user .is_authenticated and not p_anonymous_users :
185
+ if not user .is_authenticated and not perm [ "anonymous_users" ] :
172
186
return None # anonymous not permitted
173
- if p_public_read :
187
+ if perm [ "public_read" ] :
174
188
subs .append (f"{ realm } /s/{ ns_scene } /#" )
175
189
# Interactivity to extent of viewing objects is similar to publishing env
176
190
pubs .append (f"{ realm } /env/{ ns_scene } /#" )
177
- if p_public_write :
191
+ if perm [ "public_write" ] :
178
192
pubs .append (f"{ realm } /s/{ ns_scene } /#" )
179
193
# user presence objects
180
- if camid and p_users : # probable web browser write
181
- pubs .append (f"{ realm } /s/{ ns_scene } /{ camid } " )
182
- pubs .append (f"{ realm } /s/{ ns_scene } /{ camid } /#" )
183
- if handleftid and p_users :
184
- pubs .append (f"{ realm } /s/{ ns_scene } /{ handleftid } " )
185
- if handrightid and p_users :
186
- pubs .append (f"{ realm } /s/{ ns_scene } /{ handrightid } " )
187
-
194
+ if ids and perm ["users" ]: # probable web browser write
195
+ pubs .append (f"{ realm } /s/{ ns_scene } /{ ids ['camid' ]} " )
196
+ pubs .append (f"{ realm } /s/{ ns_scene } /{ ids ['camid' ]} /#" )
197
+ pubs .append (f"{ realm } /s/{ ns_scene } /{ ids ['handleftid' ]} " )
198
+ pubs .append (f"{ realm } /s/{ ns_scene } /{ ids ['handrightid' ]} " )
188
199
# chat messages
189
- if ns_scene and userid and p_users :
200
+ if ns_scene and ids and perm [ "users" ] :
190
201
namespace = ns_scene .split ("/" )[0 ]
202
+ userhandle = ids ["userid" ] + \
203
+ base64 .b64encode (ids ["userid" ].encode ()).decode ()
191
204
# receive private messages: Read
192
- subs .append (f"{ realm } /c/{ namespace } /p/{ userid } /#" )
205
+ subs .append (f"{ realm } /c/{ namespace } /p/{ ids [ ' userid' ] } /#" )
193
206
# receive open messages to everyone and/or scene: Read
194
207
subs .append (f"{ realm } /c/{ namespace } /o/#" )
195
208
# send open messages (chat keepalive, messages to all/scene): Write
196
- pubs .append (f"{ realm } /c/{ namespace } /o/{ userid } " )
209
+ pubs .append (f"{ realm } /c/{ namespace } /o/{ userhandle } " )
197
210
# private messages to user: Write
198
- pubs .append (f"{ realm } /c/{ namespace } /p/+/{ userid } " )
199
-
211
+ pubs .append (f"{ realm } /c/{ namespace } /p/+/{ userhandle } " )
200
212
# apriltags
201
213
if ns_scene :
202
214
subs .append (f"{ realm } /g/a/#" )
203
215
pubs .append (f"{ realm } /g/a/#" )
204
-
205
- # runtime manager
216
+ # arts runtime-mngr
206
217
subs .append (f"{ realm } /proc/#" )
207
218
pubs .append (f"{ realm } /proc/#" )
208
-
209
- # network metrics
219
+ # network graph
210
220
subs .append ("$NETWORK" )
211
221
pubs .append ("$NETWORK/latency" )
212
-
213
- if len (subs ) > 0 :
214
- payload ["subs" ] = clean_topics (subs )
215
- if len (pubs ) > 0 :
216
- payload ["publ" ] = clean_topics (pubs )
217
-
218
- return jwt .encode (payload , private_key , algorithm = "RS256" , headers = headers )
222
+ return pubs , subs
219
223
220
224
221
225
def clean_topics (topics ):
0 commit comments