122 lines
4.5 KiB
TypeScript
122 lines
4.5 KiB
TypeScript
import { HttpService } from "@nestjs/axios";
|
|
import { BadRequestException, CACHE_MANAGER, CallHandler, ExecutionContext, Inject, Injectable, InternalServerErrorException, NestInterceptor } from "@nestjs/common";
|
|
import { Observable, map, take, switchMap, of } from "rxjs";
|
|
import { PageDto } from "../domain/dtos";
|
|
import { EsTime } from "../domain/enums/es-time.enum";
|
|
import { Order, toOrder } from "../domain/enums/page-order.enum";
|
|
import { EsPit } from "../domain/interfaces/elastic/es-pit.interface";
|
|
import { Cache } from 'cache-manager'
|
|
import { PageMetaDto } from "../domain/dtos/page-meta.dto";
|
|
|
|
/**
|
|
* Pagination-implementing interceptor
|
|
*/
|
|
@Injectable()
|
|
export class PageInterceptor implements NestInterceptor {
|
|
/**
|
|
* Injects needed dependencies and instantiates the storage object
|
|
* @param httpService
|
|
* @param searchService
|
|
*/
|
|
constructor(
|
|
private readonly httpService: HttpService,
|
|
@Inject(CACHE_MANAGER) private cacheManager: Cache
|
|
) {}
|
|
|
|
/**
|
|
* Elastichsearch server port-number
|
|
*/
|
|
private readonly ES_PORT = process.env.ES_PORT;
|
|
|
|
/**
|
|
* Elastichsearch IP address
|
|
*/
|
|
private readonly ES_IP = process.env.ES_CONTAINER_NAME;
|
|
|
|
/**
|
|
* Override of intercept() method, specified in NestInterceptor interface
|
|
* @param context
|
|
* @param next
|
|
* @returns Page with content and metadata
|
|
*/
|
|
async intercept(context: ExecutionContext, next: CallHandler<any>): Promise<Observable<PageDto>> {
|
|
const query = context.switchToHttp().getRequest().query;
|
|
|
|
const offset = query.offset;
|
|
const limit = query.limit;
|
|
const order = query.order;
|
|
const query_string = query.query;
|
|
|
|
const prev_page = await this.cacheManager.get('prev_page');
|
|
if (prev_page) {
|
|
if (offset == prev_page[1] &&
|
|
limit == prev_page[2] &&
|
|
order == prev_page[3] &&
|
|
query_string === prev_page[4]) return of(prev_page[0]);
|
|
}
|
|
|
|
return next.handle().pipe(
|
|
switchMap(async (res) => {
|
|
// Setting the page meta-data
|
|
let meta: PageMetaDto = {
|
|
total: res.hits.total.value,
|
|
order: toOrder(order),
|
|
};
|
|
|
|
// Check if the performed search is a backwards search
|
|
let data = res?.hits?.hits;
|
|
// Omitting the redundant info and leaving only the document
|
|
data = data.map((el) => el._source);
|
|
// Change the order if set
|
|
if (order == Order.ASC) data.reverse();
|
|
|
|
// Cache and return the page
|
|
const page: PageDto = new PageDto(data, meta);
|
|
await this.cacheManager.set('prev_page', [page, offset, limit, order, query_string]);
|
|
return page;
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Acquires a PIT ID from Elasticsearch, needed for a request
|
|
* @param alive, amount of time in minutes (defaults to 1). If time unit is not specified - defaults to minutes.
|
|
* @returns PIT object <EsPit> containing PIT ID and keep_alive value
|
|
*/
|
|
public async getPIT(alive: number, unit: EsTime = EsTime.min): Promise<EsPit> {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
this.httpService.post<EsPit>(`http://${this.ES_IP}:${this.ES_PORT}/papers/_pit?keep_alive=${alive+unit}`)
|
|
.pipe(take(1), map(axiosRes => axiosRes.data))
|
|
.subscribe((res: EsPit) => {
|
|
res.keep_alive = alive + unit;
|
|
resolve(res);
|
|
});
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Deletes the PIT specified by provided ID
|
|
* @param pitID, ID of the PIT, that would be deleted
|
|
* @returns true/false, depending on the result of deletion of the PIT
|
|
*/
|
|
async deletePIT(pitID: string): Promise<boolean> {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
this.httpService.delete(`http://${this.ES_IP}:${this.ES_PORT}/_pit`, {
|
|
data: { id: pitID },
|
|
headers: { 'Content-Type': 'application/json' },
|
|
})
|
|
.pipe(take(1), map(axiosRes => axiosRes.data))
|
|
.subscribe((res) => {
|
|
resolve(res.succeeded);
|
|
});
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
})
|
|
}
|
|
} |