annotate libervia/server/websockets.py @ 1128:6414fd795df4

server, pages: multi-sites refactoring: Libervia is now handling external sites (i.e. other sites than Libervia official site). The external site are declared in sites_path_public_dict (in [DEFAULT] section) which is read by template engine, then they are linked to virtual host with vhosts_dict (linking host name to site name) in [libervia] section. Sites are only instanced once, so adding an alias is just a matter of mapping the alias host name in vhosts_dict with the same site name. menu_json and url_redirections_dict can now accept keys named after site name, which will be linked to the data for the site. Data for default site can still be keyed at first level. Libervia official pages are added to external site (if pages are not overriden), allowing to call pages of the framework and to have facilities like login handling. Deprecated url_redirections_profile option has been removed.
author Goffi <goffi@goffi.org>
date Fri, 14 Sep 2018 21:41:28 +0200
parents 28e3eb3bb217
children 2af117bfe6cc
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
995
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/python
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # Libervia: a Salut à Toi frontend
1054
f2170536ba23 date update
Goffi <goffi@goffi.org>
parents: 995
diff changeset
5 # Copyright (C) 2011-2018 Jérôme Poisson <goffi@goffi.org>
995
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.i18n import _
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 log = getLogger(__name__)
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from sat.core import exceptions
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
25
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from autobahn.twisted import websocket
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 from autobahn.twisted import resource as resource
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 from autobahn.websocket import types
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 import json
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
31
1113
cdd389ef97bc server: code style reformatting using black
Goffi <goffi@goffi.org>
parents: 1054
diff changeset
32 LIBERVIA_PROTOCOL = "libervia_page"
995
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
33
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
34
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 class LiberviaPageWSProtocol(websocket.WebSocketServerProtocol):
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 host = None
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 tokens_map = {}
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
38
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 for protocol in request.protocols:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 if token:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 break
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
50
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 if token not in self.tokens_map:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 return protocol
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 self.request.sendData = self.sendJSONData
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 self.page.onSocketOpen(self.request)
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
71
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 def onMessage(self, payload, isBinary):
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 # if it is not set (which should never happen)
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 page = self.page
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 try:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 cb = page.on_data
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 else:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 cb(page, self.request, data_json)
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
95
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 def onClose(self, wasClean, code, reason):
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 try:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 token = self.token
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 return
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 self.page.onSocketClose(self.request)
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
104
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 try:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 del self.tokens_map[token]
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 del self.request.sendData
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
123
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
128
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
129 @classmethod
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
130 def getBaseURL(cls, host, secure):
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
135
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 @classmethod
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
137 def getResource(cls, host, secure):
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
138 if cls.host is None:
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 cls.host = host
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
140 factory = websocket.WebSocketServerFactory(cls.getBaseURL(host, secure))
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 factory.protocol = cls
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
142 return resource.WebSocketResource(factory)
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
143
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 @classmethod
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
145 def registerToken(cls, token, page, request):
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
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}