mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Explicit args on modem primitive methods. API error format.
This commit is contained in:
parent
eda5580f83
commit
8c2c6a8ce0
5
modem/api_validations.py
Normal file
5
modem/api_validations.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
def validate_freedata_callsign(callsign):
|
||||||
|
regexp = "^[a-zA-Z]+\d+\w+-\d{1,2}$"
|
||||||
|
return re.compile(regexp).match(callsign) is not None
|
|
@ -165,9 +165,10 @@ class DATA:
|
||||||
self.arq.arq_session_handler(data[1], data[2])
|
self.arq.arq_session_handler(data[1], data[2])
|
||||||
|
|
||||||
elif data[0] == "PING":
|
elif data[0] == "PING":
|
||||||
# [1] mycallsign
|
# [1] mycallsign // this is being injected as None
|
||||||
# [2] dxcallsign
|
# [2] dxcallsign
|
||||||
self.ping.transmit_ping(data[1], data[2])
|
mycallsign = f"{self.config['STATION']['mycall']}-{self.config['STATION']['myssid']}"
|
||||||
|
self.ping.transmit_ping(mycallsign, data[2])
|
||||||
|
|
||||||
elif data[0] == "BEACON":
|
elif data[0] == "BEACON":
|
||||||
# [1] INTERVAL int
|
# [1] INTERVAL int
|
||||||
|
|
|
@ -13,12 +13,12 @@ class PING:
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
# ---------- PING
|
# ---------- PING
|
||||||
def transmit_ping(self, mycallsign: bytes, dxcallsign: bytes) -> None:
|
def transmit_ping(self, mycallsign: str, dxcallsign: str) -> None:
|
||||||
"""
|
"""
|
||||||
Funktion for controlling pings
|
Function for controlling pings
|
||||||
Args:
|
Args:
|
||||||
mycallsign:bytes:
|
mycallsign
|
||||||
dxcallsign:bytes:
|
dxcallsign
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# check if specific callsign is set with different SSID than the Modem is initialized
|
# check if specific callsign is set with different SSID than the Modem is initialized
|
||||||
|
@ -40,14 +40,15 @@ class PING:
|
||||||
|
|
||||||
self.dxcallsign = dxcallsign
|
self.dxcallsign = dxcallsign
|
||||||
self.dxcallsign_crc = helpers.get_crc_24(self.dxcallsign)
|
self.dxcallsign_crc = helpers.get_crc_24(self.dxcallsign)
|
||||||
self.send_data_to_socket_queue(
|
self.event_queue.put({
|
||||||
freedata="modem-message",
|
'freedata': "modem-message",
|
||||||
ping="transmitting",
|
'ping': "transmitting",
|
||||||
dxcallsign=str(dxcallsign, "UTF-8"),
|
'dxcallsign': str(dxcallsign, "UTF-8"),
|
||||||
)
|
})
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"[Modem] PING REQ ["
|
"[Modem] PING REQ ["
|
||||||
+ mycallsign
|
+ str(mycallsign, "UTF-8")
|
||||||
+ "] >>> ["
|
+ "] >>> ["
|
||||||
+ str(dxcallsign, "UTF-8")
|
+ str(dxcallsign, "UTF-8")
|
||||||
+ "]"
|
+ "]"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import Flask, request, jsonify, make_response
|
from flask import Flask, request, jsonify, make_response, abort, Response
|
||||||
from flask_sock import Sock
|
from flask_sock import Sock
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
import os
|
import os
|
||||||
|
@ -12,6 +12,7 @@ import state_manager
|
||||||
import threading
|
import threading
|
||||||
import ujson as json
|
import ujson as json
|
||||||
import websocket_manager as wsm
|
import websocket_manager as wsm
|
||||||
|
import api_validations as validations
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
@ -55,9 +56,22 @@ service_manager.SM(app)
|
||||||
app.modem_service.put("start")
|
app.modem_service.put("start")
|
||||||
|
|
||||||
# returns a standard API response
|
# returns a standard API response
|
||||||
def api_response(data):
|
def api_response(data, status = 200):
|
||||||
return make_response(jsonify(data), 200)
|
return make_response(jsonify(data), status)
|
||||||
|
|
||||||
|
def api_abort(message, code):
|
||||||
|
jsonError = json.dumps({'error': message})
|
||||||
|
abort(Response(jsonError, code))
|
||||||
|
|
||||||
|
# validates a parameter
|
||||||
|
def validate(req, param, validator, isRequired = True):
|
||||||
|
if param not in req:
|
||||||
|
if isRequired:
|
||||||
|
api_abort(f"Required parameter '{param}' is missing.", 400)
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
if not validator(req[param]):
|
||||||
|
api_abort(f"Value of '{param}' is invalid.", 400)
|
||||||
|
|
||||||
## REST API
|
## REST API
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
|
@ -104,23 +118,26 @@ def post_cqcqcq():
|
||||||
if request.method not in ['POST']:
|
if request.method not in ['POST']:
|
||||||
return api_response({"info": "endpoint for triggering a CQ via POST"})
|
return api_response({"info": "endpoint for triggering a CQ via POST"})
|
||||||
if app.states.is_modem_running:
|
if app.states.is_modem_running:
|
||||||
server_commands.cqcqcq(request.json)
|
server_commands.cqcqcq()
|
||||||
return api_response({"cmd": "cqcqcq"})
|
return api_response({"cmd": "cqcqcq"})
|
||||||
|
|
||||||
@app.route('/modem/beacon', methods=['POST'])
|
@app.route('/modem/beacon', methods=['POST'])
|
||||||
def post_beacon():
|
def post_beacon():
|
||||||
if request.method not in ['POST']:
|
if request.method not in ['POST']:
|
||||||
return api_response({"info": "endpoint for controlling BEACON STATE via POST"})
|
return api_response({"info": "endpoint for controlling BEACON STATE via POST"})
|
||||||
if app.states.is_modem_running:
|
if not app.states.is_modem_running:
|
||||||
server_commands.beacon(request.json)
|
api_abort('Modem not running', 503)
|
||||||
|
server_commands.beacon(request.json['enable_beacon'])
|
||||||
return api_response(request.json)
|
return api_response(request.json)
|
||||||
|
|
||||||
@app.route('/modem/ping_ping', methods=['POST'])
|
@app.route('/modem/ping_ping', methods=['POST'])
|
||||||
def post_ping():
|
def post_ping():
|
||||||
if request.method not in ['POST']:
|
if request.method not in ['POST']:
|
||||||
return api_response({"info": "endpoint for controlling PING via POST"})
|
return api_response({"info": "endpoint for controlling PING via POST"})
|
||||||
if app.states.is_modem_running:
|
if not app.states.is_modem_running:
|
||||||
server_commands.ping_ping(request.json)
|
api_abort('Modem not running', 503)
|
||||||
|
validate(request.json, 'dxcall', validations.validate_freedata_callsign)
|
||||||
|
server_commands.ping_ping(request.json['dxcall'])
|
||||||
return api_response(request.json)
|
return api_response(request.json)
|
||||||
|
|
||||||
@app.route('/modem/send_test_frame', methods=['POST'])
|
@app.route('/modem/send_test_frame', methods=['POST'])
|
||||||
|
|
|
@ -5,28 +5,23 @@ import threading
|
||||||
from random import randrange
|
from random import randrange
|
||||||
log = structlog.get_logger("COMMANDS")
|
log = structlog.get_logger("COMMANDS")
|
||||||
|
|
||||||
def cqcqcq(data):
|
def cqcqcq():
|
||||||
try:
|
try:
|
||||||
DATA_QUEUE_TRANSMIT.put(["CQ"])
|
DATA_QUEUE_TRANSMIT.put(["CQ"])
|
||||||
return
|
return
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log.warning("[CMD] error while transmiting CQ", e=err, command=data)
|
log.warning("[CMD] error while transmiting CQ", e=err)
|
||||||
|
|
||||||
def ping_ping(data):
|
def ping_ping(dxcall):
|
||||||
try:
|
try:
|
||||||
dxcallsign = data["dxcall"]
|
DATA_QUEUE_TRANSMIT.put(["PING", None, dxcall])
|
||||||
if not str(dxcallsign).strip():
|
|
||||||
return
|
|
||||||
DATA_QUEUE_TRANSMIT.put(["PING", None, dxcallsign])
|
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log.warning(
|
log.warning(
|
||||||
"[CMD] PING command execution error", e=err, command=data
|
"[CMD] PING command execution error", e=err
|
||||||
)
|
)
|
||||||
|
|
||||||
def beacon(data, interval=300):
|
def beacon(beacon_state, interval=300):
|
||||||
beacon_state = data['enabled'] in [True]
|
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"[CMD] Changing beacon state", state=beacon_state
|
"[CMD] Changing beacon state", state=beacon_state
|
||||||
)
|
)
|
||||||
|
@ -41,18 +36,12 @@ def modem_send_test_frame():
|
||||||
)
|
)
|
||||||
DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
|
DATA_QUEUE_TRANSMIT.put(["SEND_TEST_FRAME"])
|
||||||
|
|
||||||
def modem_arq_send_raw(data):
|
def modem_arq_send_raw(mycallsign, dxcallsign, payload, arq_uuid = "no-uuid"):
|
||||||
|
|
||||||
# wait some random time
|
# wait some random time
|
||||||
threading.Event().wait(randrange(5, 25, 5) / 10.0)
|
threading.Event().wait(randrange(5, 25, 5) / 10.0)
|
||||||
|
|
||||||
base64data = data["data"]
|
base64data = payload
|
||||||
|
|
||||||
# check if transmission uuid provided else set no-uuid
|
|
||||||
try:
|
|
||||||
arq_uuid = data["uuid"]
|
|
||||||
except Exception:
|
|
||||||
arq_uuid = "no-uuid"
|
|
||||||
|
|
||||||
if len(base64data) % 4:
|
if len(base64data) % 4:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
@ -60,36 +49,26 @@ def modem_arq_send_raw(data):
|
||||||
binarydata = base64.b64decode(base64data)
|
binarydata = base64.b64decode(base64data)
|
||||||
|
|
||||||
DATA_QUEUE_TRANSMIT.put(
|
DATA_QUEUE_TRANSMIT.put(
|
||||||
["ARQ_RAW", binarydata, arq_uuid, data["mycallsign"], data["dxcallsign"]]
|
["ARQ_RAW", binarydata, arq_uuid, mycallsign, dxcallsign]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def modem_fec_transmit(data):
|
def modem_fec_transmit(mode, wakeup, base64data, mycallsign = None):
|
||||||
log.info(
|
log.info(
|
||||||
"[CMD] Send fec frame"
|
"[CMD] Send fec frame"
|
||||||
)
|
)
|
||||||
mode = data["mode"]
|
|
||||||
wakeup = data["wakeup"]
|
|
||||||
base64data = data["payload"]
|
|
||||||
if len(base64data) % 4:
|
if len(base64data) % 4:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
payload = base64.b64decode(base64data)
|
payload = base64.b64decode(base64data)
|
||||||
|
|
||||||
try:
|
|
||||||
mycallsign = data["mycallsign"]
|
|
||||||
except:
|
|
||||||
mycallsign = None
|
|
||||||
|
|
||||||
DATA_QUEUE_TRANSMIT.put(["FEC", mode, wakeup, payload, mycallsign])
|
DATA_QUEUE_TRANSMIT.put(["FEC", mode, wakeup, payload, mycallsign])
|
||||||
|
|
||||||
def modem_fec_is_writing(data):
|
def modem_fec_is_writing(mycallsign):
|
||||||
try:
|
try:
|
||||||
mycallsign = data["mycallsign"]
|
|
||||||
DATA_QUEUE_TRANSMIT.put(["FEC_IS_WRITING", mycallsign])
|
DATA_QUEUE_TRANSMIT.put(["FEC_IS_WRITING", mycallsign])
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log.warning(
|
log.warning(
|
||||||
"[SCK] Send fec frame command execution error",
|
"[SCK] Send fec frame command execution error",
|
||||||
e=err,
|
e=err,
|
||||||
command=data,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,17 @@ def handle_connection(sock, client_list, event_queue):
|
||||||
def transmit_sock_data_worker(client_list, event_queue):
|
def transmit_sock_data_worker(client_list, event_queue):
|
||||||
while True:
|
while True:
|
||||||
event = event_queue.get()
|
event = event_queue.get()
|
||||||
|
|
||||||
|
if isinstance(event, str):
|
||||||
|
print(f"WARNING: Queue event:\n'{event}'\n still in string format")
|
||||||
|
json_event = event
|
||||||
|
else:
|
||||||
|
json_event = json.dumps(event)
|
||||||
|
|
||||||
clients = client_list.copy()
|
clients = client_list.copy()
|
||||||
for client in clients:
|
for client in clients:
|
||||||
try:
|
try:
|
||||||
client.send(event)
|
client.send(json_event)
|
||||||
except Exception:
|
except Exception:
|
||||||
client_list.remove(client)
|
client_list.remove(client)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue