Mercurial > libervia-web
annotate libervia.tac @ 2:669c531a857e
signals handling and first draft of microblogging
- server side: signal handling throught json_signal_api page
- browser side: - signal handling throught a json rpc call loop
- first draft of microblog panel
- ContactPanel put in a separate module
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 08 Feb 2011 21:18:31 +0100 |
parents | 0a7c685faa53 |
children | 154d4caa57f4 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 """ | |
5 Libervia: a Salut à Toi frontend | |
6 Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) | |
7 | |
8 This program is free software: you can redistribute it and/or modify | |
9 it under the terms of the GNU Affero General Public License as published by | |
10 the Free Software Foundation, either version 3 of the License, or | |
11 (at your option) any later version. | |
12 | |
13 This program is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU Affero General Public License for more details. | |
17 | |
18 You should have received a copy of the GNU Affero General Public License | |
19 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 """ | |
21 | |
22 from twisted.application import internet, service | |
23 from twisted.internet import glib2reactor | |
24 glib2reactor.install() | |
25 from twisted.internet import reactor, defer | |
26 | |
27 from twisted.web import server | |
28 from twisted.web import error as weberror | |
29 from twisted.web.static import File | |
30 from twisted.web.resource import Resource | |
31 from txjsonrpc.web import jsonrpc | |
32 from txjsonrpc import jsonrpclib | |
33 from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService | |
34 | |
35 TIMEOUT = 120 #Session's time out, after that the user will be disconnected | |
36 | |
37 | |
38 class MethodHandler(jsonrpc.JSONRPC): | |
39 | |
40 def __init__(self, sat_host): | |
41 jsonrpc.JSONRPC.__init__(self) | |
42 self.sat_host=sat_host | |
43 | |
44 def render(self, request): | |
1 | 45 self.session = request.getSession() |
0 | 46 try: |
1 | 47 profile = self.session.sat_profile |
0 | 48 except AttributeError: |
49 #user is not identified, we return a jsonrpc fault | |
50 parsed = jsonrpclib.loads(request.content.read()) | |
51 fault = jsonrpclib.Fault(0, "Not allowed") #FIXME: define some standard error codes for libervia | |
52 return jsonrpc.JSONRPC._cbRender(self, fault, request, parsed.get('id'), parsed.get('jsonrpc')) | |
53 return jsonrpc.JSONRPC.render(self, request) | |
54 | |
55 | |
56 def jsonrpc_getContacts(self): | |
57 """Return all passed args.""" | |
1 | 58 profile = self.session.sat_profile |
59 return self.sat_host.bridge.getContacts(profile) | |
0 | 60 |
61 class Register(jsonrpc.JSONRPC): | |
62 """This class manage the registration procedure with SàT | |
63 It provide an api for the browser, check password and setup the web server""" | |
64 | |
65 def __init__(self, sat_host): | |
66 jsonrpc.JSONRPC.__init__(self) | |
67 self.sat_host=sat_host | |
68 self.profiles_waiting={} | |
69 self.request=None | |
70 | |
71 def getWaitingRequest(self, profile): | |
72 """Tell if a profile is trying to log in""" | |
73 if self.profiles_waiting.has_key(profile): | |
74 return self.profiles_waiting[profile] | |
75 else: | |
76 return None | |
77 | |
78 def render(self, request): | |
79 """ | |
80 Render method with some hacks: | |
81 - if login is requested, try to login with form data | |
82 - except login, every method is jsonrpc | |
83 - user doesn't need to be authentified for isRegistered, but must be for all other methods | |
84 """ | |
85 if request.postpath==['login']: | |
86 return self.login(request) | |
87 _session = request.getSession() | |
88 parsed = jsonrpclib.loads(request.content.read()) | |
89 if parsed.get("method")!="isRegistered": | |
90 #if we don't call login or isRegistered, we need to be identified | |
91 try: | |
92 profile = _session.sat_profile | |
93 except AttributeError: | |
94 #user is not identified, we return a jsonrpc fault | |
95 fault = jsonrpclib.Fault(0, "Not allowed") #FIXME: define some standard error codes for libervia | |
96 return jsonrpc.JSONRPC._cbRender(self, fault, request, parsed.get('id'), parsed.get('jsonrpc')) | |
97 self.request = request | |
98 return jsonrpc.JSONRPC.render(self, request) | |
99 | |
100 def login(self, request): | |
101 """ | |
102 this method is called with the POST information from the registering form | |
103 it test if the password is ok, and log in if it's the case, | |
104 else it return an error | |
105 @param request: request of the register formulaire, must have "login" and "password" as arguments | |
106 @return: A constant indicating the state: | |
107 - BAD REQUEST: something is wrong in the request (bad arguments, profile_key for login) | |
108 - AUTH ERROR: either the profile or the password is wrong | |
109 - ALREADY WAITING: a request has already be made for this profile | |
110 - server.NOT_DONE_YET: the profile is being processed, the return value will be given by self._logged or self._logginError | |
111 """ | |
112 try: | |
113 _login = request.args['login'][0] | |
114 if _login.startswith('@'): | |
115 raise Exception('No profile_key allowed') | |
116 _pass = request.args['password'][0] | |
117 except KeyError: | |
118 return "BAD REQUEST" | |
119 | |
120 _profile_check = self.sat_host.bridge.getProfileName(_login) | |
121 _profile_pass = self.sat_host.bridge.getParamA("Password", "Connection", profile_key=_login) | |
122 | |
123 if not _profile_check or _profile_check != _login or _profile_pass != _pass: | |
124 return "AUTH ERROR" | |
125 | |
126 if self.profiles_waiting.has_key(_login): | |
127 return "ALREADY WAITING" | |
128 | |
129 if self.sat_host.bridge.isConnected(_login): | |
130 return self._logged(_login, request) | |
131 | |
132 self.profiles_waiting[_login] = request | |
133 self.sat_host.bridge.connect(_login) | |
134 return server.NOT_DONE_YET | |
135 | |
136 def __cleanWaiting(self, login): | |
137 """Remove login from waiting queue""" | |
138 try: | |
139 del self.profiles_waiting[login] | |
140 except KeyError: | |
141 pass | |
142 | |
143 def _logged(self, login, request): | |
144 """Set everything when a user just logged | |
145 and return "LOGGED" to the requester""" | |
146 self.__cleanWaiting(login) | |
147 _session = request.getSession() | |
148 _session.sat_profile = login | |
149 return 'LOGGED' | |
150 | |
151 def _logginError(self, login, request, error_type): | |
152 """Something went wrong during loggin, return an error""" | |
153 self.__cleanWaiting(login) | |
154 return error_type | |
155 | |
156 def jsonrpc_isConnected(self): | |
157 _session = self.request.getSession() | |
158 profile = _session.sat_profile | |
159 return self.sat_host.bridge.isConnected(profile) | |
160 | |
161 def jsonrpc_connect(self): | |
162 _session = self.request.getSession() | |
163 profile = _session.sat_profile | |
164 if self.profiles_waiting.has_key(profile): | |
165 raise jsonrpclib.Fault('1','Already waiting') #FIXME: define some standard error codes for libervia | |
166 self.profiles_waiting[profile] = self.request | |
167 self.sat_host.bridge.connect(profile) | |
168 return server.NOT_DONE_YET | |
169 | |
170 def jsonrpc_isRegistered(self): | |
171 """Tell if the user is already registered""" | |
172 _session = self.request.getSession() | |
173 try: | |
174 profile = _session.sat_profile | |
175 except AttributeError: | |
176 return False | |
177 return True | |
178 | |
179 class SignalHandler(jsonrpc.JSONRPC): | |
180 | |
181 def __init__(self, sat_host): | |
182 Resource.__init__(self) | |
183 self.register=None | |
184 self.sat_host=sat_host | |
2
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
185 self.signalDeferred = None |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
186 |
0 | 187 def plugRegister(self, register): |
188 self.register = register | |
2
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
189 |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
190 def jsonrpc_getSignals(self): |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
191 """Keep the connection alive until a signal is received, then send it |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
192 @return: (signal, *signal_args)""" |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
193 self.signalDeferred = defer.Deferred() |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
194 return self.signalDeferred |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
195 |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
196 def getGenericCb(self, function_name): |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
197 """Return a generic function which send all params to signalDeferred.callback""" |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
198 def genericCb(*args): |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
199 if self.signalDeferred: |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
200 self.signalDeferred.callback((function_name,args)) |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
201 else: |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
202 print("Warning: signal [%s] can't be sent" % function_name) |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
203 return genericCb |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
204 |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
205 def genericCallback(self, *args): |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
206 """"This method send all params to signalDeferred""" |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
207 if self.signalDeferred: |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
208 print ("Sending signals %s") |
0 | 209 |
210 def connected(self, profile): | |
211 assert(self.register) #register must be plugged | |
212 request = self.register.getWaitingRequest(profile) | |
213 if request: | |
214 self.register._logged(profile, request) | |
215 | |
216 def connectionError(self, error_type, profile): | |
217 assert(self.register) #register must be plugged | |
218 request = self.register.getWaitingRequest(profile) | |
219 if request: #The user is trying to log in | |
220 if error_type == "AUTH_ERROR": | |
221 _error_t = "AUTH ERROR" | |
222 else: | |
223 _error_t = "UNKNOWN" | |
224 self.register._logginError(profile, request, _error_t) | |
225 | |
2
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
226 def render(self, request): |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
227 """ |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
228 Render method wich reject access if user is not identified |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
229 """ |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
230 _session = request.getSession() |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
231 parsed = jsonrpclib.loads(request.content.read()) |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
232 try: |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
233 profile = _session.sat_profile |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
234 except AttributeError: |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
235 #user is not identified, we return a jsonrpc fault |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
236 fault = jsonrpclib.Fault(0, "Not allowed") #FIXME: define some standard error codes for libervia |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
237 return jsonrpc.JSONRPC._cbRender(self, fault, request, parsed.get('id'), parsed.get('jsonrpc')) |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
238 self.request = request |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
239 return jsonrpc.JSONRPC.render(self, request) |
0 | 240 |
241 class Libervia(service.Service): | |
242 | |
243 def __init__(self): | |
244 root = File("output/") | |
245 self.signal_handler = SignalHandler(self) | |
2
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
246 root.putChild('json_signal_api', self.signal_handler) |
0 | 247 _register = Register(self) |
248 self.signal_handler.plugRegister(_register) | |
249 root.putChild('json_api', MethodHandler(self)) | |
250 root.putChild('register_api', _register) | |
251 self.site = server.Site(root) | |
252 self.sessions = {} #key = session value = user | |
253 ## bridge ## | |
254 try: | |
255 self.bridge=DBusBridgeFrontend() | |
256 except BridgeExceptionNoService: | |
257 print(u"Can't connect to SàT backend, are you sure it's launched ?") | |
258 import sys | |
259 sys.exit(1) | |
260 self.bridge.register("connected", self.signal_handler.connected) | |
261 self.bridge.register("connectionError", self.signal_handler.connectionError) | |
2
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
262 for signal_name in ['presenceUpdate']: |
669c531a857e
signals handling and first draft of microblogging
Goffi <goffi@goffi.org>
parents:
1
diff
changeset
|
263 self.bridge.register(signal_name, self.signal_handler.getGenericCb(signal_name)) |
0 | 264 |
265 def startService(self): | |
266 reactor.listenTCP(8080, self.site) | |
1 | 267 |
0 | 268 def run(self): |
269 reactor.run() | |
270 | |
271 def stop(self): | |
272 reactor.stop() | |
273 | |
274 | |
275 | |
276 application = service.Application('Libervia') | |
277 service = Libervia() | |
278 service.setServiceParent(application) |