FreeDATA/gui_vue/src/js/chatHandler.js

583 lines
14 KiB
JavaScript
Raw Normal View History

2023-09-12 15:52:16 +00:00
const path = require("path");
const fs = require("fs");
2023-09-20 04:46:37 +00:00
const { v4: uuidv4 } = require("uuid");
2023-09-12 15:52:16 +00:00
// pinia store setup
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia);
import { useChatStore } from '../store/chatStore.js';
const chat = useChatStore(pinia);
2023-09-20 04:46:37 +00:00
import { sendMessage } from './sock.js';
const FD = require("./src/js/freedata.js");
// split character
const split_char = "0;1;";
2023-09-12 15:52:16 +00:00
// ---- 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"));
// https://stackoverflow.com/a/26227660
var appDataFolder =
process.env.APPDATA ||
(process.platform == "darwin"
? process.env.HOME + "/Library/Application Support"
: process.env.HOME + "/.config");
var configFolder = path.join(appDataFolder, "FreeDATA");
var chatDB = path.join(configFolder, "chatDB");
var db = new PouchDB(chatDB);
/* -------- CREATE DATABASE INDEXES */
createChatIndex();
// create callsign set for storing unique callsigns
2023-09-12 15:52:16 +00:00
chat.callsign_list = new Set()
2023-09-27 14:55:57 +00:00
// function for creating a new broadcast
export function newBroadcast(broadcastChannel, chatmessage){
var mode = ''
var frames = ''
var data = ''
if (typeof chatFile !== "undefined"){
var file = chatFile;
var filetype = chatFileType
var filename = chatFileName
} else {
var file = '';
var filetype = 'text'
var filename = ''
}
var file_checksum = ''//crc32(file).toString(16).toUpperCase();
var checksum = ''
var message_type = 'broadcast_transmit'
var command = ''
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);
var data_with_attachment =
timestamp +
split_char +
chatmessage +
split_char +
filename +
split_char +
filetype +
split_char +
file;
var tnc_command = "broadcast";
sendMessage(
dxcallsign,
data_with_attachment,
checksum,
uuid,
tnc_command
)
let newChatObj = new Object();
newChatObj.command = "msg"
newChatObj.hmac_signed = false
newChatObj.percent = 0
newChatObj.bytesperminute
newChatObj.is_new = false
newChatObj._id = uuid
newChatObj.timestamp = timestamp
newChatObj.dxcallsign = dxcallsign
newChatObj.dxgrid = "null"
newChatObj.msg = chatmessage
newChatObj.checksum = file_checksum
newChatObj.type = message_type
newChatObj.status = "transmitting"
newChatObj.attempt = 1
newChatObj.uuid = uuid
newChatObj._attachments = {
[filename]: {
content_type: filetype,
data: FD.btoa_FD(file),
},
}
addObjToDatabase(newChatObj)
}
// function for creating a new message
2023-09-21 21:04:12 +00:00
export function newMessage(dxcallsign, chatmessage, chatFile, chatFileName, chatFileSize, chatFileType){
2023-09-20 04:46:37 +00:00
var mode = ''
var frames = ''
var data = ''
2023-09-22 21:21:44 +00:00
if (typeof chatFile !== "undefined"){
var file = chatFile;
var filetype = chatFileType
var filename = chatFileName
} else {
var file = '';
var filetype = 'text'
var filename = ''
}
2023-09-21 21:04:12 +00:00
var file_checksum = ''//crc32(file).toString(16).toUpperCase();
2023-09-20 04:46:37 +00:00
var checksum = ''
var message_type = 'transmit'
var command = ''
2023-09-22 21:21:44 +00:00
2023-09-20 04:46:37 +00:00
var timestamp = Math.floor(Date.now() / 1000)
var uuid = uuidv4();
2023-09-22 21:21:44 +00:00
// TODO: Not sure what this uuid part is needed for ...
2023-09-20 04:46:37 +00:00
let uuidlast = uuid.lastIndexOf("-");
uuidlast += 1;
if (uuidlast > 0) {
uuid = uuid.substring(uuidlast);
}
// slice uuid for reducing overhead
2023-09-21 21:04:12 +00:00
uuid = uuid.slice(-8);
2023-09-20 04:46:37 +00:00
2023-09-22 21:21:44 +00:00
2023-09-20 04:46:37 +00:00
var data_with_attachment =
timestamp +
split_char +
chatmessage +
split_char +
filename +
split_char +
filetype +
split_char +
file;
2023-09-21 21:04:12 +00:00
2023-09-20 04:46:37 +00:00
var tnc_command = "msg";
sendMessage(
dxcallsign,
data_with_attachment,
checksum,
uuid,
tnc_command
)
let newChatObj = new Object();
newChatObj.command = "msg"
newChatObj.hmac_signed = false
newChatObj.percent = 0
newChatObj.bytesperminute
newChatObj.is_new = false
newChatObj._id = uuid
newChatObj.timestamp = timestamp
newChatObj.dxcallsign = dxcallsign
newChatObj.dxgrid = "null"
newChatObj.msg = chatmessage
newChatObj.checksum = file_checksum
newChatObj.type = message_type
2023-09-20 05:37:32 +00:00
newChatObj.status = "transmitting"
2023-09-20 04:46:37 +00:00
newChatObj.attempt = 1
newChatObj.uuid = uuid
newChatObj._attachments = {
[filename]: {
content_type: filetype,
data: FD.btoa_FD(file),
},
}
addObjToDatabase(newChatObj)
}
function sortChatList(){
// Create an empty object to store the reordered data dynamically
2023-09-13 21:28:20 +00:00
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);
}
});
//console.log(reorderedData["DJ2LS-0"])
return reorderedData
}
2023-09-12 15:52:16 +00:00
2023-09-22 21:21:44 +00:00
//repeat a message
export function repeatMessageTransmission(id){
console.log(id)
}
// 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()
}
2023-09-12 15:52:16 +00:00
// function for fetching all messages from chat / updating chat
2023-09-12 15:52:16 +00:00
export async function updateAllChat() {
//Ensure we create an index before running db.find
//We can't rely on the default index existing before we get here...... :'(
await db
.createIndex({
index: {
fields: [{ dxcallsign: "asc" }, { timestamp: "asc" }],
},
})
.then(async function (result) {
// handle result
await db
.find({
selector: {
$and: [
{ dxcallsign: { $exists: true } },
{ timestamp: { $exists: true } },
{ $or: chat.chat_filter },
],
//$or: chat.chat_filter
},
sort: [{ dxcallsign: "asc" }, { timestamp: "asc" }],
})
.then(async function (result) {
for (var item of result.docs) {
chat.callsign_list.add(item.dxcallsign)
chat.unsorted_chat_list.push(item)
2023-09-12 15:52:16 +00:00
}
chat.sorted_chat_list = sortChatList()
console.log(chat.sorted_chat_list["EI7IG-0"])
2023-09-12 15:52:16 +00:00
/*
if (typeof result !== "undefined") {
for (const item of result.docs) {
//await otherwise history will not be in chronological order
await db
.get(item._id, {
attachments: true,
})
.then(function (item_with_attachments) {
update_chat(item_with_attachments);
});
}
}
*/
})
.catch(function (err) {
console.log(err);
});
})
.catch(function (err) {
console.log(err);
});
}
2023-09-20 04:46:37 +00:00
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);
})
.catch(function (err) {
console.log(err);
});
chat.unsorted_chat_list.push(newobj)
chat.sorted_chat_list = sortChatList()
/*
// upsert footer ...
}
return doc;
})
*/
}
2023-09-12 15:52:16 +00:00
function createChatIndex() {
db.createIndex({
index: {
fields: [
"timestamp",
"uuid",
"dxcallsign",
"dxgrid",
"msg",
"checksum",
"type",
"command",
"status",
"percent",
"attempt",
"hmac_signed",
"bytesperminute",
"_attachments",
2023-09-20 04:46:37 +00:00
"is_new",
2023-09-12 15:52:16 +00:00
],
},
})
.then(function (result) {
// handle result
console.log(result);
})
.catch(function (err) {
console.log(err);
});
}
2023-09-14 19:45:07 +00:00
export function deleteChatByCallsign(callsign){
chat.callsign_list.delete(callsign)
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 (doc) {
updateAllChat(true);
return true;
})
.catch(function (err) {
console.log(err);
});
})
.catch(function (err) {
console.log(err);
});
});
}
})
.catch(function (err) {
console.log(err);
});
2023-09-20 04:46:37 +00:00
}
// function for handling a received beacon
export function newBeaconReceived(obj){
/*
{
"freedata": "tnc-message",
"beacon": "received",
"uuid": "12741312-3dbb-4a53-b0cc-100f6c930ab8",
"timestamp": 1696076869,
"dxcallsign": "DJ2LS-0",
"dxgrid": "JN48CS",
"snr": "-2.8",
"mycallsign": "DJ2LS-0"
}
*/
let newChatObj = new Object();
newChatObj.command = "beacon"
newChatObj._id = obj['uuid']
newChatObj.uuid = obj['uuid']
newChatObj.timestamp = obj['timestamp']
newChatObj.dxcallsign = obj["dxcallsign"]
newChatObj.dxgrid = obj["dxgrid"]
newChatObj.type = 'beacon'
newChatObj.status = obj["beacon"]
newChatObj.snr = obj["snr"]
addObjToDatabase(newChatObj)
}
// function for handling a received message
export function newMessageReceived(message, protocol){
2023-09-27 14:55:57 +00:00
/*
PROTOCOL
{
"freedata": "tnc-message",
"arq": "transmission",
"status": "received",
"uuid": "58d64f7d-be8c-4578-879b-3b6cb3b60ddf",
"percent": 100,
"bytesperminute": 536,
"compression": 0.5714285714285714,
"timestamp": 1695203863,
"finished": 0,
"mycallsign": "DJ2LS-0",
"dxcallsign": "DJ2LS-0",
"dxgrid": "------",
"data": "bTA7MTttc2cwOzE7MDsxOzA3ZTIwOzE7MTY5NTIwMzgzMzA7MTt0ZXN0MDsxOzA7MTtwbGFpbi90ZXh0MDsxOw==",
"irs": "True",
"hmac_signed": "False"
}
2023-09-27 14:55:57 +00:00
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 - ""
]
2023-09-27 14:55:57 +00:00
*/
console.log(protocol)
let newChatObj = new Object();
2023-09-27 14:55:57 +00:00
newChatObj.command = "msg"
newChatObj.hmac_signed = protocol["hmac_signed"]
newChatObj.percent = 100
newChatObj.bytesperminute = protocol["bytesperminute"]
newChatObj.is_new = true
newChatObj._id = message[3]
newChatObj.timestamp = message[4]
newChatObj.dxcallsign = protocol["dxcallsign"]
newChatObj.dxgrid = protocol["dxgrid"]
newChatObj.msg = message[5]
newChatObj.checksum = message[2]
newChatObj.type = message[1]
newChatObj.status = protocol["status"]
newChatObj.attempt = 1
newChatObj.uuid = message[3]
newChatObj._attachments = {
[message[6]]: {
content_type: message[7],
data: FD.btoa_FD(message[8]),
},
}
// some tweaks for broadcasts
if (protocol.fec == "broadcast") {
2023-09-27 14:55:57 +00:00
newChatObj.broadcast_sender = protocol["dxcallsign"]
newChatObj.type = 'broadcast_received'
}
addObjToDatabase(newChatObj)
}
2023-09-20 04:46:37 +00:00
// CRC CHECKSUMS
// https://stackoverflow.com/a/50579690
// crc32 calculation
//console.log(crc32('abc'));
//var crc32=function(r){for(var a,o=[],c=0;c<256;c++){a=c;for(var f=0;f<8;f++)a=1&a?3988292384^a>>>1:a>>>1;o[c]=a}for(var n=-1,t=0;t<r.length;t++)n=n>>>8^o[255&(n^r.charCodeAt(t))];return(-1^n)>>>0};
//console.log(crc32('abc').toString(16).toUpperCase()); // hex
var makeCRCTable = function () {
var c;
var crcTable = [];
for (var n = 0; n < 256; n++) {
c = n;
for (var k = 0; k < 8; k++) {
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
}
crcTable[n] = c;
}
return crcTable;
};
var crc32 = function (str) {
var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
var crc = 0 ^ -1;
for (var i = 0; i < str.length; i++) {
crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xff];
}
return (crc ^ -1) >>> 0;
};