🎨 Make the parser modular
- Move some DSB related functions from parser/index to parser/dsbmobile - Make the dsb parser a fileProvider with the DSBClient class - Initialize the parser with a fileProvider and documentParser instance
This commit is contained in:
@ -11,6 +11,8 @@ import {
|
||||
} from "./api/index.js";
|
||||
import auth from "./api/auth.js";
|
||||
import { Parser } from "./parser/index.js";
|
||||
import { DSBClient } from "./parser/dsbmobile.js";
|
||||
import { parseSubstitutionPlan } from "./parser/untis.js";
|
||||
|
||||
// Check DSB Mobile credentials are supplied
|
||||
if (!process.env.DSB_USER || !process.env.DSB_PASSWORD) {
|
||||
@ -28,8 +30,8 @@ app.use(express.urlencoded({ extended: true }));
|
||||
// Initialize the Parser and set it to update the
|
||||
// substitution plan at the specified update interval
|
||||
new Parser(
|
||||
process.env.DSB_USER,
|
||||
process.env.DSB_PASSWORD,
|
||||
new DSBClient(process.env.DSB_USER, process.env.DSB_PASSWORD),
|
||||
parseSubstitutionPlan,
|
||||
process.env.UPDATE_INTERVAL || 1 * 60 * 1000 // Default to 1 minute
|
||||
);
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
import axios from "axios";
|
||||
import { log } from "../logs.js";
|
||||
|
||||
const baseUrl = "https://mobileapi.dsbcontrol.de";
|
||||
|
||||
export async function getAuthtoken(username, password) {
|
||||
@ -32,3 +34,37 @@ export async function getTimetables(authtoken) {
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
// List of files that include timetable data
|
||||
const dsbFiles = ["Schüler_Monitor - subst_001", "Schüler Morgen - subst_001"];
|
||||
|
||||
export class DSBClient {
|
||||
constructor(dsbUser, dsbPassword) {
|
||||
this.dsbUser = dsbUser;
|
||||
this.dsbPassword = dsbPassword;
|
||||
}
|
||||
async getFiles() {
|
||||
try {
|
||||
// Get authtoken
|
||||
const token = await getAuthtoken(this.dsbUser, this.dsbPassword);
|
||||
// Fetch available files
|
||||
const response = await getTimetables(token);
|
||||
// Filter files that should be parsed
|
||||
const timetables = response.filter((e) => dsbFiles.includes(e.title));
|
||||
// Fetch the contents
|
||||
const files = [];
|
||||
for (let timetable of timetables) {
|
||||
const result = await axios.request({
|
||||
method: "GET",
|
||||
url: timetable.url,
|
||||
responseEncoding: "binary",
|
||||
});
|
||||
files.push(result.data);
|
||||
}
|
||||
|
||||
return files;
|
||||
} catch (error) {
|
||||
log("Parser / DSB Mobile", "Error getting data: " + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,12 @@
|
||||
import Prisma from "@prisma/client";
|
||||
import axios from "axios";
|
||||
import { log, getLogPath } from "../logs.js";
|
||||
import { getAuthtoken, getTimetables } from "./dsbmobile.js";
|
||||
import { parseSubstitutionPlan } from "./untis.js";
|
||||
|
||||
const dsbFiles = ["Schüler_Monitor - subst_001", "Schüler Morgen - subst_001"];
|
||||
const prisma = new Prisma.PrismaClient();
|
||||
|
||||
export class Parser {
|
||||
dsbUser;
|
||||
dsbPassword;
|
||||
constructor(dsbUser, dsbPassword, interval) {
|
||||
this.dsbUser = dsbUser;
|
||||
this.dsbPassword = dsbPassword;
|
||||
constructor(fileProvider, documentParser, interval) {
|
||||
this.fileProvider = fileProvider;
|
||||
this.documentParser = documentParser;
|
||||
|
||||
// Schedule plan updates
|
||||
setInterval(() => this.updatePlan(), interval);
|
||||
@ -22,15 +16,13 @@ export class Parser {
|
||||
async updatePlan() {
|
||||
const startedAt = new Date();
|
||||
try {
|
||||
const data = await this.fetchDSB();
|
||||
if (!data) throw "DSB request failed!";
|
||||
|
||||
// Request substitution plan files using the fileProvider
|
||||
const files = await this.fileProvider.getFiles();
|
||||
const plans = [];
|
||||
for (const entry of data) {
|
||||
// Download the substitution plan
|
||||
const file = await this.fetchFile(entry.url);
|
||||
// Parse them using the provided parser
|
||||
for (const file of files) {
|
||||
// Parse the substitution plan
|
||||
const parsed = parseSubstitutionPlan(file);
|
||||
const parsed = this.documentParser(file);
|
||||
plans.push(parsed);
|
||||
}
|
||||
// Create a new parse event
|
||||
@ -61,30 +53,6 @@ export class Parser {
|
||||
log("Parser / Main", "Parse event failed: " + error);
|
||||
}
|
||||
}
|
||||
async fetchDSB() {
|
||||
try {
|
||||
const token = await getAuthtoken(this.dsbUser, this.dsbPassword);
|
||||
// Fetch available files
|
||||
const response = await getTimetables(token);
|
||||
// Filter files that should be parsed
|
||||
const timetables = response.filter((e) => dsbFiles.includes(e.title));
|
||||
return timetables;
|
||||
} catch (error) {
|
||||
log("Parser / DSB Mobile", "Error getting data: " + error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
async fetchFile(url) {
|
||||
const result = await axios.request({
|
||||
method: "GET",
|
||||
url: url,
|
||||
responseEncoding: "binary",
|
||||
});
|
||||
return result.data;
|
||||
}
|
||||
async parsePlan(html) {
|
||||
return parseSubstitutionPlan(html);
|
||||
}
|
||||
async insertSubstitutions(parsedData, parseEvent) {
|
||||
const { date, changes } = parsedData;
|
||||
const classList = await prisma.class.findMany();
|
||||
|
Reference in New Issue
Block a user