Compare commits

...

103 Commits

Author SHA1 Message Date
Logan Cusano
a4d07db766 #16 Update variable name
Some checks failed
DRB Server Build / drb_server_build (push) Successful in 36s
DRB Tests / drb_mocha_tests (push) Failing after 1m13s
2024-05-11 14:40:10 -04:00
Logan Cusano
03c940e07c Update PDAB handler
- Move PDAB socket server startup to function
- Updated join server wrapper to start the server before opening the python app
2024-05-05 23:39:05 -04:00
Logan Cusano
fee40dd609 #16 Updated join
-  After getting all available IDs, it now checks if there are IDs. If not telling the user
2024-05-05 22:00:04 -04:00
Logan Cusano
5671503594 Omitting OP25 update in the post update for now 2024-05-05 18:29:06 -04:00
Logan Cusano
0fd511cfaf Adding handlers for discord presense 2024-05-05 18:24:59 -04:00
Logan Cusano
9d0aa0191f Resolve bug when selecting ID on join 2024-05-05 18:24:11 -04:00
Logan Cusano
9ce8928d82 Revert base image and add global gyp install
Some checks failed
DRB Server Build / drb_server_build (push) Successful in 24s
DRB Tests / drb_mocha_tests (push) Failing after 59s
2024-04-29 23:25:34 -04:00
Logan Cusano
abadcf5cb5 Change base image of the dockerfile
Some checks failed
DRB Server Build / drb_server_build (push) Failing after 9s
DRB Tests / drb_mocha_tests (push) Failing after 1m38s
2024-04-29 22:16:17 -04:00
Logan Cusano
4b18df9e2c Fix server build name and removed clean and run code, just update
Some checks failed
DRB Server Build / drb_server_build (push) Successful in 6s
DRB Tests / drb_mocha_tests (push) Failing after 58s
2024-04-29 01:28:18 -04:00
Logan Cusano
26a8d8a172 Update build to clean and run the container
All checks were successful
DRB Server Build / drb_mocha_tests (push) Successful in 6s
2024-04-29 01:20:50 -04:00
Logan Cusano
26f3493c8f Remove node setup from build action
Some checks failed
DRB Tests / drb_mocha_tests (push) Failing after 58s
DRB Server Build / drb_mocha_tests (push) Successful in 8s
2024-04-29 01:17:14 -04:00
Logan Cusano
fd261ef015 Missed addition
Some checks failed
DRB Server Build / drb_mocha_tests (push) Failing after 7s
DRB Tests / drb_mocha_tests (push) Failing after 55s
- Server build action
2024-04-29 01:13:00 -04:00
Logan Cusano
91201c3527 Update tests
- Update test names
- Added new action to build the latest server code on the server it's running on
- Removed unnecessary vars from makefile
2024-04-29 01:12:30 -04:00
Logan Cusano
dfb4c6afa1 Remove build from tests 2024-04-28 22:52:39 -04:00
Logan Cusano
3b8e70208a Update build tests
Some checks failed
DRB Build Tests / build (push) Failing after 5s
DRB Build Tests / drb_build_and_test (push) Failing after 53s
Start docker in the test
2024-04-28 22:22:01 -04:00
Logan Cusano
99b60bf02c Update build tests
Some checks failed
DRB Build Tests / build (push) Failing after 5s
DRB Build Tests / drb_build_and_test (push) Failing after 58s
2024-04-28 22:19:09 -04:00
Logan Cusano
831317b9f0 Update build test
Some checks failed
DRB Build Tests / build (push) Failing after 7s
DRB Build Tests / drb_build_and_test (push) Failing after 56s
- Switch to installing docker io
2024-04-28 20:13:25 -04:00
Logan Cusano
2477b10900 Add docker install step to build test
Some checks failed
DRB Build Tests / build (push) Failing after 1m17s
DRB Build Tests / drb_build_and_test (push) Failing after 57s
2024-04-28 06:08:57 -04:00
Logan Cusano
67c29f1d72 Remove gitea debug after potential resolution
Some checks failed
DRB Build Tests / build (push) Failing after 8s
DRB Build Tests / drb_build_and_test (push) Failing after 1m1s
2024-04-28 06:07:06 -04:00
Logan Cusano
91ed4fb1dc gitea debug 2
Some checks failed
DRB Build Tests / build (push) Failing after 1m3s
DRB Build Tests / drb_build_and_test (push) Failing after 1m31s
2024-04-28 05:50:52 -04:00
Logan Cusano
8ea02d1c0b gitea debug
Some checks failed
DRB Build Tests / build (push) Failing after 16s
DRB Build Tests / drb_build_and_test (push) Has been cancelled
2024-04-28 05:49:57 -04:00
Logan Cusano
b15ac7c973 Added working directory to build step
Some checks failed
DRB Build Tests / build (push) Failing after 14s
DRB Build Tests / drb_build_and_test (push) Failing after 52s
2024-04-28 05:32:54 -04:00
Logan Cusano
c2c90019d7 Update tests
Some checks failed
DRB Build Tests / build (push) Failing after 32s
DRB Build Tests / drb_build_and_test (push) Failing after 58s
2024-04-28 05:30:13 -04:00
Logan Cusano
686ddc8a0f Gitea runner debug
Some checks failed
DRB Build Tests / build (push) Failing after 25s
DRB Build Tests / drb_build_and_test (push) Failing after 41s
2024-04-28 05:22:20 -04:00
Logan Cusano
463ccc1bd5 Setup docker in the test
Some checks failed
DRB Build Tests / build (push) Failing after 1m13s
DRB Build Tests / drb_build_and_test (push) Failing after 59s
2024-04-28 05:17:08 -04:00
Logan Cusano
14a2b4a1b9 Update tests
Some checks failed
DRB Build Tests / build (push) Failing after 41s
DRB Build Tests / drb_build_and_test (push) Failing after 43s
- Output docker ps before curl
2024-04-28 05:13:40 -04:00
Logan Cusano
0c1f6cd867 Update dockerfile
Some checks failed
DRB Build Tests / build (push) Failing after 34s
DRB Build Tests / drb_build_and_test (push) Failing after 51s
- Use the startup command used in the terminal
2024-04-28 05:11:49 -04:00
Logan Cusano
7175487d77 Update makefile
Some checks failed
DRB Build Tests / build (push) Failing after 31s
DRB Build Tests / drb_build_and_test (push) Failing after 43s
- Run docker detached
2024-04-28 05:06:50 -04:00
Logan Cusano
f0eac45955 Replace space with tab in makefile
Some checks failed
DRB Build Tests / build (push) Failing after 12s
DRB Build Tests / drb_build_and_test (push) Has been cancelled
2024-04-28 05:05:43 -04:00
Logan Cusano
c81dce99e2 Update makefile with clean step
Some checks failed
DRB Build Tests / build (push) Failing after 7s
DRB Build Tests / drb_build_and_test (push) Has been cancelled
2024-04-28 05:04:52 -04:00
Logan Cusano
38cb1054e0 Add DISCORD_TOKEN var to tests and makefile
Some checks failed
DRB Build Tests / build (push) Failing after 12s
DRB Build Tests / drb_build_and_test (push) Failing after 59s
2024-04-28 05:00:10 -04:00
Logan Cusano
12441c5c6d Update makefile
Some checks failed
DRB Build Tests / build (push) Failing after 1m38s
DRB Build Tests / drb_build_and_test (push) Failing after 56s
- Mistake in the docker build path
2024-04-28 04:54:53 -04:00
Logan Cusano
1c1b071bd7 Update makefile
Some checks failed
DRB Build Tests / build (push) Failing after 9s
DRB Build Tests / drb_build_and_test (push) Has been cancelled
- Removed all spaces for tabs
2024-04-28 04:53:55 -04:00
Logan Cusano
961c5c19e2 Update drb tests
Some checks failed
DRB Build Tests / build (push) Failing after 7s
DRB Build Tests / drb_build_and_test (push) Failing after 56s
- Update working directory for make
2024-04-28 04:49:56 -04:00
Logan Cusano
49e52d8944 Add makefile for server and related action build test
Some checks failed
DRB Build Tests / build (push) Failing after 7s
DRB Build Tests / drb_build_and_test (push) Failing after 58s
2024-04-28 04:46:08 -04:00
Logan Cusano
63ccfa70d3 Add server docker file and related action tests
Some checks failed
DRB Build Tests / build (push) Failing after 15s
DRB Build Tests / drb_build_and_test (push) Failing after 1m2s
2024-04-28 04:34:15 -04:00
Logan Cusano
4bb8038a1d Update variables in test action
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 57s
2024-04-28 03:26:06 -04:00
Logan Cusano
a353b9adbb Improvements to tests and from testing
- Moved OP25 start outside of PDAB start callback
- Added more logging
- Set the pdabProcess variable to false when closing the discord client
- Update test variable names
- Added new WIP pdabWrappers tests to test the full wrappers as the client would
2024-04-28 03:21:03 -04:00
Logan Cusano
bf69e93e29 Improve subprocess handler
- Will now output the subprocess console when in dev mode
2024-04-28 03:18:13 -04:00
Logan Cusano
6cae18e70c Update PDAB tests
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 58s
- These new tests will likely not run in actions due to pyaudio
2024-04-27 23:34:30 -04:00
Logan Cusano
e7229322e4 Update pdab handler
- Updated socket close
- Took server outside of the init (server is always running)
- initDiscordBotClient just starts the PDAB process
2024-04-27 23:33:53 -04:00
Logan Cusano
34aa5d17dc Updates to setup from testing
All checks were successful
DRB Build Tests / drb_build_and_test (push) Successful in 52s
2024-04-26 23:46:13 -04:00
Logan Cusano
565fd5af37 Updated join voice log
All checks were successful
DRB Build Tests / drb_build_and_test (push) Successful in 1m27s
2024-04-26 21:30:27 -04:00
Logan Cusano
f04154d361 Remove client build test for now 2024-04-26 21:29:10 -04:00
Logan Cusano
383663e980 #30 Update discordBot
- Added voice states intent
2024-04-26 21:28:49 -04:00
Logan Cusano
7b21d4601f #10 Updated setup
Some checks failed
DRB Build Tests / drb_test_setup (push) Failing after 2m34s
DRB Build Tests / drb_build_and_test (push) Successful in 47s
- Re-formatted apt deps. for readability with many packages
- Added libasound-dev to try and build pyaudio
2024-04-21 15:06:59 -04:00
Logan Cusano
d0c2fcc8eb #10 #33 Update client setup and setup test
Some checks failed
DRB Build Tests / drb_test_setup (push) Failing after 2m37s
DRB Build Tests / drb_build_and_test (push) Successful in 54s
- Added a step to run the service after setting it up
- Removed `--system` option from pip3
2024-04-21 14:57:17 -04:00
Logan Cusano
9ba90af464 #10 Update setup.sh
Some checks failed
DRB Build Tests / drb_build_and_test (push) Successful in 52s
DRB Build Tests / drb_test_setup (push) Failing after 2m15s
- Remove systemctl stops as they are not needed and impact testing
2024-04-21 02:43:43 -04:00
Logan Cusano
6e8681e52d #10 Update client setup test
Some checks failed
DRB Build Tests / drb_test_setup (push) Failing after 2m1s
DRB Build Tests / drb_build_and_test (push) Successful in 1m2s
- Updated test name
- Added user pi in test environment
2024-04-21 02:34:07 -04:00
Logan Cusano
8ba1ed36d8 #10 Update actions and setup script
Some checks failed
DRB Build Tests / test_setup (push) Failing after 2m5s
DRB Build Tests / drb_build_and_test (push) Successful in 54s
- Removed the step to run the DRB client from socket tests
- Added a testing switch to the install script to return all preset values for all user input
- Added test switch to client setup action step
2024-04-21 02:28:37 -04:00
Logan Cusano
3074e88963 #10 Updated client setup test action
Some checks failed
DRB Build Tests / test_setup (push) Failing after 2m27s
DRB Build Tests / drb_build_and_test (push) Failing after 41s
- Removed comment and fixed name typo
2024-04-21 02:15:38 -04:00
Logan Cusano
737b493b23 #10 Updated client setup test action
Some checks failed
DRB Build Tests / test_setup (push) Failing after 8s
DRB Build Tests / drb_build_and_test (push) Failing after 56s
- Added working dir for setup test
2024-04-21 02:14:32 -04:00
Logan Cusano
539dbd9518 #10 Removing makefile
Some checks failed
DRB Build Tests / test_setup (push) Failing after 9s
DRB Build Tests / drb_build_and_test (push) Has been cancelled
The makefile for the client is not as useful as a install script

