🚀Bumped version to v0.2.0
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
dbccbf68f4
commit
491cdb8d71
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@odit/lfk-document-server",
|
||||
"version": "0.1.3",
|
||||
"version": "0.2.0",
|
||||
"description": "The document generation server for the LfK! runner system. This generates certificates, sponsoring aggreements and more",
|
||||
"main": "src/app.ts",
|
||||
"scripts": {
|
||||
|
@ -89,4 +89,4 @@
|
|||
"publish": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,206 +1,206 @@
|
|||
import axios from 'axios';
|
||||
import cheerio from "cheerio";
|
||||
import fs from "fs";
|
||||
import Handlebars from 'handlebars';
|
||||
import i18next from "i18next";
|
||||
import Backend from 'i18next-fs-backend';
|
||||
import mime from "mime-types";
|
||||
import path from 'path';
|
||||
import { PDFDocument } from 'pdf-lib';
|
||||
import puppeteer from "puppeteer";
|
||||
import { awaitAsyncHandlebarHelpers, helpers } from './asyncHelpers';
|
||||
import { config } from './config';
|
||||
import { Runner } from './models/Runner';
|
||||
import { RunnerGroup } from './models/RunnerGroup';
|
||||
|
||||
/**
|
||||
* This class is responsible for all things pdf creation.
|
||||
* This uses the html templates from src/templates.
|
||||
*/
|
||||
export class PdfCreator {
|
||||
private templateDir = path.join(__dirname, '/templates');
|
||||
private browser;
|
||||
private static interpolations = { eventname: config.eventname, sponsoring_receipt_minimum_amount: config.sponsoring_receipt_minimum_amount, currency_symbol: config.currency_symbol }
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
* Initializes i18n(ext), Handlebars and puppeteer.
|
||||
*/
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
* Initializes i18n(ext), Handlebars and puppeteer.
|
||||
*/
|
||||
public async init() {
|
||||
const minimal_args = [
|
||||
'--autoplay-policy=user-gesture-required',
|
||||
'--disable-background-networking',
|
||||
'--disable-background-timer-throttling',
|
||||
'--disable-backgrounding-occluded-windows',
|
||||
'--disable-breakpad',
|
||||
'--disable-client-side-phishing-detection',
|
||||
'--disable-component-update',
|
||||
'--disable-default-apps',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-domain-reliability',
|
||||
'--disable-extensions',
|
||||
'--disable-features=AudioServiceOutOfProcess',
|
||||
'--disable-hang-monitor',
|
||||
'--disable-ipc-flooding-protection',
|
||||
'--disable-notifications',
|
||||
'--disable-offer-store-unmasked-wallet-cards',
|
||||
'--disable-popup-blocking',
|
||||
'--disable-print-preview',
|
||||
'--disable-prompt-on-repost',
|
||||
'--disable-renderer-backgrounding',
|
||||
'--disable-speech-api',
|
||||
'--disable-sync',
|
||||
'--hide-scrollbars',
|
||||
'--ignore-gpu-blacklist',
|
||||
'--metrics-recording-only',
|
||||
'--mute-audio',
|
||||
'--no-default-browser-check',
|
||||
'--no-first-run',
|
||||
'--no-pings',
|
||||
'--no-zygote',
|
||||
'--password-store=basic',
|
||||
'--use-gl=swiftshader',
|
||||
'--no-sandbox'
|
||||
];
|
||||
await i18next
|
||||
.use(Backend)
|
||||
.init({
|
||||
fallbackLng: 'en',
|
||||
lng: 'en',
|
||||
backend: {
|
||||
loadPath: path.join(__dirname, '/locales/{{lng}}.json')
|
||||
}
|
||||
});
|
||||
|
||||
await Handlebars.registerHelper(helpers);
|
||||
await Handlebars.registerHelper('__',
|
||||
function (str) {
|
||||
return i18next.t(str, PdfCreator.interpolations).toString();
|
||||
}
|
||||
);
|
||||
this.browser = await puppeteer.launch({ headless: true, args: minimal_args });
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate sponsoring contract pdfs.
|
||||
* @param runner The runner you want to generate the contracts for.
|
||||
* @param locale The locale used for the contracts (default:en)
|
||||
*/
|
||||
public async generateSponsoringContract(runners: Runner[], locale: string = "en", codeformat: string = config.codeformat): Promise<Buffer> {
|
||||
if (runners.length == 1 && Object.keys(runners[0]).length == 0) {
|
||||
runners[0] = this.generateEmptyRunner();
|
||||
}
|
||||
if (runners.length > 50) {
|
||||
let pdf_promises = new Array<Promise<Buffer>>();
|
||||
let i, j;
|
||||
for (i = 0, j = runners.length; i < j; i += 50) {
|
||||
let chunk = runners.slice(i, i + 50);
|
||||
pdf_promises.push(this.generateSponsoringContract(chunk, locale));
|
||||
}
|
||||
const pdfs = await Promise.all(pdf_promises);
|
||||
return await this.mergePdfs(pdfs);
|
||||
}
|
||||
await i18next.changeLanguage(locale);
|
||||
const template_source = fs.readFileSync(`${this.templateDir}/sponsoring_contract.html`, 'utf8');
|
||||
const template = Handlebars.compile(template_source);
|
||||
let result = template({ runners, codeformat });
|
||||
result = await awaitAsyncHandlebarHelpers(result);
|
||||
const pdf = await this.renderPdf(result, { format: "A5", landscape: true });
|
||||
return pdf
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all images in html to base64.
|
||||
* Works with image files in the template directory or images from urls.
|
||||
* @param html The html string whoms images shall get replaced.
|
||||
*/
|
||||
public async imgToBase64(html): Promise<string> {
|
||||
const $ = cheerio.load(html)
|
||||
$('img').each(async (index, element) => {
|
||||
let imgsrc = $(element).attr("src");
|
||||
if (imgsrc.startsWith("data:image")) {
|
||||
return;
|
||||
}
|
||||
const img_type = mime.lookup(imgsrc);
|
||||
|
||||
if (!(img_type.includes("image"))) {
|
||||
throw new Error("File is not image mime type");
|
||||
}
|
||||
|
||||
let image;
|
||||
if (imgsrc.startsWith("http")) {
|
||||
image = (await axios.get(imgsrc)).data;
|
||||
image = Buffer.from(image).toString('base64');
|
||||
}
|
||||
else {
|
||||
if (imgsrc.startsWith("./")) {
|
||||
imgsrc = imgsrc.replace("./", "");
|
||||
}
|
||||
image = fs.readFileSync(`${this.templateDir}/${imgsrc}`, { encoding: "base64" });
|
||||
}
|
||||
|
||||
image = `data:${img_type};base64,${image}`
|
||||
$(element).attr("src", image)
|
||||
})
|
||||
|
||||
return $.html();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method manages the creation of pdfs via puppeteer.
|
||||
* @param html The HTML that should get rendered.
|
||||
* @param options Puppeteer PDF option (eg: {format: "A4"})
|
||||
*/
|
||||
public async renderPdf(html: string, options): Promise<any> {
|
||||
html = await this.imgToBase64(html);
|
||||
let page = await this.browser.newPage();
|
||||
await page.setContent(html);
|
||||
const pdf = await page.pdf(options);
|
||||
await page.close();
|
||||
return pdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple pdfs into one.
|
||||
* @param pdfs The pdfs you want to merge as an buffer array.
|
||||
* @returns The merged pdf as a buffer.
|
||||
*/
|
||||
private async mergePdfs(pdfs: Buffer[]): Promise<Buffer> {
|
||||
const mergedPdf = await PDFDocument.create();
|
||||
|
||||
for (const pdfBuffer of pdfs) {
|
||||
const pdf = await PDFDocument.load(pdfBuffer);
|
||||
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
|
||||
copiedPages.forEach((page) => {
|
||||
mergedPdf.addPage(page);
|
||||
});
|
||||
}
|
||||
|
||||
return <Buffer>(await mergedPdf.save());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new dummy runner with halfspaces for all strings.
|
||||
* Can be used to generate empty sponsoring contracts.
|
||||
* @returns A new runner object that apears to be empty.
|
||||
*/
|
||||
private generateEmptyRunner(): Runner {
|
||||
let group = new RunnerGroup();
|
||||
group.id = 0;
|
||||
group.name = " ";
|
||||
let runner = new Runner();
|
||||
runner.id = 0;
|
||||
runner.firstname = " ";
|
||||
runner.lastname = " ";
|
||||
runner.group = group;
|
||||
return runner;
|
||||
}
|
||||
import axios from 'axios';
|
||||
import cheerio from "cheerio";
|
||||
import fs from "fs";
|
||||
import Handlebars from 'handlebars';
|
||||
import i18next from "i18next";
|
||||
import Backend from 'i18next-fs-backend';
|
||||
import mime from "mime-types";
|
||||
import path from 'path';
|
||||
import { PDFDocument } from 'pdf-lib';
|
||||
import puppeteer from "puppeteer";
|
||||
import { awaitAsyncHandlebarHelpers, helpers } from './asyncHelpers';
|
||||
import { config } from './config';
|
||||
import { Runner } from './models/Runner';
|
||||
import { RunnerGroup } from './models/RunnerGroup';
|
||||
|
||||
/**
|
||||
* This class is responsible for all things pdf creation.
|
||||
* This uses the html templates from src/templates.
|
||||
*/
|
||||
export class PdfCreator {
|
||||
private templateDir = path.join(__dirname, '/templates');
|
||||
private browser;
|
||||
private static interpolations = { eventname: config.eventname, sponsoring_receipt_minimum_amount: config.sponsoring_receipt_minimum_amount, currency_symbol: config.currency_symbol }
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
* Initializes i18n(ext), Handlebars and puppeteer.
|
||||
*/
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
* Initializes i18n(ext), Handlebars and puppeteer.
|
||||
*/
|
||||
public async init() {
|
||||
const minimal_args = [
|
||||
'--autoplay-policy=user-gesture-required',
|
||||
'--disable-background-networking',
|
||||
'--disable-background-timer-throttling',
|
||||
'--disable-backgrounding-occluded-windows',
|
||||
'--disable-breakpad',
|
||||
'--disable-client-side-phishing-detection',
|
||||
'--disable-component-update',
|
||||
'--disable-default-apps',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-domain-reliability',
|
||||
'--disable-extensions',
|
||||
'--disable-features=AudioServiceOutOfProcess',
|
||||
'--disable-hang-monitor',
|
||||
'--disable-ipc-flooding-protection',
|
||||
'--disable-notifications',
|
||||
'--disable-offer-store-unmasked-wallet-cards',
|
||||
'--disable-popup-blocking',
|
||||
'--disable-print-preview',
|
||||
'--disable-prompt-on-repost',
|
||||
'--disable-renderer-backgrounding',
|
||||
'--disable-speech-api',
|
||||
'--disable-sync',
|
||||
'--hide-scrollbars',
|
||||
'--ignore-gpu-blacklist',
|
||||
'--metrics-recording-only',
|
||||
'--mute-audio',
|
||||
'--no-default-browser-check',
|
||||
'--no-first-run',
|
||||
'--no-pings',
|
||||
'--no-zygote',
|
||||
'--password-store=basic',
|
||||
'--use-gl=swiftshader',
|
||||
'--no-sandbox'
|
||||
];
|
||||
await i18next
|
||||
.use(Backend)
|
||||
.init({
|
||||
fallbackLng: 'en',
|
||||
lng: 'en',
|
||||
backend: {
|
||||
loadPath: path.join(__dirname, '/locales/{{lng}}.json')
|
||||
}
|
||||
});
|
||||
|
||||
await Handlebars.registerHelper(helpers);
|
||||
await Handlebars.registerHelper('__',
|
||||
function (str) {
|
||||
return i18next.t(str, PdfCreator.interpolations).toString();
|
||||
}
|
||||
);
|
||||
this.browser = await puppeteer.launch({ headless: true, args: minimal_args });
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate sponsoring contract pdfs.
|
||||
* @param runner The runner you want to generate the contracts for.
|
||||
* @param locale The locale used for the contracts (default:en)
|
||||
*/
|
||||
public async generateSponsoringContract(runners: Runner[], locale: string = "en", codeformat: string = config.codeformat): Promise<Buffer> {
|
||||
if (runners.length == 1 && Object.keys(runners[0]).length == 0) {
|
||||
runners[0] = this.generateEmptyRunner();
|
||||
}
|
||||
if (runners.length > 50) {
|
||||
let pdf_promises = new Array<Promise<Buffer>>();
|
||||
let i, j;
|
||||
for (i = 0, j = runners.length; i < j; i += 50) {
|
||||
let chunk = runners.slice(i, i + 50);
|
||||
pdf_promises.push(this.generateSponsoringContract(chunk, locale));
|
||||
}
|
||||
const pdfs = await Promise.all(pdf_promises);
|
||||
return await this.mergePdfs(pdfs);
|
||||
}
|
||||
await i18next.changeLanguage(locale);
|
||||
const template_source = fs.readFileSync(`${this.templateDir}/sponsoring_contract.html`, 'utf8');
|
||||
const template = Handlebars.compile(template_source);
|
||||
let result = template({ runners, codeformat });
|
||||
result = await awaitAsyncHandlebarHelpers(result);
|
||||
const pdf = await this.renderPdf(result, { format: "A5", landscape: true });
|
||||
return pdf
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all images in html to base64.
|
||||
* Works with image files in the template directory or images from urls.
|
||||
* @param html The html string whoms images shall get replaced.
|
||||
*/
|
||||
public async imgToBase64(html): Promise<string> {
|
||||
const $ = cheerio.load(html)
|
||||
$('img').each(async (index, element) => {
|
||||
let imgsrc = $(element).attr("src");
|
||||
if (imgsrc.startsWith("data:image")) {
|
||||
return;
|
||||
}
|
||||
const img_type = mime.lookup(imgsrc);
|
||||
|
||||
if (!(img_type.includes("image"))) {
|
||||
throw new Error("File is not image mime type");
|
||||
}
|
||||
|
||||
let image;
|
||||
if (imgsrc.startsWith("http")) {
|
||||
image = (await axios.get(imgsrc)).data;
|
||||
image = Buffer.from(image).toString('base64');
|
||||
}
|
||||
else {
|
||||
if (imgsrc.startsWith("./")) {
|
||||
imgsrc = imgsrc.replace("./", "");
|
||||
}
|
||||
image = fs.readFileSync(`${this.templateDir}/${imgsrc}`, { encoding: "base64" });
|
||||
}
|
||||
|
||||
image = `data:${img_type};base64,${image}`
|
||||
$(element).attr("src", image)
|
||||
})
|
||||
|
||||
return $.html();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method manages the creation of pdfs via puppeteer.
|
||||
* @param html The HTML that should get rendered.
|
||||
* @param options Puppeteer PDF option (eg: {format: "A4"})
|
||||
*/
|
||||
public async renderPdf(html: string, options): Promise<any> {
|
||||
html = await this.imgToBase64(html);
|
||||
let page = await this.browser.newPage();
|
||||
await page.setContent(html);
|
||||
const pdf = await page.pdf(options);
|
||||
await page.close();
|
||||
return pdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple pdfs into one.
|
||||
* @param pdfs The pdfs you want to merge as an buffer array.
|
||||
* @returns The merged pdf as a buffer.
|
||||
*/
|
||||
private async mergePdfs(pdfs: Buffer[]): Promise<Buffer> {
|
||||
const mergedPdf = await PDFDocument.create();
|
||||
|
||||
for (const pdfBuffer of pdfs) {
|
||||
const pdf = await PDFDocument.load(pdfBuffer);
|
||||
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
|
||||
copiedPages.forEach((page) => {
|
||||
mergedPdf.addPage(page);
|
||||
});
|
||||
}
|
||||
|
||||
return <Buffer>(await mergedPdf.save());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new dummy runner with halfspaces for all strings.
|
||||
* Can be used to generate empty sponsoring contracts.
|
||||
* @returns A new runner object that apears to be empty.
|
||||
*/
|
||||
private generateEmptyRunner(): Runner {
|
||||
let group = new RunnerGroup();
|
||||
group.id = 0;
|
||||
group.name = " ";
|
||||
let runner = new Runner();
|
||||
runner.id = 0;
|
||||
runner.firstname = " ";
|
||||
runner.lastname = " ";
|
||||
runner.group = group;
|
||||
return runner;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,30 +1,30 @@
|
|||
import { Body, JsonController, Post, QueryParam, Res } from 'routing-controllers';
|
||||
import { OpenAPI } from 'routing-controllers-openapi';
|
||||
import { Runner } from '../models/Runner';
|
||||
import { PdfCreator } from '../PdfCreator';
|
||||
|
||||
/**
|
||||
* The pdf controller handels all endpoints concerning pdf generation.
|
||||
* It therefore is the hearth of the document-generation server's endpoints.
|
||||
* All endpoints have to accept a locale query-param to support i18n.
|
||||
*/
|
||||
@JsonController()
|
||||
export class PdfController {
|
||||
private pdf: PdfCreator = new PdfCreator();
|
||||
private initialized: boolean = false;
|
||||
|
||||
@Post('/contracts')
|
||||
@OpenAPI({ description: "Generate Sponsoring contract pdfs from runner objects.<br>You can choose your prefered locale by passing the 'locale' query-param.<br> If you provide more than 100 runenrs this could take a moment or two (we tested up to 1000 runners in about 70sec so far)." })
|
||||
async generateContracts(@Body({ validate: true, options: { limit: "500mb" } }) runners: Runner | Runner[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("codeformat") codeformat: string) {
|
||||
if (!this.initialized) {
|
||||
await this.pdf.init();
|
||||
this.initialized = true;
|
||||
}
|
||||
if (!Array.isArray(runners)) {
|
||||
runners = [runners];
|
||||
}
|
||||
const contracts = await this.pdf.generateSponsoringContract(runners, locale, codeformat);
|
||||
res.setHeader('content-type', 'application/pdf');
|
||||
return contracts;
|
||||
}
|
||||
}
|
||||
import { Body, JsonController, Post, QueryParam, Res } from 'routing-controllers';
|
||||
import { OpenAPI } from 'routing-controllers-openapi';
|
||||
import { Runner } from '../models/Runner';
|
||||
import { PdfCreator } from '../PdfCreator';
|
||||
|
||||
/**
|
||||
* The pdf controller handels all endpoints concerning pdf generation.
|
||||
* It therefore is the hearth of the document-generation server's endpoints.
|
||||
* All endpoints have to accept a locale query-param to support i18n.
|
||||
*/
|
||||
@JsonController()
|
||||
export class PdfController {
|
||||
private pdf: PdfCreator = new PdfCreator();
|
||||
private initialized: boolean = false;
|
||||
|
||||
@Post('/contracts')
|
||||
@OpenAPI({ description: "Generate Sponsoring contract pdfs from runner objects.<br>You can choose your prefered locale by passing the 'locale' query-param.<br> If you provide more than 100 runenrs this could take a moment or two (we tested up to 1000 runners in about 70sec so far)." })
|
||||
async generateContracts(@Body({ validate: true, options: { limit: "500mb" } }) runners: Runner | Runner[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("codeformat") codeformat: string) {
|
||||
if (!this.initialized) {
|
||||
await this.pdf.init();
|
||||
this.initialized = true;
|
||||
}
|
||||
if (!Array.isArray(runners)) {
|
||||
runners = [runners];
|
||||
}
|
||||
const contracts = await this.pdf.generateSponsoringContract(runners, locale, codeformat);
|
||||
res.setHeader('content-type', 'application/pdf');
|
||||
return contracts;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,79 +1,79 @@
|
|||
import axios from "axios"
|
||||
import faker from "faker"
|
||||
import { Runner } from '../models/Runner'
|
||||
import { RunnerGroup } from '../models/RunnerGroup'
|
||||
|
||||
const baseurl = "http://localhost:4010"
|
||||
|
||||
axios.interceptors.request.use((config) => {
|
||||
config.headers['request-startTime'] = process.hrtime()
|
||||
return config
|
||||
})
|
||||
|
||||
axios.interceptors.response.use((response) => {
|
||||
const start = response.config.headers['request-startTime']
|
||||
const end = process.hrtime(start)
|
||||
const milliseconds = Math.round((end[0] * 1000) + (end[1] / 1000000))
|
||||
response.headers['request-duration'] = milliseconds
|
||||
return response
|
||||
})
|
||||
|
||||
function generateRunners(amount: number): Runner[] {
|
||||
let runners: Runner[] = new Array<Runner>();
|
||||
let group = new RunnerGroup();
|
||||
let runner = new Runner();
|
||||
for (var i = 0; i < amount; i++) {
|
||||
group.name = faker.company.bsBuzz();
|
||||
group.id = Math.floor(Math.random() * (9999999 - 1) + 1);
|
||||
runner.firstname = faker.name.firstName();
|
||||
runner.lastname = faker.name.lastName();
|
||||
runner.id = Math.floor(Math.random() * (9999999 - 1) + 1);
|
||||
runners.push(runner);
|
||||
}
|
||||
return runners;
|
||||
}
|
||||
|
||||
async function postContracts(runners: Runner[]): Promise<Measurement> {
|
||||
const res = await axios.post(`${baseurl}/contracts`, runners);
|
||||
return new Measurement("contract", runners.length, parseInt(res.headers['request-duration']))
|
||||
}
|
||||
|
||||
async function testContracts(sizes): Promise<Measurement[]> {
|
||||
let measurements = new Array<Measurement>();
|
||||
console.log("#### Testing contracts ####");
|
||||
|
||||
for (let size of sizes) {
|
||||
const m = await postContracts(generateRunners(size));
|
||||
console.log(m.toString());
|
||||
measurements.push(m);
|
||||
}
|
||||
return measurements;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const sizes = [0, 1, 10, 50, 100, 200, 500, 1000]
|
||||
console.log("########### Speedtest ###########");
|
||||
console.log(`Document server version (according to the api): ${(await axios.get("http://localhost:4010/version")).data.version}`);
|
||||
console.log("####### Running tests #######");
|
||||
const contractResults = await testContracts(sizes);
|
||||
console.log("####### Results #######");
|
||||
console.table(contractResults);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
class Measurement {
|
||||
public type: string;
|
||||
public inputcount: number;
|
||||
public responsetime: number;
|
||||
|
||||
constructor(type: string, input: number, time: number) {
|
||||
this.type = type;
|
||||
this.inputcount = input;
|
||||
this.responsetime = time;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return `It took ${this.responsetime}ms to generate ${this.inputcount} pdfs for the type ${this.type}.`
|
||||
}
|
||||
import axios from "axios"
|
||||
import faker from "faker"
|
||||
import { Runner } from '../models/Runner'
|
||||
import { RunnerGroup } from '../models/RunnerGroup'
|
||||
|
||||
const baseurl = "http://localhost:4010"
|
||||
|
||||
axios.interceptors.request.use((config) => {
|
||||
config.headers['request-startTime'] = process.hrtime()
|
||||
return config
|
||||
})
|
||||
|
||||
axios.interceptors.response.use((response) => {
|
||||
const start = response.config.headers['request-startTime']
|
||||
const end = process.hrtime(start)
|
||||
const milliseconds = Math.round((end[0] * 1000) + (end[1] / 1000000))
|
||||
response.headers['request-duration'] = milliseconds
|
||||
return response
|
||||
})
|
||||
|
||||
function generateRunners(amount: number): Runner[] {
|
||||
let runners: Runner[] = new Array<Runner>();
|
||||
let group = new RunnerGroup();
|
||||
let runner = new Runner();
|
||||
for (var i = 0; i < amount; i++) {
|
||||
group.name = faker.company.bsBuzz();
|
||||
group.id = Math.floor(Math.random() * (9999999 - 1) + 1);
|
||||
runner.firstname = faker.name.firstName();
|
||||
runner.lastname = faker.name.lastName();
|
||||
runner.id = Math.floor(Math.random() * (9999999 - 1) + 1);
|
||||
runners.push(runner);
|
||||
}
|
||||
return runners;
|
||||
}
|
||||
|
||||
async function postContracts(runners: Runner[]): Promise<Measurement> {
|
||||
const res = await axios.post(`${baseurl}/contracts`, runners);
|
||||
return new Measurement("contract", runners.length, parseInt(res.headers['request-duration']))
|
||||
}
|
||||
|
||||
async function testContracts(sizes): Promise<Measurement[]> {
|
||||
let measurements = new Array<Measurement>();
|
||||
console.log("#### Testing contracts ####");
|
||||
|
||||
for (let size of sizes) {
|
||||
const m = await postContracts(generateRunners(size));
|
||||
console.log(m.toString());
|
||||
measurements.push(m);
|
||||
}
|
||||
return measurements;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const sizes = [0, 1, 10, 50, 100, 200, 500, 1000]
|
||||
console.log("########### Speedtest ###########");
|
||||
console.log(`Document server version (according to the api): ${(await axios.get("http://localhost:4010/version")).data.version}`);
|
||||
console.log("####### Running tests #######");
|
||||
const contractResults = await testContracts(sizes);
|
||||
console.log("####### Results #######");
|
||||
console.table(contractResults);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
class Measurement {
|
||||
public type: string;
|
||||
public inputcount: number;
|
||||
public responsetime: number;
|
||||
|
||||
constructor(type: string, input: number, time: number) {
|
||||
this.type = type;
|
||||
this.inputcount = input;
|
||||
this.responsetime = time;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return `It took ${this.responsetime}ms to generate ${this.inputcount} pdfs for the type ${this.type}.`
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue