- first commit

This commit is contained in:
Arno Kaimbacher 2022-11-07 13:55:02 +01:00
commit 407717d4b5
57 changed files with 5510 additions and 0 deletions

View file

@ -0,0 +1,71 @@
import config from "../../config/oai.config";
export default class Configuration {
/**
* Hold path where to store temporary resumption token files.
*
* @var string
*/
private _pathTokens = "";
private _maxListIds = 15;
/**
* Return maximum number of listable identifiers per request.
*
* @return {number} Maximum number of listable identifiers per request.
*/
public get maxListIds(): number {
return this._maxListIds;
}
public set maxListIds(value: number) {
this._maxListIds = value;
}
/**
* Holds maximum number of records to list per request.
*
* @var number
*/
private _maxListRecs = 15;
/**
* Return maximum number of listable records per request.
*
* @return {number} Maximum number of listable records per request.
*/
public get maxListRecs() {
return this._maxListRecs;
}
public set maxListRecs(value) {
this._maxListRecs = value;
}
constructor() {
this._maxListIds = config.max.listidentifiers as number;
this._maxListRecs = config.max.listrecords as number;
// $this->maxListIds = config('oai.max.listidentifiers');
// $this->maxListRecs = config('oai.max.listrecords');
// $this->pathTokens = config('app.workspacePath')
// . DIRECTORY_SEPARATOR .'tmp'
// . DIRECTORY_SEPARATOR . 'resumption';
}
/**
* Return temporary path for resumption tokens.
*
* @returns {string} token path.
*/
get getResumptionTokenPath(): string {
return this._pathTokens;
}
/**
* Return maximum number of listable records per request.
*
* @return {number} Maximum number of listable records per request.
*/
// get getMaxListRecords(): number {
// return this._maxListRecs;
// }
}

View file

@ -0,0 +1,107 @@
export default class ResumptionToken {
/**
* Holds dcoument ids
*
* @var array
*/
private _documentIds: number[] = [];
/**
* Holds metadata prefix information
*
* @var {string}
*/
private _metadataPrefix = "";
/**
* Holds resumption id (only if token is stored)
*
* @var {string}
*/
private _resumptionId = "";
/**
* Holds start postion
*
* @var {number}
*/
private _startPosition = 0;
/**
* Holds total amount of document ids
*
* @var {number}
*/
private _totalIds = 0;
//#region properties
get Key(): string{
return this.MetadataPrefix + this.StartPosition + this.TotalIds;
}
/**
* Returns current holded document ids.
*
* @return array
*/
public get DocumentIds(): number[] {
return this._documentIds;
}
public set DocumentIds(idsToStore: number | number[]) {
if (!Array.isArray(idsToStore)) {
idsToStore = new Array(idsToStore);
}
this._documentIds = idsToStore;
}
/**
* Returns metadata prefix information.
*
* @return string
*/
public get MetadataPrefix(): string {
return this._metadataPrefix;
}
public set MetadataPrefix(value) {
this._metadataPrefix = value;
}
/**
* Return setted resumption id after successful storing of resumption token.
*
* @return string
*/
public get ResumptionId() {
return this._resumptionId;
}
public set ResumptionId(resumptionId) {
this._resumptionId = resumptionId;
}
/**
* Returns start position.
*
* @return in
*/
public get StartPosition() {
return this._startPosition;
}
public set StartPosition(startPosition) {
this._startPosition = startPosition;
}
/**
* Returns total number of document ids for this request
*
* @return int
*/
public get TotalIds() {
return this._totalIds;
}
public set TotalIds(totalIds) {
this._totalIds = totalIds;
}
//#endregion properties
}

View file