- Updated test action to install client deps.
- Added new action to specifically test the install script for client
2024-04-21 02:13:35 -04:00
Logan Cusano
59bfdbe143 #10 Updating build test
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 2m17s
- Adding the pi user in the test environment to match raspbian
2024-04-21 01:46:34 -04:00
Logan Cusano
560ed401cf #10 Updated Makefile
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 2m39s
- Updated sed command in setup_pulse_audio
2024-04-21 01:38:45 -04:00
Logan Cusano
7b91667414 #10 Update Makefiles
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 2m26s
- Removed the client_dir var as it's not needed
2024-04-21 01:31:04 -04:00
Logan Cusano
fd9b6d9d1c #10 Updating build test to remove threads and sudo
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 29s
2024-04-21 01:26:44 -04:00
Logan Cusano
3aae427249 #10 Updating makefile to include sudo
Some checks failed
DRB Build Tests / drb_build_and_test (push) Has been cancelled
2024-04-21 01:24:24 -04:00
Logan Cusano
bc4c8f72d0 #10 Update makefile
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 2m27s
- Working on issue running OP25 install script
2024-04-21 01:14:40 -04:00
Logan Cusano
cc4e5e762d #10 Added sudo to makefile test
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 2m49s
2024-04-21 01:07:51 -04:00
Logan Cusano
31cedb2e9c #10 Combining tests
Some checks failed
DRB Build Tests / drb_build_and_test (push) Failing after 2m16s
- Combined all tests
2024-04-21 01:01:32 -04:00
Logan Cusano
61a616ec6b #10 Updates
Some checks failed
DRB Client Makefile Build Test / build (push) Failing after 54s
DRB Socket Communication Tests / test (push) Successful in 1m58s
- Added check for updates at boot
- Updated post update script to update OP25 and PDAB
- Added initial makefile to replace the `setup.sh`
- Added new test to make sure makefile builds
- Renamed socket tests
2024-04-21 00:52:15 -04:00
Logan Cusano
d7b7b04f78 Update PDAB Wrappers
All checks were successful
Run Discord Radio Bot v3 Tests / test (push) Successful in 46s
- Close the socket server when there are no active connections
2024-04-14 23:59:04 -04:00
Logan Cusano
2c9383824e Updated client setup script
- Added pip
- updated branch for op25
- Improved the python deps install
2024-04-14 23:46:43 -04:00
Logan Cusano
cebd316939 Fixed bug if statement
All checks were successful
Run Discord Radio Bot v3 Tests / test (push) Successful in 46s
2024-04-14 20:43:06 -04:00
Logan Cusano
af19db8e17 Add PDAB setup
All checks were successful
Run Discord Radio Bot v3 Tests / test (push) Successful in 53s
2024-04-14 20:41:22 -04:00
Logan Cusano
45b9a62c64 Removed dev comments stopping OP25
All checks were successful
Run Discord Radio Bot v3 Tests / test (push) Successful in 48s
2024-04-14 16:39:24 -04:00
Logan Cusano
8c3164029f Updated typo for pdab_port action var
All checks were successful
Run Discord Radio Bot v3 Tests / test (push) Successful in 48s
2024-04-14 16:03:30 -04:00
Logan Cusano
bec4072837 Merge test actions into one action
Some checks failed
Run Discord Radio Bot v3 Tests / test (push) Failing after 1m17s
2024-04-14 15:58:00 -04:00
Logan Cusano
ac82b0efd0 Removed hardcoded IDs in test 2024-04-14 15:51:31 -04:00
Logan Cusano
854c73cc4e Testing updates
All checks were successful
Client Tests / test (push) Successful in 1m30s
Run Socket Server Tests / test (push) Successful in 1m15s
- Added client tests, started with the pdabHandler interactions
- Updated caps in socket server tests
- Updated pdabHandler with uniform 'guild_id'
- Updated pdabHandler with production check to launch or not launch the python client
-
2024-04-14 15:47:29 -04:00
Logan Cusano
238fe6a254 Updating server workflows
All checks were successful
Run Socket Server Tests / test (push) Successful in 34s
- trying to get mongo container to work
2024-04-07 20:26:47 -04:00
Logan Cusano
96d9c38425 Removed unused imports from tests
Some checks failed
Run Socket Server Tests / test (push) Failing after 1m20s
2024-04-07 19:07:31 -04:00
Logan Cusano
4df3de4d4a Passing local server tests
Some checks failed
Run Socket Server Tests / test (push) Failing after 30s
2024-04-07 19:01:00 -04:00
Logan Cusano
461b449194 Added success emits for server functions 2024-04-07 17:01:51 -04:00
Logan Cusano
757fdfb3b2 Rename tests file to test for mocha 2024-04-07 16:59:51 -04:00
Logan Cusano
9bc80887ce Updated Package 2024-04-07 16:59:16 -04:00
Logan Cusano
0ce0f72ed3 Update Server
- Move socket server start to main server file
- This way tests and the main function can use the same code
2024-04-07 16:58:50 -04:00
Logan Cusano
49ae941e83 Updating tests
Some checks failed
Run Socket Server Tests / test (push) Failing after 33s
- Removed bugged --name param
2024-04-07 16:56:03 -04:00
Logan Cusano
8e73659855 Updating tests
Some checks failed
Run Socket Server Tests / test (push) Failing after 26s
2024-04-07 16:53:54 -04:00
Logan Cusano
0a76804490 Updating tests file to use mongo docker for testing
Some checks failed
Run Socket Server Tests / build (push) Failing after 0s
Run Socket Server Tests / test (push) Failing after 31s
2024-04-07 16:43:35 -04:00
9ad24ca8ec Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Failing after 30s
Removing deprecated dev set
2024-04-06 14:17:05 -04:00
7676e883a5 Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Has been cancelled
Setting the node environment to development
2024-04-06 14:16:21 -04:00
86a71d3d6f Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Failing after 17s
Setting production flag as passed 'dev' var to npm is installing the dev package
2024-04-06 14:14:31 -04:00
1dd53ffc84 Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Failing after 37s
Installing GYP before dev depends
2024-04-06 13:56:58 -04:00
fc31026304 Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Failing after 32s
Forgot the working directory
2024-04-06 03:42:34 -04:00
8a4b7685d2 Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Failing after 7s
Add a new step to remove package-lock.json
2024-04-06 03:41:41 -04:00
Logan Cusano
49c1a1d724 Clear the package-lock.json from in the workflow
Some checks failed
Run Socket Server Tests / test (push) Failing after 0s
2024-04-06 03:39:48 -04:00
Logan Cusano
a423417949 Update versions and install param
Some checks failed
Run Socket Server Tests / test (push) Failing after 25s
2024-04-06 03:36:36 -04:00
Logan Cusano
2fb0bc8920 Update server package.json to use mocha tests
Some checks failed
Run Socket Server Tests / test (push) Failing after 17s
2024-04-06 03:32:18 -04:00
38470bd788 Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Failing after 19s
Fix node version
2024-04-06 03:27:56 -04:00
8995f8b372 Update .gitea/workflows/server_tests.yaml
Some checks failed
Run Socket Server Tests / test (push) Failing after 8s
Potential fix for not running
2024-04-06 03:26:54 -04:00
a6c26d61da Update .gitea/workflows/server_tests.yaml
Fixing errors in the workflow
2024-04-06 03:25:07 -04:00
ab0f94baf8 Merge pull request 'Implementing-Python-Client_#19' (#32) from Implementing-Python-Client_#19 into master
Reviewed-on: #32
2024-04-06 03:22:18 -04:00
Logan Cusano
62c00eec09 Implementing disconnection of discord client 2024-04-06 01:02:42 -04:00
Logan Cusano
ea63abcb93 Update the subprocess handler to take a CWD 2024-04-06 01:01:36 -04:00
Logan Cusano
1df2027a29 Update test version 2024-04-03 22:57:45 -04:00
Logan Cusano
a36ddd9614 Added extra echo 2024-04-03 03:16:27 -04:00
Logan Cusano
ce4a6e925e Fixing the on for the action 2024-04-03 03:15:22 -04:00
Logan Cusano
8790fb05fb Merge branch 'master' into Implementing-Python-Client_#19 2024-04-03 03:14:10 -04:00
Logan Cusano
0f8dc86dd5 trying v3 2024-04-03 03:11:49 -04:00
Logan Cusano
3319a9617e fixes to tests
Some checks failed
Run Socket Server Tests / test (push) Failing after 45s
2024-04-03 02:28:34 -04:00
Logan Cusano
c78ed89707 Initial implementation of python client with socket.io IPC 2024-04-03 02:24:21 -04:00
32 changed files with 3802 additions and 472 deletions

View 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

View 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

View 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"

View File

@@ -1,26 +0,0 @@
name: Run Socket Server Tests
on:
push:
branches:
- all
# You can adjust the branches as needed
jobs:
test:
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: Install dependencies
run: npm install
- name: Run tests
run: npm test

View File

@@ -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();

View File

@@ -1,148 +0,0 @@
import {
NoSubscriberBehavior,
StreamType,
createAudioPlayer,
createAudioResource,
entersState,
AudioPlayerStatus,
VoiceConnectionStatus,
joinVoiceChannel,
getVoiceConnection,
} from '@discordjs/voice';
import { GatewayIntentBits } from 'discord-api-types/v10';
import { Client, Events, ActivityType } from 'discord.js';
import prism_media from 'prism-media';
const { FFmpeg } = prism_media;
// Import the DAB settings from the dynamic settings file
import {device, maxTransmissionGap, type} from './dabSettings.mjs'
const player = createAudioPlayer({
behaviors: {
noSubscriber: NoSubscriberBehavior.Play,
maxMissedFrames: Math.round(maxTransmissionGap / 20),
},
});
function attachRecorder() {
player.play(
createAudioResource(
new FFmpeg({
args: [
'-analyzeduration',
'0',
'-loglevel',
'0',
'-f',
type,
'-i',
type === 'dshow' ? `audio=${device}` : device,
'-acodec',
'libopus',
'-f',
'opus',
'-ar',
'48000',
'-ac',
'2',
],
}),
{
inputType: StreamType.OggOpus,
},
),
);
console.log('Attached recorder - ready to go!');
}
player.on('stateChange', (oldState, newState) => {
if (oldState.status === AudioPlayerStatus.Idle && newState.status === AudioPlayerStatus.Playing) {
console.log('Playing audio output on audio player');
} else if (newState.status === AudioPlayerStatus.Idle) {
console.log('Playback has stopped. Attempting to restart.');
attachRecorder();
}
});
/**
*
* @param {any} channel
* @returns {any}
*/
export async function connectToChannel(channel) {
const connection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator,
});
try {
await entersState(connection, VoiceConnectionStatus.Ready, 30_000);
await connection.subscribe(player);
return connection;
} catch (error) {
connection.destroy();
throw error;
}
}
export async function getVoiceChannelFromID(client, channelID) {
return client.channels.cache.get(channelID)
}
export async function checkIfConnectedToVC(guildId) {
const connection = getVoiceConnection(guildId)
console.log("Connection!", connection);
return connection
}
export const getVoiceConnectionFromGuild = async (guildId) => {
return getVoiceConnection(guildId);
}
export async function initDiscordBotClient(token, systemName, readyCallback) {
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.MessageContent],
});
client.on(Events.ClientReady, () => {
console.log('discord.js client is ready!');
// Attach the recorder to the VC connection
attachRecorder();
// Set the activity of the bot user
client.user.setPresence({
activities: [{ name: `${systemName}`, type: ActivityType.Listening }],
});
//
readyCallback(client);
});
/* on event create
// TODO - Implement methods for discord users to interact directly with the bots for realtime info (last talked ID/TG, etc.)
client.on(Events.MessageCreate, async (message) => {
if (!message.guild) return;
console.log(`New Message:`, message.content);
if (message.content === '-join') {
const channel = message.member?.voice.channel;
if (channel) {
try {
const connection = await connectToChannel(channel);
connection.subscribe(player);
await message.reply('Playing now!');
} catch (error) {
console.error(error);
}
} else {
await message.reply('Join a voice channel then try again!');
}
}
});
*/
client.login(token);
}

