FreeDATA/gui/src/js/chatHandler.ts
2024-01-17 18:49:14 +00:00

1111 lines
28 KiB
TypeScript

const path = require("path");
const { v4: uuidv4 } = require("uuid");
// pinia store setup
import { setActivePinia } from "pinia";
import pinia from "../store/index";
setActivePinia(pinia);
import { useChatStore } from "../store/chatStore.js";
const chat = useChatStore(pinia);
import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia);
import { settingsStore as settings } from "../store/settingsStore.js";
import { getAppDataPath } from "../js/freedata";
import { displayToast } from "./popupHandler.js";
//const FD = require("./src/js/freedata.js");
import {
atob_FD,
btoa_FD,
sortByProperty,
sortByPropertyDesc,
} from "./freedata.js";
import { sendModemARQRaw } from "../js/api.js";
const split_char = "0;1;";
// define default message object
interface Attachment {
content_type: string;
data: string;
}
interface messageDefaultObject {
command: string;
hmac_signed: boolean;
percent: number;
bytesperminute: number;
is_new: boolean;
_id: string;
timestamp: number;
dxcallsign: string;
dxgrid: string;
msg: string;
checksum: string;
type: string;
status: string;
attempt: number;
uuid: string;
duration: number;
nacks: number;
speed_list: string;
broadcast_sender?: string; // optional for broadcasts
_attachments: {
[filename: string]: Attachment;
};
}
interface beaconDefaultObject {
command: string;
is_new: boolean;
_id: string;
timestamp: number;
dxcallsign: string;
dxgrid: string;
type: string;
status: string;
uuid: string;
snr: string;
}
interface newChatDefaultObject {
command: string;
is_new: boolean;
timestamp: number;
dxcallsign: string;
}
// ---- MessageDB
try {
var PouchDB = require("pouchdb");
} catch (err) {
console.log(err);
/*
This is a fix for raspberryPi where we get an error when loading pouchdb because of
leveldown package isnt running on ARM devices.
pouchdb-browser does not depend on leveldb and seems to be working.
*/
console.log("using pouchdb-browser fallback");
var PouchDB = require("pouchdb-browser");
}
PouchDB.plugin(require("pouchdb-find"));
//PouchDB.plugin(require('pouchdb-replication'));
PouchDB.plugin(require("pouchdb-upsert"));
var appDataPath = getAppDataPath();
var configFolder = path.join(appDataPath, "FreeDATA");
var chatDB = path.join(configFolder, "chatDB");
console.log("database path:" + chatDB);
var db = new PouchDB(chatDB);
/* -------- CREATE DATABASE INDEXES */
//These aren't needed anylonger aslong as we await createIndex() where necessary
//createChatIndex();
/* -------- RUN A DATABASE CLEANUP ON STARTUP */
//dbClean()
updateAllChat(true);
// create callsign set for storing unique callsigns
chat.callsign_list = new Set();
// function for creating a new broadcast
export function newBroadcast(broadcastChannel, chatmessage) {
var file = "";
var filetype = "text";
var filename = "";
var file_checksum = ""; //crc32(file).toString(16).toUpperCase();
var message_type = "broadcast_transmit";
var timestamp = Math.floor(Date.now() / 1000);
var uuid = uuidv4();
// TODO: Not sure what this uuid part is needed for ...
let uuidlast = uuid.lastIndexOf("-");
uuidlast += 1;
if (uuidlast > 0) {
uuid = uuid.substring(uuidlast);
}
// slice uuid for reducing overhead
uuid = uuid.slice(-4);
let newChatObj: messageDefaultObject = {
command: "broadcast",
hmac_signed: false,
percent: 0,
bytesperminute: 0, // You need to assign a value here
is_new: false,
_id: uuid,
timestamp: timestamp,
dxcallsign: broadcastChannel,
dxgrid: "null",
msg: chatmessage,
checksum: file_checksum,
type: message_type,
status: "transmitting",
attempt: 1,
uuid: uuid,
duration: 0,
nacks: 0,
speed_list: "null",
_attachments: {
[filename]: {
content_type: filetype,
data: btoa_FD(file),
},
},
};
//sendMessage(newChatObj)
//sendBroadcastChannel(newChatObj);
addObjToDatabase(newChatObj);
}
// function for creating a new message
export function newMessage(
dxcallsign,
chatmessage,
chatFile,
chatFileName,
chatFileSize,
chatFileType,
) {
var filename = "";
var filetype = "";
var file = "";
if (typeof chatFile !== "undefined") {
file = chatFile;
filetype = chatFileType;
filename = chatFileName;
} else {
file = "";
filetype = "";
filename = "";
}
console.log(file);
console.log(filetype);
console.log(filename);
var file_checksum = ""; //crc32(file).toString(16).toUpperCase();
var message_type = "transmit";
var command = "msg";
var timestamp = Math.floor(Date.now() / 1000);
var uuid = uuidv4();
// TODO: Not sure what this uuid part is needed for ...
let uuidlast = uuid.lastIndexOf("-");
uuidlast += 1;
if (uuidlast > 0) {
uuid = uuid.substring(uuidlast);
}
// slice uuid for reducing overhead
uuid = uuid.slice(-8);
let newChatObj: messageDefaultObject = {
command: command,
hmac_signed: false,
percent: 0,
bytesperminute: 0, // You need to assign a value here
is_new: false,
_id: uuid,
timestamp: timestamp,
dxcallsign: dxcallsign,
dxgrid: "null",
msg: chatmessage,
checksum: file_checksum,
type: message_type,
status: "transmitting",
attempt: 1,
uuid: uuid,
duration: 0,
nacks: 0,
speed_list: "null",
_attachments: {
[filename]: {
content_type: filetype,
data: btoa_FD(file),
},
},
};
sendMessage(newChatObj);
addObjToDatabase(newChatObj);
}
// function for creating a list, accessible by callsign
function sortChatList() {
// Create an empty object to store the reordered data dynamically
var reorderedData = {};
var jsonObjects = chat.unsorted_chat_list;
// Iterate through the list of JSON objects and reorder them dynamically
jsonObjects.forEach((obj) => {
var dxcallsign = obj.dxcallsign;
if (dxcallsign) {
if (!reorderedData[dxcallsign]) {
reorderedData[dxcallsign] = [];
}
reorderedData[dxcallsign].push(obj);
reorderedData[dxcallsign] = reorderedData[dxcallsign].sort(
sortByProperty("timestamp"),
);
}
});
//console.log(reorderedData["2LS-0"])
return reorderedData;
}
export function getMessageAttachment(id) {
return new Promise(async (resolve, reject) => {
try {
const findResult = await db.find({
selector: {
_id: id,
},
});
const getResult = await db.get(findResult.docs[0]._id, {
attachments: true,
});
let obj = getResult;
let filename = Object.keys(obj._attachments)[0];
let filetype = obj._attachments[filename].content_type;
let file = obj._attachments[filename].data;
resolve([filename, filetype, file]);
} catch (err) {
console.log(err);
reject(false); // Reject the Promise if there's an error
}
});
}
//repeat a message
export function repeatMessageTransmission(id) {
// 1. get message object by ID
// 2. Upsert Attempts
// 3. send message
db.find({
selector: {
_id: id,
},
})
.then(function (result) {
console.log(result);
let obj = result.docs[0];
console.log(obj);
obj.attempt += 1;
databaseUpsert(obj.uuid, "attempt", obj.attempt);
updateUnsortedChatListEntry(obj.uuid, "attempt", obj.attempt);
sendMessage(obj);
})
.catch(function (err) {
console.log(err);
});
}
// delete a message from databse and gui
export function deleteMessageFromDB(id) {
console.log("deleting: " + id);
db.get(id).then(function (doc) {
db.remove(doc);
});
// overwrote unsorted chat list by filtering if not ID
chat.unsorted_chat_list = chat.unsorted_chat_list.filter(
(entry) => entry.uuid !== id,
);
// and finally generate our sorted chat list, which is the key store for chat gui rendering
// the removed entry should be removed now from gui
chat.sorted_chat_list = sortChatList();
}
//Function to clean old beacons and optimize database
async function dbClean() {
//Only keep the most x latest days of beacons
let beaconKeep = 4;
let itemCount = 0;
let timestampPurge = Math.floor(
(Date.now() - beaconKeep * 24 * 60 * 60 * 1000) / 1000,
);
//Items to purge from database
var purgeFilter = [
{ type: "beacon" },
{ type: "ping-ack" },
{ type: "ping" },
{ type: "request" },
{ type: "response" },
];
await db
.find({
selector: {
$and: [{ timestamp: { $lt: timestampPurge } }, { $or: purgeFilter }],
},
})
.then(async function (result) {
//console.log("Purging " + result.docs.length + " beacons received before " + timestampPurge);
itemCount = result.docs.length;
result.docs.forEach(async function (item) {
await deleteMessageFromDB(item._id);
});
})
.catch(function (err) {
console.log(err);
});
//Compact database
//Too slow on older/slower machines
//await db.compact();
let message = "Database maintenance is complete, ";
//displayToast("info", "bi bi-info-circle", message, 5000);
message += "removed " + itemCount + " items from database";
console.log(message);
}
// function to update transmission status
export function updateTransmissionStatus(obj) {
// update database entries
databaseUpsert(obj.uuid, "percent", obj.percent);
databaseUpsert(obj.uuid, "bytesperminute", obj.bytesperminute);
databaseUpsert(obj.uuid, "status", obj.status);
// update screen rendering / messages
updateUnsortedChatListEntry(obj.uuid, "percent", obj.percent);
updateUnsortedChatListEntry(obj.uuid, "bytesperminute", obj.bytesperminute);
updateUnsortedChatListEntry(obj.uuid, "status", obj.status);
}
export function updateUnsortedChatListEntry(uuid, object, value) {
var data = getFromUnsortedChatListByUUID(uuid);
if (data) {
data[object] = value;
//console.log("Entry updated:", data[object]);
chat.sorted_chat_list = sortChatList();
return data;
}
/*
for (const entry of chat.unsorted_chat_list) {
if (entry.uuid === uuid) {
entry[object] = value;
console.log("Entry updated:", entry[object]);
chat.sorted_chat_list = sortChatList();
return entry;
}
}
*/
//console.log("Entry not updated:", object);
return null; // Return null if not found
}
function getFromUnsortedChatListByUUID(uuid) {
for (const entry of chat.unsorted_chat_list) {
if (entry.uuid === uuid) {
return entry;
}
}
return false;
}
export function getNewMessagesByDXCallsign(dxcallsign): [number, number, any] {
let new_counter = 0;
let total_counter = 0;
let item_array = [];
try {
if (
typeof dxcallsign !== "undefined" &&
typeof chat.sorted_chat_list[dxcallsign] !== "undefined"
) {
for (const key in chat.sorted_chat_list[dxcallsign]) {
//console.log(chat.sorted_chat_list[dxcallsign][key])
//item_array.push(chat.sorted_chat_list[dxcallsign][key])
if (chat.sorted_chat_list[dxcallsign][key].is_new) {
item_array.push(chat.sorted_chat_list[dxcallsign][key]);
new_counter += 1;
}
total_counter += 1;
}
}
return [total_counter, new_counter, item_array];
} catch (e) {
console.log(e);
return [0, 0, item_array];
}
}
export function resetIsNewMessage(uuid, value) {
databaseUpsert(uuid, "is_new", value);
updateUnsortedChatListEntry(uuid, "is_new", value);
}
export function databaseUpsert(id, object, value) {
db.upsert(id, function (doc) {
if (!doc[object]) {
doc[object] = value;
}
doc[object] = value;
return doc;
})
.then(function (res) {
// success, res is {rev: '1-xxx', updated: true, id: 'myDocId'}
//console.log(res);
})
.catch(function (err) {
// error
console.log(err);
});
}
// function for fetching all messages from chat / updating chat
export async function updateAllChat(cleanup) {
// run cleanup if requested
if (cleanup) {
await dbClean();
}
let indexFields = [{ dxcallsign: "asc" }, { timestamp: "asc" }];
let filter = {
selector: {
$and: [
{ dxcallsign: { $exists: true } },
{ timestamp: { $exists: true } },
//{ $or: chat.chat_filter },
],
},
sort: [{ dxcallsign: "asc" }, { timestamp: "asc" }],
};
//"{ dxcallsign: \"asc\" }, { timestamp: \"asc\" }"
await createIndex(indexFields);
getFromDBByFilter(filter)
.then(function (result) {
for (var item of (result as any).docs) {
const dxcallsign = item.dxcallsign;
// Check if dxcallsign already exists as a property in the result object
if (!chat.sorted_beacon_list[dxcallsign]) {
// If not, initialize it with an empty array for snr values
chat.sorted_beacon_list[dxcallsign] = {
dxcallsign,
snr: [],
timestamp: [],
};
chat.callsign_list.add(dxcallsign);
}
if (item.type === "beacon") {
//console.log(item);
// TODO: sort beacon list .... maybe a part for a separate function
const jsonData = [item];
// Process each JSON item step by step
jsonData.forEach((jsonitem) => {
const { snr, timestamp } = item;
// Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr);
chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp);
});
} else {
chat.unsorted_chat_list.push(item);
chat.sorted_chat_list = sortChatList();
// check if message is expired
let timeNow = Math.floor(Date.now() / 1000);
let expireTimestamp = timeNow - 10 * 60;
let isExpired = false;
if (expireTimestamp >= item.timestamp) {
isExpired = true;
}
if (item.status == "transmitting" && isExpired) {
console.log("message expired - resetting status");
console.log(item);
databaseUpsert(item.uuid, "status", "failed");
updateUnsortedChatListEntry(item.uuid, "status", "failed");
databaseUpsert(item.uuid, "percent", 0);
updateUnsortedChatListEntry(item.uuid, "percent", 0);
}
// lets update the message if it is failed. Then its always 0 percent
if (item.status == "failed") {
databaseUpsert(item.uuid, "percent", 0);
updateUnsortedChatListEntry(item.uuid, "percent", 0);
databaseUpsert(item.uuid, "bytesperminute", 0);
updateUnsortedChatListEntry(item.uuid, "bytesperminute", 0);
}
}
}
})
.catch(function (err) {
console.log(err);
});
}
function addObjToDatabase(newobj) {
console.log(newobj);
/*
db.upsert(newobj._id, function (doc) {
if (!doc._id) {
console.log("upsert")
console.log(doc)
doc = newobj
} else {
console.log("new...")
*/
db.post(newobj)
.then(function (response) {
// handle response
console.log("new database entry");
console.log(response);
if (newobj.command === "msg" || newobj.command === "newchat") {
chat.unsorted_chat_list.push(newobj);
chat.sorted_chat_list = sortChatList();
}
})
.catch(function (err) {
console.log(err);
console.log(newobj);
// try upserting status in case we tried sending a message to our selfes
databaseUpsert(newobj.uuid, "status", newobj.status);
updateUnsortedChatListEntry(newobj.uuid, "status", newobj.status);
});
/*
// upsert footer ...
}
return doc;
})
*/
}
/*
function createChatIndex() {
db.createIndex({
index: {
fields: [
"timestamp",
"uuid",
"dxcallsign",
"dxgrid",
"msg",
"checksum",
"type",
"command",
"status",
"percent",
"attempt",
"hmac_signed",
"bytesperminute",
"_attachments",
"is_new",
"nacks",
"duration",
"speed_list",
],
},
})
.then(function (result) {
// handle result
console.log(result);
})
.catch(function (err) {
console.log(err);
});
}
*/
export function deleteChatByCallsign(callsign) {
chat.callsign_list.delete(callsign);
// @ts-expect-error
delete chat.unsorted_chat_list.callsign;
delete chat.sorted_chat_list.callsign;
deleteFromDatabaseByCallsign(callsign);
}
function deleteFromDatabaseByCallsign(callsign) {
db.find({
selector: {
dxcallsign: callsign,
},
})
.then(function (result) {
// handle result
if (typeof result !== "undefined") {
result.docs.forEach(function (item) {
console.log(item);
db.get(item._id)
.then(function (doc) {
db.remove(doc)
.then(function () {
//updateAllChat(false);
return true;
})
.catch(function (err) {
console.log(err);
});
})
.catch(function (err) {
console.log(err);
});
});
}
})
.catch(function (err) {
console.log(err);
});
}
//Function creates a new 'newchat' database entry when user initates a new chat, otherwise cannot send messages unless receiving a message/beacon from user first
/**
* Add a newuser to the database, for when newuser button is clicked
* @param {string} call callsign of new user
*/
export function startChatWithNewStation(call) {
let newchat: newChatDefaultObject = {
command: "newchat",
is_new: false,
timestamp: Math.floor(new Date().getTime() / 1000),
dxcallsign: call,
};
addObjToDatabase(newchat);
if (!chat.sorted_beacon_list[call]) {
// If not, initialize it with an empty array for snr values
chat.sorted_beacon_list[call] = {
call,
snr: [],
timestamp: [],
};
chat.callsign_list.add(call);
}
//chat.unsorted_chat_list.push(newchat);
//chat.sorted_chat_list = sortChatList();
}
// function for handling a received beacon
export function newBeaconReceived(obj) {
/*
{
"freedata": "modem-message",
"beacon": "received",
"uuid": "12741312-3dbb-4a53-b0cc-100f6c930ab8",
"timestamp": 1696076869,
"dxcallsign": "DJ2LS-0",
"dxgrid": "JN48CS",
"snr": "-2.8",
"mycallsign": "DJ2LS-0"
}
*/
let newChatObj: beaconDefaultObject = {
command: "beacon",
is_new: false,
_id: obj["uuid"],
timestamp: obj["timestamp"],
dxcallsign: obj["dxcallsign"],
dxgrid: obj["dxgrid"],
type: "beacon",
status: obj["beacon"],
uuid: obj["uuid"],
snr: obj["snr"], // adding the new field
};
addObjToDatabase(newChatObj);
console.log(obj);
const jsonData = [obj];
const dxcallsign = obj.dxcallsign;
// Process each JSON item step by step
jsonData.forEach((item) => {
const { snr, timestamp } = obj;
// Check if dxcallsign already exists as a property in the result object
if (!chat.sorted_beacon_list[dxcallsign]) {
// If not, initialize it with an empty array for snr values
chat.sorted_beacon_list[dxcallsign] = {
dxcallsign,
snr: [],
timestamp: [],
};
}
// Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr);
chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp);
});
// check if auto retry enabled
//console.log("-----------------------------------------");
//console.log(settings.enable_auto_retry.toUpperCase());
//if (settings.enable_auto_retry.toUpperCase() == "TRUE") {
// checkForWaitingMessages(dxcallsign);
//}
}
// function for handling a received message
export function newMessageReceived(message, protocol) {
/*
PROTOCOL
{
"freedata": "modem-message",
"arq": "transmission",
"status": "received",
"uuid": "5a3caa57-7feb-4436-853d-e341b085350f",
"percent": 100,
"bytesperminute": 206,
"compression": 0.5833333333333334,
"timestamp": 1697048385,
"finished": 0,
"mycallsign": "DJ2LS-0",
"dxcallsign": "DJ2LS-0",
"dxgrid": "------",
"data": "bTA7MTttc2cwOzE7MDsxOzBlNGE3YjQ2MDsxOzE2OTcwNDgzMTkwOzE7dGVzdDMwOzE7MDsxO3RleHQwOzE7",
"irs": "False",
"hmac_signed": "False",
"duration": 44.385897636413574,
"nacks": 1,
"speed_list": [
{
"snr": 0,
"bpm": 106,
"timestamp": 1697048362
},
{
"snr": -6,
"bpm": 104,
"timestamp": 1697048370
},
{
"snr": -6,
"bpm": 81,
"timestamp": 1697048370
},
{
"snr": -5.7,
"bpm": 161,
"timestamp": 1697048378
},
{
"snr": -5.7,
"bpm": 133,
"timestamp": 1697048379
},
{
"snr": -5.4,
"bpm": 206,
"timestamp": 1697048385
},
{
"snr": -5.8,
"bpm": 179,
"timestamp": 1697048391
}
]
}
MESSAGE; decoded from "data"
[
0 - protocol type message - "m",
1 - type - "msg",
2 - checksum "",
3 - uuid - "07e2",
4 - timestamp - "1695203833",
5 - message - "test",
6 - file name - "",
7 - mime - "plain/text",
8 - file - ""
]
*/
console.log(protocol);
var encoded_data = atob_FD(message);
var splitted_data = encoded_data.split(split_char);
// new message received
if (splitted_data[0] == "m") {
console.log(splitted_data);
message = splitted_data;
} else {
return;
}
let newChatObj: messageDefaultObject = {
command: "msg",
hmac_signed: false,
percent: 100,
bytesperminute: 0,
is_new: true,
_id: message[3],
timestamp: message[4],
dxcallsign: protocol["dxcall"],
dxgrid: "",
msg: message[5],
checksum: message[2],
type: "received",
status: "received",
attempt: 1,
uuid: message[3],
duration: 0,
nacks: 0,
speed_list: "[]",
_attachments: {
[message[6]]: {
content_type: message[7],
data: btoa_FD(message[8]),
},
},
};
// some tweaks for broadcasts
if (protocol.fec == "broadcast") {
newChatObj.broadcast_sender = protocol["dxcallsign"];
newChatObj.type = "broadcast_received";
}
addObjToDatabase(newChatObj);
}
export function setStateFailed() {
state.arq_seconds_until_finish = 0;
state.arq_seconds_until_timeout = 180;
state.arq_seconds_until_timeout_percent = 100;
}
export function setStateSuccess() {
state.arq_seconds_until_finish = 0;
state.arq_seconds_until_timeout = 180;
state.arq_seconds_until_timeout_percent = 100;
}
export function requestMessageInfo(id) {
console.log(id);
chat.arq_speed_list_bpm = [];
chat.arq_speed_list_timestamp = [];
chat.arq_speed_list_snr = [];
//@ts-expect-error
chat.selectedMessageObject = [];
// id and uuid are the same
var data = getFromUnsortedChatListByUUID(id);
chat.selectedMessageObject = data;
console.log(data);
if (
typeof data["speed_list"] !== "undefined" &&
data["speed_list"].length > 0
) {
prepareStatsDataForStore(data["speed_list"]);
} else {
prepareStatsDataForStore([{}]);
}
return;
}
// THis is a nearly duplicate of the same function in sock.js :-(
function prepareStatsDataForStore(data) {
// dummy data
//state.arq_speed_list = [{"snr":0.0,"bpm":104,"timestamp":1696189769},{"snr":0.0,"bpm":80,"timestamp":1696189778},{"snr":0.0,"bpm":70,"timestamp":1696189783},{"snr":0.0,"bpm":58,"timestamp":1696189792},{"snr":0.0,"bpm":52,"timestamp":1696189797},{"snr":"NaN","bpm":42,"timestamp":1696189811},{"snr":0.0,"bpm":22,"timestamp":1696189875},{"snr":0.0,"bpm":21,"timestamp":1696189881},{"snr":0.0,"bpm":17,"timestamp":1696189913},{"snr":0.0,"bpm":15,"timestamp":1696189932},{"snr":0.0,"bpm":15,"timestamp":1696189937},{"snr":0.0,"bpm":14,"timestamp":1696189946},{"snr":-6.1,"bpm":14,"timestamp":1696189954},{"snr":-6.1,"bpm":14,"timestamp":1696189955},{"snr":-5.5,"bpm":28,"timestamp":1696189963},{"snr":-5.5,"bpm":27,"timestamp":1696189963}]
console.log(data);
console.log();
var speed_listSize = 0;
if (typeof data == "undefined") {
speed_listSize = 0;
} else {
speed_listSize = data.length;
}
var speed_list_bpm = [];
for (let i = 0; i < speed_listSize; i++) {
speed_list_bpm.push(data[i].bpm);
}
var speed_list_timestamp = [];
for (let i = 0; i < speed_listSize; i++) {
let timestamp = data[i].timestamp * 1000;
let h = new Date(timestamp).getHours();
let m = new Date(timestamp).getMinutes();
let s = new Date(timestamp).getSeconds();
let time = h + ":" + m + ":" + s;
speed_list_timestamp.push(time);
}
var speed_list_snr = [];
for (let i = 0; i < speed_listSize; i++) {
let snr = NaN;
if (data[i].snr !== 0) {
snr = data[i].snr;
} else {
snr = NaN;
}
speed_list_snr.push(snr);
}
chat.arq_speed_list_bpm = speed_list_bpm;
chat.arq_speed_list_timestamp = speed_list_timestamp;
chat.arq_speed_list_snr = speed_list_snr;
return;
}
async function createIndex(myIndexFields) {
db.createIndex({
index: {
fields: myIndexFields,
},
}).catch((err) => {
console.log(err);
});
}
async function getFromDBByFilter(filter) {
/*
USAGE:
let filter = {
selector: {
dxcallsign: dxcall,
type: "transmit",
status: "failed",
//attempt: { $lt: parseInt(config.max_retry_attempts) }
},
}
getFromDBByFilter(filter)
.then(result => {
console.log(result)
})
.catch(err => {
console.log(err)
});
*/
return new Promise((resolve, reject) => {
return db
.find(filter)
.then((result) => {
//console.log(result);
resolve(result);
})
.catch((err) => {
console.log(err);
reject(err);
});
});
}
async function checkForWaitingMessages(dxcall) {
let filter = {
selector: {
dxcallsign: dxcall,
type: "transmit",
status: "failed",
//attempt: { $lt: parseInt(config.max_retry_attempts) }
},
};
getFromDBByFilter(filter)
.then((result) => {
let message =
// @ts-expect-error
"Found " + result.docs.length + " waiting messages for " + dxcall;
console.log(message);
displayToast("info", "bi bi-info-circle", message, 5000);
console.log(result);
// @ts-expect-error
console.log(result.docs);
// @ts-expect-error
console.log(result.docs.length);
// handle result
// @ts-expect-error
if (result.docs.length > 0) {
// only want to process the first available item object, then return
// this ensures, we are only sending one message at once
// @ts-expect-error
console.log(result.docs[0]);
//console.log(
// "attempt: " +
// result.docs[0].attempt +
// "/" +
// settings.max_retry_attempts,
//);
// @ts-expect-error
if (result.docs[0].attempt < settings.max_retry_attempts) {
console.log("repeating message...");
// @ts-expect-error
repeatMessageTransmission(result.docs[0].uuid);
}
return;
}
})
.catch((err) => {
console.log(err);
});
}
export function sendMessage(obj) {
let dxcallsign = obj.dxcallsign;
let checksum = obj.checksum;
let uuid = obj.uuid;
let command = obj.command;
let filename = Object.keys(obj._attachments)[0];
//let filetype = filename.split(".")[1]
let filetype = obj._attachments[filename].content_type;
let file = obj._attachments[filename].data;
let data_with_attachment =
obj.timestamp +
split_char +
obj.msg +
split_char +
filename +
split_char +
filetype +
split_char +
file;
let data = btoa_FD(
"m" +
split_char +
command +
split_char +
checksum +
split_char +
uuid +
split_char +
data_with_attachment,
);
let mycallsign =
settings.remote.STATION.mycall + "-" + settings.remote.STATION.myssid;
sendModemARQRaw(mycallsign, dxcallsign, data, uuid);
}