From d5f17d66d9e1d23b8ecf6214f4625ec398b1e3c4 Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Sat, 11 May 2019 12:58:09 +0200 Subject: [PATCH] replace central entry --- openwebrx.py | 754 +++------------------------------------------------ server.py | 45 --- 2 files changed, 31 insertions(+), 768 deletions(-) mode change 100755 => 100644 openwebrx.py delete mode 100644 server.py diff --git a/openwebrx.py b/openwebrx.py old mode 100755 new mode 100644 index 07c91e1..113dfaf --- a/openwebrx.py +++ b/openwebrx.py @@ -1,737 +1,45 @@ -#!/usr/bin/python2 -print "" # python2.7 is required to run OpenWebRX instead of python3. Please run me by: python2 openwebrx.py -""" +from http.server import HTTPServer +from owrx.http import RequestHandler +from owrx.config import PropertyManager, FeatureDetector +from owrx.source import SdrService +from socketserver import ThreadingMixIn - This file is part of OpenWebRX, - an open-source SDR receiver software with a web UI. - Copyright (c) 2013-2015 by Andras Retzler +import logging +logging.basicConfig(level = logging.DEBUG, format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s") - 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 . - -""" -sw_version="v0.17" -#0.15 (added nmux) - -import os -import code -import importlib -import csdr -import thread -import time -import datetime -import subprocess -import os -from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer -from SocketServer import ThreadingMixIn -import fcntl -import time -import md5 -import random -import threading -import sys -import traceback -from collections import namedtuple -import Queue -import ctypes - -#import rtl_mus -import rxws -import uuid -import signal -import socket - -try: import sdrhu -except: sdrhu=False -avatar_ctime="" - -#pypy compatibility -try: import dl -except: pass -try: import __pypy__ -except: pass -pypy="__pypy__" in globals() - -""" -def import_all_plugins(directory): - for subdir in os.listdir(directory): - if os.path.isdir(directory+subdir) and not subdir[0]=="_": - exact_path=directory+subdir+"/plugin.py" - if os.path.isfile(exact_path): - importname=(directory+subdir+"/plugin").replace("/",".") - print "[openwebrx-import] Found plugin:",importname - importlib.import_module(importname) -""" - -class MultiThreadHTTPServer(ThreadingMixIn, HTTPServer): +class ThreadedHttpServer(ThreadingMixIn, HTTPServer): pass -def handle_signal(sig, frame): - global spectrum_dsp - if sig == signal.SIGUSR1: - print "[openwebrx] Verbose status information on USR1 signal" - print - print "time.time() =", time.time() - print "clients_mutex.locked() =", clients_mutex.locked() - print "clients_mutex_locker =", clients_mutex_locker - if server_fail: print "server_fail = ", server_fail - print "spectrum_thread_watchdog_last_tick =", spectrum_thread_watchdog_last_tick - print - print "clients:",len(clients) - for client in clients: - print - for key in client._fields: - print "\t%s = %s"%(key,str(getattr(client,key))) - elif sig == signal.SIGUSR2: - code.interact(local=globals()) - else: - print "[openwebrx] Ctrl+C: aborting." - cleanup_clients(True) - spectrum_dsp.stop() - os._exit(1) #not too graceful exit - -def access_log(data): - global logs - logs.access_log.write("["+datetime.datetime.now().isoformat()+"] "+data+"\n") - logs.access_log.flush() - -receiver_failed=spectrum_thread_watchdog_last_tick=rtl_thread=spectrum_dsp=server_fail=None def main(): - global clients, clients_mutex, pypy, lock_try_time, avatar_ctime, cfg, logs - global serverfail, rtl_thread - print - print "OpenWebRX - Open Source SDR Web App for Everyone! | for license see LICENSE file in the package" - print "_________________________________________________________________________________________________" - print - print "Author contact info: Andras Retzler, HA7ILM " - print + print() + print("OpenWebRX - Open Source SDR Web App for Everyone! | for license see LICENSE file in the package") + print("_________________________________________________________________________________________________") + print() + print("Author contact info: Andras Retzler, HA7ILM ") + print() - no_arguments=len(sys.argv)==1 - if no_arguments: print "[openwebrx-main] Configuration script not specified. I will use: \"config_webrx.py\"" - cfg=__import__("config_webrx" if no_arguments else sys.argv[1]) - for option in ("access_log","csdr_dynamic_bufsize","csdr_print_bufsizes","csdr_through"): - if not option in dir(cfg): setattr(cfg, option, False) #initialize optional config parameters - - #Open log files - logs = type("logs_class", (object,), {"access_log":open(cfg.access_log if cfg.access_log else "/dev/null","a"), "error_log":""})() - - #Set signal handler - signal.signal(signal.SIGINT, handle_signal) #http://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python - signal.signal(signal.SIGUSR1, handle_signal) - signal.signal(signal.SIGUSR2, handle_signal) - - #Pypy - if pypy: print "pypy detected (and now something completely different: c code is expected to run at a speed of 3*10^8 m/s?)" - - #Change process name to "openwebrx" (to be seen in ps) - try: - for libcpath in ["/lib/i386-linux-gnu/libc.so.6","/lib/libc.so.6"]: - if os.path.exists(libcpath): - libc = dl.open(libcpath) - libc.call("prctl", 15, "openwebrx", 0, 0, 0) - break - except: - pass - - #Start rtl thread - if os.system("csdr 2> /dev/null") == 32512: #check for csdr - print "[openwebrx-main] You need to install \"csdr\" to run OpenWebRX!\n" - return - if os.system("nmux --help 2> /dev/null") == 32512: #check for nmux - print "[openwebrx-main] You need to install an up-to-date version of \"csdr\" that contains the \"nmux\" tool to run OpenWebRX! Please upgrade \"csdr\"!\n" - return - if cfg.start_rtl_thread: - nmux_bufcnt = nmux_bufsize = 0 - while nmux_bufsize < cfg.samp_rate/4: nmux_bufsize += 4096 - while nmux_bufsize * nmux_bufcnt < cfg.nmux_memory * 1e6: nmux_bufcnt += 1 - if nmux_bufcnt == 0 or nmux_bufsize == 0: - print "[openwebrx-main] Error: nmux_bufsize or nmux_bufcnt is zero. These depend on nmux_memory and samp_rate options in config_webrx.py" - return - print "[openwebrx-main] nmux_bufsize = %d, nmux_bufcnt = %d" % (nmux_bufsize, nmux_bufcnt) - cfg.start_rtl_command += "| nmux --bufsize %d --bufcnt %d --port %d --address 127.0.0.1" % (nmux_bufsize, nmux_bufcnt, cfg.iq_server_port) - rtl_thread=threading.Thread(target = lambda:subprocess.Popen(cfg.start_rtl_command, shell=True), args=()) - rtl_thread.start() - print "[openwebrx-main] Started rtl_thread: "+cfg.start_rtl_command - print "[openwebrx-main] Waiting for I/Q server to start..." - while True: - testsock=socket.socket() - try: testsock.connect(("127.0.0.1", cfg.iq_server_port)) - except: - time.sleep(0.1) + cfg = __import__("config_webrx") + pm = PropertyManager.getSharedInstance() + for name, value in cfg.__dict__.items(): + if name.startswith("__"): continue - testsock.close() - break - print "[openwebrx-main] I/Q server started." + pm[name] = value - #Initialize clients - clients=[] - clients_mutex=threading.Lock() - lock_try_time=0 + featureDetector = FeatureDetector() + if not featureDetector.is_available("core"): + print("you are missing required dependencies to run openwebrx. " + "please check that the following core requirements are installed:") + print(", ".join(featureDetector.get_requirements("core"))) + return - #Start watchdog thread - print "[openwebrx-main] Starting watchdog threads." - mutex_test_thread=threading.Thread(target = mutex_test_thread_function, args = ()) - mutex_test_thread.start() - mutex_watchdog_thread=threading.Thread(target = mutex_watchdog_thread_function, args = ()) - mutex_watchdog_thread.start() + # Get error messages about unknown / unavailable features as soon as possible + SdrService.loadProps() + + server = ThreadedHttpServer(('0.0.0.0', pm.getPropertyValue("web_port")), RequestHandler) + server.serve_forever() - #Start spectrum thread - print "[openwebrx-main] Starting spectrum thread." - spectrum_thread=threading.Thread(target = spectrum_thread_function, args = ()) - spectrum_thread.start() - #spectrum_watchdog_thread=threading.Thread(target = spectrum_watchdog_thread_function, args = ()) - #spectrum_watchdog_thread.start() - - get_cpu_usage() - bcastmsg_thread=threading.Thread(target = bcastmsg_thread_function, args = ()) - bcastmsg_thread.start() - - #threading.Thread(target = measure_thread_function, args = ()).start() - - #Start sdr.hu update thread - if sdrhu and cfg.sdrhu_key and cfg.sdrhu_public_listing: - print "[openwebrx-main] Starting sdr.hu update thread..." - avatar_ctime=str(os.path.getctime("htdocs/gfx/openwebrx-avatar.png")) - sdrhu_thread=threading.Thread(target = sdrhu.run, args = ()) - sdrhu_thread.start() - - #Start HTTP thread - httpd = MultiThreadHTTPServer(('', cfg.web_port), WebRXHandler) - print('[openwebrx-main] Starting HTTP server.') - access_log("Starting OpenWebRX...") - httpd.serve_forever() - - -# This is a debug function below: -measure_value=0 -def measure_thread_function(): - global measure_value - while True: - print "[openwebrx-measure] value is",measure_value - measure_value=0 - time.sleep(1) - -def bcastmsg_thread_function(): - global clients - while True: - time.sleep(3) - try: cpu_usage=get_cpu_usage() - except: cpu_usage=0 - cma("bcastmsg_thread") - for i in range(0,len(clients)): - clients[i].bcastmsg="MSG cpu_usage={0} clients={1}".format(int(cpu_usage*100),len(clients)) - cmr() - -def mutex_test_thread_function(): - global clients_mutex, lock_try_time - while True: - time.sleep(0.5) - lock_try_time=time.time() - clients_mutex.acquire() - clients_mutex.release() - lock_try_time=0 - -def cma(what): #clients_mutex acquire - global clients_mutex - global clients_mutex_locker - if not clients_mutex.locked(): clients_mutex_locker = what - clients_mutex.acquire() - -def cmr(): - global clients_mutex - global clients_mutex_locker - clients_mutex_locker = None - clients_mutex.release() - -def mutex_watchdog_thread_function(): - global lock_try_time - global clients_mutex_locker - global clients_mutex - while True: - if lock_try_time != 0 and time.time()-lock_try_time > 3.0: - #if 3 seconds pass without unlock - print "[openwebrx-mutex-watchdog] Mutex unlock timeout. Locker: \""+str(clients_mutex_locker)+"\" Now unlocking..." - clients_mutex.release() - time.sleep(0.5) - -def spectrum_watchdog_thread_function(): - global spectrum_thread_watchdog_last_tick, receiver_failed - while True: - time.sleep(60) - if spectrum_thread_watchdog_last_tick and time.time()-spectrum_thread_watchdog_last_tick > 60.0: - print "[openwebrx-spectrum-watchdog] Spectrum timeout. Seems like no I/Q data is coming from the receiver.\nIf you're using RTL-SDR, the receiver hardware may randomly fail under some circumstances:\n1) high temperature,\n2) insufficient current available from the USB port." - print "[openwebrx-spectrum-watchdog] Deactivating receiver." - receiver_failed="spectrum" - return - -def check_server(): - global spectrum_dsp, server_fail, rtl_thread - if server_fail: return server_fail - #print spectrum_dsp.process.poll() - if spectrum_dsp and spectrum_dsp.process.poll()!=None: server_fail = "spectrum_thread dsp subprocess failed" - #if rtl_thread and not rtl_thread.is_alive(): server_fail = "rtl_thread failed" - if server_fail: print "[openwebrx-check_server] >>>>>>> ERROR:", server_fail - return server_fail - -def apply_csdr_cfg_to_dsp(dsp): - dsp.csdr_dynamic_bufsize = cfg.csdr_dynamic_bufsize - dsp.csdr_print_bufsizes = cfg.csdr_print_bufsizes - dsp.csdr_through = cfg.csdr_through - -def spectrum_thread_function(): - global clients, spectrum_dsp, spectrum_thread_watchdog_last_tick - spectrum_dsp=dsp=csdr.dsp() - dsp.nc_port=cfg.iq_server_port - dsp.set_demodulator("fft") - dsp.set_samp_rate(cfg.samp_rate) - dsp.set_fft_size(cfg.fft_size) - dsp.set_fft_fps(cfg.fft_fps) - dsp.set_fft_averages(int(round(1.0 * cfg.samp_rate / cfg.fft_size / cfg.fft_fps / (1.0 - cfg.fft_voverlap_factor))) if cfg.fft_voverlap_factor>0 else 0) - dsp.set_fft_compression(cfg.fft_compression) - dsp.set_format_conversion(cfg.format_conversion) - apply_csdr_cfg_to_dsp(dsp) - sleep_sec=0.87/cfg.fft_fps - print "[openwebrx-spectrum] Spectrum thread initialized successfully." - dsp.start() - if cfg.csdr_dynamic_bufsize: - dsp.read(8) #dummy read to skip bufsize & preamble - print "[openwebrx-spectrum] Note: CSDR_DYNAMIC_BUFSIZE_ON = 1" - print "[openwebrx-spectrum] Spectrum thread started." - bytes_to_read=int(dsp.get_fft_bytes_to_read()) - spectrum_thread_counter=0 - while True: - data=dsp.read(bytes_to_read) - #print "gotcha",len(data),"bytes of spectrum data via spectrum_thread_function()" - if spectrum_thread_counter >= cfg.fft_fps: - spectrum_thread_counter=0 - spectrum_thread_watchdog_last_tick = time.time() #once every second - else: spectrum_thread_counter+=1 - cma("spectrum_thread") - correction=0 - for i in range(0,len(clients)): - i-=correction - if (clients[i].ws_started): - if clients[i].spectrum_queue.full(): - print "[openwebrx-spectrum] client spectrum queue full, closing it." - close_client(i, False) - correction+=1 - else: - clients[i].spectrum_queue.put([data]) # add new string by "reference" to all clients - cmr() - -def get_client_by_id(client_id, use_mutex=True): - global clients - output=-1 - if use_mutex: cma("get_client_by_id") - for i in range(0,len(clients)): - if(clients[i].id==client_id): - output=i - break - if use_mutex: cmr() - if output==-1: - raise ClientNotFoundException - else: - return output - -def log_client(client, what): - print "[openwebrx-httpd] client {0}#{1} :: {2}".format(client.ip,client.id,what) - -def cleanup_clients(end_all=False): - # - if a client doesn't open websocket for too long time, we drop it - # - or if end_all is true, we drop all clients - global clients - cma("cleanup_clients") - correction=0 - for i in range(0,len(clients)): - i-=correction - #print "cleanup_clients:: len(clients)=", len(clients), "i=", i - if end_all or ((not clients[i].ws_started) and (time.time()-clients[i].gen_time)>45): - if not end_all: print "[openwebrx] cleanup_clients :: client timeout to open WebSocket" - close_client(i, False) - correction+=1 - cmr() - -def generate_client_id(ip): - #add a client - global clients - new_client=namedtuple("ClientStruct", "id gen_time ws_started sprectum_queue ip closed bcastmsg dsp loopstat") - new_client.id=md5.md5(str(random.random())).hexdigest() - new_client.gen_time=time.time() - new_client.ws_started=False # to check whether client has ever tried to open the websocket - new_client.spectrum_queue=Queue.Queue(1000) - new_client.ip=ip - new_client.bcastmsg="" - new_client.closed=[False] #byref, not exactly sure if required - new_client.dsp=None - cma("generate_client_id") - clients.append(new_client) - log_client(new_client,"client added. Clients now: {0}".format(len(clients))) - cmr() - cleanup_clients() - return new_client.id - -def close_client(i, use_mutex=True): - global clients - log_client(clients[i],"client being closed.") - if use_mutex: cma("close_client") - try: - clients[i].dsp.stop() - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - print "[openwebrx] close_client dsp.stop() :: error -",exc_type,exc_value - traceback.print_tb(exc_traceback) - clients[i].closed[0]=True - access_log("Stopped streaming to client: "+clients[i].ip+"#"+str(clients[i].id)+" (users now: "+str(len(clients)-1)+")") - del clients[i] - if use_mutex: cmr() - -# http://www.codeproject.com/Articles/462525/Simple-HTTP-Server-and-Client-in-Python -# some ideas are used from the artice above - -class WebRXHandler(BaseHTTPRequestHandler): - def proc_read_thread(): - pass - - def send_302(self,what): - self.send_response(302) - self.send_header('Content-type','text/html') - self.send_header("Location", "http://{0}:{1}/{2}".format(cfg.server_hostname,cfg.web_port,what)) - self.end_headers() - self.wfile.write("