View File

@@ -1,23 +0,0 @@
import { executeCommand } from '../modules/cliHandler.mjs';
import { extractValue } from '../modules/baseUtils.mjs';
import os from 'os';
// Defaults to Windows values for testing
let device = "VoiceMeeter VAIO3 Output (VB-Audio VoiceMeeter VAIO3)";
let maxTransmissionGap = 500;
let type = "dshow";
// Set Linux values for use in production
if (os.platform() === 'linux') {
await new Promise((res) => {
executeCommand("pactl", ['list', 'short', 'sources']).then(cliOutput => {
const extracted_device_details = extractValue(cliOutput, '(?:\\d(?:\\t|[\\s]{1,9})(?<device>[\\w\\d\\-\\.\\_]+?)(?:\\t|[\\s]{1,9})(?<card>[\\w\\d\\-\\.\\_]+)(?:\\t|[\\s]{1,9})(?:(?<device_type>[\\w\\d\\-\\.\\_]+?) (?<channels>\\dch) (?<frequency>\\d+Hz))(?:\\t|[\\s]{1,9})(?:IDLE|RUNNING|SUSPENDED))')
device = extracted_device_details.groups.device;
console.log("Device:", device);
res();
});
});
type = "pulse"; // Replace with appropriate type for Linux
}
export { device, maxTransmissionGap, type };

