Mercurial > libervia-web
diff libervia.tac @ 0:140cec48224a
Initial commit
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 30 Jan 2011 21:50:22 +0100 |
parents | |
children | 0a7c685faa53 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libervia.tac Sun Jan 30 21:50:22 2011 +0100 @@ -0,0 +1,248 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Libervia: a Salut à Toi frontend +Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +""" + +from twisted.application import internet, service +from twisted.internet import glib2reactor +glib2reactor.install() +from twisted.internet import reactor, defer + +from twisted.web import server +from twisted.web import error as weberror +from twisted.web.static import File +from twisted.web.resource import Resource +from txjsonrpc.web import jsonrpc +from txjsonrpc import jsonrpclib +from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService + +TIMEOUT = 120 #Session's time out, after that the user will be disconnected + + +class MethodHandler(jsonrpc.JSONRPC): + + def __init__(self, sat_host): + jsonrpc.JSONRPC.__init__(self) + self.sat_host=sat_host + + def render(self, request): + _session = request.getSession() + try: + profile = _session.sat_profile + except AttributeError: + #user is not identified, we return a jsonrpc fault + parsed = jsonrpclib.loads(request.content.read()) + fault = jsonrpclib.Fault(0, "Not allowed") #FIXME: define some standard error codes for libervia + return jsonrpc.JSONRPC._cbRender(self, fault, request, parsed.get('id'), parsed.get('jsonrpc')) + return jsonrpc.JSONRPC.render(self, request) + + + def jsonrpc_getContacts(self): + """Return all passed args.""" + d = defer.Deferred() + reactor.callLater(10, d.callback, [unicode(contact[0]) for contact in self.sat_host.bridge.getContacts()]) + return d + +class Register(jsonrpc.JSONRPC): + """This class manage the registration procedure with SàT + It provide an api for the browser, check password and setup the web server""" + + def __init__(self, sat_host): + jsonrpc.JSONRPC.__init__(self) + self.sat_host=sat_host + self.profiles_waiting={} + self.request=None + + def getWaitingRequest(self, profile): + """Tell if a profile is trying to log in""" + if self.profiles_waiting.has_key(profile): + return self.profiles_waiting[profile] + else: + return None + + def render(self, request): + """ + Render method with some hacks: + - if login is requested, try to login with form data + - except login, every method is jsonrpc + - user doesn't need to be authentified for isRegistered, but must be for all other methods + """ + if request.postpath==['login']: + return self.login(request) + _session = request.getSession() + parsed = jsonrpclib.loads(request.content.read()) + if parsed.get("method")!="isRegistered": + #if we don't call login or isRegistered, we need to be identified + try: + profile = _session.sat_profile + except AttributeError: + #user is not identified, we return a jsonrpc fault + fault = jsonrpclib.Fault(0, "Not allowed") #FIXME: define some standard error codes for libervia + return jsonrpc.JSONRPC._cbRender(self, fault, request, parsed.get('id'), parsed.get('jsonrpc')) + self.request = request + return jsonrpc.JSONRPC.render(self, request) + + def login(self, request): + """ + this method is called with the POST information from the registering form + it test if the password is ok, and log in if it's the case, + else it return an error + @param request: request of the register formulaire, must have "login" and "password" as arguments + @return: A constant indicating the state: + - BAD REQUEST: something is wrong in the request (bad arguments, profile_key for login) + - AUTH ERROR: either the profile or the password is wrong + - ALREADY WAITING: a request has already be made for this profile + - server.NOT_DONE_YET: the profile is being processed, the return value will be given by self._logged or self._logginError + """ + try: + _login = request.args['login'][0] + if _login.startswith('@'): + raise Exception('No profile_key allowed') + _pass = request.args['password'][0] + except KeyError: + return "BAD REQUEST" + + _profile_check = self.sat_host.bridge.getProfileName(_login) + _profile_pass = self.sat_host.bridge.getParamA("Password", "Connection", profile_key=_login) + + if not _profile_check or _profile_check != _login or _profile_pass != _pass: + return "AUTH ERROR" + + if self.profiles_waiting.has_key(_login): + return "ALREADY WAITING" + + if self.sat_host.bridge.isConnected(_login): + return self._logged(_login, request) + + self.profiles_waiting[_login] = request + self.sat_host.bridge.connect(_login) + return server.NOT_DONE_YET + + def __cleanWaiting(self, login): + """Remove login from waiting queue""" + try: + del self.profiles_waiting[login] + except KeyError: + pass + + def _logged(self, login, request): + """Set everything when a user just logged + and return "LOGGED" to the requester""" + self.__cleanWaiting(login) + _session = request.getSession() + _session.sat_profile = login + return 'LOGGED' + + def _logginError(self, login, request, error_type): + """Something went wrong during loggin, return an error""" + self.__cleanWaiting(login) + return error_type + + def jsonrpc_isConnected(self): + _session = self.request.getSession() + profile = _session.sat_profile + return self.sat_host.bridge.isConnected(profile) + + def jsonrpc_connect(self): + _session = self.request.getSession() + profile = _session.sat_profile + if self.profiles_waiting.has_key(profile): + raise jsonrpclib.Fault('1','Already waiting') #FIXME: define some standard error codes for libervia + self.profiles_waiting[profile] = self.request + self.sat_host.bridge.connect(profile) + return server.NOT_DONE_YET + + def jsonrpc_isRegistered(self): + """Tell if the user is already registered""" + _session = self.request.getSession() + try: + profile = _session.sat_profile + except AttributeError: + return False + return True + +class SignalHandler(jsonrpc.JSONRPC): + + def __init__(self, sat_host): + Resource.__init__(self) + self.register=None + self.sat_host=sat_host + + def plugRegister(self, register): + self.register = register + + def presenceUpdate(self, entity, show, priority, statuses, profile): + print "update de",entity + + def connected(self, profile): + assert(self.register) #register must be plugged + request = self.register.getWaitingRequest(profile) + if request: + self.register._logged(profile, request) + + def connectionError(self, error_type, profile): + assert(self.register) #register must be plugged + request = self.register.getWaitingRequest(profile) + if request: #The user is trying to log in + if error_type == "AUTH_ERROR": + _error_t = "AUTH ERROR" + else: + _error_t = "UNKNOWN" + self.register._logginError(profile, request, _error_t) + + +class Libervia(service.Service): + + def __init__(self): + root = File("output/") + self.signal_handler = SignalHandler(self) + root.putChild('test', self.signal_handler) + _register = Register(self) + self.signal_handler.plugRegister(_register) + root.putChild('json_api', MethodHandler(self)) + root.putChild('register_api', _register) + self.site = server.Site(root) + self.sessions = {} #key = session value = user + ## bridge ## + try: + self.bridge=DBusBridgeFrontend() + except BridgeExceptionNoService: + print(u"Can't connect to SàT backend, are you sure it's launched ?") + import sys + sys.exit(1) + self.bridge.register("presenceUpdate", self.signal_handler.presenceUpdate) + self.bridge.register("connected", self.signal_handler.connected) + self.bridge.register("connectionError", self.signal_handler.connectionError) + + def startService(self): + reactor.listenTCP(8080, self.site) + + def run(self): + debug(_("running app")) + reactor.run() + + def stop(self): + debug(_("stopping app")) + reactor.stop() + + + +application = service.Application('Libervia') +service = Libervia() +service.setServiceParent(application)