Mercurial > libervia-web
annotate libervia/server/websockets.py @ 1131:9cf592d1e6aa
server: better error handling when a named page mentioned in menu_json is missing
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 18 Sep 2018 21:16:51 +0200 |
parents | 28e3eb3bb217 |
children | 2af117bfe6cc |
rev | line source |
---|---|
995 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # Libervia: a Salut à Toi frontend | |
1054 | 5 # Copyright (C) 2011-2018 Jérôme Poisson <goffi@goffi.org> |
995 | 6 |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 from sat.core.i18n import _ | |
21 from sat.core.log import getLogger | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
22 |
995 | 23 log = getLogger(__name__) |
24 from sat.core import exceptions | |
25 | |
26 from autobahn.twisted import websocket | |
27 from autobahn.twisted import resource as resource | |
28 from autobahn.websocket import types | |
29 | |
30 import json | |
31 | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
32 LIBERVIA_PROTOCOL = "libervia_page" |
995 | 33 |
34 | |
35 class LiberviaPageWSProtocol(websocket.WebSocketServerProtocol): | |
36 host = None | |
37 tokens_map = {} | |
38 | |
39 def onConnect(self, request): | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
40 prefix = LIBERVIA_PROTOCOL + u"_" |
995 | 41 for protocol in request.protocols: |
42 if protocol.startswith(prefix): | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
43 token = protocol[len(prefix) :].strip() |
995 | 44 if token: |
45 break | |
46 else: | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
47 raise types.ConnectionDeny( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
48 types.ConnectionDeny.NOT_IMPLEMENTED, u"Can't use this subprotocol" |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
49 ) |
995 | 50 |
51 if token not in self.tokens_map: | |
52 log.warning(_(u"Can't activate page socket: unknown token")) | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
53 raise types.ConnectionDeny( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
54 types.ConnectionDeny.FORBIDDEN, u"Bad token, please reload page" |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
55 ) |
995 | 56 self.token = token |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
57 self.page = self.tokens_map[token]["page"] |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
58 self.request = self.tokens_map[token]["request"] |
995 | 59 return protocol |
60 | |
61 def onOpen(self): | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
62 log.debug( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
63 _( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
64 u"Websocket opened for {page} (token: {token})".format( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
65 page=self.page, token=self.token |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
66 ) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
67 ) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
68 ) |
995 | 69 self.request.sendData = self.sendJSONData |
70 self.page.onSocketOpen(self.request) | |
71 | |
72 def onMessage(self, payload, isBinary): | |
73 try: | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
74 data_json = json.loads(payload.decode("utf8")) |
995 | 75 except ValueError as e: |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
76 log.warning( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
77 _(u"Not valid JSON, ignoring data: {msg}\n{data}").format( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
78 msg=e, data=payload |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
79 ) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
80 ) |
995 | 81 return |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
82 # we request page first, to raise an AttributeError |
995 | 83 # if it is not set (which should never happen) |
84 page = self.page | |
85 try: | |
86 cb = page.on_data | |
87 except AttributeError: | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
88 log.warning( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
89 _( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
90 u'No "on_data" method set on dynamic page, ignoring data:\n{data}' |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
91 ).format(data=data_json) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
92 ) |
995 | 93 else: |
94 cb(page, self.request, data_json) | |
95 | |
96 def onClose(self, wasClean, code, reason): | |
97 try: | |
98 token = self.token | |
99 except AttributeError: | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
100 log.warning(_(u"Websocket closed but no token is associated")) |
995 | 101 return |
102 | |
103 self.page.onSocketClose(self.request) | |
104 | |
105 try: | |
106 del self.tokens_map[token] | |
107 del self.request.sendData | |
108 except (KeyError, AttributeError): | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
109 raise exceptions.InternalError( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
110 _(u"Token or sendData doesn't exist, this should never happen!") |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
111 ) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
112 log.debug( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
113 _( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
114 u"Websocket closed for {page} (token: {token}). {reason}".format( |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
115 page=self.page, |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
116 token=self.token, |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
117 reason=u"" |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
118 if wasClean |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
119 else _(u"Reason: {reason}").format(reason=reason), |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
120 ) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
121 ) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
122 ) |
995 | 123 |
124 def sendJSONData(self, type_, **data): | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
125 assert "type" not in data |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
126 data["type"] = type_ |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
127 self.sendMessage(json.dumps(data, ensure_ascii=False).encode("utf8")) |
995 | 128 |
129 @classmethod | |
130 def getBaseURL(cls, host, secure): | |
131 return u"ws{sec}://localhost:{port}".format( | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
132 sec="s" if secure else "", |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
133 port=cls.host.options["port_https" if secure else "port"], |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
134 ) |
995 | 135 |
136 @classmethod | |
137 def getResource(cls, host, secure): | |
138 if cls.host is None: | |
139 cls.host = host | |
140 factory = websocket.WebSocketServerFactory(cls.getBaseURL(host, secure)) | |
141 factory.protocol = cls | |
142 return resource.WebSocketResource(factory) | |
143 | |
144 @classmethod | |
145 def registerToken(cls, token, page, request): | |
146 if token in cls.tokens_map: | |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
147 raise exceptions.ConflictError(_(u"This token is already registered")) |
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
148 cls.tokens_map[token] = {"page": page, "request": request} |