View File

@@ -1,135 +0,0 @@
import { connectToChannel, checkIfConnectedToVC, initDiscordBotClient, getVoiceChannelFromID, getVoiceConnectionFromGuild } from './dab.mjs';
import { openOP25, closeOP25 } from '../op25Handler/op25Handler.mjs';
let activeDiscordClient = undefined;
const activeDiscordVoiceConnections = {};
/**
* Join the requested server VC and listen to the requested system
* @param {object} joinData The object containing all the information to join the server
*/
export const joinDiscordVC = async (joinData) => {
console.log("Join requested: ", joinData)
const connection = await new Promise((res) => {
// Check if a client already exists
if (!activeDiscordClient) {
// Open a new client and join the requested channel with the requested ID
initDiscordBotClient(joinData.clientID, joinData.system, client => {
// Open an instance of OP25
openOP25(joinData.system);
getVoiceChannelFromID(client, joinData.channelID).then(vc => {
// Add the client object to the IO instance
activeDiscordClient = client;
const connection = connectToChannel(vc);
activeDiscordVoiceConnections[vc.guild.id] = connection;
console.log("Bot Connected to VC");
res(connection);
});
});
} else {
// Join the requested channel with the requested ID
getVoiceChannelFromID(activeDiscordClient, joinData.channelID).then(vc => {
// Add the client object to the IO instance
const connection = connectToChannel(vc);
activeDiscordVoiceConnections[vc.guild.id] = connection;
console.log("Bot Connected to VC");
res(connection);
});
}
});
return connection;
}
/**
* Leave VC on the requested server
* @param {string} guildId The guild ID to disconnect from VC
*/
export const leaveDiscordVC = async (guildId) => {
console.log("Leave requested");
if (await checkIfConnectedToVC(guildId)) {
const connection = await getVoiceConnectionFromGuild(guildId);
if (connection) {
console.log("There is an open VC connection, closing it now");
// Destroy the open VC connection
connection.destroy();
// Remove the connection from the object
delete activeDiscordVoiceConnections[guildId];
// Check if this was the last open VC connection
if (Object.keys(activeDiscordVoiceConnections).length == 0) {
console.log("No more open VC connections, closing the client-side discord client and OP25")
// Close the active client if there are no open VCs after this one
activeDiscordClient.destroy();
activeDiscordClient = undefined;
// Close OP25
await closeOP25();
}
}
}
}
/**
* Check if the bot is connected to a discord VC in the given server
* @param {string} guildId The guild id to check the connection status in
* @returns {boolean} If the node is connected to VC in the given guild
*/
export const checkIfDiscordVCConnected = async (guildId) => {
console.log("Requested status check");
if (await checkIfConnectedToVC(guildId)) {
console.log("There is an open VC connection");
return (true);
} else {
return (false);
}
}
/**
* Get the username of the bot in a given guild
* (there may be a server nickname given to the bot in a certain guild)
* @param {string} guildId The guild id to check the connection status in
* @returns {string} The username of the bot in the given guild's VC
*/
export const getDiscordUsername = async (guildId) => {
console.log("Requested username");
if (activeDiscordClient) {
// Fetch the guild
const guild = await activeDiscordClient.guilds.fetch(guildId);
// Fetch the bot member in the guild
const botMember = await guild.members.fetch(activeDiscordClient.user.id);
// Return bot's nickname if available, otherwise return username
return botMember.nickname || botMember.user.username;
}
else return (undefined);
}
/**
* Get the ID of the currently running bot
* @returns {string} The ID of the active client
*/
export const getDiscordID = async () => {
console.log("Requested username");
if (activeDiscordClient) {
return (activeDiscordClient.user.id);
}
else return (undefined);
}
/**
* Check if there is an open discord client
* @returns {boolean} If the client is open or not
*/
export const checkIfClientIsOpen = async () => {
if (activeDiscordClient) {
return (true);
}
return (false);
}

