import time from threading import Thread, Lock, BoundedSemaphore import requests from kivy.event import EventDispatcher from kivy.clock import Clock from kivy.app import App from .login import LoginForm from .utils import NeedLogin, InsufficientPrivilege, HTTPError class ThreadCall(Thread,EventDispatcher): def __init__(self,target, args=(), kwargs={}): Thread.__init__(self) EventDispatcher.__init__(self) self.register_event_type('on_result') self.register_event_type('on_error') self.rez = None self.daemon = False self.target = target self.args = args self.timing = None self.kwargs = kwargs def start(self): Thread.start(self) self.timing = Clock.schedule_once(self.checkStop,0) def run(self): try: self.rez = self.target(*self.args,**self.kwargs) self.dispatch('on_result',self.rez) except Exception as e: self.dispatch('on_error',e) def on_result(self, v): pass def on_error(self,e): pass def checkStop(self,timestamp): x = self.join(timeout=0.001) if self.is_alive(): self.timing = Clock.schedule_once(self.checkStop,0) return class Workers(Thread): def __init__(self,maxworkers): super().__init__() self.max_workers = maxworkers self.tasks = [] # task = [callee,callback,kwargs] self.lock = Lock() self.work_sema = BoundedSemaphore(value=self.max_workers) self.running = False def run(self): self.running = True while self.running: if len(self.tasks) == 0: time.sleep(0.001) continue task = None with self.lock: task = self.tasks.pop() if task is None: continue with self.work_sema: callee,callback,errback,kwargs = task x = ThreadCall(callee,kwargs=kwargs) x.bind(on_result=callback) if errback: x.bind(on_error=errback) x.start() def add(self,callee,callback,errback=None,kwargs={}): with self.lock: self.tasks.insert(0,[callee,callback,errback,kwargs]) hostsessions = {} class HttpClient: def __init__(self): self.s = requests.Session() self.workers = App.get_running_app().workers def url2domain(self,url): parts = url.split('/')[:3] pre = '/'.join(parts) return pre def webcall(self,url,method="GET",params={},files={},headers={}): app = App.get_running_app() domain = self.url2domain(url) sessionid = hostsessions.get(domain,None) print('hostsessions=', hostsessions, 'sessionid=',sessionid, 'domain=',domain, 'url=',url ) if sessionid: headers.update({'session':sessionid}) elif app.getAuthHeader(): headers.update(app.getAuthHeader()) print('headers=',headers) if method in ['GET']: req = requests.Request(method,url, params=params,headers=headers) else: req = requests.Request(method,url, data=params,files=files,headers=headers) prepped = self.s.prepare_request(req) resp = self.s.send(prepped) if resp.status_code == 200: h = resp.headers.get('Set-Cookie',None) if h: print('*************set-Cookie=',h,'domain=',domain) sessionid = h.split(';')[0] hostsessions[domain] = sessionid try: data = resp.json() if type(data) != type({}): return data status = data.get('status',None) if status is None: return data if status == 'OK': return data['data'] return data except: return resp.text if resp.status_code == 401: print('NeedLogin:',url) raise NeedLogin if resp.status_code == 403: raise InsufficientPrivilege print('Error', url, method, params, resp.status_code, type(resp.status_code)) raise HTTPError(resp.status_code) def __call__(self,url,method="GET",params={},headers={},files={},callback=None,errback=None): def cb(t,resp): return resp if callback is None: try: resp = self.webcall(url, method=method, params=params, files=files, headers=headers) return cb(None,resp) except Exception as e: raise e except Exception as e: if errback is not None: errback(e) return None kwargs = { "url":url, "method":method, "params":params, "files":files, "headers":headers } self.workers.add(self.webcall,callback,errback,kwargs=kwargs) def get(self, url, params={}, headers={}, callback=None, errback=None): return self.__call__(url,method='GET',params=params, headers=headers, callback=callback, errback=errback) def post(self, url, params={}, headers={}, files={}, callback=None, errback=None): return self.__call__(url,method='POST',params=params, files=files, headers=headers, callback=callback, errback=errback) def put(self, url, params={}, headers={}, callback=None, errback=None): return self.__call__(url,method='PUT',params=params, headers=headers, callback=callback, errback=errback) def delete(self, url, params={}, headers={}, callback=None, errback=None): return self.__call__(url,method='DELETE',params=params, headers=headers, callback=callback, errback=errback) def option(self, url, params={}, headers={}, callback=None, errback=None): return self.__call__(url,method='OPTION',params=params, headers=headers, callback=callback, errback=errback) if __name__ == '__main__': from kivy.uix.textinput import TextInput from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button class MyApp(App): def build(self): self.hc = HttpClient() x = BoxLayout(orientation='vertical') y = BoxLayout(orientation='horizontal',size_hint_y=0.07) self.ti = TextInput(size_hint_x=0.95,multiline=False) btn = Button(size_hint_x=0.05,text='go') y.add_widget(self.ti) y.add_widget(btn) btn.bind(on_press=self.getHtml) self.texti = TextInput(multiline=True,readonly=True) x.add_widget(y) x.add_widget(self.texti) return x def getHtml(self,v=None): url = self.ti.text self.hc.get(url,callback=self.showResult) self.texti.text = 'loading...' def showResult(self,target,resp): if resp.status_code==200: self.texti.text = resp.text else: print(reps.status_code,'...............') MyApp().run()