def _stopLoop(self): if self.loop is not None: try: self.loop.quit() except Exception as x: AVNLog.error("unable to stop dbus event loop %s" % str(x)) self.loop = None
def writeFileFromInput(self, outname, rlen, overwrite=False, stream=None): if os.path.exists(outname) and not overwrite: raise Exception("file %s already exists" % outname) writename = outname + ".tmp" AVNLog.info("start upload of file %s", outname) fh = open(writename, "wb") if fh is None: raise Exception("unable to write to %s" % outname) if stream is None: stream = self.rfile bToRead = int(rlen) bufSize = 1000000 try: while bToRead > 0: buf = stream.read(bufSize if bToRead >= bufSize else bToRead) if len(buf) == 0 or buf is None: raise Exception("no more data received") bToRead -= len(buf) fh.write(buf) fh.close() if os.path.exists(outname): os.unlink(outname) os.rename(writename, outname) except: try: os.unlink(writename) except: pass raise
def do_POST(self): maxlen = 5000000 (path, sep, query) = self.path.partition('?') if not path.startswith(self.server.navurl): self.send_error(404, "unsupported post url") return try: ctype, pdict = cgi.parse_header( self.headers.getheader('content-type')) if ctype == 'multipart/form-data': postvars = cgi.parse_multipart(self.rfile, pdict) elif ctype == 'application/x-www-form-urlencoded': length = int(self.headers.getheader('content-length')) if length > maxlen: raise Exception("too much data" + unicode(length)) postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1) elif ctype == 'application/json': length = int(self.headers.getheader('content-length')) if length > maxlen: raise Exception("too much data" + unicode(length)) postvars = {'_json': self.rfile.read(length)} else: postvars = {} requestParam = urlparse.parse_qs(query, True) requestParam.update(postvars) self.handleNavRequest(path, requestParam) except Exception as e: txt = traceback.format_exc() AVNLog.ld("unable to process request for ", path, query, txt) self.send_response(500, txt) self.end_headers() return
def handleNavRequest(self, path, requestParam): #check if we have something behind the navurl #treat this as a filename and set it ion the request parameter fname = path[(len(self.server.navurl) + 1):] if fname is not None and fname != "": fname = fname.split('?', 1)[0] if fname != "": if requestParam.get('filename') is None: requestParam['filename'] = [fname.encode('utf-8')] requestType = requestParam.get('request') if requestType is None: requestType = 'gps' else: requestType = requestType[0] AVNLog.ld('navrequest', requestParam) try: rtj = None if requestType == 'gps' or requestType == 'self': rtj = self.handleGpsRequest(requestParam) elif requestType == 'nmeaStatus': rtj = self.handleNmeaStatus(requestParam) elif requestType == 'ais': rtj = self.handleAISRequest(requestParam) elif requestType == 'status': rtj = self.handleStatusRequest(requestParam) elif requestType == 'debuglevel' or requestType == 'loglevel': rtj = self.handleDebugLevelRequest(requestParam) elif requestType == 'listdir' or requestType == 'list': rtj = self.handleListDir(requestParam) elif requestType == 'download': #download requests are special # the dow not return json... self.handleDownloadRequest(requestParam) return elif requestType == 'upload': try: rtj = self.handleUploadRequest(requestParam) except Exception as e: AVNLog.error("upload error: %s", unicode(e)) rtj = json.dumps({'status': unicode(e)}) elif requestType == 'delete': rtj = self.handleDeleteRequest(requestParam) elif requestType == 'capabilities': rtj = self.handleCapabilityRequest(requestParam) elif requestType == 'api': #new handling for dedicated requests for some handler type = self.getRequestParam(requestParam, 'type') rtj = self.handleSpecificRequest(requestParam, type) else: #legacy: have the api type as requestType rtj = self.handleSpecificRequest(requestParam, requestType) self.sendNavResponse(rtj, requestParam) except Exception as e: text = unicode(e) rtj = json.dumps( AVNUtil.getReturnData(error=text, stack=traceback.format_exc())) self.sendNavResponse(rtj, requestParam) return
def timeChanged(self): AVNLog.info("%s: time changed, re-register", self.getName()) try: self._deregisterAll() except: pass self.stateSequence += 1
def log_message(self, format, *args): if self.id is None: self.id = AVNLog.getThreadId() if self.id is None: self.id = "?" threading.current_thread().setName("[%s]HTTPHandler" % (self.id)) AVNLog.debug(format, *args)
def _newService(self, interface, protocol, name, stype, domain, flags): AVNLog.info("detected new service %s.%s at %i.%i", stype, name, interface, protocol) try: self.foundServices.add( FoundService(stype, name, interface, protocol)) except Exception as e: AVNLog.error("unable to add service: %s", e)
def registerHandler(handler): """add a handler class""" if not issubclass(handler, worker.AVNWorker): raise TypeError("handler is not of type AVNWorker") name = handler.getConfigName() if handlerList.get(name) is not None: return logger.info("register handler %s", name) handlerList[name] = handler
def __init__(self, request, client_address, server): #allow write buffering #see https://lautaportti.wordpress.com/2011/04/01/basehttprequesthandler-wastes-tcp-packets/ self.wbufsize = -1 self.id = None self.getRequestParam = AVNUtil.getHttpRequestParam AVNLog.ld("receiver thread started", client_address) SimpleHTTPServer.SimpleHTTPRequestHandler.__init__( self, request, client_address, server)
def setInfo(self,name,info,status,childId=None,canDelete=False,timeout=None): existing=self.status.get(name) if existing: if existing.update(status,info,timeout=timeout): AVNLog.info("%s",str(existing)) return True else: ns=WorkerStatus(name,status,info,childId=childId,canDelete=canDelete,timeout=timeout) self.status[name]=ns AVNLog.info("%s",str(ns))
def _runInternal(self): self.usedResources=[] AVNLog.info("run started") try: self.run() self.setInfo('main','handler stopped',WorkerStatus.INACTIVE) except Exception as e: self.setInfo('main','handler stopped with %s'%str(e),WorkerStatus.ERROR) AVNLog.error("handler run stopped with exception %s",traceback.format_exc()) self.usedResources=[] self.currentThread=None
def getThreadPrefix(self): ''' nicely compute the name prefix for a thread if we have the default name (just from the config name) - avoid to have this twice @return: ''' n = self.getName() if "AVN%s" % n == self.getConfigName(): return "[ %s]-%s" % (AVNLog.getThreadId(), n) else: return "[ %s]-%s-%s" % (AVNLog.getThreadId(), self.getConfigName(), n)
def handleDownloadRequest(self, requestParam): type = self.getRequestParam(requestParam, "type") try: handler = self.server.getRequestHandler('download', type) if handler is not None: AVNLog.debug("found handler %s to handle download %s" % (handler.getConfigName(), type)) dl = handler.handleApiRequest('download', type, requestParam, handler=self) if dl is None: raise Exception("unable to download %s", type) if dl.get('mimetype') is None: raise Exception("no mimetype") if dl.get('size') is None: raise Exception("no size") if dl.get("stream") is None: raise Exception("missing stream") self.send_response(200) fname = self.getRequestParam(requestParam, "filename") if fname is not None and fname != "" and self.getRequestParam( requestParam, 'noattach') is None: self.send_header("Content-Disposition", "attachment") self.send_header("Content-type", dl['mimetype']) self.send_header("Content-Length", dl['size']) self.send_header("Last-Modified", self.date_time_string()) self.end_headers() try: self.writeStream(dl['size'], dl['stream']) except: try: dl['stream'].close() except: pass return except Exception as e: if self.getRequestParam(requestParam, 'noattach') is None: #send some empty data data = StringIO.StringIO("error: %s" % e.message) data.seek(0) self.send_response(200) self.send_header("Content-type", "application/octet-stream") try: self.copyfile(data, self.wfile) finally: data.close() else: self.send_error(404, traceback.format_exc(1)) return self.send_error(404, "invalid download request %s" % type)
def handleDebugLevelRequest(self, requestParam): rt = {'status': 'ERROR', 'info': 'missing parameter'} level = self.getRequestParam(requestParam, 'level') if not level is None: crt = AVNLog.changeLogLevel(level) if crt: rt['status'] = 'OK' rt['info'] = 'set loglevel to ' + str(level) else: rt['info'] = "invalid level " + str(level) filter = self.getRequestParam(requestParam, 'filter') AVNLog.setFilter(filter) return json.dumps(rt)
def startStopAlarm(self, start, name=ALARMS.waypoint): alert = self.findHandlerByName("AVNAlarmHandler") if alert is None: return if start: if self.activatedAlarms.get(name) is None: AVNLog.info("starting alarm %s", name) self.activatedAlarms[name] = True alert.startAlarm(name) else: if self.activatedAlarms.get(name) is not None: AVNLog.info("stopping alarm %s", name) del self.activatedAlarms[name] alert.stopAlarm(name)
def sendNavResponse(self, rtj, requestParam): if not rtj is None: self.send_response(200) if not requestParam.get('callback') is None: rtj = "%s(%s);" % (requestParam.get('callback'), rtj) self.send_header("Content-type", "text/javascript") else: self.send_header("Content-type", "application/json") self.send_header("Content-Length", str(len(rtj))) self.send_header("Last-Modified", self.date_time_string()) self.end_headers() self.wfile.write(rtj) AVNLog.ld("nav response", rtj) else: raise Exception("empty response")
def getTileData(self, tile, source): if not self.isOpen: raise Exception("not open") request = QueueEntry(tile) self.cond.acquire() try: self.requestQueue.append(request) self.cond.notify_all() except: pass self.cond.release() AVNLog.debug("waiting for tile") data = request.waitAndGet() AVNLog.debug("tile received") return data
def _deregister(self, description: ServiceDescription) -> object: if description.group is None: description.reset() return try: AVNLog.info("deregister") description.reset() description.group.Reset() description.group.Free() description.group = None self.deleteInfo(description.getKey()) except Exception as e: AVNLog.error("unable to deregister: %s", str(e)) self.setInfo(description.getKey(), "error in deregister %s" % str(e), WorkerStatus.ERROR)
def handleDeleteRequest(self, requestParam): type = self.getRequestParam(requestParam, "type") if type is None: raise Exception("no type for delete") handler = self.server.getRequestHandler('delete', type) rt = {'status': 'OK'} if handler is not None: AVNLog.debug("found handler for delete request %s:%s" % (type, handler.getConfigName())) handler.handleApiRequest('delete', type, requestParam, handler=self) return json.dumps(rt) raise Exception("invalid type %s" % type)
def handleGemfRequest(self, path, query): try: path = path.replace("/gemf/", "", 1) parr = path.split("/") gemfname = parr[0] + ".gemf" for g in self.server.gemflist.values(): if g['name'] == gemfname: AVNLog.debug("gemf file %s, request %s, lend=%d", gemfname, path, len(parr)) #found file #basically we can today handle 2 types of requests: #get the overview /gemf/<name>/avnav.xml #get a tile /gemf/<name>/<srcname>/z/x/y.png if parr[1] == self.server.navxml: AVNLog.debug("avnav request for GEMF %s", gemfname) data = g['avnav'] self.send_response(200) self.send_header("Content-type", "text/xml") self.send_header("Content-Length", len(data)) self.send_header("Last-Modified", self.date_time_string()) self.end_headers() self.wfile.write(data) return None if len(parr) != 5: raise Exception("invalid request to GEMF file %s: %s" % (gemfname, path)) data = g['gemf'].getTileData((int(parr[2]), int( parr[3]), int(parr[4].replace(".png", ""))), parr[1]) if data is None: empty = self.server.emptytile if empty is not None: data = empty if data is None: self.send_error(404, "File %s not found" % (path)) return None self.send_response(200) self.send_header("Content-type", "image/png") self.send_header("Content-Length", len(data)) self.send_header("Last-Modified", self.date_time_string()) self.end_headers() self.wfile.write(data) return None raise Exception("gemf file %s not found" % (gemfname)) except: self.send_error(500, "Error: %s" % (traceback.format_exc())) return
def handleCurrentLevelRequest(self, requestParam): (level, filter) = AVNLog.getCurrentLevelAndFilter() return json.dumps({ 'status': 'OK', 'level': level, 'filter': filter }, cls=Encoder)
def startInstance(self,navdata): """ @type navdata: AVNStore """ self.navdata=navdata self.feeder = self.findFeeder(self.getStringParam('feederName')) try: self.checkConfig(self.param) except Exception as e: self.setInfo('main','%s'%str(e),WorkerStatus.ERROR) raise if not self.isDisabled(): self.startThread() else: self.setInfo('main','disabled',WorkerStatus.INACTIVE) AVNLog.info("not starting %s (disabled) with config %s", self.getName(), self.getConfigString())
def fillInfo(self, baseDir): routeFile = os.path.join(baseDir, self.name) try: if os.path.isfile(routeFile): content = "" with open(routeFile, "r", encoding='utf-8') as f: content = f.read() parser = gpxparser.GPXParser(content) gpx = parser.parse() if gpx.routes is None or len(gpx.routes) == 0: AVNLog.error("no routes in %s", routeFile) else: route = gpx.routes[0] self.numpoints = len(route.points) self.length = route.length() / AVNUtil.NM except Exception as e: AVNLog.error("error when parsing route %s: %s", routeFile, str(e))
def computeAnchor(self): curGps = self.navdata.getDataByPrefix(AVNStore.BASE_KEY_GPS, 1) lat = curGps.get('lat') lon = curGps.get('lon') if lat is None or lon is None: self.startStopAlarm(False, self.ALARMS.anchor) if self.activatedAlarms.get(self.ALARMS.gps) is None: self.startStopAlarm(True, self.ALARMS.gps) return self.startStopAlarm(False, self.ALARMS.gps) anchorDistance = AVNUtil.distanceM( (lat, lon), self.wpToLatLon(self.currentLeg.getFrom())) AVNLog.debug("Anchor distance %d, allowed %d", anchorDistance, self.currentLeg.getAnchorDistance()) if anchorDistance > self.currentLeg.getAnchorDistance(): self.startStopAlarm(True, self.ALARMS.anchor) return
def handleListDir(self, requestParam): type = self.getRequestParam(requestParam, "type") if type is None: raise Exception("no type for listdir") handler = self.server.getRequestHandler('list', type) if handler is not None: AVNLog.debug("found handler for list request %s:%s" % (type, handler.getConfigName())) rt = handler.handleApiRequest('list', type, requestParam, handler=self) if rt is None: raise Exception("invalid list response") return json.dumps(rt) raise Exception("invalid type %s" % type)
def resolveService(self, type, name): ''' resove a service (IPv4) @param type: the service type @param name: the service name @return: a tuple (hostname,ip,port) if found or None otherwise ''' if self.server is None: return None try: res = self.server.ResolveService(self.IF_UNSPEC, self.PROTO_INET, name, type, "local", self.PROTO_INET, 0) return (str(res[5]), str(res[7]), int(res[8])) except Exception as e: AVNLog.error("unable to resolve service %s.%s: %s", type, name, str(e)) return None
def periodicRun(self): hasLeg = False hasRMB = False if self.currentLeg and self.currentLeg.isActive(): hasLeg = True if self.currentLeg.getAnchorDistance() is not None: routerInfo = "Anchor watch, from %s, (anchor radius %sm)" % ( str(self.currentLeg.getFrom()), str(self.currentLeg.getAnchorDistance())) else: routerInfo = "from %s, to %s, route=%s, activeWp=%s, approach=%s (approach radius %sm)" % ( str(self.currentLeg.getFrom()), str( self.currentLeg.getTo()), self.currentLeg.getRouteName(), self.currentLeg.getCurrentTarget(), self.currentLeg.isApproach(), self.currentLeg.getApproachDistance()) AVNLog.debug(routerInfo) self.setInfo("leg", routerInfo, WorkerStatus.RUNNING) try: if self.currentLeg is not None and self.currentLeg.getAnchorDistance( ) is not None: self.computeAnchor() else: self.startStopAlarm(False, self.ALARMS.anchor) self.startStopAlarm(False, self.ALARMS.gps) computeRMB = self.getBoolParam("computeRMB") computeAPB = self.getBoolParam("computeAPB") if computeRMB or computeAPB: hasRMB = self.computeRMB(computeRMB, computeAPB) except Exception as e: AVNLog.warn("exception in computeRMB %s, retrying", traceback.format_exc()) try: self.computeApproach() except: AVNLog.warn("exception in computeApproach %s, retrying", traceback.format_exc()) if (not hasLeg): self.setInfo("leg", "no leg", WorkerStatus.INACTIVE) if (not hasRMB): self.setInfo("autopilot", "no autopilot data", WorkerStatus.INACTIVE) try: lat = self.navdata.getSingleValue(AVNStore.BASE_KEY_GPS + ".lat") lon = self.navdata.getSingleValue(AVNStore.BASE_KEY_GPS + ".lon") if lat is not None and lon is not None: self.startStopAlarm(False, self.ALARMS.gps) except: pass AVNLog.debug("router main loop")
def createOverview(self): zoomlevels = [] zoomLevelBoundings = {} connection = sqlite3.connect(self.filename) if connection is None: raise Exception("unable to open mbtiles file %s" % (self.filename)) AVNLog.info("opening mbtiles file %s", self.filename) cu = None hasAvnavScheme = False try: cu = connection.cursor() for sr in cu.execute("select value from metadata where name=?", ["avnav_scheme"]): v = sr[0] if v is not None: v = v.lower() if v in ['tms', 'xyz']: AVNLog.info("setting scheme for %s to %s", self.filename, v) self.schemeTMS = False if v == "xyz" else True self.schemeInconsistent = False hasAvnavScheme = True #check if there is a schema entry for sr in cu.execute("select value from metadata where name=?", ["scheme"]): v = sr[0] if v is not None: v = v.lower() self.originalScheme = v if not hasAvnavScheme: self.schemeInconsistent = True for zl in cu.execute("select distinct zoom_level from tiles;"): zoomlevels.append(zl[0]) for zl in zoomlevels: el = {} for rowmima in cu.execute( "select min(tile_row),max(tile_row) from tiles where zoom_level=?", [zl]): # names must match getGemfInfo in create_overview if self.schemeTMS: el['ymin'] = self.rowToY(zl, rowmima[1]) el['ymax'] = self.rowToY(zl, rowmima[0]) else: el['ymin'] = self.rowToY(zl, rowmima[0]) el['ymax'] = self.rowToY(zl, rowmima[1]) for colmima in cu.execute( "select min(tile_column),max(tile_column) from tiles where zoom_level=?", [zl]): el['xmin'] = self.colToX(zl, colmima[0]) el['xmax'] = self.colToX(zl, colmima[1]) zoomLevelBoundings[zl] = el except Exception as e: AVNLog.error("error reading base info from %s:%s", self.filename, str(e)) self.zoomlevels = zoomlevels self.zoomLevelBoundings = zoomLevelBoundings if cu is not None: cu.close() connection.close() self.changeCount = AVNUtil.utcnow()
def setCurrentLeg(self, leg): # type: (AVNRoutingLeg) -> object changed = self.currentLeg == None or not self.currentLeg.equal(leg) if changed: self.navdata.updateChangeCounter(self.LEG_CHANGE_KEY) self.currentLeg = leg if leg is None: if os.path.exists(self.currentLegFileName): os.unlink(self.currentLegFileName) AVNLog.info("current leg removed") return AVNLog.info("new leg %s", str(leg)) f = open(self.currentLegFileName, "w", encoding='utf-8') try: f.write(json.dumps(leg.getJson())) except: f.close() raise f.close() if not leg.isActive(): self.computeApproach( ) #ensure that we immediately switch off alarms
def handleUploadRequest(self, requestParam): rlen = None try: rlen = self.headers.get("Content-Length") if rlen is None: raise Exception("Content-Length not set in upload request") self.connection.settimeout(30) type = self.getRequestParam(requestParam, "type") handler = self.server.getRequestHandler("upload", type) if handler is not None: AVNLog.debug("found handler for upload request %s:%s" % (type, handler.getConfigName())) rt = handler.handleApiRequest("upload", type, requestParam, rfile=self.rfile, flen=rlen, handler=self) return json.dumps(rt) else: raise Exception("invalid request %s", type) except Exception as e: return json.dumps({'status': unicode(e)})