Submodule client/discordAudioBot/pdab added at fc6c114473

View File

@@ -0,0 +1,138 @@
// server.js
import express from 'express';
import http from 'http';
import { Server } from 'socket.io';
import { launchProcess } from '../modules/subprocessHandler.mjs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
dotenv.config()
const app = express();
const server = http.createServer(app);
const io = new Server(server);
let pdabProcess = false;
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
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;
io.on('connection', (socket) => {
console.log('A user connected');
socket.on('disconnect', () => {
console.log('User disconnected');
});
// Listen for the discord client ready event
socket.on('discord_ready', (message) => {
console.log("Message from local client", message);
botCallback();
});
});
server.listen(port, async () => {
console.log(`Server is running on port ${port}`);
});
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
export const connectToChannel = (channelId) => {
return new Promise((res) => {
io.timeout(25000).emit('join_server', { channelId: channelId }, (status, value) => {
console.log("Status returned from bot:", status, value);
res(value[0]);
});
});
};
// Function to emit a command to leave a voice channel
export const leaveVoiceChannel = async (guildId) => {
return await new Promise((res) => {
io.timeout(25000).emit('leave_server', { guildId: guildId }, (status, clientRemainsOpen) => {
console.log("Discord client remains open?", clientRemainsOpen);
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)
export const checkIfConnectedToVC = async (guildId) => {
console.log("Pdab process var:", pdabProcess);
if (!pdabProcess) return false;
return await new Promise((res) => {
io.timeout(25000).emit('check_discord_vc_connected', { guildId: guildId }, (status, result) => {
console.log(`Discord VC connected for guild ${guildId}: ${result}`);
res((result[0]));
});
})
};
export const requestDiscordUsername = (guildId) => {
return new Promise((res) => {
io.timeout(25000).emit('request_discord_username', { guildId: guildId }, (status, result) => {
console.log(`Discord username: ${result[0]}`);
res(result[0]);
});
})
};
export const checkIfClientIsOpen = () => {
return new Promise((res) => {
io.timeout(25000).emit('check_client_is_open', (status, result) => {
console.log(`Client is open: ${result}`);
res(result[0])
});
});
};
export const requestDiscordID = () => {
return new Promise((res) => {
io.timeout(25000).emit('request_discord_id', (status, result) => {
console.log(`Discord ID: ${result}`);
res(result[0]);
});
});
};
export const requestDiscordClientClose = () => {
return new Promise((res) => {
io.timeout(25000).emit('request_client_close');
pdabProcess = false;
res();
});
};

View File

@@ -0,0 +1,122 @@
import { connectToChannel, leaveVoiceChannel, checkIfConnectedToVC, initDiscordBotClient, requestDiscordUsername, requestDiscordID, requestDiscordClientClose, closePdabSocketServer, setDiscordClientPrsense, startPdabSocketServer } from './pdabHandler.mjs';
import { openOP25, closeOP25 } from '../op25Handler/op25Handler.mjs';
let activeDiscordClient = undefined;
/**
* Join the requested server VC and listen to the requested system
* @param {object} joinData The object containing all the information to join the server
*/
export const joinDiscordVC = async (joinData) => {
console.log("Join requested: ", joinData);
const connection = await new Promise(async (res) => {
// Check if a client already exists
console.log("Checking if there is a client open");
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
initDiscordBotClient(joinData.clientID, () => {
console.log("Started PDAB");
console.log("Setting the presense of the bot");
setDiscordClientPrsense(joinData.system);
// Add the client object to the IO instance
console.log("Connecting to channel")
connectToChannel(joinData.channelID, (connectionStatus) => {
console.log("Bot Connected to VC:", connectionStatus);
res(connectionStatus);
});
});
} else {
// Join the requested channel with the requested ID
console.log("There is an open client");
console.log("Connecting to channel")
const connection = connectToChannel(joinData.channelID);
console.log("Bot Connected to VC::");
res(connection);
}
});
return connection;
}
/**
* Leave VC on the requested server
* @param {string} guildId The guild ID to disconnect from VC
*/
export const leaveDiscordVC = async (guildId) => {
console.log("Leave requested");
if (await checkIfConnectedToVC(guildId)) {
const clientRemainsOpen = await leaveVoiceChannel(guildId);
console.log("Client should remain open: ", clientRemainsOpen);
if (!clientRemainsOpen) {
console.log("There are no open VC connections");
await closeOP25();
// Close the python client
await requestDiscordClientClose();
// Close the IPC server
await closePdabSocketServer();
}
}
}
/**
* Check if the bot is connected to a discord VC in the given server
* @param {string} guildId The guild id to check the connection status in
* @returns {boolean} If the node is connected to VC in the given guild
*/
export const checkIfDiscordVCConnected = async (guildId) => {
console.log("Requested status check");
if (await checkIfConnectedToVC(guildId)) {
console.log("There is an open VC connection");
return (true);
} else {
return (false);
}
}
/**
* Get the username of the bot in a given guild
* (there may be a server nickname given to the bot in a certain guild)
* @param {string} guildId The guild id to check the connection status in
* @returns {string} The username of the bot in the given guild's VC
*/
export const getDiscordUsername = async (guildId) => {
console.log("Requested username");
if (checkIfClientIsOpen()) {
return await requestDiscordUsername(guildId)
} else return (undefined);
}
/**
* Get the ID of the currently running bot
* @returns {string} The ID of the active client
*/
export const getDiscordID = async () => {
console.log("Requested ID");
if (checkIfClientIsOpen()) {
return await requestDiscordID();
}
else return (undefined);
}
/**
* Check if there is an open discord client
* @returns {boolean} If the client is open or not
*/
export const checkIfClientIsOpen = async () => {
if (activeDiscordClient) {
return (true);
}
return (false);
}

View File

@@ -1,4 +1,4 @@
import { checkIfDiscordVCConnected, joinDiscordVC, leaveDiscordVC, getDiscordUsername, checkIfClientIsOpen, getDiscordID } from '../discordAudioBot/dabWrappers.mjs'; import { checkIfDiscordVCConnected, joinDiscordVC, leaveDiscordVC, getDiscordUsername, checkIfClientIsOpen, getDiscordID } from '../discordAudioBot/pdabWrappers.mjs';
import { getCurrentSystem } from '../op25Handler/op25Handler.mjs'; import { getCurrentSystem } from '../op25Handler/op25Handler.mjs';
import { checkForUpdates } from './selfUpdater.mjs'; import { checkForUpdates } from './selfUpdater.mjs';

View File

@@ -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,18 +14,42 @@ 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) => { export const launchProcess = (processName, args, waitForClose = false, pcwd = undefined) => {
if (!runningProcesses[processName]) { if (!runningProcesses[processName]) {
const childProcess = spawn(processName, args); let childProcess;
if (pcwd) {
childProcess = spawn(processName, args, { cwd: pcwd });
}
else {
childProcess = spawn(processName, args);
}
// Store reference to the spawned process // Store reference to the spawned process
runningProcesses[processName] = childProcess; runningProcesses[processName] = childProcess;
code = new Promise(res => { // 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 => {
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);
}) })
}); });

