From 2bdad0ae7a3a6e4ec5116becd39910388b679ed2 Mon Sep 17 00:00:00 2001 From: Leif Johansson Date: Thu, 4 Oct 2012 15:39:08 +0200 Subject: restructure --- meetingtools/ac/__init__.py | 57 ++++++++++++ meetingtools/ac/api.py | 214 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 meetingtools/ac/__init__.py create mode 100644 meetingtools/ac/api.py (limited to 'meetingtools/ac') diff --git a/meetingtools/ac/__init__.py b/meetingtools/ac/__init__.py new file mode 100644 index 0000000..2bbd25f --- /dev/null +++ b/meetingtools/ac/__init__.py @@ -0,0 +1,57 @@ +from meetingtools.ac.api import ACPClient +import time +from meetingtools.apps.cluster.models import acc_for_user +from django.core.cache import cache +from Queue import Queue +import logging +from django.contrib.auth.models import User + +_pools = {} + +MAXCALLS = 10 +MAXIDLE = 10 + +class ClientPool(object): + + def __init__(self,acc,maxsize=0,increment=2): + self._q = Queue(maxsize) + self._acc = acc + self._increment = increment + + def allocate(self): + now = time.time() + api = None + while not api: + if self._q.empty(): + for i in range(1,self._increment): + logging.debug("adding instance %d" % i) + api = ACPClient(self._acc.api_url,self._acc.user,self._acc.password,cpool=self) + self._q.put_nowait(api) + + api = self._q.get() + if api and (api.age > MAXCALLS or now - api.lastused > MAXIDLE): + api = None + return api + +# with ac_api_client(acc) as api +# ... + +def ac_api_client(o): + acc = o + logging.debug("ac_api_client(%s)" % repr(o)) + if hasattr(o,'user') and isinstance(getattr(o,'user'),User): + acc = acc_for_user(getattr(o,'user')) + elif hasattr(o,'acc'): + acc = getattr(o,'acc') + + tag = 'ac_api_client_%d' % acc.id + pool = _pools.get(tag) + if pool is None: + pool = ClientPool(acc,maxsize=30) + _pools[tag] = pool + + return pool.allocate() + + + + \ No newline at end of file diff --git a/meetingtools/ac/api.py b/meetingtools/ac/api.py new file mode 100644 index 0000000..5fbcfbf --- /dev/null +++ b/meetingtools/ac/api.py @@ -0,0 +1,214 @@ +''' +Created on Jan 31, 2011 + +@author: leifj +''' +from StringIO import StringIO + +import httplib2 +from urllib import quote_plus +import logging +from pprint import pformat +import os +import tempfile +import time +from lxml import etree +from meetingtools.site_logging import logger +import lxml +from django.http import HttpResponseRedirect +from celery.execute import send_task + +class ACPException(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return etree.tostring(self.value) + +def _first_or_none(x): + if not x: + return None + return x[0] + +class ACPResult(): + + def __init__(self,content): + self.et = etree.fromstring(content) + self.status = _first_or_none(self.et.xpath('//status')) + + def is_error(self): + return self.status_code() != 'ok' + + def status_code(self): + return self.status.get('code') + + def subcode(self): + return self.status.get('subcode') + + def exception(self): + raise ACPException,self.status + + def get_principal(self): + logger.debug(lxml.etree.tostring(self.et)) + return _first_or_none(self.et.xpath('//principal')) + +def _enc(v): + ev = v + if isinstance(ev,str) or isinstance(ev,unicode): + ev = ev.encode('iso-8859-1') + return ev + +def _getset(d,key,value=None): + if value: + if d.has_key(key): + return d[key] + else: + return None + else: + d[key] = value + +class ACPClient(): + + def __init__(self,url,username=None,password=None,cache=True,cpool=None): + self._cpool = cpool + self.age = 0 + self.createtime = time.time() + self.lastused = self.createtime + self.url = url + self.session = None + if username and password: + self.login(username,password) + if cache: + self._cache = {'login':{},'group':{}} + + def __exit__(self,type,value,traceback): + if self._cpool and not value: + self._cpool._q.put_nowait(self) + + def __enter__(self): + return self + + + def request(self,method,p={},raise_error=False): + self.age += 1 + self.lastused = time.time() + u = list() + u.append("action=%s" % method) + if self.session: + u.append("session=%s" % self.session) + for k,v in p.items(): + value = v + if type(v) == int: + value = "%d" % value + u.append('%s=%s' % (k,quote_plus(value.encode("utf-8")))) + + url = self.url + '?' + '&'.join(u) + + h = httplib2.Http(tempfile.gettempdir()+os.sep+".cache",disable_ssl_certificate_validation=True); + logging.debug(url) + resp, content = h.request(url, "GET") + logging.debug(pformat(resp)) + logging.debug(pformat(content)) + if resp.status != 200: + raise ACPException,resp.reason + + if resp.has_key('set-cookie'): + cookie = resp['set-cookie'] + if cookie: + avp = cookie.split(";") + if len(avp) > 0: + av = avp[0].split('=') + self.session = av[1] + + r = ACPResult(content) + if r.is_error() and raise_error: + raise r.exception() + + return r; + + def redirect_to(self,url): + if self.session: + return HttpResponseRedirect("%s?session=%s" % (url,self.session)) + else: + return HttpResponseRedirect(url) + + def login(self,username,password): + result = self.request('login',{'login':username,'password':password}) + if result.is_error(): + raise result.exception() + return result + + def find_or_create_principal(self,key,value,t,d): + if not self._cache.has_key(t): + self._cache[t] = {} + cache = self._cache[t] + + # lxml etree Elements are not picklable + p = None + if not cache.has_key(key): + p = self._find_or_create_principal(key,value,t,d) + cache[key] = etree.tostring(p) + else: + p = etree.parse(StringIO(cache[key])) + return p + + def find_principal(self,key,value,t): + return self.find_or_create_principal(key,value,t,None) + + def _find_or_create_principal(self,key,value,t,d): + result = self.request('principal-list',{'filter-%s' % key: value,'filter-type': t}, True) + principal = result.get_principal() + if result.is_error(): + if result.status_code() != 'no_data': + result.exception() + elif principal and d: + d['principal-id'] = principal.get('principal-id') + + rp = principal + if d: + update_result = self.request('principal-update',d) + rp = update_result.get_principal() + if not rp: + rp = principal + return rp + + def find_builtin(self,t): + result = self.request('principal-list', {'filter-type': t}, True) + return result.get_principal() + + def find_group(self,name): + result = self.request('principal-list',{'filter-name':name,'filter-type':'group'},True) + return result.get_principal() + + def find_user(self,login): + return self.find_principal("login", login, "user") + + def add_remove_member(self,principal_id,group_id,is_member): + m = "0" + if is_member: + m = "1" + self.request('group-membership-update',{'group-id': group_id, 'principal-id': principal_id,'is-member':m},True) + + def add_member(self,principal_id,group_id): + return self.add_remove_member(principal_id, group_id, True) + + def remove_member(self,principal_id,group_id): + return self.add_remove_member(principal_id, group_id, False) + + def user_counts(self,sco_id): + user_count = None + host_count = None + userlist = self.request('meeting-usermanager-user-list',{'sco-id': sco_id},False) + if userlist.status_code() == 'ok': + user_count = int(userlist.et.xpath("count(.//userdetails)")) + host_count = int(userlist.et.xpath("count(.//userdetails/role[text() = 'host'])")) + elif userlist.status_code() == 'no-access' and userlist.subcode() == 'not-available': #no active session + user_count = 0 + host_count = 0 + + return (user_count,host_count) + + def poll_user_counts(self,room): + (room.user_count,room.host_count) = self.user_counts(room.sco_id) + room.save() + return (room.user_count,room.host_count) \ No newline at end of file -- cgit v1.1