Skip to content

Commit

Permalink
Added some more typings and better /api/status route
Browse files Browse the repository at this point in the history
  • Loading branch information
Its4Nik committed Dec 2, 2024
1 parent 3c276e0 commit 604532f
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 13 deletions.
11 changes: 11 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
- [ ] Better Offline mode using "faker" library or self written (probably self written)
- [ ] HA compatibility
- [ ] Add automatic notifications when container state changes, according to selected level for notification service
- [ ] Image update and update notifications
- [ ] trigger container restart / stop / start via backend routes
- [ ] Add more logging
- [ ] Strucuture code differently
- [ ] Write new README and make the docs better
- [ ] Update more files to correct TS syntax => remove "any"
- [ ] Websockets
- [X] Better /api/status endpoint with connection status of each host
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.7",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dockerode": "^4.0.2",
"express": "^4.21.1",
"express-rate-limit": "^7.4.1",
Expand All @@ -33,6 +34,7 @@
},
"devDependencies": {
"@types/bcrypt": "^5.0.2",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/express-handlebars": "^5.3.1",
"@types/node": "^22.9.0",
Expand Down
2 changes: 1 addition & 1 deletion src/config/dockerConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
"port": "2375"
}
]
}
}
2 changes: 1 addition & 1 deletion src/controllers/fetchData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import logger from "../utils/logger";
import fs from "fs";
const filePath = "./src/data/states.json";

let previousState: { [key: string]: any } = {};
let previousState: { [key: string]: string } = {};

interface Container {
name: string;
Expand Down
6 changes: 3 additions & 3 deletions src/routes/auth/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let passwordData: {
salt: string;
};

async function authEnabled() {
async function authEnabled(): Promise<boolean> {
let isAuthEnabled: boolean = false;
let data: string = "";
try {
Expand Down Expand Up @@ -88,7 +88,7 @@ async function setFalse() {
* 500:
* description: Error saving password.
*/
router.post("/enable", (req: Request, res: Response) => {
router.post("/enable", async (req: Request, res: Response) => {
const password = req.query.password as string;
if (await authEnabled()) {
logger.error(
Expand Down Expand Up @@ -143,7 +143,7 @@ router.post("/enable", (req: Request, res: Response) => {
* 500:
* description: Error disabling authentication.
*/
router.post("/disable", (req: Request, res: Response) => {
router.post("/disable", async (req: Request, res: Response) => {
const password = req.query.password as string;
if (!password) {
logger.error("Password is required!");
Expand Down
32 changes: 24 additions & 8 deletions src/routes/getter/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import fetchAllContainers from "../../utils/containerService";
import { getCurrentSchedule } from "../../controllers/scheduler";
import logger from "../../utils/logger";
import fs from "fs";
import checkReachability from "../../utils/connectionChecker";
const configPath = "./src/config/dockerConfig.json";
const router = Router();

Expand Down Expand Up @@ -265,24 +266,39 @@ router.get("/current-schedule", (req: Request, res: Response) => {
* @swagger
* /api/status:
* get:
* summary: Check server status
* summary: Check the DockStatAPI and docker socket status of each host
* tags: [Misc]
* description: Returns a 200 status with an "up" message to indicate the server is up and running. Used for Healthchecks
* description: Returns the status of the backend and online components, indicating which nodes are reachable or offline.
* responses:
* 200:
* description: Server is running
* description: Server and backend status
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* example: "up"
* backendReachable:
* type: boolean
* example: true
* online:
* type: object
* properties:
* Host-1:
* type: boolean
* example: true
* Host-2:
* type: boolean
* example: false
*/
router.get("/status", (req: Request, res: Response) => {

router.get("/status", async (req: Request, res: Response) => {
logger.debug("Fetching /api/status");
res.status(200).json({ status: "up" });
try {
let jsonData = await checkReachability();
res.status(200).json(jsonData);
} catch (error: any) {
logger.error(`Error while fetching data: ${error}`);
}
});

/**
Expand Down
2 changes: 2 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import conf from "./routes/setter/routes";
import authMiddleware from "./middleware/authMiddleware";
import { limiter } from "./middleware/rateLimiter";
import { scheduleFetch } from "./controllers/scheduler";
import cors from "cors";

// Initialize express app
const app = express();
const PORT: number = 9876; // Port should be a number
app.use(cors());

// Middleware to parse JSON requests
app.use(express.json());
Expand Down
77 changes: 77 additions & 0 deletions src/utils/connectionChecker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import * as fs from "fs";
import * as net from "net";
import logger from "../config/loggerConfig";

const filePath: string = "./src/config/dockerConfig.json";

interface Host {
name: string;
url: string;
port: string;
}

interface StatusResponse {
ApiReachable: boolean;
online: { [key: string]: boolean };
}

async function checkHostStatus(hosts: Host[]): Promise<StatusResponse> {
const results: { [key: string]: boolean } = {};
for (const host of hosts) {
const { name, url, port } = host;

const isOnline = await checkPort(url, parseInt(port, 10));

results[name] = isOnline ? true : false;

if (results[name] == true) {
logger.debug(`${host.url}:${port} is online`);
} else {
logger.debug(`${host.url}:${port} is unreachable`);
}
}

return {
ApiReachable: true,
online: results,
};
}

function checkPort(host: string, port: number): Promise<boolean> {
return new Promise((resolve) => {
const socket = new net.Socket();
socket.setTimeout(3000);

socket.on("connect", () => {
socket.end();
resolve(true);
});

socket.on("timeout", () => {
socket.destroy();
resolve(false);
});

socket.on("error", () => {
socket.destroy();
resolve(false);
});

socket.connect(port, host);
});
}

async function checkReachability(): Promise<StatusResponse | undefined> {
try {
const data = fs.readFileSync(filePath, "utf-8");
const parsedData = JSON.parse(data);
const hosts: Host[] = parsedData.hosts;
const resp = await checkHostStatus(hosts);
return resp;
} catch (error) {
logger.error(`Error reading file: ${error}`);
return undefined;
}
}

export default checkReachability;

0 comments on commit 604532f

Please sign in to comment.