updated command stack

also fixed a problem with receiving data within GUI #129
This commit is contained in:
dj2ls 2022-01-30 14:16:08 +01:00
parent 459e39daea
commit 3835e19c4a
5 changed files with 468 additions and 355 deletions

View file

@ -11,7 +11,7 @@ var configPath = path.join(configFolder, 'config.json')
const config = require(configPath);
var daemon = new net.Socket();
var msg = ''; // Current message, per connection.
var socketchunk = ''; // Current message, per connection.
setTimeout(connectDAEMON, 500)
@ -20,7 +20,7 @@ function connectDAEMON() {
console.log('connecting to DAEMON...')
//clear message buffer after reconnecting or inital connection
msg = '';
socketchunk = '';
if (config.tnclocation == 'localhost') {
daemon.connect(3001, '127.0.0.1')
@ -97,22 +97,58 @@ writeDaemonCommand = function(command) {
// "https://stackoverflow.com/questions/9070700/nodejs-net-createserver-large-amount-of-data-coming-in"
daemon.on('data', function(data) {
daemon.on('data', function(socketdata) {
data = data.toString('utf8'); /* convert data to string */
msg += data.toString('utf8'); /*append data to buffer so we can stick long data together */
/*
inspired by:
stackoverflow.com questions 9070700 nodejs-net-createserver-large-amount-of-data-coming-in
*/
/* check if we reached an EOF, if true, clear buffer and parse JSON data */
if (data.endsWith('}\n')) {
/*console.log(msg)*/
try {
/*console.log(msg)*/
data = JSON.parse(msg)
} catch (e) {
console.log(e); /* "SyntaxError */
socketdata = socketdata.toString('utf8'); // convert data to string
socketchunk += socketdata// append data to buffer so we can stick long data together
// check if we received begin and end of json data
if (socketchunk.startsWith('{"') && socketchunk.endsWith('"}\n')) {
var data = ''
// split data into chunks if we received multiple commands
socketchunk = socketchunk.split("\n");
data = JSON.parse(socketchunk[0])
// search for empty entries in socketchunk and remove them
for (i = 0; i < socketchunk.length; i++) {
if (socketchunk[i] === ''){
socketchunk.splice(i, 1);
}
msg = '';
/*console.log("EOF detected!")*/
}
//iterate through socketchunks array to execute multiple commands in row
for (i = 0; i < socketchunk.length; i++) {
//check if data is not empty
if(socketchunk[i].length > 0){
//try to parse JSON
try {
data = JSON.parse(socketchunk[i])
} catch (e) {
console.log(e); // "SyntaxError
console.log(socketchunk[i])
socketchunk = ''
}
}
if (data['command'] == 'daemon_state') {
let Data = {
@ -138,9 +174,13 @@ daemon.on('data', function(data) {
}
////// check if EOF ...
}
//finally delete message buffer
socketchunk = '';
}
});
function hexToBytes(hex) {

View file

@ -988,6 +988,7 @@ ipcRenderer.on('action-update-tnc-state', (event, arg) => {
toast.show()
}
// ARQ RECEIVING SUCCESS TOAST
console.log(arg.info[i])
if (arg.info[i] == "ARQ;RECEIVING;SUCCESS"){
document.getElementById("transmission_progress").className = "progress-bar progress-bar-striped bg-success";
@ -1294,6 +1295,7 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
var tbl = document.getElementById("rx-data");
document.getElementById("rx-data").innerHTML = ''
for (i = 0; i < arg.data.length; i++) {
// first we update the PING window
@ -1308,6 +1310,8 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
}
// now we update the received files list
var row = document.createElement("tr");
@ -1338,9 +1342,10 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
dxGrid.appendChild(dxGridText);
*/
console.log(arg.data)
var fileName = document.createElement("td");
var fileNameText = document.createElement('span');
var fileNameString = arg.data[i]['rxdata'][0]['fn']
var fileNameString = arg.data[i]['data'][0]['fn']
fileNameText.innerText = fileNameString
fileName.appendChild(fileNameText);
@ -1349,7 +1354,6 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
row.appendChild(dxCall);
// row.appendChild(dxGrid);
row.appendChild(fileName);
tbl.appendChild(row);
// https://stackoverflow.com/a/26227660
@ -1368,8 +1372,8 @@ ipcRenderer.on('action-update-rx-buffer', (event, arg) => {
});
// write file to rxdata folder
var base64String = arg.data[i]['rxdata'][0]['d']
// write file to data folder
var base64String = arg.data[i]['data'][0]['d']
// remove header from base64 String
// https://www.codeblocq.com/2016/04/Convert-a-base64-string-to-a-file-in-Node/
var base64Data = base64String.split(';base64,').pop()

View file

@ -11,7 +11,7 @@ var configPath = path.join(configFolder, 'config.json')
const config = require(configPath);
var client = new net.Socket();
var msg = ''; // Current message, per connection.
var socketchunk = ''; // Current message, per connection.
// globals for getting new data only if available so we are saving bandwith
var rxBufferLengthTnc = 0
@ -27,7 +27,7 @@ function connectTNC() {
//console.log('connecting to TNC...')
//clear message buffer after reconnecting or inital connection
msg = '';
socketchunk = '';
if (config.tnclocation == 'localhost') {
client.connect(3000, '127.0.0.1')
@ -99,27 +99,55 @@ writeTncCommand = function(command) {
}
}
client.on('data', function(data) {
client.on('data', function(socketdata) {
/*
inspired by:
stackoverflow.com questions 9070700 nodejs-net-createserver-large-amount-of-data-coming-in
*/
data = data.toString('utf8'); // convert data to string
msg += data.toString('utf8'); // append data to buffer so we can stick long data together
//console.log(data)
// check if we reached an EOF, if true, clear buffer and parse JSON data
if (data.endsWith('"EOF":"EOF"}\n') || data.endsWith('"}\n')) {
//console.log(msg)
try {
//console.log(msg)
data = JSON.parse(msg)
} catch (e) {
console.log(e); /* "SyntaxError*/
}
msg = '';
/* console.log("EOF detected!") */
socketdata = socketdata.toString('utf8'); // convert data to string
socketchunk += socketdata// append data to buffer so we can stick long data together
// check if we received begin and end of json data
if (socketchunk.startsWith('{"') && socketchunk.endsWith('"}\n')) {
var data = ''
// split data into chunks if we received multiple commands
socketchunk = socketchunk.split("\n");
data = JSON.parse(socketchunk[0])
// search for empty entries in socketchunk and remove them
for (i = 0; i < socketchunk.length; i++) {
if (socketchunk[i] === ''){
socketchunk.splice(i, 1);
}
}
//iterate through socketchunks array to execute multiple commands in row
for (i = 0; i < socketchunk.length; i++) {
//check if data is not empty
if(socketchunk[i].length > 0){
//try to parse JSON
try {
data = JSON.parse(socketchunk[i])
} catch (e) {
console.log(e); // "SyntaxError
console.log(socketchunk[i])
socketchunk = ''
}
}
if (data['command'] == 'tnc_state') {
@ -157,46 +185,26 @@ client.on('data', function(data) {
stations: data['stations'],
beacon_state: data['beacon_state'],
};
//console.log(Data)
ipcRenderer.send('request-update-tnc-state', Data);
}
/* A TEST WITH THE NEW STREAMING DATA .... */
/* A TEST WITH STREAMING DATA .... */
if (data['arq'] == 'received') {
rxBufferLengthGui = data['data'].length
console.log(data['uuid'])
console.log(data['type'])
let Data = {
data: data['data'],
};
alert(data['data'])
ipcRenderer.send('request-update-rx-buffer', Data);
}
if (data['command'] == 'rx_buffer') {
console.log(data['data-array'])
// iterate through buffer list and sort it to file or message array
dataArray = []
messageArray = []
for (i = 0; i < data['data-array'].length; i++) {
if(data['data-array'][i]['rxdata'][0]['dt'] == 'f'){
dataArray.push(data['data-array'][i])
if(data['data'][0]['dt'] == 'f'){
dataArray.push(data)
}
if(data['data-array'][i]['rxdata'][0]['dt'] == 'm'){
messageArray.push(data['data-array'][i])
if(data['data'][0]['dt'] == 'm'){
messageArray.push(data)
}
}
rxBufferLengthGui = dataArray.length
let Files = {
@ -208,14 +216,56 @@ client.on('data', function(data) {
let Messages = {
data: messageArray,
};
ipcRenderer.send('request-update-rx-msg-buffer', Messages);
}
if (data['command'] == 'rx_buffer') {
// iterate through buffer list and sort it to file or message array
dataArray = []
messageArray = []
for (i = 0; i < data['data-array'].length; i++) {
try{
if(data['data-array'][i]['data'][0]['dt'] == 'f'){
dataArray.push(data['data-array'][i])
}
if(data['data-array'][i]['data'][0]['dt'] == 'm'){
messageArray.push(data['data-array'][i])
}
} catch (e) {
console.log(e)
}
}
console.log(dataArray)
rxBufferLengthGui = dataArray.length
let Files = {
data: dataArray,
};
ipcRenderer.send('request-update-rx-buffer', Files);
rxMsgBufferLengthGui = messageArray.length
let Messages = {
data: messageArray,
};
ipcRenderer.send('request-update-rx-msg-buffer', Messages);
}
}
//finally delete message buffer
socketchunk = '';
}
});
function hexToBytes(hex) {
@ -237,11 +287,6 @@ exports.getDataState = function() {
//writeTncCommand(command)
}
//Get Heard Stations
//exports.getHeardStations = function() {
// command = '{"type" : "GET", "command" : "HEARD_STATIONS", "timestamp" : ' + Date.now() + '}';
// writeTncCommand(command)
//}
// Send Ping
exports.sendPing = function(dxcallsign) {

View file

@ -386,7 +386,7 @@ class DATA():
# check if data_frame_crc is equal with received crc
if data_frame_crc == data_frame_crc_received:
structlog.get_logger("structlog").info("[TNC] ARQ | RX | DATA FRAME SUCESSFULLY RECEIVED")
static.INFO.append("ARQ;RECEIVING;SUCCESS")
# decompression
data_frame_decompressed = zlib.decompress(data_frame)
@ -418,25 +418,8 @@ class DATA():
jsondata = {"arq":"received", "uuid" : static.RX_BUFFER[i][0], "timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": [rawdata]}
data_out = json.dumps(jsondata)
sock.SOCKET_QUEUE.put(data_out)
static.INFO.append("ARQ;RECEIVING;SUCCESS")
'''
if rawdata["dt"] == "f" or rawdata["dt"] == "m":
#structlog.get_logger("structlog").debug("RECEIVED FILE --> MOVING DATA TO RX BUFFER")
static.RX_BUFFER.append([uuid4(), datatype ,static.DXCALLSIGN,static.DXGRID,int(time.time()), data_frame])
jsondata = {"arq":"received", "uuid" : static.RX_BUFFER[i][0], "type" : static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "timestamp": static.RX_BUFFER[i][4], "data": [rawdata]}
data_out = json.dumps(jsondata)
sock.SOCKET_QUEUE.put(data_out)
# if datatype is a file, we append to RX_MSG_BUFFER, which contains messages only
#elif rawdata["dt"] == "m":
# static.RX_MSG_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), data_frame])
# here we should have our raw data
else:
static.RX_BUFFER.append([static.DXCALLSIGN,static.DXGRID,int(time.time()), data_frame])
jsondata = {"arq":"raw", "dxcallsign": str(static.RX_BUFFER[i][0], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][1], 'utf-8'), "timestamp": static.RX_BUFFER[i][2], "data": [rawdata]}
data_out = json.dumps(jsondata)
sock.SOCKET_QUEUE.put(data_out)
'''
# BUILDING ACK FRAME FOR DATA FRAME
ack_frame = bytearray(14)
ack_frame[:1] = bytes([61])

View file

@ -67,12 +67,15 @@ class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
sock_data = bytes(data, 'utf-8')
sock_data += b'\n' # append line limiter
# send data to all clients
try:
for client in CONNECTED_CLIENTS:
try:
client.send(sock_data)
except:
print("connection lost...")
CONNECTED_CLIENTS.remove(self.request)
except:
print("client not anymore in client list")
# we want to transmit scatter data only once to reduce network traffic
static.SCATTER = []
@ -135,31 +138,39 @@ def process_tnc_commands(data):
received_json = json.loads(data)
# CQ CQ CQ -----------------------------------------------------
if received_json["command"] == "cqcqcq":
try:
data_handler.DATA_QUEUE_TRANSMIT.put(['CQ'])
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# START_BEACON -----------------------------------------------------
if received_json["command"] == "start_beacon":
try:
static.BEACON_STATE = True
interval = int(received_json["parameter"])
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', interval, True])
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# STOP_BEACON -----------------------------------------------------
if received_json["command"] == "stop_beacon":
try:
static.BEACON_STATE = False
structlog.get_logger("structlog").warning("[TNC] Stopping beacon!")
data_handler.DATA_QUEUE_TRANSMIT.put(['BEACON', None, False])
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# PING ----------------------------------------------------------
if received_json["type"] == 'ping' and received_json["command"] == "ping":
# send ping frame and wait for ACK
try:
dxcallsign = received_json["dxcallsign"]
data_handler.DATA_QUEUE_TRANSMIT.put(['PING', dxcallsign])
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# TRANSMIT RAW DATA -------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "send_raw":
try:
dxcallsign = received_json["parameter"][0]["dxcallsign"]
mode = int(received_json["parameter"][0]["mode"])
n_frames = int(received_json["parameter"][0]["n_frames"])
@ -172,9 +183,11 @@ def process_tnc_commands(data):
data_out = bytes(dataframe, 'utf-8')
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_RAW', data_out, mode, n_frames])
print(data_handler.DATA_QUEUE_TRANSMIT.qsize())
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# TRANSMIT FILE ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "send_file":
try:
static.TNC_STATE = 'BUSY'
# on a new transmission we reset the timer
@ -204,8 +217,11 @@ def process_tnc_commands(data):
data_out = bytes(dataframe, 'utf-8')
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_FILE', data_out, mode, n_frames])
print(data_handler.DATA_QUEUE_TRANSMIT.qsize())
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# TRANSMIT MESSAGE ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "send_message":
try:
static.TNC_STATE = 'BUSY'
print(received_json)
# on a new transmission we reset the timer
@ -233,37 +249,45 @@ def process_tnc_commands(data):
data_out = bytes(dataframe, 'utf-8')
data_handler.DATA_QUEUE_TRANSMIT.put(['ARQ_MESSAGE', data_out, mode, n_frames])
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
# STOP TRANSMISSION ----------------------------------------------------------
if received_json["type"] == 'arq' and received_json["command"] == "stop_transmission":
try:
if static.TNC_STATE == 'BUSY' or static.ARQ_STATE:
data_handler.DATA_QUEUE_TRANSMIT.put(['STOP'])
structlog.get_logger("structlog").warning("[TNC] Stopping transmission!")
static.TNC_STATE = 'IDLE'
static.ARQ_STATE = False
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'get' and received_json["command"] == 'rx_buffer':
try:
output = {
"command": "rx_buffer",
"data-array": [],
"EOF": "EOF",
}
for i in range(0, len(static.RX_BUFFER)):
rawdata = json.loads(static.RX_BUFFER[i][4])
output["data-array"].append({"uuid": static.RX_BUFFER[i][0],"timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "rxdata": [rawdata]})
output["data-array"].append({"uuid": static.RX_BUFFER[i][0],"timestamp": static.RX_BUFFER[i][1], "dxcallsign": str(static.RX_BUFFER[i][2], 'utf-8'), "dxgrid": str(static.RX_BUFFER[i][3], 'utf-8'), "data": [rawdata]})
jsondata = json.dumps(output)
#self.request.sendall(bytes(jsondata, encoding))
print(jsondata)
SOCKET_QUEUE.put(jsondata)
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
'''
if received_json["type"] == 'GET' and received_json["command"] == 'rx_msg_buffer':
output = {
"command": "rx_msg_buffer",
"data-array": [],
"EOF": "EOF",
}
for i in range(0, len(static.RX_MSG_BUFFER)):
@ -275,7 +299,10 @@ def process_tnc_commands(data):
SOCKET_QUEUE.put(jsondata)
'''
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_buffer':
try:
static.RX_BUFFER = []
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
'''
if received_json["type"] == 'set' and received_json["command"] == 'del_rx_msg_buffer':
@ -283,9 +310,10 @@ def process_tnc_commands(data):
'''
# exception, if JSON cant be decoded
except Exception as e:
structlog.get_logger("structlog").error("[TNC] Network error", e=e)
structlog.get_logger("structlog").error("[TNC] JSON decoding error", e=e)
def send_tnc_state():
encoding = 'utf-8'
output = {
@ -313,7 +341,6 @@ def send_tnc_state():
"mycallsign": str(static.MYCALLSIGN, encoding),
"dxcallsign": str(static.DXCALLSIGN, encoding),
"dxgrid": str(static.DXGRID, encoding),
"EOF": "EOF",
}
# add heard stations to heard stations object
@ -329,6 +356,7 @@ def process_daemon_commands(data):
received_json = json.loads(data)
if received_json["type"] == 'set' and received_json["command"] == 'mycallsign':
try:
callsign = received_json["parameter"]
print(received_json)
if bytes(callsign, 'utf-8') == b'':
@ -339,18 +367,26 @@ def process_daemon_commands(data):
static.MYCALLSIGN_CRC = helpers.get_crc_16(static.MYCALLSIGN)
structlog.get_logger("structlog").info("[DMN] SET MYCALL", call=static.MYCALLSIGN, crc=static.MYCALLSIGN_CRC)
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'mygrid':
try:
mygrid = received_json["parameter"]
if bytes(mygrid, 'utf-8') == b'':
self.request.sendall(b'INVALID GRID')
else:
static.MYGRID = bytes(mygrid, 'utf-8')
structlog.get_logger("structlog").info("[DMN] SET MYGRID", grid=static.MYGRID)
structlog.get_logger("structlog").info("[SCK] SET MYGRID", grid=static.MYGRID)
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'start_tnc' and not static.TNCSTARTED:
try:
mycall = str(received_json["parameter"][0]["mycall"])
mygrid = str(received_json["parameter"][0]["mygrid"])
rx_audio = str(received_json["parameter"][0]["rx_audio"])
@ -383,11 +419,12 @@ def process_daemon_commands(data):
rigctld_ip, \
rigctld_port \
])
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'get' and received_json["command"] == 'test_hamlib':
try:
devicename = str(received_json["parameter"][0]["devicename"])
deviceport = str(received_json["parameter"][0]["deviceport"])
serialspeed = str(received_json["parameter"][0]["serialspeed"])
@ -412,12 +449,16 @@ def process_daemon_commands(data):
rigctld_ip, \
rigctld_port \
])
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
if received_json["type"] == 'set' and received_json["command"] == 'stop_tnc':
try:
static.TNCPROCESS.kill()
structlog.get_logger("structlog").warning("[DMN] Stopping TNC")
static.TNCSTARTED = False
except Exception as e:
structlog.get_logger("structlog").warning("[SCK] command execution error", e=e, command=received_json)
def send_daemon_state():