import bottle from bottle import route, run, Bottle, request import sys, os, re, urllib import datetime #I think I need this import time #I think I need this from gevent import queue from gevent import Greenlet import gevent import StringIO from datetime import datetime #from gevent import pywsgi #Don't need this yet fcpHost = "127.0.0.1" import fcp #node = fcp.FCPNode(host=fcpHost, verbosity=fcp.DETAIL) jobs={} app = Bottle() #https://stackoverflow.com/questions/17262170/bottle-py-enabling-cors-for-jquery-ajax-requests#17262900 # the decorator def enable_cors(fn): def _enable_cors(*args, **kwargs): # set CORS headers response.headers['Access-Control-Allow-Origin'] = '*' response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS' response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token' if bottle.request.method != 'OPTIONS': # actual request; reply with the actual response return fn(*args, **kwargs) return _enable_cors def delim_filter(config): bottle.debug(True) print("Entering delim_filter") ''' Matches a comma separated list of numbers. ''' aconfig = config or "%20" print ("aconfig=" + aconfig) delimiter = urllib.unquote(aconfig).decode('utf8') print("delimiter=" + delimiter) regexp = r'(?!{a_delim})+({a_delim}(?!{a_delim})+)*'.format(a_delim=re.escape(delimiter)) print("regexp="+regexp) def to_python(match): print("Converting Match") print("Math=" + match) ms = map(urllib.unquote(aconfig).decode,match.split()) print( "ms=" + ms ) return ms def to_url(astr): print("Converting to URL") print ("astr=" + astr) astr2 = delimiter.join(map(urllib.unquote(aconfig).decode,astr)) print("astr2="+astr2) print astr2 return astr2 return regexp, to_python, to_url app.router.add_filter('delim', delim_filter) def split_urlArgs(url,delim=" ", decode='All', xfm_de=lambda a: urllib.unquote(a).decode('utf8'), xfm_split=lambda a, b: re.split(a,b), #Typically a is a regular expression and b a string fn_regexp = lambda a: r'(?!{a_delim})+({a_delim}(?!{a_delim})+)*'.format(a_delim=a) ): bottle.debug(True) ''' Matches a comma separated list of numbers. ''' print("delimiter=" + delim) if decode == "Args": ms = xfm_split(fn_regexp(a),url) elif decode == "All": url2 = xfm_de(url) #Decode the URL delim= xfm_de(delim) #Decode the delimitor ms = xfm_split(fn_regexp(delim),url) elif decode == "None": ms = xfm_split(fn_regexp(delim),url) #SPlit the URL based on a regular expression. print( "ms=" + "["+",".join(ms) +"]" ) return ms, delim def combine_urlArgs(args,delim=" ", encode='All', xfm_encode=lambda a: urllib.quote(a, safe=''), xfm_join=lambda a, b: a.join(b)): #Typically a is the delimiter and b is a list print("Converting to URL") print ("astr=" + args) if decode == "Args": astr2 = xfm_join(delim,(map(lambda a: xfm_encode,args))) elif decode == "All": astr2 = urllib.unquote(xfm_join(delim,args)) elif decode=="None": astr2 = xfm_join(delim,args) print("astr2="+astr2) return astr2 #@app.route('//%09//') # %09 == tab #@app.route('//%20//') # %20 == ' ' #@app.route('// //') # %20 == ' ' #@app.route('//%3B//') # %3B == ';' #@app.route('//;//') # %3B == ';' #@app.route('//%2C//') # %2C == ',' #@app.route('//,//') # %2C == ',' @app.route('////') # %2C == ',' def mystery(key,cmd,args,sep=""): bottle.debug(True) print("engering mystery") print("sep=" + sep) if len(sep) > 0 : # True if seperator is a wild card args, sep = split_urlArgs(args,sep) if key == '1234': # %2C == ',' print(key) print(cmd) print(args) #delimiter = urllib.unquote(aconfig).decode('utf8') #print(delimiter) result1 = os.popen("IFS=".format(a_dilim=sep)).read() print("result1=" + result1) result2 = result1 + "
" print("result2=" + result2) cmd_str=cmd + sep + sep.join(args) print(cmd_str) result3 = result2 +os.popen(cmd_str).read() print("result3=" + result3) return "
" + result3 + "
" #return result3.replace("\n","
") #return ('key=' + key + '
' + # 'sep=' + sep + '
' + # 'cmd=' + cmd + '
' + # 'args=' + "[" + ",".join(args)+"]") def generateFreeWorker(job_or_uri,message=None,afile=None,fcpHost = "127.0.0.1",fcpPort= 9481,aBody=None,OutputType="HTML"): fw = FreeWorkerFactory(job_or_uri,message,afile,fcpHost,fcpPort,aBody,OutputType) return fw #class calbackExecuter: # __init__(self,calbacks): # self.callbacks=calbacks # def execute(): # for c in self.calbacks(): # c() class loggerContainer: def __init__(self,job=None,node=None,**kw): self.ready = False self.strBuff = StringIO.StringIO() self.job = job self.Brk = kw.get('Brk',"\n") self.body = kw.get('body',None) #The html body to write to. self.complete=False self.msgDict={} self.meseges=[None]*5 self.msgPosNext=0 self.msgPos=-1 self.msgMax=5 self.msgLnCnt=0 self.node=node def filterMSG(self,msg): #We don't want to see the same log message too often t1=self.msgDict.get(msg,None) if t1 is not None: #isinstance(t1,datetime): t2=datetime.now() delta = t2 - t1 #https://stackoverflow.com/questions/2880713/time-difference-in-seconds-as-a-floating-point if delta.seconds>20: return True else: return False return True def do_logfunc(self,msgline,cb=None): print("self.msgPosNext="+str(self.msgPosNext)) self.meseges[self.msgPosNext]={ "msg_str" : msgline, "time" : datetime.now() } self.msgPos=self.msgPosNext print("self.msgMax="+str(self.msgMax)) self.msgPosNext=((self.msgPosNext+1)%(self.msgMax)) self.msgDict[msgline]=datetime.now() if self.msgLnCnt"): if cb is None: cb=self.print_and_put_cb if self.filterMSG(msgline): self.do_logfunc(msgline,cb) cb(msgline) def filterForBody(self,msg): if msg.startswith("NODE:") or msg.startswith("CLIENT:"): return True else: return False def bodyPut_cb(self,msg,HTML_lb="
"): if filterForBody(msg): self.body.put(self.msg_to_str(msg)+HTML_lb) def detectEndMsg(self,msg): if filterForBody(self,msg): node_or_client = True else node_or_client = False if return node_or_client def print_and_put_cb(self,msg,HTML_lb="
"): print self.msg_to_str(msg) if self.body is not None: self.bodyPut_cb(msg,HTML_lb) def msg_to_str(self,msg): if type(msg) == str: return msg elif type(msg) is dict: #isinstance(msg, collections.Mapping): #https://stackoverflow.com/questions/25231989/how-to-check-if-a-variable-is-a-dictionary-in-python return msg['msg_str'] else: return "Empty Message" def tail(self,lines=0,cb=None,delta=None): if cb is None: cb=self.print_and_put_cb if lines == 0: N=self.msgMax else: N=min(self.msgMax,lines) for i in range(self.msgPost,self.msgPos-N+1,-1): msg_i=self.meseges[i%self.msgMax] if delta is not None: t2=datetime.now() t1=msg_i['time'] delta2=t2-t1 if delta2.delta.microseconds > delta.microseconds: break cb(self.meseges[i%self.msgMax]) #self.body.put(msgline) def myLogger(self, level, msg): print("level="+level + " msg=" + msg) if level > self.job.verbosity: return if not msg.endswith(self.Brk): msg += "\n" strBuff.write(msg) self.isReady = True #strBuff.flush() #time.sleep(0.001) def getLogger(self): #THis might be redundant return self.myLogger def isReady(self): return self.ready def flush(self): val=self.strBuff.getvalue() self.strBuff.close() self.strBuff = StringIO.StringIO() self.isRead=False return val def getValue(self): self.strBuff.getValue() def readBuf(self): if self.ready: val = self.flush() ready = True return val, ready else: ready = False val = "" return val, ready return val, ready def isComplete(self): # We might also want to check for an EndMessage and wait if needed return self.complete #if self.job.msg['hdr'] == 'PutSuccessful': # return True #elif self.job.msg['hdr'] == 'PutFailed': # return True def callback(self, status, value): if status == 'PutSuccessful': self.complete=True elif status == 'PutFailed': self.complete=True #elif status == 'URIGenerated': # self.complete=True #self.msg=value def getCallback(self): return self.callback class FreeWorkerFactory: #self.job = None #A freenet job #self.g = None #self.body = None #self.OutputType =None def __init__(self,job_or_uri,**kw): self.kw={} self.kw['message']=kw.get('message',None) self.kw['file']=kw.get(file,None) self.loggerContainer=kw.get('loggerContainer',None) #if self.kw['logger'] is not None: # loggerContainer self.host=kw.get('host',"127.0.0.1") self.port=self.kw.get('port',9481) self.OutputType=self.kw.get('OutputType','HTML') #selffcpPort,aBody,OutputType if type(job_or_uri) is str: print("__init__" + "uri as input") if job_or_uri in jobs: print("uri in jobs") self.job=jobs[job_or_uri] else: print("making job") node = fcp.FCPNode(fcpHost,verbosity='fcp.DETAIL',port=self.kw) val = self.kw['message'] ksk = job_or_uri uri = "KSK@" + ksk node.put("KSK@"+ksk, data=val, mimetype="text/plain", verbosity=fcp.DETAIL) self.job = node.get(uri, async=True) else: print("__init__"+"job as input") self.job=job_or_uri if self.OutputType == "HTML": self.Brk="
" elif self.OutputType == "UNIX": self.Brk="" #We won't use "\n" since print automatically generates the \n. Write can be used instead if one wants to explicitly use the /n self.body=None self.setBody(kw.get('body',None)) #def freenetWorker(self): # # Empty Callback: http://echochamber.me/viewtopic.php?t=64825 # #stop_me = lambda *_, **_: None def on_data(self): # we can poll the job while True: val, ready = self.loggerContainer.readBuf() if ready: print val self.body.put(val) if self.loggerContainer.isComplete(): print "Yay! job complete" self.body.put(job.getResult()) #Returns the completion message. break else: print "Waiting" + datetime.now().strftime('%s(s) %m/%d/%Y')+self.Brk self.body.put("Waiting" + datetime.now().strftime('%s(s) %m/%d/%Y')+self.Brk) time.sleep(0.001) gevent.sleep(5) #This yields control to another greenlet self.on_finish() #Maybe we can sequence the greenlets instead of putting this here. def on_finish(self): self.body.put('') #There should be a way to seperate these last two lines from this method. self.body.put(StopIteration) def header(self,start_response=None): if self.OutputType == "HTML": if start_response is not None: start_response('200 OK', [('Content-Type', 'text/html')]) self.body.put(' ' * 1000) if self.OutputType == "HTML": self.body.put("

Current Time:

") def handle(self,environ=None, start_response=None,aBody=None): lambda a: self.start(self,enviorn,start_response) #g = Greenlet.spawn(on_data, body) def setBody(self,aBody=None): if aBody is None: if self.body is None: self.body = queue.Queue() self.g = Greenlet(self.on_data) self.loggerContainer.body=self.body else: self.body = aBody def start(self,environ=None, start_response=None,aBody=None): # Not sure #https://stackoverflow.com/questions/20824218/how-to-implement-someasyncworker-from-bottle-asynchronous-primer #g = Greenlet.spawn(current_time, lambda a: on_data(body)) print("Set Body") self.setBody(aBody) print("header") self.header(start_response) print("start") self.g.start() return self.body, self.g #@enable_cors @app.post('/KSK/insert') def rest_test(): fcpHost=request.json.get('host','127.0.0.1') fcpVerbosity=request.json.get('verbosity',fcp.NOISY) fcpPort=request.json.get('port',9481) val = request.json.get('message') ksk = request.json.get('ksk') uri = "KSK@" + ksk print "Inserting %s, containing '%s'" % (uri, val) # do the put - note that 'data=' inserts a string directly # note too that mimetype is optional, defaulting to text/plain #node.put("KSK@"+ksk, data=val, mimetype="text/plain") # ------------------------------------------ # now, demonstrate asynchronous requests print "Launching asynchronous request" lgrCnt=loggerContainer() node = fcp.FCPNode(host=fcpHost,verbosity=fcp.NOISY,port=fcpPort,logfunc=lgrCnt.logfunc) job = node.put(uri, data=val, async=True) #, verbosity=fcp.DETAIL loggerContainer.job=job loggerContainer.node=node jobs["KSK@"+ksk]=job #node.logfunc=lgrCnt.logfunc job._log=lgrCnt.getLogger() job.callback=lgrCnt.getCallback() worker = FreeWorkerFactory(job,loggerContainer=lgrCnt) body, g = worker.start() #Returns the greenelet #body = gevent.queue.Queue() #worker = getFreenetWorker(job) #worker.on_data(body.put) #Finish https://stackoverflow.com/questions/20824218/how-to-implement-someasyncworker-from-bottle-asynchronous-primer #worker.on_finish(lambda: body.put(StopIteration)) # body.put('') return body #yield job_waitt("KSK@"+ksk) #return "KSK Inserted" # We probably want to do wsomething smarter than this. # or we can await its completion #@app.route('/USK@,,/') #def hello(hashKey,ecryptionKey,encryption,metaData): # # mimetype, val1 = node.get(uri) # return ('hashKey=' + hashKey + '
' + # 'ecryptionKey=' + ecryptionKey + '
' + # 'encryption=' + encryption + '
' + # 'metaData=' + metaData) # #Regular eressions use a seperate filter; https://bottlepy.org/docs/dev/routing.html app.run(host='localhost', port=8082, debug=True)