Basic functionality done

This commit is contained in:
Douglas Barone 2023-06-20 15:21:28 -04:00
parent 568332e502
commit d02c580d1b
16 changed files with 588 additions and 34 deletions

1
globals.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'net-snmp'

172
package-lock.json generated
View File

@ -1,11 +1,11 @@
{
"name": "ifms-healthtracker",
"name": "ifms-printer-manager",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ifms-healthtracker",
"name": "ifms-printer-manager",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
@ -25,6 +25,7 @@
"nodemon": "^2.0.22",
"prisma": "^4.15.0",
"rimraf": "^5.0.1",
"ts-node": "^10.9.1",
"tsx": "^3.12.7",
"typescript": "^5.1.3"
}
@ -48,6 +49,18 @@
"node": ">= 10"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild-kit/cjs-loader": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz",
@ -447,6 +460,31 @@
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@ -489,6 +527,30 @@
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.15.0-28.8fbc245156db7124f997f4cecdd8d1219e360944.tgz",
"integrity": "sha512-sVOig4tjGxxlYaFcXgE71f/rtFhzyYrfyfNFUsxCIEJyVKU9rdOWIlIwQ2NQ7PntvGnn+x0XuFo4OC1jvPJKzg=="
},
"node_modules/@tsconfig/node10": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
"dev": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
"node_modules/@types/asn1": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@types/asn1/-/asn1-0.2.0.tgz",
@ -620,6 +682,27 @@
"node": ">= 0.6"
}
},
"node_modules/acorn": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
"integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
@ -657,6 +740,12 @@
"node": ">= 8"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@ -896,6 +985,12 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/cron-validate": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/cron-validate/-/cron-validate-1.4.5.tgz",
@ -949,6 +1044,15 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/dotenv": {
"version": "16.1.4",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.1.4.tgz",
@ -1703,6 +1807,12 @@
"node": "14 || >=16.14"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -2427,6 +2537,49 @@
"nodetouch": "bin/nodetouch.js"
}
},
"node_modules/ts-node": {
"version": "10.9.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/tsx": {
"version": "3.12.7",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.7.tgz",
@ -2499,6 +2652,12 @@
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -2618,6 +2777,15 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/yup": {
"version": "0.32.9",
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.9.tgz",

View File

@ -5,10 +5,13 @@
"main": "index.js",
"type": "module",
"scripts": {
"clean": "rimraf ./dist",
"build": "npm run clean && tsc",
"clean": "rimraf ./dist ./public",
"build:server": "npm run clean && tsc",
"build:web": "cd web && npm run build",
"build": "npm run build:server && npm run build:web",
"start": "NODE_ENV=production node dist",
"dev": "nodemon --ext js,ts,mts,mjs,json,prisma --exec \"tsx src/index.ts\""
"dev": "nodemon --ext js,ts,mts,mjs,json,prisma --exec \"tsx src/index.ts\"",
"devLegacy": "NODE_OPTIONS=\"--loader ts-node/esm\" node ./src/index.ts"
},
"prisma": {
"seed": "tsx prisma/seed.ts"
@ -23,6 +26,7 @@
"nodemon": "^2.0.22",
"prisma": "^4.15.0",
"rimraf": "^5.0.1",
"ts-node": "^10.9.1",
"tsx": "^3.12.7",
"typescript": "^5.1.3"
},

View File

@ -23,7 +23,7 @@ CREATE TABLE "Printer" (
"serialNumber" TEXT,
"hostname" TEXT,
"ip" TEXT NOT NULL,
"model" TEXT,
"model" TEXT NOT NULL,
"blackTonerModel" TEXT,
"cyanTonerModel" TEXT,
"magentaTonerModel" TEXT,
@ -54,5 +54,8 @@ CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Printer_serialNumber_key" ON "Printer"("serialNumber");
-- CreateIndex
CREATE UNIQUE INDEX "Printer_ip_key" ON "Printer"("ip");
-- AddForeignKey
ALTER TABLE "PrinterStatus" ADD CONSTRAINT "PrinterStatus_printerId_fkey" FOREIGN KEY ("printerId") REFERENCES "Printer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -0,0 +1,5 @@
-- DropForeignKey
ALTER TABLE "PrinterStatus" DROP CONSTRAINT "PrinterStatus_printerId_fkey";
-- AddForeignKey
ALTER TABLE "PrinterStatus" ADD CONSTRAINT "PrinterStatus_printerId_fkey" FOREIGN KEY ("printerId") REFERENCES "Printer"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -38,8 +38,8 @@ model Printer {
serialNumber String? @unique
hostname String?
ip String
model String?
ip String @unique
model String
blackTonerModel String?
cyanTonerModel String?
@ -49,7 +49,7 @@ model Printer {
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
PrinterStatus PrinterStatus[]
status PrinterStatus[]
}
model PrinterStatus {
@ -65,5 +65,5 @@ model PrinterStatus {
createdAt DateTime @default(now())
printerId Int
printer Printer @relation(fields: [printerId], references: [id])
printer Printer @relation(fields: [printerId], references: [id], onDelete: Cascade)
}

View File

@ -2,6 +2,7 @@ import { Request, Response, Router } from 'express'
import { hasRolesMiddleware } from '../middlewares/hasRolesMiddleware.js'
import { prisma } from '../prisma.js'
import { PrinterStatusService } from '../services/PrinterStatusService.js'
const router = Router()
@ -21,7 +22,7 @@ class PrinterController {
const printer = await prisma.printer.findUnique({
where: { id: Number(id) },
include: {
PrinterStatus: {
status: {
where: {
createdAt: {
gte
@ -35,27 +36,44 @@ class PrinterController {
}
static async create(req: Request, res: Response) {
const { friendlyName, ip, location } = req.body
const { friendlyName, ip } = req.body
const printer = await prisma.printer.create({
data: { friendlyName, ip, location }
})
try {
const model = await PrinterStatusService.getPrinterModel(ip)
const printer = await prisma.printer.create({
data: { friendlyName, ip, model }
})
// Run snmp here
new PrinterStatusService(printer)
res.json(printer)
res.json(printer)
} catch (e) {
res
.status(400)
.json({ error: 'Este endereço não é de uma impressora suportada.' })
return
}
}
static async edit(req: Request, res: Response) {
const { id } = req.params
const { friendlyName, ip, location } = req.body
const { friendlyName, ip } = req.body
const printer = await prisma.printer.update({
where: { id: Number(id) },
data: { friendlyName, ip, location }
// Verify if printer exists
const printerExists = await prisma.printer.findUnique({
where: { id: Number(id) }
})
res.json(printer)
if (printerExists) {
const printer = await prisma.printer.update({
where: { id: Number(id) },
data: { friendlyName, ip }
})
res.json(printer)
} else {
res.status(400).json({ error: 'Printer not found' })
}
}
static async delete(req: Request, res: Response) {
@ -70,7 +88,9 @@ class PrinterController {
router.use(hasRolesMiddleware(['ADMIN', 'INSPECTOR']))
router.get('/', PrinterController.index)
router.post('/', PrinterController.create)
router.get('/:id', PrinterController.show)
router.put('/:id', PrinterController.edit)
router.delete('/:id', PrinterController.delete)
export default router

View File

@ -0,0 +1,20 @@
import { Router, Request, Response } from 'express'
import { prisma } from '../prisma.js'
import { PrinterStatusService } from '../services/PrinterStatusService.js'
const router = Router()
class PrinterStatusController {
static async update(req: Request, res: Response) {
const printers = await prisma.printer.findMany()
printers.forEach(async printer => {
new PrinterStatusService(printer)
})
res.json({ message: 'Updating printer status' })
}
}
router.get('/update', PrinterStatusController.update)
export default router

View File

@ -1,6 +1,5 @@
import 'dotenv/config'
import * as path from 'node:path'
import * as process from 'node:process'
import { fileURLToPath } from 'node:url'
import { app } from './server.js'
@ -13,7 +12,7 @@ app.listen(PORT, () => {
console.log(
`Running in ${
process.env.NODE_ENV == 'production' ? 'PRODUCTION' : 'DEVELOPMENT'
} mode. Server listening on port ${PORT}`
} mode. \nServer listening http://127.0.0.1:${PORT}`
)
})
@ -24,8 +23,9 @@ const bree = new Bree({
logger: false,
jobs: [
{
name: 'printerStatus',
interval: '2s'
name: 'updatePrinterStatus',
interval: process.env.UPDATE_INTERVAL || '10m',
timeout: 0
}
]
})

View File

@ -1,5 +0,0 @@
export function snmpUpdate() {
console.log('snmpUpdate!!!!!')
}
snmpUpdate()

View File

@ -0,0 +1,14 @@
import { prisma } from '../prisma.js'
import { PrinterStatusService } from '../services/PrinterStatusService.js'
function updatePrinterStatus() {
console.log(`Updating printer status ${new Date().toISOString()}`)
prisma.printer.findMany().then(printers => {
printers.forEach(async printer => {
new PrinterStatusService(printer)
})
})
}
updatePrinterStatus()

View File

@ -0,0 +1,109 @@
export type PrinterObjectIds = {
model: string
objectIds: {
model: string
serialNumber: string
counter: string
location: string
toners: {
black: {
current: string
max: string
model: string
}
cyan?: {
current: string
max: string
model: string
}
magenta?: {
current: string
max: string
model: string
}
yellow?: {
current: string
max: string
model: string
}
}
}
}
const objectIds: PrinterObjectIds[] = [
{
model: 'ECOSYS M3655idn',
objectIds: {
model: '1.3.6.1.2.1.25.3.2.1.3.1',
serialNumber: '1.3.6.1.2.1.43.5.1.1.17.1',
counter: '1.3.6.1.4.1.1347.43.10.1.1.12.1.1',
location: '1.3.6.1.2.1.1.6.0',
toners: {
black: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.1',
max: '1.3.6.1.2.1.43.11.1.1.8.1.1',
model: '1.3.6.1.2.1.43.11.1.1.6.1.1'
}
}
}
},
{
model: 'ECOSYS P6235cdn',
objectIds: {
model: '1.3.6.1.2.1.25.3.2.1.3.1',
serialNumber: '1.3.6.1.2.1.43.5.1.1.17.1',
counter: '1.3.6.1.4.1.1347.43.10.1.1.12.1.1',
location: '1.3.6.1.2.1.1.6.0',
toners: {
black: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.4',
max: '1.3.6.1.2.1.43.11.1.1.8.1.4',
model: '1.3.6.1.2.1.43.11.1.1.6.1.4'
},
cyan: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.1',
max: '1.3.6.1.2.1.43.11.1.1.8.1.1',
model: '1.3.6.1.2.1.43.11.1.1.6.1.1'
},
magenta: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.2',
max: '1.3.6.1.2.1.43.11.1.1.8.1.2',
model: '1.3.6.1.2.1.43.11.1.1.6.1.2'
},
yellow: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.3',
max: '1.3.6.1.2.1.43.11.1.1.8.1.3',
model: '1.3.6.1.2.1.43.11.1.1.6.1.3'
}
}
}
},
{
model: 'ECOSYS M2040dn',
objectIds: {
model: '1.3.6.1.2.1.25.3.2.1.3.1',
serialNumber: '1.3.6.1.2.1.43.5.1.1.17.1',
counter: '1.3.6.1.4.1.1347.43.10.1.1.12.1.1',
location: '1.3.6.1.2.1.1.6.0',
toners: {
black: {
current: '1.3.6.1.2.1.43.11.1.1.9.1.1',
max: '1.3.6.1.2.1.43.11.1.1.8.1.1',
model: '1.3.6.1.2.1.43.11.1.1.6.1.1'
}
}
}
}
]
export class objectIdsRepository {
private constructor() {}
static getPrinterObjectIds(model: string): PrinterObjectIds {
const printerObjectIds = objectIds.find(printer => printer.model === model)
if (!printerObjectIds) throw new Error('Model not found')
return printerObjectIds
}
}

View File

@ -6,6 +6,7 @@ import { authMiddleware } from './middlewares/authMiddleware.js'
import LoginRouter from './controllers/LoginController.js'
import PrinterRouter from './controllers/PrinterController.js'
import PrinterStatusRouter from './controllers/PrinterStatusController.js'
export const app = express()
@ -16,6 +17,7 @@ app.use(populateUserMiddleware)
app.use('/api/login', LoginRouter)
app.use('/api/printer', PrinterRouter)
app.use('/api/printer-status', PrinterStatusRouter)
app.get('/api/me', authMiddleware, async (req: Request, res: Response) =>
res.json(res.locals.user)

View File

@ -0,0 +1,213 @@
import snmp from 'net-snmp'
import { Printer, PrinterStatus } from '@prisma/client'
import { prisma } from '../prisma.js'
import {
objectIdsRepository,
PrinterObjectIds
} from '../repositories/ObjectIDRepository.js'
type VarbindString = {
oid: string
type: number
value: string
}
export type Varbind = {
oid: string
type: number
value: string | Buffer
}
export type PrinterInfo = {
serialNumber: string
counter: number
location: string
toners: {
black: {
level: number
model: string
}
cyan?: {
level: number
model: string
}
magenta?: {
level: number
model: string
}
yellow?: {
level: number
model: string
}
}
}
export class PrinterStatusService {
constructor(private printer: Printer) {
this.getPrinterInfo().then(async printerStatus => {
await prisma.printer.update({
where: { id: this.printer.id },
data: {
serialNumber: printerStatus.serialNumber,
location: printerStatus.location,
blackTonerModel: printerStatus.toners.black.model,
cyanTonerModel: printerStatus.toners.cyan?.model,
magentaTonerModel: printerStatus.toners.magenta?.model,
yellowTonerModel: printerStatus.toners.yellow?.model,
status: {
create: {
counter: printerStatus.counter,
tonerBlackLevel: printerStatus.toners.black.level,
tonerCyanLevel: printerStatus.toners.cyan?.level,
tonerMagentaLevel: printerStatus.toners.magenta?.level,
tonerYellowLevel: printerStatus.toners.yellow?.level
}
}
}
})
})
}
private objectIdsArray(): string[] {
const oIDsArray: string[] = []
function extractObjValues(obj: any) {
for (let key in obj) {
if (typeof obj[key] === 'object') {
extractObjValues(obj[key])
} else {
const oID = obj[key]
oIDsArray.push(oID)
}
}
}
extractObjValues(
objectIdsRepository.getPrinterObjectIds(this.printer.model).objectIds
)
return oIDsArray
}
private deBufferizeVarbinds(varbinds: Varbind[]) {
const varbindsString: VarbindString[] = []
varbinds.forEach((varbind: Varbind) => {
if (varbind.value instanceof Buffer)
varbindsString.push({ ...varbind, value: varbind.value.toString() })
else varbindsString.push({ ...varbind, value: varbind.value })
})
return varbindsString
}
static getPrinterModel(ip: string): Promise<string> {
return new Promise((resolve, reject) => {
const snmpSession = snmp.createSession(ip, 'public')
snmpSession.get(
['1.3.6.1.2.1.25.3.2.1.3.1'],
(error: any, varbinds: any) => {
if (error) {
reject(error)
} else {
resolve(varbinds[0].value.toString())
}
snmpSession.close()
}
)
})
}
async getPrinterInfo(): Promise<PrinterInfo> {
return new Promise((resolve, reject) => {
const session = snmp.createSession(this.printer.ip, 'public')
const oIDsArray = this.objectIdsArray()
session.get(oIDsArray, (error: any, varbinds: Varbind[]) => {
if (error) reject(error)
const varbindsString = this.deBufferizeVarbinds(varbinds)
const info = this.objectIDsToPrinterInfo(varbindsString)
resolve(info)
session.close()
})
})
}
private calcTonerLevelPercentage(
current: string | undefined,
max: string | undefined
) {
if (typeof current === 'undefined' || typeof max === 'undefined')
throw new Error('current or max is undefined')
return (+current! / +max!) * 100
}
private objectIDsToPrinterInfo(varbinds: Varbind[]): PrinterInfo {
const snmpInfo = this.deBufferizeVarbinds(varbinds)
const { objectIds }: PrinterObjectIds =
objectIdsRepository.getPrinterObjectIds(this.printer.model)
const printerInfo: PrinterInfo = {
serialNumber: snmpInfo.find(x => x.oid === objectIds.serialNumber)
?.value as string,
counter: Number(snmpInfo.find(x => x.oid === objectIds.counter)?.value),
location: snmpInfo.find(x => x.oid === objectIds.location)
?.value as string,
toners: {
black: {
level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.black.current)?.value,
snmpInfo.find(x => x.oid === objectIds.toners.black.max)?.value
),
model: snmpInfo.find(x => x.oid === objectIds.toners.black.model)
?.value as string
},
cyan: objectIds.toners.cyan
? {
level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.cyan?.current)
?.value,
snmpInfo.find(x => x.oid === objectIds.toners.cyan?.max)?.value
),
model: snmpInfo.find(x => x.oid === objectIds.toners.cyan?.model)
?.value as string
}
: undefined,
magenta: objectIds.toners.magenta
? {
level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.magenta?.current)
?.value,
snmpInfo.find(x => x.oid === objectIds.toners.magenta?.max)
?.value
),
model: snmpInfo.find(
x => x.oid === objectIds.toners.magenta?.model
)?.value as string
}
: undefined,
yellow: objectIds.toners.yellow
? {
level: this.calcTonerLevelPercentage(
snmpInfo.find(x => x.oid === objectIds.toners.yellow?.current)
?.value,
snmpInfo.find(x => x.oid === objectIds.toners.yellow?.max)
?.value
),
model: snmpInfo.find(
x => x.oid === objectIds.toners.yellow?.model
)?.value as string
}
: undefined
}
}
return printerInfo
}
}

View File

@ -14,12 +14,12 @@ export class UserService {
if (!ldapUser) throw new Error('User not found!')
const user = {
const user: Omit<User, 'id' | 'createdAt' | 'updatedAt'> = {
username: ldapUser.username,
displayName: ldapUser.displayName,
mail: ldapUser.mail,
thumbnailPhoto: ldapUser.thumbnailPhoto,
roles: [] as User['roles']
roles: []
}
ldapUser.groups?.forEach(group => {

View File

@ -106,5 +106,5 @@
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": ["src/**/*", "jobs/**/*"]
"include": ["src/**/*", "jobs/**/*", "globals.d.ts"]
}