Object moved

Please click here to continue.".format(what)) - - - def do_GET(self): - self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - global dsp_plugin, clients_mutex, clients, avatar_ctime, sw_version, receiver_failed - rootdir = 'htdocs' - self.path=self.path.replace("..","") - path_temp_parts=self.path.split("?") - self.path=path_temp_parts[0] - request_param=path_temp_parts[1] if(len(path_temp_parts)>1) else "" - access_log("GET "+self.path+" from "+self.client_address[0]) - try: - if self.path=="/": - self.path="/index.wrx" - # there's even another cool tip at http://stackoverflow.com/questions/4419650/how-to-implement-timeout-in-basehttpserver-basehttprequesthandler-python - #if self.path[:5]=="/lock": cma("do_GET /lock/") # to test mutex_watchdog_thread. Do not uncomment in production environment! - if self.path[:4]=="/ws/": - print "[openwebrx-ws] Client requested WebSocket connection" - if receiver_failed: self.send_error(500,"Internal server error") - try: - # ========= WebSocket handshake ========= - ws_success=True - try: - rxws.handshake(self) - cma("do_GET /ws/") - client_i=get_client_by_id(self.path[4:], False) - myclient=clients[client_i] - except rxws.WebSocketException: ws_success=False - except ClientNotFoundException: ws_success=False - finally: - if clients_mutex.locked(): cmr() - if not ws_success: - self.send_error(400, 'Bad request.') - return - - # ========= Client handshake ========= - if myclient.ws_started: - print "[openwebrx-httpd] error: second WS connection with the same client id, throwing it." - self.send_error(400, 'Bad request.') #client already started - return - rxws.send(self, "CLIENT DE SERVER openwebrx.py") - client_ans=rxws.recv(self, True) - if client_ans[:16]!="SERVER DE CLIENT": - rxws.send("ERR Bad answer.") - return - myclient.ws_started=True - #send default parameters - rxws.send(self, "MSG center_freq={0} bandwidth={1} fft_size={2} fft_fps={3} audio_compression={4} fft_compression={5} max_clients={6} setup".format(str(cfg.shown_center_freq),str(cfg.samp_rate),cfg.fft_size,cfg.fft_fps,cfg.audio_compression,cfg.fft_compression,cfg.max_clients)) - - # ========= Initialize DSP ========= - dsp=csdr.dsp() - dsp_initialized=False - dsp.set_audio_compression(cfg.audio_compression) - dsp.set_fft_compression(cfg.fft_compression) #used by secondary chains - dsp.set_format_conversion(cfg.format_conversion) - dsp.set_offset_freq(0) - dsp.set_bpf(-4000,4000) - dsp.set_secondary_fft_size(cfg.digimodes_fft_size) - dsp.nc_port=cfg.iq_server_port - apply_csdr_cfg_to_dsp(dsp) - myclient.dsp=dsp - do_secondary_demod=False - access_log("Started streaming to client: "+self.client_address[0]+"#"+myclient.id+" (users now: "+str(len(clients))+")") - - while True: - myclient.loopstat=0 - if myclient.closed[0]: - print "[openwebrx-httpd:ws] client closed by other thread" - break - - # ========= send audio ========= - if dsp_initialized: - myclient.loopstat=10 - temp_audio_data=dsp.read(256) - myclient.loopstat=11 - rxws.send(self, temp_audio_data, "AUD ") - - # ========= send spectrum ========= - while not myclient.spectrum_queue.empty(): - myclient.loopstat=20 - spectrum_data=myclient.spectrum_queue.get() - #spectrum_data_mid=len(spectrum_data[0])/2 - #rxws.send(self, spectrum_data[0][spectrum_data_mid:]+spectrum_data[0][:spectrum_data_mid], "FFT ") - # (it seems GNU Radio exchanges the first and second part of the FFT output, we correct it) - myclient.loopstat=21 - rxws.send(self, spectrum_data[0],"FFT ") - - # ========= send smeter_level ========= - smeter_level=None - while True: - try: - myclient.loopstat=30 - smeter_level=dsp.get_smeter_level() - if smeter_level == None: break - except: - break - if smeter_level!=None: - myclient.loopstat=31 - rxws.send(self, "MSG s={0}".format(smeter_level)) - - # ========= send bcastmsg ========= - if myclient.bcastmsg!="": - myclient.loopstat=40 - rxws.send(self,myclient.bcastmsg) - myclient.bcastmsg="" - - # ========= send secondary ========= - if do_secondary_demod: - myclient.loopstat=41 - while True: - try: - secondary_spectrum_data=dsp.read_secondary_fft(dsp.get_secondary_fft_bytes_to_read()) - if len(secondary_spectrum_data) == 0: break - # print "len(secondary_spectrum_data)", len(secondary_spectrum_data) #TODO digimodes - rxws.send(self, secondary_spectrum_data, "FFTS") - except: break - myclient.loopstat=42 - while True: - try: - myclient.loopstat=422 - secondary_demod_data=dsp.read_secondary_demod(1) - myclient.loopstat=423 - if len(secondary_demod_data) == 0: break - # print "len(secondary_demod_data)", len(secondary_demod_data), secondary_demod_data #TODO digimodes - rxws.send(self, secondary_demod_data, "DAT ") - except: break - - # ========= process commands ========= - while True: - myclient.loopstat=50 - rdata=rxws.recv(self, False) - myclient.loopstat=51 - #try: - if not rdata: break - elif rdata[:3]=="SET": - print "[openwebrx-httpd:ws,%d] command: %s"%(client_i,rdata) - pairs=rdata[4:].split(" ") - bpf_set=False - new_bpf=dsp.get_bpf() - filter_limit=dsp.get_output_rate()/2 - for pair in pairs: - param_name, param_value = pair.split("=") - if param_name == "low_cut" and -filter_limit <= int(param_value) <= filter_limit: - bpf_set=True - new_bpf[0]=int(param_value) - elif param_name == "high_cut" and -filter_limit <= int(param_value) <= filter_limit: - bpf_set=True - new_bpf[1]=int(param_value) - elif param_name == "offset_freq" and -cfg.samp_rate/2 <= int(param_value) <= cfg.samp_rate/2: - myclient.loopstat=510 - dsp.set_offset_freq(int(param_value)) - elif param_name == "squelch_level" and float(param_value) >= 0: - myclient.loopstat=520 - dsp.set_squelch_level(float(param_value)) - elif param_name=="mod": - if (dsp.get_demodulator()!=param_value): - myclient.loopstat=530 - if dsp_initialized: dsp.stop() - dsp.set_demodulator(param_value) - if dsp_initialized: dsp.start() - elif param_name == "output_rate": - if not dsp_initialized: - myclient.loopstat=540 - dsp.set_output_rate(int(param_value)) - myclient.loopstat=541 - dsp.set_samp_rate(cfg.samp_rate) - elif param_name=="action" and param_value=="start": - if not dsp_initialized: - myclient.loopstat=550 - dsp.start() - dsp_initialized=True - elif param_name=="secondary_mod" and cfg.digimodes_enable: - if (dsp.get_secondary_demodulator() != param_value): - if dsp_initialized: dsp.stop() - if param_value == "off": - dsp.set_secondary_demodulator(None) - do_secondary_demod = False - else: - dsp.set_secondary_demodulator(param_value) - do_secondary_demod = True - rxws.send(self, "MSG secondary_fft_size={0} if_samp_rate={1} secondary_bw={2} secondary_setup".format(cfg.digimodes_fft_size, dsp.if_samp_rate(), dsp.secondary_bw())) - if dsp_initialized: dsp.start() - elif param_name=="secondary_offset_freq" and 0 <= int(param_value) <= dsp.if_samp_rate()/2 and cfg.digimodes_enable: - dsp.set_secondary_offset_freq(int(param_value)) - else: - print "[openwebrx-httpd:ws] invalid parameter" - if bpf_set: - myclient.loopstat=560 - dsp.set_bpf(*new_bpf) - #code.interact(local=locals()) - except: - myclient.loopstat=990 - exc_type, exc_value, exc_traceback = sys.exc_info() - print "[openwebrx-httpd:ws] exception: ",exc_type,exc_value - traceback.print_tb(exc_traceback) #TODO digimodes - #if exc_value[0]==32: #"broken pipe", client disconnected - # pass - #elif exc_value[0]==11: #"resource unavailable" on recv, client disconnected - # pass - #else: - # print "[openwebrx-httpd] error in /ws/ handler: ",exc_type,exc_value - # traceback.print_tb(exc_traceback) - - #stop dsp for the disconnected client - myclient.loopstat=991 - try: - dsp.stop() - del dsp - except: - print "[openwebrx-httpd] error in dsp.stop()" - - #delete disconnected client - myclient.loopstat=992 - try: - cma("do_GET /ws/ delete disconnected") - id_to_close=get_client_by_id(myclient.id,False) - close_client(id_to_close,False) - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - print "[openwebrx-httpd] client cannot be closed: ",exc_type,exc_value - traceback.print_tb(exc_traceback) - finally: - cmr() - myclient.loopstat=1000 - return - elif self.path in ("/status", "/status/"): - #self.send_header('Content-type','text/plain') - getbands=lambda: str(int(cfg.shown_center_freq-cfg.samp_rate/2))+"-"+str(int(cfg.shown_center_freq+cfg.samp_rate/2)) - self.wfile.write("status="+("inactive" if receiver_failed else "active")+"\nname="+cfg.receiver_name+"\nsdr_hw="+cfg.receiver_device+"\nop_email="+cfg.receiver_admin+"\nbands="+getbands()+"\nusers="+str(len(clients))+"\nusers_max="+str(cfg.max_clients)+"\navatar_ctime="+avatar_ctime+"\ngps="+str(cfg.receiver_gps)+"\nasl="+str(cfg.receiver_asl)+"\nloc="+cfg.receiver_location+"\nsw_version="+sw_version+"\nantenna="+cfg.receiver_ant+"\n") - print "[openwebrx-httpd] GET /status/ from",self.client_address[0] - else: - f=open(rootdir+self.path) - data=f.read() - extension=self.path[(len(self.path)-4):len(self.path)] - extension=extension[2:] if extension[1]=='.' else extension[1:] - checkresult=check_server() - if extension == "wrx" and (checkresult or receiver_failed): - self.send_302("inactive.html") - return - anyStringsPresentInUserAgent=lambda a: reduce(lambda x,y:x or y, map(lambda b:self.headers['user-agent'].count(b), a), False) - if extension == "wrx" and ( (not anyStringsPresentInUserAgent(("Chrome","Firefox","Googlebot","iPhone","iPad","iPod"))) if 'user-agent' in self.headers.keys() else True ) and (not request_param.count("unsupported")): - self.send_302("upgrade.html") - return - if extension == "wrx": - cleanup_clients(False) - if cfg.max_clients<=len(clients): - self.send_302("retry.html") - return - self.send_response(200) - if(("wrx","html","htm").count(extension)): - self.send_header('Content-type','text/html') - elif(extension=="js"): - self.send_header('Content-type','text/javascript') - elif(extension=="css"): - self.send_header('Content-type','text/css') - self.end_headers() - if extension == "wrx": - replace_dictionary=( - ("%[RX_PHOTO_DESC]",cfg.photo_desc), - ("%[CLIENT_ID]", generate_client_id(self.client_address[0])) if "%[CLIENT_ID]" in data else "", - ("%[WS_URL]","ws://"+cfg.server_hostname+":"+str(cfg.web_port)+"/ws/"), - ("%[RX_TITLE]",cfg.receiver_name), - ("%[RX_LOC]",cfg.receiver_location), - ("%[RX_QRA]",cfg.receiver_qra), - ("%[RX_ASL]",str(cfg.receiver_asl)), - ("%[RX_GPS]",str(cfg.receiver_gps[0])+","+str(cfg.receiver_gps[1])), - ("%[RX_PHOTO_HEIGHT]",str(cfg.photo_height)),("%[RX_PHOTO_TITLE]",cfg.photo_title), - ("%[RX_ADMIN]",cfg.receiver_admin), - ("%[RX_ANT]",cfg.receiver_ant), - ("%[RX_DEVICE]",cfg.receiver_device), - ("%[AUDIO_BUFSIZE]",str(cfg.client_audio_buffer_size)), - ("%[START_OFFSET_FREQ]",str(cfg.start_freq-cfg.center_freq)), - ("%[START_MOD]",cfg.start_mod), - ("%[WATERFALL_COLORS]",cfg.waterfall_colors), - ("%[WATERFALL_MIN_LEVEL]",str(cfg.waterfall_min_level)), - ("%[WATERFALL_MAX_LEVEL]",str(cfg.waterfall_max_level)), - ("%[WATERFALL_AUTO_LEVEL_MARGIN]","[%d,%d]"%cfg.waterfall_auto_level_margin), - ("%[DIGIMODES_ENABLE]",("true" if cfg.digimodes_enable else "false")), - ("%[MATHBOX_WATERFALL_FRES]",str(cfg.mathbox_waterfall_frequency_resolution)), - ("%[MATHBOX_WATERFALL_THIST]",str(cfg.mathbox_waterfall_history_length)), - ("%[MATHBOX_WATERFALL_COLORS]",cfg.mathbox_waterfall_colors) - ) - for rule in replace_dictionary: - while data.find(rule[0])!=-1: - data=data.replace(rule[0],rule[1]) - self.wfile.write(data) - f.close() - return - except IOError: - self.send_error(404, 'Invalid path.') - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - print "[openwebrx-httpd] error (@outside):", exc_type, exc_value - traceback.print_tb(exc_traceback) - - -class ClientNotFoundException(Exception): - pass - -last_worktime=0 -last_idletime=0 - -def get_cpu_usage(): - global last_worktime, last_idletime - try: - f=open("/proc/stat","r") - except: - return 0 #Workaround, possibly we're on a Mac - line="" - while not "cpu " in line: line=f.readline() - f.close() - spl=line.split(" ") - worktime=int(spl[2])+int(spl[3])+int(spl[4]) - idletime=int(spl[5]) - dworktime=(worktime-last_worktime) - didletime=(idletime-last_idletime) - rate=float(dworktime)/(didletime+dworktime) - last_worktime=worktime - last_idletime=idletime - if(last_worktime==0): return 0 - return rate - - -if __name__=="__main__": +if __name__ == "__main__": main() diff --git a/server.py b/server.py deleted file mode 100644 index 113dfaf..0000000 --- a/server.py +++ /dev/null @@ -1,45 +0,0 @@ -from http.server import HTTPServer -from owrx.http import RequestHandler -from owrx.config import PropertyManager, FeatureDetector -from owrx.source import SdrService -from socketserver import ThreadingMixIn - -import logging -logging.basicConfig(level = logging.DEBUG, format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s") - - -class ThreadedHttpServer(ThreadingMixIn, HTTPServer): - pass - - -def main(): - print() - print("OpenWebRX - Open Source SDR Web App for Everyone! | for license see LICENSE file in the package") - print("_________________________________________________________________________________________________") - print() - print("Author contact info: Andras Retzler, HA7ILM ") - print() - - cfg = __import__("config_webrx") - pm = PropertyManager.getSharedInstance() - for name, value in cfg.__dict__.items(): - if name.startswith("__"): - continue - pm[name] = value - - featureDetector = FeatureDetector() - if not featureDetector.is_available("core"): - print("you are missing required dependencies to run openwebrx. " - "please check that the following core requirements are installed:") - print(", ".join(featureDetector.get_requirements("core"))) - return - - # Get error messages about unknown / unavailable features as soon as possible - SdrService.loadProps() - - server = ThreadedHttpServer(('0.0.0.0', pm.getPropertyValue("web_port")), RequestHandler) - server.serve_forever() - - -if __name__ == "__main__": - main()