1674
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -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": "",
@@ -15,13 +15,18 @@
"convert-units": "^2.3.4", "convert-units": "^2.3.4",
"discord.js": "^14.14.1", "discord.js": "^14.14.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"express": "^4.19.2",
"libsodium-wrappers": "^0.7.13", "libsodium-wrappers": "^0.7.13",
"prism-media": "^1.3.5", "prism-media": "^1.3.5",
"replace-in-file": "^7.1.0", "replace-in-file": "^7.1.0",
"simple-git": "^3.22.0", "simple-git": "^3.22.0",
"socket.io": "^4.7.5",
"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"
} }
} }

View File

@@ -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

View File

@@ -16,23 +16,45 @@ 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() {
if [[ "$TEST_MODE" == "true" ]]; then
echo "TESTING" # Use the pre-set value
else
read -p "$1: " input read -p "$1: " input
echo "$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() {
if [[ "$TEST_MODE" == "true" ]]; then
echo "radio" # Use the pre-set value
else
default_capabilities="radio" # Default value default_capabilities="radio" # Default value
read -p "Select CLIENT_CAPABILITIES (comma-separated, default: $default_capabilities): " capabilities read -p "Select CLIENT_CAPABILITIES (comma-separated, default: $default_capabilities): " capabilities
capabilities="${capabilities:-$default_capabilities}" # Use default value if input is empty capabilities="${capabilities:-$default_capabilities}" # Use default value if input is empty
echo "$capabilities" 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() {
if [[ "$TEST_MODE" == "true" ]]; then
echo "\"TESTING-Node\": {
\"frequencies\": [\"$(echo "155750000,154750000,156555550" | sed 's/,/","/g')\"],
\"mode\": \"p25\",
\"trunkFile\": \"testing_trunk.tsv\",
\"whitelistFile\": \"testing_whitelist.tsv\"
}," # Use the pre-set value
else
local system_name="" local system_name=""
local frequencies="" local frequencies=""
local mode="" local mode=""
@@ -53,9 +75,17 @@ prompt_nearby_system() {
\"mode\": \"$mode\", \"mode\": \"$mode\",
\"trunkFile\": \"$trunk_file\", \"trunkFile\": \"$trunk_file\",
\"whitelistFile\": \"$whitelist_file\" \"whitelistFile\": \"$whitelist_file\"
}," },"
fi
} }
# 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..."

