mirror of
https://github.com/donavon04/licensetrackerbackend.git
synced 2025-01-18 00:30:57 -07:00
Initial Commit
This commit is contained in:
commit
b7095bbca4
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# Node.js specific files and folders
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm/
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Optional coverage directory
|
||||
coverage/
|
||||
|
||||
# Optional config files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Debugger directories and files
|
||||
.vscode/
|
||||
.idea/
|
||||
.DS_
|
22
Dockerfile
Normal file
22
Dockerfile
Normal file
@ -0,0 +1,22 @@
|
||||
# Use the official Node.js 14 image as the base image
|
||||
FROM node:21.4-alpine
|
||||
|
||||
# Set the working directory inside the container
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package.json and package-lock.json to the working directory
|
||||
COPY package*.json ./
|
||||
|
||||
# Install project dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy the project files to the working directory
|
||||
COPY . ./
|
||||
|
||||
# Expose port 3000 for the Node.js application
|
||||
EXPOSE 3000
|
||||
|
||||
WORKDIR /app/src
|
||||
|
||||
# Start the Node.js application
|
||||
CMD [ "node", "app.js" ]
|
375
app.js
Normal file
375
app.js
Normal file
@ -0,0 +1,375 @@
|
||||
const express = require('express');
|
||||
const mariadb = require('mariadb');
|
||||
const cors = require('cors');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
app.use(cors());
|
||||
|
||||
const version = "V1.1";
|
||||
|
||||
const dbip = process.env.DBIP || "192.168.2.56";
|
||||
const dbusername = process.env.DBUSERNAME || "root";
|
||||
const dbpassword = process.env.DBPASSWORD || "U&P7UH1mhRG@JF2K";
|
||||
const db = process.env.DB || "LicenseTracker";
|
||||
|
||||
|
||||
let pollRate = "1000"; //Initialize the value
|
||||
|
||||
|
||||
// Database details
|
||||
const pool = mariadb.createPool({
|
||||
host: "192.168.2.56",
|
||||
user: "root",
|
||||
password: "U&P7UH1mhRG@JF2K",
|
||||
database: "LicenseTracker"
|
||||
});
|
||||
|
||||
//Initialize pollrate variable
|
||||
let pollrate = 5000; // 5 Seconds
|
||||
|
||||
//Api Key
|
||||
const token = "&v94gt8ZHFTTTeuT";
|
||||
|
||||
//Allows the clients to check if the server is alive
|
||||
app.get('/api', (req, res) => {
|
||||
console.log("Welcome to the MPE licenses api");
|
||||
res.sendStatus(200).json({ success: "Welcome to the MPE licenses api" });
|
||||
});
|
||||
|
||||
//Allows the clients to check if the server is alive
|
||||
app.get('/api/healthcheck', (req, res) => {
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
//This will show all of the records for a specific program. It takes a program name as a parameter in the body and returns all records that have that program name
|
||||
app.post('/api/programRecords', async (req, res) => {
|
||||
try {
|
||||
const { programName } = req.body;
|
||||
if (!programName) {
|
||||
return res.status(400).json({ error: "Program name is required" });
|
||||
}
|
||||
|
||||
// Get the records for the specified program name
|
||||
const records = await getProgramRecords(programName);
|
||||
res.status(200).json(records);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving the program records. More info: " + error);
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
//Test to see if a connection to the database is feasible
|
||||
async function testDatabaseConnection() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
// Create a connection to the database
|
||||
connection = await pool.getConnection();
|
||||
|
||||
// Test the connection
|
||||
console.log('Database connection successful');
|
||||
} catch (error) {
|
||||
console.error('Database connection failed:', error.message);
|
||||
} finally {
|
||||
// Ensure the connection is closed
|
||||
if (connection) {
|
||||
try {
|
||||
await connection.end();
|
||||
} catch (endError) {
|
||||
console.error('Error closing the connection:', endError.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const getProgramRecords = async (programName) => {
|
||||
let n = (pollRate / 1000) + ((pollRate / 1000) * 0.25); // Milliseconds to seconds
|
||||
let records = [];
|
||||
//console.log('Retrieving program records');
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Get the records for the specified program name within the time constraints
|
||||
const query = `
|
||||
SELECT * FROM usedLicenses
|
||||
WHERE program = ? AND date >= DATE_SUB(NOW(), INTERVAL ? SECOND)
|
||||
`;
|
||||
records = await conn.query(query, [programName, n]);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
}
|
||||
finally {
|
||||
conn.release(); // Ensure the connection is released
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
}
|
||||
return records;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// This gives the client a list of all of the programs that are currently being requested
|
||||
app.post('/api/licenseCount', async (req, res) => {
|
||||
try {
|
||||
const { programName } = req.body;
|
||||
if (!programName) {
|
||||
return res.status(400).json({ error: "Program name is required" });
|
||||
}
|
||||
|
||||
// Call getLicensesCount function for the provided programName
|
||||
const count = await getLicensesCount(programName);
|
||||
//console.log(count.toString());
|
||||
res.status(200).json({ program: programName, count: count.toString() });
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving the license count. More info: " + error);
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
const getLicensesCount = async (programName) => {
|
||||
let n = (pollRate / 1000) + ((pollRate / 1000) * 0.25); // Milliseconds to seconds
|
||||
let count = 0;
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Get the current time minus n seconds
|
||||
const query = `
|
||||
SELECT COUNT(*) AS count FROM usedLicenses
|
||||
WHERE program = ? AND date >= DATE_SUB(NOW(), INTERVAL ? SECOND)
|
||||
`;
|
||||
const result = await conn.query(query, [programName, n]);
|
||||
count = result[0].count;
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
} finally {
|
||||
conn.release(); // Ensure the connection is released
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
// This gives the client a list of all of the programs that are currently being requested
|
||||
app.get('/api/programs', async (req, res) => {
|
||||
try {
|
||||
const programsResult = await getRequestedPrograms();
|
||||
// Extract program names from the result
|
||||
const programNames = programsResult.map(record => record.name);
|
||||
res.status(200).json(programNames);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving the programs. More info: " + error);
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
const getRequestedPrograms = async () => {
|
||||
let result = [];
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Query to get all requested programs
|
||||
const query = `SELECT name FROM requestedLicenses`;
|
||||
result = await conn.query(query);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving program names. More info: " + error);
|
||||
} finally {
|
||||
conn.release(); // Ensure the connection is released
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving program names. More info: " + error);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// This tells the client how often to phone home
|
||||
app.get('/api/pollrate', async (req, res) => {
|
||||
try {
|
||||
pollrate = await getPollRate();
|
||||
// Used to change the poll rate
|
||||
res.json({ pollrate: `${pollrate}` }); // In milliseconds
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving the poll rate. More info: " + error);
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
const getPollRate = async () => {
|
||||
// Debugging! console.log('Retrieving poll rate');
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Query to get the poll rate where sid = 1
|
||||
const query = `SELECT pollrate FROM settings WHERE sid = 1`;
|
||||
const result = await conn.query(query);
|
||||
|
||||
if (result.length > 0) {
|
||||
pollRate = result[0].pollrate; // Extract poll rate from the result
|
||||
} else {
|
||||
console.log("[INFO]: No poll rate found for sid = 1.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving the poll rate. More info: " + error);
|
||||
} finally {
|
||||
conn.release(); // Ensure the connection is released
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving the poll rate. More info: " + error);
|
||||
}
|
||||
return pollRate;
|
||||
};
|
||||
|
||||
// Retrieves currently used licenses from the database
|
||||
app.get('/api/licenses', async (req, res) => {
|
||||
try {
|
||||
// Retrieve the currently used licenses from the database
|
||||
const licenses = await getLicenses();
|
||||
res.json(licenses);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving licenses. More info: " + error);
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieves currently used licenses from the database
|
||||
const getLicenses = async () => {
|
||||
let n = (pollRate / 1000) + ((pollRate/1000) * 0.25); //Milliseconds to seconds
|
||||
let records = [];
|
||||
//console.log('Retrieving list');
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Get the current time minus n minutes
|
||||
const query = `
|
||||
SELECT * FROM usedLicenses
|
||||
WHERE date >= DATE_SUB(NOW(), INTERVAL ? SECOND)
|
||||
`;
|
||||
records = await conn.query(query, [n]);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
} finally {
|
||||
conn.release(); // Ensure the connection is released
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
}
|
||||
return records;
|
||||
};
|
||||
|
||||
app.get('/api/count', async (req, res) => {
|
||||
try {
|
||||
// Retrieve the currently used licenses count along with the total and available licenses
|
||||
const programs = await getLicenseCounts();
|
||||
res.json({ programs });
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error retrieving licenses. More info: " + error);
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieves currently used licenses count, total licenses, and available licenses grouped by program
|
||||
const getLicenseCounts = async () => {
|
||||
let n = (pollRate / 1000) + ((pollRate / 1000) * 0.25); // Convert pollRate to seconds and add 25%
|
||||
let records = [];
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Get the current time minus n seconds and count the number of licenses per program
|
||||
const query = `
|
||||
SELECT ul.program, COUNT(*) as activecount, rl.total,
|
||||
(rl.total - COUNT(*)) as available
|
||||
FROM usedLicenses ul
|
||||
JOIN requestedLicenses rl ON ul.program = rl.name
|
||||
WHERE ul.date >= DATE_SUB(NOW(), INTERVAL ? SECOND)
|
||||
GROUP BY ul.program, rl.total
|
||||
`;
|
||||
const results = await conn.query(query, [n]);
|
||||
|
||||
// Convert the results to handle bigint serialization
|
||||
records = results.map(row => ({
|
||||
program: row.program,
|
||||
activecount: String(row.activecount), // Convert bigint to string
|
||||
total: String(row.total), // Convert bigint to string
|
||||
available: String(row.available) // Convert bigint to string
|
||||
}));
|
||||
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
} finally {
|
||||
conn.release(); // Ensure the connection is released
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error reading from the database. More info: " + error);
|
||||
}
|
||||
return records;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Clients use this route to tell the server what programs they have open
|
||||
app.post('/api/currentPrograms', (req, res) => {
|
||||
//console.log('Post request received:', JSON.stringify(req.body));
|
||||
const { applicationName, machineName, apiKey } = req.body;
|
||||
if(apiKey == token){ //Verify the client is one of our own
|
||||
addProgram(applicationName, machineName);
|
||||
}
|
||||
// Handle the request further if needed
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
// Adds a program and machine name to the database
|
||||
const addProgram = async (programName, machineName) => {
|
||||
// Get the current date and format it for MariaDB datetime
|
||||
const date = new Date().toISOString().slice(0, 19).replace('T', ' ');
|
||||
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
// Check if a record with the same machineName and programName already exists
|
||||
const existingRecord = await conn.query('SELECT * FROM usedLicenses WHERE machine = ? AND program = ?', [machineName, programName]);
|
||||
|
||||
if (existingRecord.length > 0) {
|
||||
// If record exists, update its timestamp
|
||||
await conn.query('UPDATE usedLicenses SET date = ? WHERE machine = ? AND program = ?', [date, machineName, programName]);
|
||||
//console.log("[SUCCESS]: Existing record updated in the database.");
|
||||
} else {
|
||||
// If no record exists, insert a new one
|
||||
await conn.query('INSERT INTO usedLicenses (program, machine, date) VALUES (?, ?, ?)', [programName, machineName, date]);
|
||||
//console.log("[SUCCESS]: New record added to the database.");
|
||||
}
|
||||
} finally {
|
||||
conn.release(); // Ensure the connection is released
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]: There was an error adding/updating the record in the database. More info: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
testDatabaseConnection();
|
||||
}, 1000);
|
||||
|
||||
//Start the api and display the port it is running on
|
||||
const port = process.env.PORT || 3000;
|
||||
app.listen(port, () => {
|
||||
console.log(`**********************************`);
|
||||
console.log(`** **`);
|
||||
console.log(`* MPE License Tracker API *`);
|
||||
console.log(`** **`);
|
||||
console.log(`* ${version} *`);
|
||||
console.log(`** **`);
|
||||
console.log(`**********************************`);
|
||||
console.log(`API is running on port ${port}`);
|
||||
|
||||
// Run the function to test the database connection
|
||||
//testDatabaseConnection();
|
||||
//console.log(`Configured to use database IP ${dbip}`);
|
||||
//console.log(`Using user ${dbusername} for database`);
|
||||
});
|
1091
package-lock.json
generated
Normal file
1091
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
package.json
Normal file
19
package.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "licensetracker",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.2",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.19.2",
|
||||
"mariadb": "^3.3.0",
|
||||
"nodemon": "^3.1.1"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user