@ -0,0 +1,194 @@
import ResumptionToken from "./ResumptionToken";
import { realpathSync } from "fs";
import { createClient, RedisClientType } from "redis";
import InternalServerErrorException from "../../exceptions/InternalServerError";
import { sprintf } from "sprintf-js";
import dayjs from "dayjs";
import * as crypto from "crypto";
export default class TokenWorker {
private resumptionPath = "";
// private resumptionId = null;
protected filePrefix = "rs_";
protected fileExtension = "txt";
private cache: RedisClientType;
private ttl: number;
private url: string;
private connected: boolean = false;
constructor(ttl: number) {
// if (resPath) {
// this.setResumptionPath(resPath);
// }
// [1] define ttl and create redis connection
this.ttl = ttl;
this.url = process.env.REDIS_URL || "redis://127.0.0.1:6379";
// this.cache.on("connect", () => {
// console.log(`Redis connection established`);
// });
// this.cache.on("error", (error: string) => {
// console.error(`Redis error, service degraded: ${error}`);
// });
// The Redis client must be created in an async closure
// (async () => {
// this.cache = createClient({
// url,
// });
// this.cache.on("error", (err) => console.log("[Redis] Redis Client Error: ", err));
// await this.cache.connect();
// console.log("[Redis]: Successfully connected to the Redis server");
// })();
}
public async connect() {
const url = process.env.REDIS_URL || "redis://localhost:6379";
this.cache = createClient({
url,
});
this.cache.on("error", (err) => {
this.connected = false;
console.log("[Redis] Redis Client Error: ", err);
});
this.cache.on("connect", () => {
this.connected = true;
// console.log(`Redis connection established`);
});
await this.cache.connect();
}
public get Connected(): boolean {
return this.connected;
}
public async has(key: string): Promise<boolean> {
const result = await this.cache.get(key);
return result !== undefined && result !== null;
}
public async set(token: ResumptionToken) {
let fc = 0;
const uniqueId = dayjs().unix().toString(); // 1548381600;
let uniqueName: string;
let cacheKeyExists = true;
do {
// format values
// %s - String
// %d - Signed decimal number (negative, zero or positive)
// [0-9] (Specifies the minimum width held of to the variable value)
uniqueName = sprintf("%s%05d", uniqueId, fc++);
// let file = uniqueName;
cacheKeyExists = await this.has(uniqueName);
} while (cacheKeyExists);
// uniqueName = this.checksum(token.Key);
const serialToken = JSON.stringify(token);
await this.cache.setEx(uniqueName, this.ttl, serialToken);
return uniqueName;
// token.ResumptionId = uniqueName;
}
// public connected(): boolean {
// return this.cache.connected;
// }
public async get(key: string): Promise<ResumptionToken | null> {
if (!this.cache) {
throw new InternalServerErrorException("Dataset is not available for OAI export!");
}
const result = await this.cache.get(key);
if (result) {
const rToken: ResumptionToken = new ResumptionToken();
const parsed = JSON.parse(result);
Object.assign(rToken, parsed);
return rToken;
} else {
return null;
}
}
public del(key: string) {
this.cache.del(key);
}
public flush() {
this.cache.flushAll();
}
public async close() {
await this.cache.disconnect();
this.connected = false;
}
private checksum(str: string, algorithm?: string, encoding?: string): string {
/**
* @type {BinaryToTextEncoding}
*/
const ENCODING_OUT = "hex"; // Initializer type string is not assignable to variable type BinaryToTextEncoding
return crypto
.createHash(algorithm || 'md5')
.update(str, 'utf8')
.digest(ENCODING_OUT)
}
/**
* Set resumption path where the resumption token files are stored.
*
* @throws Oai_Model_ResumptionTokenException Thrown if directory operations failed.
* @return void
*/
public setResumptionPath(resPath: string): void {
// expanding all symbolic links and resolving references
const realPath = realpathSync(resPath);
// if (empty($realPath) or false === is_dir($realPath)) {
// throw new Oai_Model_ResumptionTokenException(
// 'Given resumption path "' . $resPath . '" (real path: "' . $realPath . '") is not a directory.'
// );
// }
// if (false === is_writable($realPath)) {
// throw new Oai_Model_ResumptionTokenException(
// 'Given resumption path "' . $resPath . '" (real path: "' . $realPath . '") is not writeable.'
// );
// }
this.resumptionPath = realPath;
}
/**
* Store a resumption token
*
* @param Oai_Model_Resumptiontoken $token Token to store.
* @throws Oai_Model_ResumptionTokenException Thrown on file operation error.
* @return void
*/
public storeResumptionToken(token: ResumptionToken): void {
// $fileName = $this->generateResumptionName();
const uniqueName = "100";
const serialToken = JSON.stringify(token);
// Cache::put($uniqueName, $serialToken, now()->addMinutes(60));
this.cache.setEx(uniqueName, 86400, serialToken);
// $token->setResumptionId($this->resumptionId);
}
// private async get(key: string) {
// return await this.redisClient.get(key);
// }
// public async getResumptionToken(resId: string): Promise<ResumptionToken | null> {
// let token: ResumptionToken | null = null;
// var data = await this.get(resId);
// if (data) {
// token = JSON.parse(data);
// if (token instanceof ResumptionToken) {
// return token;
// }
// }
// return token;
// }
}