View 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();
});
});

View 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
View 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", "."]

View File

@@ -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

View File

@@ -25,6 +25,8 @@ export async function autocomplete(nodeIo, interaction) {
const focusedValue = interaction.options.getFocused(); const focusedValue = interaction.options.getFocused();
const choices = (await checkOnlineBotsInGuild(nodeIo, interaction.guild.id)); const choices = (await checkOnlineBotsInGuild(nodeIo, interaction.guild.id));
console.log(choices);
const filtered = choices.filter(choice => choice.name.startsWith(focusedValue)).map(choice => choice = {name: choice.name, value: choice.nuid}); const filtered = choices.filter(choice => choice.name.startsWith(focusedValue)).map(choice => choice = {name: choice.name, value: choice.nuid});
console.log(focusedValue, choices, filtered); console.log(focusedValue, choices, filtered);

View File

@@ -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 () => {

View File

@@ -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
View 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)

View File

@@ -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');
});

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -4,12 +4,17 @@
"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": {
"chai": "^5.1.0",
"mocha": "^10.4.0",
"socket.io-client": "^4.7.5"
},
"dependencies": { "dependencies": {
"discord.js": "^14.14.1", "discord.js": "^14.14.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",

View File

@@ -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;

View 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
});
})
});

View File

@@ -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
});