Compare commits
94 Commits
62c00eec09
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4d07db766 | ||
|
|
03c940e07c | ||
|
|
fee40dd609 | ||
|
|
5671503594 | ||
|
|
0fd511cfaf | ||
|
|
9d0aa0191f | ||
|
|
9ce8928d82 | ||
|
|
abadcf5cb5 | ||
|
|
4b18df9e2c | ||
|
|
26a8d8a172 | ||
|
|
26f3493c8f | ||
|
|
fd261ef015 | ||
|
|
91201c3527 | ||
|
|
dfb4c6afa1 | ||
|
|
3b8e70208a | ||
|
|
99b60bf02c | ||
|
|
831317b9f0 | ||
|
|
2477b10900 | ||
|
|
67c29f1d72 | ||
|
|
91ed4fb1dc | ||
|
|
8ea02d1c0b | ||
|
|
b15ac7c973 | ||
|
|
c2c90019d7 | ||
|
|
686ddc8a0f | ||
|
|
463ccc1bd5 | ||
|
|
14a2b4a1b9 | ||
|
|
0c1f6cd867 | ||
|
|
7175487d77 | ||
|
|
f0eac45955 | ||
|
|
c81dce99e2 | ||
|
|
38cb1054e0 | ||
|
|
12441c5c6d | ||
|
|
1c1b071bd7 | ||
|
|
961c5c19e2 | ||
|
|
49e52d8944 | ||
|
|
63ccfa70d3 | ||
|
|
4bb8038a1d | ||
|
|
a353b9adbb | ||
|
|
bf69e93e29 | ||
|
|
6cae18e70c | ||
|
|
e7229322e4 | ||
|
|
34aa5d17dc | ||
|
|
565fd5af37 | ||
|
|
f04154d361 | ||
|
|
383663e980 | ||
|
|
7b21d4601f | ||
|
|
d0c2fcc8eb | ||
|
|
9ba90af464 | ||
|
|
6e8681e52d | ||
|
|
8ba1ed36d8 | ||
|
|
3074e88963 | ||
|
|
737b493b23 | ||
|
|
539dbd9518 | ||
|
|
59bfdbe143 | ||
|
|
560ed401cf | ||
|
|
7b91667414 | ||
|
|
fd9b6d9d1c | ||
|
|
3aae427249 | ||
|
|
bc4c8f72d0 | ||
|
|
cc4e5e762d | ||
|
|
31cedb2e9c | ||
|
|
61a616ec6b | ||
|
|
d7b7b04f78 | ||
|
|
2c9383824e | ||
|
|
cebd316939 | ||
|
|
af19db8e17 | ||
|
|
45b9a62c64 | ||
|
|
8c3164029f | ||
|
|
bec4072837 | ||
|
|
ac82b0efd0 | ||
|
|
854c73cc4e | ||
|
|
238fe6a254 | ||
|
|
96d9c38425 | ||
|
|
4df3de4d4a | ||
|
|
461b449194 | ||
|
|
757fdfb3b2 | ||
|
|
9bc80887ce | ||
|
|
0ce0f72ed3 | ||
|
|
49ae941e83 | ||
|
|
8e73659855 | ||
|
|
0a76804490 | ||
| 9ad24ca8ec | |||
| 7676e883a5 | |||
| 86a71d3d6f | |||
| 1dd53ffc84 | |||
| fc31026304 | |||
| 8a4b7685d2 | |||
|
|
49c1a1d724 | ||
|
|
a423417949 | ||
|
|
2fb0bc8920 | ||
| 38470bd788 | |||
| 8995f8b372 | |||
| a6c26d61da | |||
| ab0f94baf8 |
32
.gitea/workflows/DRBv3-Client_Setup_tests.yaml.disabled
Normal file
32
.gitea/workflows/DRBv3-Client_Setup_tests.yaml.disabled
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: DRB Build Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
drb_test_setup:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Test setup script
|
||||||
|
working-directory: "./client"
|
||||||
|
run: |
|
||||||
|
sudo useradd -m -s /bin/bash pi
|
||||||
|
sudo bash setup.sh --test
|
||||||
|
|
||||||
|
- name: Test running client node
|
||||||
|
working-directory: "./client"
|
||||||
|
run: |
|
||||||
|
bash serviceStart.sh
|
||||||
24
.gitea/workflows/DRBv3_server_build.yaml
Normal file
24
.gitea/workflows/DRBv3_server_build.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: DRB Server Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_ENV: production
|
||||||
|
SERVER_PORT: 3000
|
||||||
|
MONGO_URL: ${{ secrets.MONGO_URL }}
|
||||||
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
drb_server_build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build the latest code
|
||||||
|
working-directory: './server'
|
||||||
|
run: make build
|
||||||
81
.gitea/workflows/DRBv3_tests.yaml
Normal file
81
.gitea/workflows/DRBv3_tests.yaml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
name: DRB Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_ENV: development
|
||||||
|
MONGO_INITDB_ROOT_USERNAME: admin
|
||||||
|
MONGO_INITDB_ROOT_PASSWORD: admin
|
||||||
|
MONGO_INITDB_DATABASE: drb
|
||||||
|
SERVER_PORT: 3000
|
||||||
|
MONGO_URL: "mongodb://mongodb:27017/drb"
|
||||||
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
|
TEST_GUILD_ID: ${{ secrets.TEST_GUILD_ID }}
|
||||||
|
TEST_CLIENT_TOKEN: ${{ secrets.TEST_CLIENT_TOKEN }}
|
||||||
|
TEST_CHANNEL_ID: ${{ secrets.TEST_CHANNEL_ID }}
|
||||||
|
TEST_SYSTEM: ${{ secrets.TEST_SYSTEM }}
|
||||||
|
EXPECTED_CLIENT_ID: ${{ secrets.TEST_CLIENT_ID }}
|
||||||
|
EXPECTED_USERNAME: ${{ secrets.EXPECTED_USERNAME }}
|
||||||
|
PDAB_PORT: ${{ vars.PDAB_PORT }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
drb_mocha_tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
services:
|
||||||
|
mongodb:
|
||||||
|
image: mongo:latest
|
||||||
|
ports:
|
||||||
|
- 27017:27017
|
||||||
|
options: >-
|
||||||
|
--health-cmd mongo
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Remove package-lock.json (Server)
|
||||||
|
working-directory: "./server"
|
||||||
|
run: rm package-lock.json
|
||||||
|
|
||||||
|
- name: Install Node-GYP (Server)
|
||||||
|
working-directory: "./server"
|
||||||
|
run: npm install -g node-gyp
|
||||||
|
|
||||||
|
- name: Install dependencies (Server)
|
||||||
|
working-directory: "./server"
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Remove package-lock.json (Client)
|
||||||
|
working-directory: "./client"
|
||||||
|
run: rm package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies (Client)
|
||||||
|
working-directory: "./client"
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- run: echo "Node has finished installing dependencies"
|
||||||
|
|
||||||
|
- name: Run Server tests
|
||||||
|
working-directory: "./server"
|
||||||
|
run: npm test
|
||||||
|
|
||||||
|
- name: Run Client tests
|
||||||
|
working-directory: "./client"
|
||||||
|
run: npm test
|
||||||
|
|
||||||
|
- run: echo "Completed the DRB tests"
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
name: Run Socket Server Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- all
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '22'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
working-directory: './server'
|
|
||||||
run: npm install
|
|
||||||
run: echo "Node has finished installing dependencies"
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
working-directory: './server'
|
|
||||||
run: npm test
|
|
||||||
run: echo "Completed the tests"
|
|
||||||
@@ -2,6 +2,7 @@ import { generateUniqueID } from './modules/baseUtils.mjs';
|
|||||||
import { updateId } from './modules/updateConfig.mjs';
|
import { updateId } from './modules/updateConfig.mjs';
|
||||||
import { ClientNodeConfig } from './modules/clientObjectDefinitions.mjs';
|
import { ClientNodeConfig } from './modules/clientObjectDefinitions.mjs';
|
||||||
import { initSocketConnection } from './modules/socketClient.mjs';
|
import { initSocketConnection } from './modules/socketClient.mjs';
|
||||||
|
import { checkForUpdates } from './modules/selfUpdater.mjs'
|
||||||
|
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
@@ -9,6 +10,9 @@ dotenv.config()
|
|||||||
var localNodeConfig = new ClientNodeConfig({})
|
var localNodeConfig = new ClientNodeConfig({})
|
||||||
|
|
||||||
async function boot() {
|
async function boot() {
|
||||||
|
// Check if there have been any updates
|
||||||
|
await checkForUpdates();
|
||||||
|
|
||||||
if (localNodeConfig.node.nuid === undefined || localNodeConfig.node.nuid === '' || localNodeConfig.node.nuid === '0' || localNodeConfig.node.nuid === 0) {
|
if (localNodeConfig.node.nuid === undefined || localNodeConfig.node.nuid === '' || localNodeConfig.node.nuid === '0' || localNodeConfig.node.nuid === 0) {
|
||||||
// Run the first time boot sequence
|
// Run the first time boot sequence
|
||||||
await firstTimeBoot();
|
await firstTimeBoot();
|
||||||
|
|||||||
1
client/discordAudioBot/pdab
Submodule
1
client/discordAudioBot/pdab
Submodule
Submodule client/discordAudioBot/pdab added at fc6c114473
@@ -6,6 +6,9 @@ import { launchProcess } from '../modules/subprocessHandler.mjs';
|
|||||||
import { join, dirname } from 'path';
|
import { join, dirname } from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
const io = new Server(server);
|
const io = new Server(server);
|
||||||
@@ -14,7 +17,16 @@ let pdabProcess = false;
|
|||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
export const initDiscordBotClient = (clientId, callback) => {
|
let botCallback;
|
||||||
|
|
||||||
|
export const initDiscordBotClient = (clientId, callback, runPDAB = true) => {
|
||||||
|
botCallback = callback;
|
||||||
|
|
||||||
|
if (runPDAB) launchProcess("python", [join(__dirname, "./pdab/main.py"), process.env.AUDIO_DEVICE_ID, clientId, port], false, join(__dirname, "./pdab"));
|
||||||
|
pdabProcess = true; // TODO - Make this more dynamic
|
||||||
|
}
|
||||||
|
|
||||||
|
export const startPdabSocketServer = () => {
|
||||||
const port = process.env.PDAB_PORT || 3000;
|
const port = process.env.PDAB_PORT || 3000;
|
||||||
|
|
||||||
io.on('connection', (socket) => {
|
io.on('connection', (socket) => {
|
||||||
@@ -27,18 +39,24 @@ export const initDiscordBotClient = (clientId, callback) => {
|
|||||||
// Listen for the discord client ready event
|
// Listen for the discord client ready event
|
||||||
socket.on('discord_ready', (message) => {
|
socket.on('discord_ready', (message) => {
|
||||||
console.log("Message from local client", message);
|
console.log("Message from local client", message);
|
||||||
callback();
|
botCallback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(port, async () => {
|
server.listen(port, async () => {
|
||||||
console.log(`Server is running on port ${port}`);
|
console.log(`Server is running on port ${port}`);
|
||||||
|
|
||||||
launchProcess("python", [join(__dirname, "./pdab/main.py"), process.env.AUDIO_DEVICE_ID, clientId, port], false, join(__dirname, "./pdab"));
|
|
||||||
pdabProcess = true; // TODO - Make this more dynamic
|
|
||||||
});
|
});
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const closePdabSocketServer = () => {
|
||||||
|
if (io.sockets && io.sockets.length > 0) {
|
||||||
|
io.sockets.forEach(socket => {
|
||||||
|
socket.destroy();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return io.close();
|
||||||
|
}
|
||||||
|
|
||||||
// Function to emit a command to join a voice channel
|
// Function to emit a command to join a voice channel
|
||||||
export const connectToChannel = (channelId) => {
|
export const connectToChannel = (channelId) => {
|
||||||
@@ -53,13 +71,22 @@ export const connectToChannel = (channelId) => {
|
|||||||
// Function to emit a command to leave a voice channel
|
// Function to emit a command to leave a voice channel
|
||||||
export const leaveVoiceChannel = async (guildId) => {
|
export const leaveVoiceChannel = async (guildId) => {
|
||||||
return await new Promise((res) => {
|
return await new Promise((res) => {
|
||||||
io.timeout(25000).emit('leave_server', { guild_id: guildId }, (status, clientRemainsOpen) => {
|
io.timeout(25000).emit('leave_server', { guildId: guildId }, (status, clientRemainsOpen) => {
|
||||||
console.log("Discord client remains open?", clientRemainsOpen);
|
console.log("Discord client remains open?", clientRemainsOpen);
|
||||||
res(clientRemainsOpen[0])
|
res(clientRemainsOpen[0])
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set the presense of the discord client
|
||||||
|
export const setDiscordClientPrsense = (system) => {
|
||||||
|
return new Promise((res) => {
|
||||||
|
io.timeout(25000).emit('set_system', { system: system }, (status) => {
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Placeholder functions (replace with actual implementation)
|
// Placeholder functions (replace with actual implementation)
|
||||||
export const checkIfConnectedToVC = async (guildId) => {
|
export const checkIfConnectedToVC = async (guildId) => {
|
||||||
console.log("Pdab process var:", pdabProcess);
|
console.log("Pdab process var:", pdabProcess);
|
||||||
@@ -67,7 +94,7 @@ export const checkIfConnectedToVC = async (guildId) => {
|
|||||||
if (!pdabProcess) return false;
|
if (!pdabProcess) return false;
|
||||||
|
|
||||||
return await new Promise((res) => {
|
return await new Promise((res) => {
|
||||||
io.timeout(25000).emit('check_discord_vc_connected', { guild_id: guildId }, (status, result) => {
|
io.timeout(25000).emit('check_discord_vc_connected', { guildId: guildId }, (status, result) => {
|
||||||
console.log(`Discord VC connected for guild ${guildId}: ${result}`);
|
console.log(`Discord VC connected for guild ${guildId}: ${result}`);
|
||||||
res((result[0]));
|
res((result[0]));
|
||||||
});
|
});
|
||||||
@@ -76,7 +103,7 @@ export const checkIfConnectedToVC = async (guildId) => {
|
|||||||
|
|
||||||
export const requestDiscordUsername = (guildId) => {
|
export const requestDiscordUsername = (guildId) => {
|
||||||
return new Promise((res) => {
|
return new Promise((res) => {
|
||||||
io.timeout(25000).emit('request_discord_username', { guild_id: guildId }, (status, result) => {
|
io.timeout(25000).emit('request_discord_username', { guildId: guildId }, (status, result) => {
|
||||||
console.log(`Discord username: ${result[0]}`);
|
console.log(`Discord username: ${result[0]}`);
|
||||||
res(result[0]);
|
res(result[0]);
|
||||||
});
|
});
|
||||||
@@ -105,6 +132,7 @@ export const requestDiscordID = () => {
|
|||||||
export const requestDiscordClientClose = () => {
|
export const requestDiscordClientClose = () => {
|
||||||
return new Promise((res) => {
|
return new Promise((res) => {
|
||||||
io.timeout(25000).emit('request_client_close');
|
io.timeout(25000).emit('request_client_close');
|
||||||
|
pdabProcess = false;
|
||||||
res();
|
res();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { connectToChannel, leaveVoiceChannel, checkIfConnectedToVC, initDiscordBotClient, requestDiscordUsername, requestDiscordID, requestDiscordClientClose } from './pdabHandler.mjs';
|
import { connectToChannel, leaveVoiceChannel, checkIfConnectedToVC, initDiscordBotClient, requestDiscordUsername, requestDiscordID, requestDiscordClientClose, closePdabSocketServer, setDiscordClientPrsense, startPdabSocketServer } from './pdabHandler.mjs';
|
||||||
import { openOP25, closeOP25 } from '../op25Handler/op25Handler.mjs';
|
import { openOP25, closeOP25 } from '../op25Handler/op25Handler.mjs';
|
||||||
|
|
||||||
let activeDiscordClient = undefined;
|
let activeDiscordClient = undefined;
|
||||||
@@ -8,16 +8,26 @@ let activeDiscordClient = undefined;
|
|||||||
* @param {object} joinData The object containing all the information to join the server
|
* @param {object} joinData The object containing all the information to join the server
|
||||||
*/
|
*/
|
||||||
export const joinDiscordVC = async (joinData) => {
|
export const joinDiscordVC = async (joinData) => {
|
||||||
console.log("Join requested: ", joinData)
|
console.log("Join requested: ", joinData);
|
||||||
const connection = await new Promise(async (res) => {
|
const connection = await new Promise(async (res) => {
|
||||||
// Check if a client already exists
|
// Check if a client already exists
|
||||||
|
console.log("Checking if there is a client open");
|
||||||
if (!await checkIfClientIsOpen()) {
|
if (!await checkIfClientIsOpen()) {
|
||||||
|
console.log("There is no open client, starting it now");
|
||||||
|
await startPdabSocketServer();
|
||||||
|
// Open an instance of OP25
|
||||||
|
console.log("Starting OP25")
|
||||||
|
openOP25(joinData.system);
|
||||||
|
|
||||||
// Open a new client and join the requested channel with the requested ID
|
// Open a new client and join the requested channel with the requested ID
|
||||||
initDiscordBotClient(joinData.clientID, () => {
|
initDiscordBotClient(joinData.clientID, () => {
|
||||||
// Open an instance of OP25
|
console.log("Started PDAB");
|
||||||
// TODO DELTE comment DEV ONLY openOP25(joinData.system);
|
|
||||||
|
console.log("Setting the presense of the bot");
|
||||||
|
setDiscordClientPrsense(joinData.system);
|
||||||
|
|
||||||
// Add the client object to the IO instance
|
// Add the client object to the IO instance
|
||||||
|
console.log("Connecting to channel")
|
||||||
connectToChannel(joinData.channelID, (connectionStatus) => {
|
connectToChannel(joinData.channelID, (connectionStatus) => {
|
||||||
console.log("Bot Connected to VC:", connectionStatus);
|
console.log("Bot Connected to VC:", connectionStatus);
|
||||||
res(connectionStatus);
|
res(connectionStatus);
|
||||||
@@ -25,7 +35,9 @@ export const joinDiscordVC = async (joinData) => {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Join the requested channel with the requested ID
|
// Join the requested channel with the requested ID
|
||||||
// Add the client object to the IO instance
|
console.log("There is an open client");
|
||||||
|
|
||||||
|
console.log("Connecting to channel")
|
||||||
const connection = connectToChannel(joinData.channelID);
|
const connection = connectToChannel(joinData.channelID);
|
||||||
console.log("Bot Connected to VC::");
|
console.log("Bot Connected to VC::");
|
||||||
res(connection);
|
res(connection);
|
||||||
@@ -46,10 +58,13 @@ export const leaveDiscordVC = async (guildId) => {
|
|||||||
console.log("Client should remain open: ", clientRemainsOpen);
|
console.log("Client should remain open: ", clientRemainsOpen);
|
||||||
if (!clientRemainsOpen) {
|
if (!clientRemainsOpen) {
|
||||||
console.log("There are no open VC connections");
|
console.log("There are no open VC connections");
|
||||||
// TODO DELETE comment DEV ONLY await closeOP25();
|
await closeOP25();
|
||||||
|
|
||||||
// Close the python client
|
// Close the python client
|
||||||
await requestDiscordClientClose();
|
await requestDiscordClientClose();
|
||||||
|
|
||||||
|
// Close the IPC server
|
||||||
|
await closePdabSocketServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { spawn } from "child_process";
|
import { spawn } from "child_process";
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object to store references to spawned processes.
|
* Object to store references to spawned processes.
|
||||||
@@ -12,11 +14,11 @@ const runningProcesses = {};
|
|||||||
* @param {string[]} args - The arguments to pass to the process.
|
* @param {string[]} args - The arguments to pass to the process.
|
||||||
* @param {boolean} waitForClose - Set this to wait to return until the process exits
|
* @param {boolean} waitForClose - Set this to wait to return until the process exits
|
||||||
*/
|
*/
|
||||||
export const launchProcess = (processName, args, waitForClose=false, pcwd=undefined) => {
|
export const launchProcess = (processName, args, waitForClose = false, pcwd = undefined) => {
|
||||||
if (!runningProcesses[processName]) {
|
if (!runningProcesses[processName]) {
|
||||||
let childProcess;
|
let childProcess;
|
||||||
if (pcwd) {
|
if (pcwd) {
|
||||||
childProcess = spawn(processName, args, {cwd: pcwd});
|
childProcess = spawn(processName, args, { cwd: pcwd });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
childProcess = spawn(processName, args);
|
childProcess = spawn(processName, args);
|
||||||
@@ -25,11 +27,29 @@ export const launchProcess = (processName, args, waitForClose=false, pcwd=undefi
|
|||||||
// Store reference to the spawned process
|
// Store reference to the spawned process
|
||||||
runningProcesses[processName] = childProcess;
|
runningProcesses[processName] = childProcess;
|
||||||
|
|
||||||
|
// Output the process output in development
|
||||||
|
var scriptOutput = "";
|
||||||
|
|
||||||
|
// Get the stdout from the child process
|
||||||
|
childProcess.stdout.setEncoding('utf8');
|
||||||
|
childProcess.stdout.on('data', (data) => {
|
||||||
|
if (process.env.NODE_ENV === "development") console.log(`Data from ${processName}:`, data);
|
||||||
|
scriptOutput += data.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the stderr from the child process
|
||||||
|
childProcess.stderr.setEncoding('utf8');
|
||||||
|
childProcess.stderr.on('data', (data) => {
|
||||||
|
if (process.env.NODE_ENV === "development") console.log(`Data from ${processName}:`, data);
|
||||||
|
scriptOutput += data.toString();
|
||||||
|
})
|
||||||
|
|
||||||
let code = new Promise(res => {
|
let code = new Promise(res => {
|
||||||
childProcess.on('exit', (code, signal) => {
|
childProcess.on('exit', (code, signal) => {
|
||||||
// Remove reference to the process when it exits
|
// Remove reference to the process when it exits
|
||||||
delete runningProcesses[processName];
|
delete runningProcesses[processName];
|
||||||
console.log(`${processName} process exited with code ${code} and signal ${signal}`);
|
console.log(`${processName} process exited with code ${code} and signal ${signal}`);
|
||||||
|
console.log("Child process console output: ", scriptOutput);
|
||||||
res(code);
|
res(code);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
865
client/package-lock.json
generated
865
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "client.js",
|
"main": "client.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "mocha --timeout 10000"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -24,6 +24,9 @@
|
|||||||
"socket.io-client": "^4.7.2"
|
"socket.io-client": "^4.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"chai-http": "^4.4.0",
|
||||||
|
"chai": "^5.1.0",
|
||||||
|
"mocha": "^10.4.0",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Install client package updates
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
|
# Install OP25 Updates
|
||||||
|
#cd ./op25
|
||||||
|
#bash rebuild.sh
|
||||||
|
|
||||||
|
# Check for PDAB updates
|
||||||
|
cd ../discordAudioBot/pdab
|
||||||
|
git pull
|
||||||
113
client/setup.sh
113
client/setup.sh
@@ -16,46 +16,76 @@ if [[ ! -f "$(pwd)/package.json" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check to make sure the pi user exists
|
||||||
|
if ! id "pi" &>/dev/null; then
|
||||||
|
echo "Error: User pi does not exist."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
####------------------- Functions
|
####------------------- Functions
|
||||||
# Function to prompt user for input with a specific message and store the result in a variable
|
# Function to prompt user for input with a specific message and store the result in a variable
|
||||||
prompt_user() {
|
prompt_user() {
|
||||||
read -p "$1: " input
|
if [[ "$TEST_MODE" == "true" ]]; then
|
||||||
echo "$input"
|
echo "TESTING" # Use the pre-set value
|
||||||
|
else
|
||||||
|
read -p "$1: " input
|
||||||
|
echo "$input"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to prompt user for capabilities options and store the result in a variable
|
# Function to prompt user for capabilities options and store the result in a variable
|
||||||
prompt_capabilities() {
|
prompt_capabilities() {
|
||||||
default_capabilities="radio" # Default value
|
if [[ "$TEST_MODE" == "true" ]]; then
|
||||||
read -p "Select CLIENT_CAPABILITIES (comma-separated, default: $default_capabilities): " capabilities
|
echo "radio" # Use the pre-set value
|
||||||
capabilities="${capabilities:-$default_capabilities}" # Use default value if input is empty
|
else
|
||||||
echo "$capabilities"
|
default_capabilities="radio" # Default value
|
||||||
|
read -p "Select CLIENT_CAPABILITIES (comma-separated, default: $default_capabilities): " capabilities
|
||||||
|
capabilities="${capabilities:-$default_capabilities}" # Use default value if input is empty
|
||||||
|
echo "$capabilities"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to prompt user for nearby systems details
|
# Function to prompt user for nearby systems details
|
||||||
prompt_nearby_system() {
|
prompt_nearby_system() {
|
||||||
local system_name=""
|
if [[ "$TEST_MODE" == "true" ]]; then
|
||||||
local frequencies=""
|
echo "\"TESTING-Node\": {
|
||||||
local mode=""
|
\"frequencies\": [\"$(echo "155750000,154750000,156555550" | sed 's/,/","/g')\"],
|
||||||
local trunk_file=""
|
\"mode\": \"p25\",
|
||||||
local whitelist_file=""
|
\"trunkFile\": \"testing_trunk.tsv\",
|
||||||
|
\"whitelistFile\": \"testing_whitelist.tsv\"
|
||||||
|
}," # Use the pre-set value
|
||||||
|
else
|
||||||
|
local system_name=""
|
||||||
|
local frequencies=""
|
||||||
|
local mode=""
|
||||||
|
local trunk_file=""
|
||||||
|
local whitelist_file=""
|
||||||
|
|
||||||
read -p "Enter system name: " system_name
|
read -p "Enter system name: " system_name
|
||||||
read -p "Enter frequencies (comma-separated): " frequencies
|
read -p "Enter frequencies (comma-separated): " frequencies
|
||||||
read -p "Enter mode (p25/nbfm): " mode
|
read -p "Enter mode (p25/nbfm): " mode
|
||||||
|
|
||||||
if [[ "$mode" == "p25" ]]; then
|
if [[ "$mode" == "p25" ]]; then
|
||||||
read -p "Enter trunk file: " trunk_file
|
read -p "Enter trunk file: " trunk_file
|
||||||
read -p "Enter whitelist file: " whitelist_file
|
read -p "Enter whitelist file: " whitelist_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "\"$system_name\": {
|
||||||
|
\"frequencies\": [\"$(echo "$frequencies" | sed 's/,/","/g')\"],
|
||||||
|
\"mode\": \"$mode\",
|
||||||
|
\"trunkFile\": \"$trunk_file\",
|
||||||
|
\"whitelistFile\": \"$whitelist_file\"
|
||||||
|
},"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "\"$system_name\": {
|
|
||||||
\"frequencies\": [\"$(echo "$frequencies" | sed 's/,/","/g')\"],
|
|
||||||
\"mode\": \"$mode\",
|
|
||||||
\"trunkFile\": \"$trunk_file\",
|
|
||||||
\"whitelistFile\": \"$whitelist_file\"
|
|
||||||
},"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check if test mode is enabled
|
||||||
|
if [[ "$1" == "--test" ]]; then
|
||||||
|
TEST_MODE="true"
|
||||||
|
else
|
||||||
|
TEST_MODE="false"
|
||||||
|
fi
|
||||||
|
|
||||||
# Install Node Repo
|
# Install Node Repo
|
||||||
# Get the CPU architecture
|
# Get the CPU architecture
|
||||||
cpu_arch=$(uname -m)
|
cpu_arch=$(uname -m)
|
||||||
@@ -68,6 +98,7 @@ if [[ "$cpu_arch" == "armv6"* ]]; then
|
|||||||
echo "----- CPU Architecture is ARMv6 or compatible. -----"
|
echo "----- CPU Architecture is ARMv6 or compatible. -----"
|
||||||
echo "----- CPU Architectre is not compatible with dependencies of this project, please use a newer CPU architecture -----"
|
echo "----- CPU Architectre is not compatible with dependencies of this project, please use a newer CPU architecture -----"
|
||||||
exit
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
|
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
|
||||||
|
|
||||||
@@ -77,7 +108,18 @@ apt upgrade -y
|
|||||||
|
|
||||||
# Install the necessary packages
|
# Install the necessary packages
|
||||||
echo "Installing dependencies..."
|
echo "Installing dependencies..."
|
||||||
apt install -y nodejs portaudio19-dev libportaudio2 libpulse-dev pulseaudio apulse git ffmpeg git
|
apt install -y \
|
||||||
|
nodejs \
|
||||||
|
libasound-dev \
|
||||||
|
portaudio19-dev \
|
||||||
|
libportaudio2 \
|
||||||
|
libpulse-dev \
|
||||||
|
pulseaudio \
|
||||||
|
apulse \
|
||||||
|
git \
|
||||||
|
ffmpeg \
|
||||||
|
python3 \
|
||||||
|
python3-pip
|
||||||
|
|
||||||
echo "Setting up Pulse Audio"
|
echo "Setting up Pulse Audio"
|
||||||
|
|
||||||
@@ -104,13 +146,21 @@ usermod -aG pulse-access pi
|
|||||||
|
|
||||||
# Enable the PulseAudio service
|
# Enable the PulseAudio service
|
||||||
systemctl enable PulseAudio.service
|
systemctl enable PulseAudio.service
|
||||||
systemctl stop PulseAudio.service
|
|
||||||
|
|
||||||
####------------------- Install and setup node
|
####------------------- Install and setup node
|
||||||
# Run npm install to install dependencies listed in package.json
|
# Run npm install to install dependencies listed in package.json
|
||||||
echo "Installing npm dependencies..."
|
echo "Installing npm dependencies..."
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
|
# Get rid of PEP 668
|
||||||
|
rm -rf /usr/lib/python3.11/EMTERNALL-MANAGED # Not sure if this was an attrocious fat finger or if this is needed, doesn't throw an error, so...
|
||||||
|
rm -rf /usr/lib/python3.11/EXTERNALLY-MANAGED
|
||||||
|
|
||||||
|
# Getting the Python DAB
|
||||||
|
echo "Installing PDAB and Dependencies"
|
||||||
|
git clone -b DRBv3 https://git.vpn.cusano.net/logan/Python-Discord-Audio-Bot.git ./discordAudioBot/pdab
|
||||||
|
pip3 install -r ./discordAudioBot/pdab/requirements.txt
|
||||||
|
|
||||||
# Generate .env file
|
# Generate .env file
|
||||||
echo "Creating the config .env file..."
|
echo "Creating the config .env file..."
|
||||||
echo "# Client Config" > .env
|
echo "# Client Config" > .env
|
||||||
@@ -138,6 +188,11 @@ echo "OP25_FULL_PATH=$op25_full_path" >> .env
|
|||||||
echo "" >> .env
|
echo "" >> .env
|
||||||
echo "# Core config, DO NOT TOUCH UNLESS YOU KNOW WHAT YOU ARE DOING" >> .env
|
echo "# Core config, DO NOT TOUCH UNLESS YOU KNOW WHAT YOU ARE DOING" >> .env
|
||||||
echo "CONFIG_PATH=./config/radioPresets.json" >> .env
|
echo "CONFIG_PATH=./config/radioPresets.json" >> .env
|
||||||
|
runuser -l pi -c 'python3 ./discordAudioBot/pdab/getDevices.py'
|
||||||
|
audio_device_id=$(prompt_user "Enter the ID of the 'input' audio device you would like to use (most often 'default')")
|
||||||
|
echo "AUDIO_DEVICE_ID=$audio_device_id" >> .env
|
||||||
|
echo "PDAB_PORT=3110" >> .env
|
||||||
|
echo "NODE_ENV=production" >> .env
|
||||||
|
|
||||||
echo ".env file generated successfully."
|
echo ".env file generated successfully."
|
||||||
|
|
||||||
@@ -183,14 +238,13 @@ echo "$service_content" > /etc/systemd/system/discord-radio-bot.service
|
|||||||
# Reload systemd daemon
|
# Reload systemd daemon
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable discord-radio-bot.service
|
systemctl enable discord-radio-bot.service
|
||||||
systemctl stop discord-radio-bot.service
|
|
||||||
|
|
||||||
echo "\n\n\t\tDiscord Client Node install completed!\n\n"
|
echo "\n\n\t\tDiscord Client Node install completed!\n\n"
|
||||||
|
|
||||||
####------------------- OP25 Installation
|
####------------------- OP25 Installation
|
||||||
# Clone OP25 from the git repository
|
# Clone OP25 from the git repository
|
||||||
echo "Cloning OP25 from the git repository..."
|
echo "Cloning OP25 from the git repository..."
|
||||||
git clone https://github.com/boatbod/op25.git
|
git clone -b gr310 https://github.com/boatbod/op25.git
|
||||||
|
|
||||||
# Navigate to the OP25 directory
|
# Navigate to the OP25 directory
|
||||||
ogPwd=$(pwd)
|
ogPwd=$(pwd)
|
||||||
@@ -226,7 +280,6 @@ echo "$service_content" > /etc/systemd/system/op25-multi_rx.service
|
|||||||
|
|
||||||
# Reload systemd daemon
|
# Reload systemd daemon
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl stop op25-multi_rx.service
|
|
||||||
|
|
||||||
# Install OP25 using the provided installation script
|
# Install OP25 using the provided installation script
|
||||||
echo "Installing OP25..."
|
echo "Installing OP25..."
|
||||||
@@ -251,7 +304,7 @@ confirm="${confirm,,}"
|
|||||||
#echo "To configure the app, please go to http://$nodeIP:$nodePort" # TODO - uncomment when webapp is built
|
#echo "To configure the app, please go to http://$nodeIP:$nodePort" # TODO - uncomment when webapp is built
|
||||||
echo "Thank you for joining the network!"
|
echo "Thank you for joining the network!"
|
||||||
|
|
||||||
if [[ "$confirm" != "y" && "$confirm" != "yes" ]]; then
|
if [[ "$confirm" == "y" && "$confirm" == "yes" ]]; then
|
||||||
# Prompt user to press any key before rebooting
|
# Prompt user to press any key before rebooting
|
||||||
read -rsp $'System will now reboot, press any key to continue or Ctrl+C to cancel...\n' -n1 key
|
read -rsp $'System will now reboot, press any key to continue or Ctrl+C to cancel...\n' -n1 key
|
||||||
echo "Rebooting..."
|
echo "Rebooting..."
|
||||||
|
|||||||
194
client/test/pdabHandler.test.js
Normal file
194
client/test/pdabHandler.test.js
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
// Import necessary modules for testing
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import io from 'socket.io-client';
|
||||||
|
const ioClient = io;
|
||||||
|
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
|
import { initDiscordBotClient, connectToChannel, leaveVoiceChannel, checkIfConnectedToVC, requestDiscordUsername, requestDiscordID, requestDiscordClientClose, closePdabSocketServer } from '../discordAudioBot/pdabHandler.mjs';
|
||||||
|
|
||||||
|
let socket;
|
||||||
|
|
||||||
|
before(async done => {
|
||||||
|
// Any setup needed before tests
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await closePdabSocketServer();
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Socket Server Tests', done => {
|
||||||
|
after(async () => {
|
||||||
|
// Any teardown needed after tests
|
||||||
|
try {
|
||||||
|
await socket.close();
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
console.log("Socket already closed");
|
||||||
|
}
|
||||||
|
console.log('Closing PDAB Socker Server');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should open a socket server and callback when the client is connected and ready', done => {
|
||||||
|
const clientId = process.env.TEST_CLIENT_TOKEN;
|
||||||
|
|
||||||
|
const callback = () => {
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
initDiscordBotClient(clientId, callback, false);
|
||||||
|
|
||||||
|
socket = ioClient.connect(`http://localhost:${process.env.PDAB_PORT}`);
|
||||||
|
|
||||||
|
socket.on('connect', () => {
|
||||||
|
socket.emit('discord_ready')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return status from join server', async () => {
|
||||||
|
socket.on('join_server', (data, callback) => {
|
||||||
|
console.log('Join data from server:', data);
|
||||||
|
expect(data).to.deep.equal({ channelId: process.env.TEST_CHANNEL_ID });
|
||||||
|
callback(true, true);
|
||||||
|
})
|
||||||
|
|
||||||
|
// Simulate emitting 'join_server' event
|
||||||
|
const status = await connectToChannel(process.env.TEST_CHANNEL_ID);
|
||||||
|
|
||||||
|
// Check the server sent the expected info
|
||||||
|
|
||||||
|
// Assert the status returned from the server
|
||||||
|
expect(status).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return open status for leave server', async () => {
|
||||||
|
socket.on('leave_server', (data, callback) => {
|
||||||
|
console.log('Leave data from server:', data);
|
||||||
|
expect(data).to.deep.equal({ guildId: process.env.TEST_GUILD_ID });
|
||||||
|
callback(false, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Simulate emitting 'leave_server' event
|
||||||
|
const openStatus = await leaveVoiceChannel(process.env.TEST_GUILD_ID);
|
||||||
|
|
||||||
|
// Assert the open status returned from the server
|
||||||
|
expect(openStatus).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return status if connected to voice channel', async () => {
|
||||||
|
socket.on('check_discord_vc_connected', (data, callback) => {
|
||||||
|
console.log('Client Check data:', data);
|
||||||
|
expect(data).to.deep.equal({ guildId: process.env.TEST_GUILD_ID });
|
||||||
|
callback(true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Simulate emitting 'check_discord_vc_connected' event
|
||||||
|
const isConnected = await checkIfConnectedToVC(process.env.TEST_GUILD_ID);
|
||||||
|
|
||||||
|
// Assert the connection status returned from the server
|
||||||
|
expect(isConnected).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return username for request discord username', async () => {
|
||||||
|
socket.on('request_discord_username', (data, callback) => {
|
||||||
|
console.log('Username Check data:', data);
|
||||||
|
expect(data).to.deep.equal({ guildId: process.env.TEST_GUILD_ID });
|
||||||
|
callback(process.env.EXPECTED_USERNAME);
|
||||||
|
});
|
||||||
|
// Simulate emitting 'request_discord_username' event
|
||||||
|
const username = await requestDiscordUsername(process.env.TEST_GUILD_ID);
|
||||||
|
|
||||||
|
// Assert the username returned from the server
|
||||||
|
expect(username).to.equal(process.env.EXPECTED_USERNAME);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return discord client ID', async () => {
|
||||||
|
socket.on('request_discord_id', (callback) => {
|
||||||
|
callback(process.env.EXPECTED_CLIENT_ID);
|
||||||
|
});
|
||||||
|
// Simulate emitting 'request_discord_id' event
|
||||||
|
const clientId = await requestDiscordID();
|
||||||
|
|
||||||
|
// Assert the client ID returned from the server
|
||||||
|
expect(clientId).to.equal(process.env.EXPECTED_CLIENT_ID);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for discord client to close', done => {
|
||||||
|
socket.on('request_client_close', async () => {
|
||||||
|
await socket.close();
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
// Simulate emitting 'request_client_close' event
|
||||||
|
requestDiscordClientClose();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Socket Client & Python IPC Tests', done => {
|
||||||
|
it('Should open a socket server and callback when the client is connected and ready', done => {
|
||||||
|
let clientConnected = false;
|
||||||
|
const clientId = process.env.TEST_CLIENT_TOKEN;
|
||||||
|
|
||||||
|
const callback = () => {
|
||||||
|
clientConnected = true;
|
||||||
|
expect(clientConnected).to.be.true;
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
initDiscordBotClient(clientId, callback);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return status from join server', async () => {
|
||||||
|
// Simulate emitting 'join_server' event
|
||||||
|
const status = await connectToChannel(process.env.TEST_CHANNEL_ID);
|
||||||
|
|
||||||
|
// Check the server sent the expected info
|
||||||
|
|
||||||
|
// Assert the status returned from the server
|
||||||
|
expect(status).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return status if connected to voice channel', async () => {
|
||||||
|
// Simulate emitting 'check_discord_vc_connected' event
|
||||||
|
const isConnected = await checkIfConnectedToVC(process.env.TEST_GUILD_ID);
|
||||||
|
|
||||||
|
// Assert the connection status returned from the server
|
||||||
|
expect(isConnected).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return username for request discord username', async () => {
|
||||||
|
// Simulate emitting 'request_discord_username' event
|
||||||
|
const username = await requestDiscordUsername(process.env.TEST_GUILD_ID);
|
||||||
|
|
||||||
|
// Assert the username returned from the server
|
||||||
|
expect(username).to.equal(process.env.EXPECTED_USERNAME);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return discord client ID', async () => {
|
||||||
|
// Simulate emitting 'request_discord_id' event
|
||||||
|
const clientId = await requestDiscordID();
|
||||||
|
|
||||||
|
console.log("type of client id", typeof clientId, typeof process.env.EXPECTED_CLIENT_ID);
|
||||||
|
|
||||||
|
// Assert the client ID returned from the server
|
||||||
|
expect(clientId).to.equal(Number(process.env.EXPECTED_CLIENT_ID));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for and return open status for leave server', async () => {
|
||||||
|
// Simulate emitting 'leave_server' event
|
||||||
|
const openStatus = await leaveVoiceChannel(process.env.TEST_GUILD_ID);
|
||||||
|
|
||||||
|
// Assert the open status returned from the server
|
||||||
|
expect(openStatus).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should emit command for discord client to close', async () => {
|
||||||
|
// Simulate emitting 'request_client_close' event
|
||||||
|
await requestDiscordClientClose();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
40
client/test/pdabWrappers.test.js.bak
Normal file
40
client/test/pdabWrappers.test.js.bak
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { use } from 'chai';
|
||||||
|
import chaiHttp from 'chai-http';
|
||||||
|
const chai = use(chaiHttp)
|
||||||
|
chai.should();
|
||||||
|
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
|
import { joinDiscordVC, leaveDiscordVC } from '../discordAudioBot/pdabWrappers.mjs'
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
// Any setup needed before tests
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
// Any teardown needed after tests
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PDAB Wrapper Tests', () => {
|
||||||
|
it('Should open the discord bot, and join the first server when requested', async () => {
|
||||||
|
// Test case
|
||||||
|
const joinData = {
|
||||||
|
channelID: process.env.TEST_CHANNEL_ID,
|
||||||
|
clientID: process.env.TEST_CLIENT_TOKEN,
|
||||||
|
system: process.env.TEST_SYSTEM,
|
||||||
|
};
|
||||||
|
const connection = await joinDiscordVC(joinData);
|
||||||
|
console.log("Connection:", connection);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should open OP25', async () => {
|
||||||
|
const res = await chai.request('http://localhost:8081').get('/');
|
||||||
|
expect(res).to.have.status(200); // Assuming 200 is the expected status code
|
||||||
|
// Add more assertions if needed
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should disconnect from the discord server", async () => {
|
||||||
|
await leaveDiscordVC(process.env.TEST_GUILD_ID);
|
||||||
|
})
|
||||||
|
});
|
||||||
21
server/Dockerfile
Normal file
21
server/Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Use the official Node.js image as the base image
|
||||||
|
FROM node:20
|
||||||
|
|
||||||
|
# Set the working directory inside the container
|
||||||
|
WORKDIR /server
|
||||||
|
|
||||||
|
# Copy package.json and package-lock.json (if available) to the working directory
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm install -g node-gyp
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy the rest of the application code to the working directory
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose the port on which your Node.js application will run
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Command to run the Node.js application
|
||||||
|
CMD ["node", "."]
|
||||||
@@ -41,9 +41,10 @@ export async function autocomplete(nodeIo, interaction) {
|
|||||||
*/
|
*/
|
||||||
export async function execute(nodeIo, interaction) {
|
export async function execute(nodeIo, interaction) {
|
||||||
// Check if the user is in a VC
|
// Check if the user is in a VC
|
||||||
if (!interaction.member.voice.channel) { return await interaction.editReply({ content: `<@${interaction.member.id}>, you need to enter a voice channel before use the command`, ephemeral: true }) }
|
if (!interaction.member.voice.channel) { return await interaction.editReply({ content: `<@${interaction.member.id}>, you need to enter a voice channel before you use this command`, ephemeral: true }) }
|
||||||
// Grab the channel if the user is connected to VC
|
// Grab the channel if the user is connected to VC
|
||||||
const channelToJoin = interaction.member.voice.channel;
|
const channelToJoin = interaction.member.voice.channel;
|
||||||
|
console.log(`The user '${interaction.member.id}' is in the voice channel '${channelToJoin}'`);
|
||||||
|
|
||||||
// Get the selected system option from the command interaction
|
// Get the selected system option from the command interaction
|
||||||
const selectedSystem = interaction.options.getString('system');
|
const selectedSystem = interaction.options.getString('system');
|
||||||
@@ -56,13 +57,19 @@ export async function execute(nodeIo, interaction) {
|
|||||||
const joinSelectedNode = async (selectedNodeSocketId) => {
|
const joinSelectedNode = async (selectedNodeSocketId) => {
|
||||||
const openSocket = await nodeIo.sockets.sockets.get(selectedNodeSocketId);
|
const openSocket = await nodeIo.sockets.sockets.get(selectedNodeSocketId);
|
||||||
// Get the open ID for this connection\
|
// Get the open ID for this connection\
|
||||||
const discordToken = await getAvailableTokensInGuild(nodeIo, interaction.guild.id);
|
const ss = await getAvailableTokensInGuild(nodeIo, interaction.guild.id);
|
||||||
// TODO - Implement a method to have preferred tokens (bot users) for specific systems
|
console.log("Available discord tokens: ", discordTokens);
|
||||||
|
|
||||||
console.log("Joining selected open socket:", selectedNodeSocketId, system.name, channelToJoin.id, openSocket.node.name, discordToken);
|
if (discordTokens.length >= 1) {
|
||||||
|
// TODO - Implement a method to have preferred tokens (bot users) for specific systems
|
||||||
|
console.log("Joining selected open socket:", selectedNodeSocketId, system.name, channelToJoin.id, openSocket.node.name, discordTokens[0].token);
|
||||||
|
|
||||||
// Ask the node to join the selected channel and system
|
// Ask the node to join the selected channel and system
|
||||||
await requestNodeJoinSystem(openSocket, system.name, channelToJoin.id, discordToken[0].token);
|
await requestNodeJoinSystem(openSocket, system.name, channelToJoin.id, discordTokens[0].token);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return await interaction.editReply({ content: `<@${interaction.member.id}>, there are no free bots. Free up or create a new bot ID (discord app) to listen to this system.`, ephemeral: true })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all open socket nodes
|
// Get all open socket nodes
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export function addEnabledEventListeners(serverClient, _eventsPath = "./events")
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The discord client
|
// The discord client
|
||||||
export const serverClient = new Client({ intents: [GatewayIntentBits.Guilds] });
|
export const serverClient = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates] });
|
||||||
|
|
||||||
// Run when the bot is ready
|
// Run when the bot is ready
|
||||||
serverClient.on('ready', async () => {
|
serverClient.on('ready', async () => {
|
||||||
|
|||||||
@@ -37,10 +37,7 @@ export const checkOnlineBotsInGuild = async (nodeIo, guildId) => {
|
|||||||
console.log("Online bots in the guild:", onlineBots);
|
console.log("Online bots in the guild:", onlineBots);
|
||||||
|
|
||||||
// Filter any discordIDs that are not active
|
// Filter any discordIDs that are not active
|
||||||
var availableDiscordIDs = discordIDs.filter(discordID => discordID.active == true);
|
const availableDiscordIDs = discordIDs.filter(discordID => discordID.active == true).filter(discordID => !onlineBots.some(bot => Number(bot.discord_id) == discordID.discord_id));
|
||||||
|
|
||||||
// Filter out discordIDs that are not found in onlineBots
|
|
||||||
availableDiscordIDs = availableDiscordIDs.filter(discordID => !onlineBots.some(bot => bot.discord_id === discordID.discord_id));
|
|
||||||
|
|
||||||
// Return the unavailable discordIDs
|
// Return the unavailable discordIDs
|
||||||
return availableDiscordIDs;
|
return availableDiscordIDs;
|
||||||
|
|||||||
25
server/makefile
Normal file
25
server/makefile
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Define variables
|
||||||
|
DOCKER_IMAGE_NAME := drb-server
|
||||||
|
|
||||||
|
# Define targets and rules
|
||||||
|
.PHONY: clean build run
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning existing Docker images, containers, and builds..."
|
||||||
|
docker stop drb || true
|
||||||
|
docker rm drb || true
|
||||||
|
docker rmi $(DOCKER_IMAGE_NAME) || true
|
||||||
|
|
||||||
|
build:
|
||||||
|
@echo "Building Docker image..."
|
||||||
|
docker build -t $(DOCKER_IMAGE_NAME) .
|
||||||
|
|
||||||
|
run:
|
||||||
|
@echo "Running Docker container..."
|
||||||
|
docker run -d -e NODE_ENV=${NODE_ENV} \
|
||||||
|
-e SERVER_PORT=${SERVER_PORT} \
|
||||||
|
-e MONGO_URL=${MONGO_URL} \
|
||||||
|
-e DISCORD_TOKEN=${DISCORD_TOKEN} \
|
||||||
|
-p ${SERVER_PORT}:${SERVER_PORT} \
|
||||||
|
--name=drb \
|
||||||
|
$(DOCKER_IMAGE_NAME)
|
||||||
@@ -17,13 +17,19 @@ app.get('/', (req, res) => {
|
|||||||
nodeIo.on('connection', (socket) => {
|
nodeIo.on('connection', (socket) => {
|
||||||
console.log('a user connected', socket.id);
|
console.log('a user connected', socket.id);
|
||||||
|
|
||||||
socket.on('node-login', (data) => {
|
socket.on('node-login', async (data) => {
|
||||||
nodeLoginWrapper(data, socket);
|
await nodeLoginWrapper(data, socket);
|
||||||
|
await socket.emit('node-login-successful');
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('node-update', (data) => {
|
socket.on('node-update', async (data) => {
|
||||||
nodeUpdateWrapper(data.node);
|
let tempPromises = [];
|
||||||
nearbySystemsUpdateWraper(data.node.nuid, data.nearbySystems)
|
tempPromises.push(nodeUpdateWrapper(data.node));
|
||||||
|
tempPromises.push(nearbySystemsUpdateWraper(data.node.nuid, data.nearbySystems));
|
||||||
|
|
||||||
|
await Promise.all(tempPromises);
|
||||||
|
|
||||||
|
await socket.emit('node-update-successful')
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
@@ -31,8 +37,3 @@ nodeIo.on('connection', (socket) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Startup the node server
|
|
||||||
server.listen(3000, () => {
|
|
||||||
console.log('server running at http://localhost:3000');
|
|
||||||
});
|
|
||||||
@@ -28,15 +28,17 @@ export const nodeLoginWrapper = async (data, socket) => {
|
|||||||
console.log("After grabbing", node);
|
console.log("After grabbing", node);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
const insertedId = await createNode(data);
|
const insertedId = await createNode(data);
|
||||||
node = await getNodeByNuid(data.nuid);
|
|
||||||
console.log("Added new node to the database:", insertedId);
|
console.log("Added new node to the database:", insertedId);
|
||||||
|
} else {
|
||||||
|
// Check for updates
|
||||||
|
const updatedNode = await updateNodeByNuid(data.nuid, data)
|
||||||
|
console.log("Updated node:", updatedNode);
|
||||||
}
|
}
|
||||||
// Check for updates if so
|
|
||||||
// Check for System updates
|
node = await getNodeByNuid(data.nuid);
|
||||||
|
|
||||||
// Add the socket/node connection
|
// Add the socket/node connection
|
||||||
socket.node = node;
|
socket.node = node;
|
||||||
//socket.id = node.nuid;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
980
server/package-lock.json
generated
980
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,15 +4,16 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "mocha --timeout 5000",
|
||||||
"start": "node server.js"
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"author": "Logan Cusano",
|
"author": "Logan Cusano",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "^8.4.0",
|
"chai": "^5.1.0",
|
||||||
"chai": "^4.3.4"
|
"mocha": "^10.4.0",
|
||||||
|
"socket.io-client": "^4.7.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^14.14.1",
|
"discord.js": "^14.14.1",
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ import { serverClient, addEnabledEventListeners } from './discordBot/discordBot.
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
|
// Startup the node server
|
||||||
|
server.listen(process.env.SERVER_PORT || 3000, () => {
|
||||||
|
console.log(`server running at http://localhost:${process.env.SERVER_PORT}`);
|
||||||
|
});
|
||||||
|
|
||||||
// Add objects to the others
|
// Add objects to the others
|
||||||
serverClient.nodeIo = nodeIo;
|
serverClient.nodeIo = nodeIo;
|
||||||
nodeIo.serverClient = serverClient;
|
nodeIo.serverClient = serverClient;
|
||||||
|
|||||||
290
server/test/socketServerWrappers.test.js
Normal file
290
server/test/socketServerWrappers.test.js
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
// Import necessary modules for testing
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import ioClient from 'socket.io-client';
|
||||||
|
import { deleteNodeByNuid, getNodeByNuid } from '../modules/mongoNodesWrappers.mjs';
|
||||||
|
import { deleteSystemByName, getSystemByName } from '../modules/mongoSystemsWrappers.mjs';
|
||||||
|
import { nodeIo } from '../modules/socketServer.mjs';
|
||||||
|
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
|
process.env.SERVER_PORT = 6000
|
||||||
|
|
||||||
|
// Define necessary variables for testing, such as mocked database connections or socket instances
|
||||||
|
const localNodeConfig = {
|
||||||
|
serverIp: 'localhost',
|
||||||
|
serverPort: process.env.SERVER_PORT,
|
||||||
|
node: {
|
||||||
|
nuid: "4f29a6340901a12affc87047c0ac16b01b92496c460c880a2459abe8c7928374",
|
||||||
|
name: "testyv7",
|
||||||
|
location: "china",
|
||||||
|
capabilities: ["radio"]
|
||||||
|
},
|
||||||
|
nearbySystems: {
|
||||||
|
"Testing P25 System Name": {
|
||||||
|
"frequencies": [
|
||||||
|
155344000,
|
||||||
|
155444000,
|
||||||
|
155555000,
|
||||||
|
155588550
|
||||||
|
],
|
||||||
|
"mode": "p25",
|
||||||
|
"trunkFile": "trunk.tsv",
|
||||||
|
"whitelistFile": "whitelist.tsv"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatedLocalNodeConfig = {
|
||||||
|
node: {
|
||||||
|
nuid: localNodeConfig.node.nuid,
|
||||||
|
name: "updatedName",
|
||||||
|
location: "updatedLocation",
|
||||||
|
capabilities: ["radio", "weather"] // Updated capabilities
|
||||||
|
},
|
||||||
|
nearbySystems: {
|
||||||
|
"Testing P25 System Name": {
|
||||||
|
"frequencies": [
|
||||||
|
155444000,
|
||||||
|
155555000,
|
||||||
|
155500000
|
||||||
|
],
|
||||||
|
"mode": "p25",
|
||||||
|
"trunkFile": "trunk2.tsv",
|
||||||
|
"whitelistFile": "whitelist2.tsv"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start the Socket.IO server before running tests
|
||||||
|
let clientSocket; // The socket client
|
||||||
|
let serverClientSocket // The open client socket on the server
|
||||||
|
before(done => {
|
||||||
|
// Startup the node server
|
||||||
|
nodeIo.listen(process.env.SERVER_PORT || 3000, () => {
|
||||||
|
console.log(`server running at http://localhost:${process.env.SERVER_PORT}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect a client socket to the server
|
||||||
|
clientSocket = ioClient.connect(`http://localhost:${process.env.SERVER_PORT}`);
|
||||||
|
|
||||||
|
nodeIo.on('connection', (socket) => {
|
||||||
|
serverClientSocket = socket;
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close the Socket.IO server after running tests
|
||||||
|
after(async () => {
|
||||||
|
// Disconnect client socket
|
||||||
|
clientSocket.disconnect();
|
||||||
|
|
||||||
|
// Close the server
|
||||||
|
nodeIo.close();
|
||||||
|
|
||||||
|
// Remove the test data
|
||||||
|
deleteNodeByNuid(localNodeConfig.node.nuid); // Delete the user
|
||||||
|
deleteSystemByName(Object.keys(localNodeConfig.nearbySystems)[0])
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Node Core Server Tests', () => {
|
||||||
|
// Test Node Login functionality
|
||||||
|
describe('Node Login', () => {
|
||||||
|
it('Should add a new node if it does not exist', async () => {
|
||||||
|
// Simulate a node login request
|
||||||
|
// Use the getNodeByNuid mock function to simulate checking if node exists
|
||||||
|
const existingNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
// Assert that existingNode is null before node login
|
||||||
|
expect(existingNode).to.be.null;
|
||||||
|
|
||||||
|
// Wait for the update
|
||||||
|
const node_login = new Promise(res => {
|
||||||
|
clientSocket.on('node-login-successful', async () => {
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit the login command
|
||||||
|
clientSocket.emit("node-login", localNodeConfig.node);
|
||||||
|
|
||||||
|
// Wait for the successful login event
|
||||||
|
await node_login;
|
||||||
|
|
||||||
|
// Now we need to check if the node is added to the database
|
||||||
|
// We can use getNodeByNuid again to verify if the node was added correctly
|
||||||
|
const addedNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
console.log("Added Node:", addedNode);
|
||||||
|
|
||||||
|
// Assert that the node is added correctly
|
||||||
|
expect(addedNode).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(addedNode).to.have.property('nuid', localNodeConfig.node.nuid);
|
||||||
|
expect(addedNode).to.have.property('name', localNodeConfig.node.name);
|
||||||
|
expect(addedNode).to.have.property('location', localNodeConfig.node.location);
|
||||||
|
expect(addedNode).to.have.deep.property('capabilities', localNodeConfig.node.capabilities);
|
||||||
|
})
|
||||||
|
it('Should update a node if it exists', async () => {
|
||||||
|
// Simulate a node login request
|
||||||
|
// Use the getNodeByNuid mock function to simulate checking if node exists
|
||||||
|
const existingNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
// Assert that existingNode is matches the existing data before logging in
|
||||||
|
expect(existingNode).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(existingNode).to.have.property('nuid', localNodeConfig.node.nuid);
|
||||||
|
expect(existingNode).to.have.property('name', localNodeConfig.node.name);
|
||||||
|
expect(existingNode).to.have.property('location', localNodeConfig.node.location);
|
||||||
|
expect(existingNode).to.have.deep.property('capabilities', localNodeConfig.node.capabilities);
|
||||||
|
|
||||||
|
// Wait for the update
|
||||||
|
const node_login = new Promise(res => {
|
||||||
|
clientSocket.on('node-login-successful', async () => {
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit the login command
|
||||||
|
clientSocket.emit("node-login", updatedLocalNodeConfig.node);
|
||||||
|
|
||||||
|
// Wait for the successful login event
|
||||||
|
await node_login;
|
||||||
|
|
||||||
|
// Now we need to check if the node is added to the database
|
||||||
|
// We can use getNodeByNuid again to verify if the node was added correctly
|
||||||
|
const updatedNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
console.log("Updated Node:", updatedNode);
|
||||||
|
|
||||||
|
// Assert that the node is added correctly
|
||||||
|
expect(updatedNode).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(updatedNode).to.have.property('nuid', updatedLocalNodeConfig.node.nuid);
|
||||||
|
expect(updatedNode).to.have.property('name', updatedLocalNodeConfig.node.name);
|
||||||
|
expect(updatedNode).to.have.property('location', updatedLocalNodeConfig.node.location);
|
||||||
|
expect(updatedNode).to.have.deep.property('capabilities', updatedLocalNodeConfig.node.capabilities);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test Node Update functionality
|
||||||
|
describe('Node Update', () => {
|
||||||
|
it('Should add a node\'s nearby systems', async () => {
|
||||||
|
// Simulate an update request sent from the client to the server
|
||||||
|
|
||||||
|
// Get the existing node in the database
|
||||||
|
const existingNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
// Assert that existingNode matches the updatedLocalNodeConfig
|
||||||
|
expect(existingNode).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(existingNode).to.have.property('nuid', updatedLocalNodeConfig.node.nuid);
|
||||||
|
expect(existingNode).to.have.property('name', updatedLocalNodeConfig.node.name);
|
||||||
|
expect(existingNode).to.have.property('location', updatedLocalNodeConfig.node.location);
|
||||||
|
expect(existingNode).to.have.deep.property('capabilities', updatedLocalNodeConfig.node.capabilities);
|
||||||
|
|
||||||
|
// Get the system from the DB
|
||||||
|
const existsingSystem = await getSystemByName("Testing P25 System Name");
|
||||||
|
|
||||||
|
// Assert that there is no existing system in the DB
|
||||||
|
expect(existsingSystem).to.be.null;
|
||||||
|
|
||||||
|
// Wait for the update
|
||||||
|
const node_system_update = new Promise(res => {
|
||||||
|
clientSocket.on('node-update-successful', async () => {
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit the update command
|
||||||
|
clientSocket.emit("node-update", updatedLocalNodeConfig);
|
||||||
|
|
||||||
|
// Wait for the successful update event
|
||||||
|
await node_system_update;
|
||||||
|
|
||||||
|
// Now we need to check if the system is added to the database
|
||||||
|
// We can use getNodeByNuid again to verify if the node was added correctly
|
||||||
|
const updatedNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
console.log("Updated Node:", updatedNode);
|
||||||
|
|
||||||
|
// Assert that the node is added correctly
|
||||||
|
expect(updatedNode).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(updatedNode).to.have.property('nuid', updatedLocalNodeConfig.node.nuid);
|
||||||
|
expect(updatedNode).to.have.property('name', updatedLocalNodeConfig.node.name);
|
||||||
|
expect(updatedNode).to.have.property('location', updatedLocalNodeConfig.node.location);
|
||||||
|
expect(updatedNode).to.have.deep.property('capabilities', updatedLocalNodeConfig.node.capabilities);
|
||||||
|
|
||||||
|
// Get the updated system
|
||||||
|
const addedSystem = await getSystemByName("Testing P25 System Name");
|
||||||
|
|
||||||
|
console.log("Added system:", addedSystem);
|
||||||
|
|
||||||
|
expect(addedSystem).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(addedSystem).to.have.property('nodes'); // Check if nodes property exists
|
||||||
|
expect(addedSystem.nodes).to.include(updatedLocalNodeConfig.node.nuid) // Check if this node ID is in the nodes array
|
||||||
|
expect(addedSystem).to.have.deep.property('frequencies', updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].frequencies);
|
||||||
|
expect(addedSystem).to.have.property('mode', updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].mode);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should update a node and its nearby systems', async () => {
|
||||||
|
// Get the existing node in the database
|
||||||
|
const existingNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
// Assert that existingNode matches the updatedLocalNodeConfig
|
||||||
|
expect(existingNode).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(existingNode).to.have.property('nuid', updatedLocalNodeConfig.node.nuid);
|
||||||
|
expect(existingNode).to.have.property('name', updatedLocalNodeConfig.node.name);
|
||||||
|
expect(existingNode).to.have.property('location', updatedLocalNodeConfig.node.location);
|
||||||
|
expect(existingNode).to.have.deep.property('capabilities', updatedLocalNodeConfig.node.capabilities);
|
||||||
|
|
||||||
|
// Get the updated system
|
||||||
|
const existingSystem = await getSystemByName("Testing P25 System Name");
|
||||||
|
expect(existingSystem).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(existingSystem).to.have.property('nodes'); // Check if nodes property exists
|
||||||
|
expect(existingSystem.nodes).to.include(updatedLocalNodeConfig.node.nuid) // Check if this node ID is in the nodes array
|
||||||
|
expect(existingSystem).to.have.deep.property('frequencies', updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].frequencies);
|
||||||
|
expect(existingSystem).to.have.property('mode', updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].mode);
|
||||||
|
|
||||||
|
|
||||||
|
// Wait for the update
|
||||||
|
const node_update = new Promise(res => {
|
||||||
|
clientSocket.on('node-update-successful', async () => {
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit the update command
|
||||||
|
clientSocket.emit("node-update", localNodeConfig);
|
||||||
|
|
||||||
|
// Wait for the successful update event
|
||||||
|
await node_update;
|
||||||
|
|
||||||
|
const updatedNode = await getNodeByNuid(localNodeConfig.node.nuid);
|
||||||
|
|
||||||
|
console.log("Updated Node:", updatedNode);
|
||||||
|
|
||||||
|
// Assert that the node is added correctly
|
||||||
|
expect(updatedNode).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(updatedNode).to.have.property('nuid', localNodeConfig.node.nuid);
|
||||||
|
expect(updatedNode).to.have.property('name', localNodeConfig.node.name);
|
||||||
|
expect(updatedNode).to.have.property('location', localNodeConfig.node.location);
|
||||||
|
expect(updatedNode).to.have.deep.property('capabilities', localNodeConfig.node.capabilities);
|
||||||
|
|
||||||
|
// Get the updated system
|
||||||
|
const updatedSystem = await getSystemByName("Testing P25 System Name");
|
||||||
|
|
||||||
|
console.log("Updated system:", updatedSystem);
|
||||||
|
|
||||||
|
expect(updatedSystem).to.have.property('_id'); // Check if _id property exists
|
||||||
|
expect(updatedSystem).to.have.property('nodes'); // Check if nodes property exists
|
||||||
|
expect(updatedSystem.nodes).include(localNodeConfig.node.nuid) // Check if this node ID is in the nodes array
|
||||||
|
expect(updatedSystem).to.have.deep.property('frequencies', localNodeConfig.nearbySystems['Testing P25 System Name'].frequencies);
|
||||||
|
expect(updatedSystem).to.have.property('mode', localNodeConfig.nearbySystems['Testing P25 System Name'].mode);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Node Disconnect', () => {
|
||||||
|
it('Should trigger cleanup actions upon socket disconnection', async () => {
|
||||||
|
// Write test code to simulate a socket disconnection
|
||||||
|
// Check if the appropriate cleanup actions are triggered
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import { expect } from 'chai';
|
|
||||||
import { createNode, getNodeByNuid, updateNodeByNuid } from '../modules/mongoNodesWrappers'; // Import necessary functions from your wrappers
|
|
||||||
import { nodeLoginWrapper, nodeUpdateWrapper, nearbySystemsUpdateWraper } from '../modules/socketServerWrappers'; // Import the functions you want to test
|
|
||||||
import { ClientNodeObject, ClientNodeConfig } from '../../client/modules/clientObjectDefinitions.mjs'; // Import the objects definitions
|
|
||||||
|
|
||||||
describe('Socket Server Wrappers', function() {
|
|
||||||
describe('nodeLoginWrapper', function() {
|
|
||||||
it('should create a new node if it does not exist', async function() {
|
|
||||||
const socket = {
|
|
||||||
node: undefined, // Initialize a socket with no node
|
|
||||||
id: 'mockSocketId' // Mock socket id
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mock data using ClientNodeConfig object
|
|
||||||
const config = new ClientNodeConfig({
|
|
||||||
_nuid: 'mockNuid',
|
|
||||||
_name: 'mockName',
|
|
||||||
_location: 'mockLocation',
|
|
||||||
_capabilities: { /* mock capabilities */ }
|
|
||||||
});
|
|
||||||
|
|
||||||
await nodeLoginWrapper(config, socket);
|
|
||||||
|
|
||||||
// Check if the node was created
|
|
||||||
const createdNode = await getNodeByNuid('mockNuid');
|
|
||||||
expect(createdNode).to.exist;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add more test cases as needed
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nodeUpdateWrapper', function() {
|
|
||||||
it('should update the node data in the database', async function() {
|
|
||||||
// Mock node data using ClientNodeObject
|
|
||||||
const nodeData = new ClientNodeObject({
|
|
||||||
_nuid: 'mockNuid',
|
|
||||||
_name: 'mockName',
|
|
||||||
_location: 'mockLocation',
|
|
||||||
_capabilities: { /* mock capabilities */ }
|
|
||||||
});
|
|
||||||
|
|
||||||
await nodeUpdateWrapper(nodeData);
|
|
||||||
|
|
||||||
// Check if the node was updated in the database
|
|
||||||
const updatedNode = await getNodeByNuid('mockNuid');
|
|
||||||
// Assert that the node has been updated with the new data
|
|
||||||
expect(updatedNode).to.deep.include({
|
|
||||||
nuid: 'mockNuid',
|
|
||||||
name: 'mockName',
|
|
||||||
location: 'mockLocation',
|
|
||||||
capabilities: { /* mock capabilities */ }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add more test cases as needed
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nearbySystemsUpdateWraper', function() {
|
|
||||||
it('should update nearby systems in the database', async function() {
|
|
||||||
// Mock nearby systems data
|
|
||||||
const nearbySystems = {
|
|
||||||
// Mock nearby systems data
|
|
||||||
};
|
|
||||||
const nuid = 'mockNuid'; // Mock nuid
|
|
||||||
|
|
||||||
await nearbySystemsUpdateWraper(nuid, nearbySystems);
|
|
||||||
|
|
||||||
// Perform assertions to ensure nearby systems are updated correctly
|
|
||||||
// You may need to check the database for updated nearby systems
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add more test cases as needed
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add more describe blocks for other functions and their respective test cases
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user