comparison libervia.tac @ 0:140cec48224a

Initial commit
author Goffi <goffi@goffi.org>
date Sun, 30 Jan 2011 21:50:22 +0100
parents
children 0a7c685faa53
comparison
equal deleted inserted replaced
-1:000000000000 0:140cec48224a
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):
45 _session = request.getSession()
46 try:
47 profile = _session.sat_profile
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."""
58 d = defer.Deferred()
59 reactor.callLater(10, d.callback, [unicode(contact[0]) for contact in self.sat_host.bridge.getContacts()])
60 return d
61
62 class Register(jsonrpc.JSONRPC):
63 """This class manage the registration procedure with SàT
64 It provide an api for the browser, check password and setup the web server"""
65
66 def __init__(self, sat_host):
67 jsonrpc.JSONRPC.__init__(self)
68 self.sat_host=sat_host
69 self.profiles_waiting={}
70 self.request=None
71
72 def getWaitingRequest(self, profile):
73 """Tell if a profile is trying to log in"""
74 if self.profiles_waiting.has_key(profile):
75 return self.profiles_waiting[profile]
76 else:
77 return None
78
79 def render(self, request):
80 """
81 Render method with some hacks:
82 - if login is requested, try to login with form data
83 - except login, every method is jsonrpc
84 - user doesn't need to be authentified for isRegistered, but must be for all other methods
85 """
86 if request.postpath==['login']:
87 return self.login(request)
88 _session = request.getSession()
89 parsed = jsonrpclib.loads(request.content.read())
90 if parsed.get("method")!="isRegistered":
91 #if we don't call login or isRegistered, we need to be identified
92 try:
93 profile = _session.sat_profile
94 except AttributeError:
95 #user is not identified, we return a jsonrpc fault
96 fault = jsonrpclib.Fault(0, "Not allowed") #FIXME: define some standard error codes for libervia
97 return jsonrpc.JSONRPC._cbRender(self, fault, request, parsed.get('id'), parsed.get('jsonrpc'))
98 self.request = request
99 return jsonrpc.JSONRPC.render(self, request)
100
101 def login(self, request):
102 """
103 this method is called with the POST information from the registering form
104 it test if the password is ok, and log in if it's the case,
105 else it return an error
106 @param request: request of the register formulaire, must have "login" and "password" as arguments
107 @return: A constant indicating the state:
108 - BAD REQUEST: something is wrong in the request (bad arguments, profile_key for login)
109 - AUTH ERROR: either the profile or the password is wrong
110 - ALREADY WAITING: a request has already be made for this profile
111 - server.NOT_DONE_YET: the profile is being processed, the return value will be given by self._logged or self._logginError
112 """
113 try:
114 _login = request.args['login'][0]
115 if _login.startswith('@'):
116 raise Exception('No profile_key allowed')
117 _pass = request.args['password'][0]
118 except KeyError:
119 return "BAD REQUEST"
120
121 _profile_check = self.sat_host.bridge.getProfileName(_login)
122 _profile_pass = self.sat_host.bridge.getParamA("Password", "Connection", profile_key=_login)
123
124 if not _profile_check or _profile_check != _login or _profile_pass != _pass:
125 return "AUTH ERROR"
126
127 if self.profiles_waiting.has_key(_login):
128 return "ALREADY WAITING"
129
130 if self.sat_host.bridge.isConnected(_login):
131 return self._logged(_login, request)
132
133 self.profiles_waiting[_login] = request
134 self.sat_host.bridge.connect(_login)
135 return server.NOT_DONE_YET
136
137 def __cleanWaiting(self, login):
138 """Remove login from waiting queue"""
139 try:
140 del self.profiles_waiting[login]
141 except KeyError:
142 pass
143
144 def _logged(self, login, request):
145 """Set everything when a user just logged
146 and return "LOGGED" to the requester"""
147 self.__cleanWaiting(login)
148 _session = request.getSession()
149 _session.sat_profile = login
150 return 'LOGGED'
151
152 def _logginError(self, login, request, error_type):
153 """Something went wrong during loggin, return an error"""
154 self.__cleanWaiting(login)
155 return error_type
156
157 def jsonrpc_isConnected(self):
158 _session = self.request.getSession()
159 profile = _session.sat_profile
160 return self.sat_host.bridge.isConnected(profile)
161
162 def jsonrpc_connect(self):
163 _session = self.request.getSession()
164 profile = _session.sat_profile
165 if self.profiles_waiting.has_key(profile):
166 raise jsonrpclib.Fault('1','Already waiting') #FIXME: define some standard error codes for libervia
167 self.profiles_waiting[profile] = self.request
168 self.sat_host.bridge.connect(profile)
169 return server.NOT_DONE_YET
170
171 def jsonrpc_isRegistered(self):
172 """Tell if the user is already registered"""
173 _session = self.request.getSession()
174 try:
175 profile = _session.sat_profile
176 except AttributeError:
177 return False
178 return True
179
180 class SignalHandler(jsonrpc.JSONRPC):
181
182 def __init__(self, sat_host):
183 Resource.__init__(self)
184 self.register=None
185 self.sat_host=sat_host
186
187 def plugRegister(self, register):
188 self.register = register
189
190 def presenceUpdate(self, entity, show, priority, statuses, profile):
191 print "update de",entity
192
193 def connected(self, profile):
194 assert(self.register) #register must be plugged
195 request = self.register.getWaitingRequest(profile)
196 if request:
197 self.register._logged(profile, request)
198
199 def connectionError(self, error_type, profile):
200 assert(self.register) #register must be plugged
201 request = self.register.getWaitingRequest(profile)
202 if request: #The user is trying to log in
203 if error_type == "AUTH_ERROR":
204 _error_t = "AUTH ERROR"
205 else:
206 _error_t = "UNKNOWN"
207 self.register._logginError(profile, request, _error_t)
208
209
210 class Libervia(service.Service):
211
212 def __init__(self):
213 root = File("output/")
214 self.signal_handler = SignalHandler(self)
215 root.putChild('test', self.signal_handler)
216 _register = Register(self)
217 self.signal_handler.plugRegister(_register)
218 root.putChild('json_api', MethodHandler(self))
219 root.putChild('register_api', _register)
220 self.site = server.Site(root)
221 self.sessions = {} #key = session value = user
222 ## bridge ##
223 try:
224 self.bridge=DBusBridgeFrontend()
225 except BridgeExceptionNoService:
226 print(u"Can't connect to SàT backend, are you sure it's launched ?")
227 import sys
228 sys.exit(1)
229 self.bridge.register("presenceUpdate", self.signal_handler.presenceUpdate)
230 self.bridge.register("connected", self.signal_handler.connected)
231 self.bridge.register("connectionError", self.signal_handler.connectionError)
232
233 def startService(self):
234 reactor.listenTCP(8080, self.site)
235
236 def run(self):
237 debug(_("running app"))
238 reactor.run()
239
240 def stop(self):
241 debug(_("stopping app"))
242 reactor.stop()
243
244
245
246 application = service.Application('Libervia')
247 service = Libervia()
248 service.setServiceParent(application)