Picsur/frontend/src/app/services/api/info.service.ts

112 lines
3.2 KiB
TypeScript

import { Inject, Injectable } from '@angular/core';
import { LOCATION } from '@ng-web-apis/common';
import { InfoResponse } from 'picsur-shared/dist/dto/api/info.dto';
import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types';
import { SemVerRegex } from 'picsur-shared/dist/util/common-regex';
import { BehaviorSubject, filter, Observable, take } from 'rxjs';
import pkg from '../../../../package.json';
import { ServerInfo } from '../../models/dto/server-info.dto';
import { Logger } from '../logger/logger.service';
import { InfoStorageService } from '../storage/info-storage.service';
import { ApiService } from './api.service';
@Injectable({
providedIn: 'root',
})
export class InfoService {
private readonly logger = new Logger(InfoService.name);
public get live() {
return this.infoSubject;
}
public get snapshot() {
return this.infoSubject.value;
}
constructor(
@Inject(LOCATION) private readonly location: Location,
private readonly api: ApiService,
private readonly infoStorage: InfoStorageService,
) {
this.updateInfo().catch((e) => this.logger.warn(e));
}
private infoSubject = new BehaviorSubject<ServerInfo>(
this.infoStorage?.get() ?? new ServerInfo(),
);
public async getLoadedSnapshot(): Promise<ServerInfo> {
if (this.isLoaded()) {
return this.snapshot;
}
return new Promise((resolve) => {
const filtered = this.live.pipe(
filter((info) => info.version !== '0.0.0'),
take(1),
);
(filtered as Observable<ServerInfo>).subscribe(resolve);
});
}
public getFrontendVersion(): string {
return pkg.version;
}
public getHostname(allowOverride = false): string {
if (allowOverride) {
const info = this.snapshot;
if (info.host_override !== undefined) {
return info.host_override;
}
}
return this.location.protocol + '//' + this.location.host;
}
// If either version starts with 0. it has to be exactly the same
// If both versions start with something else, they have to match the first part
public async isCompatibleWithServer(): AsyncFailable<boolean> {
const info = await this.getLoadedSnapshot();
if (HasFailed(info)) return info;
const serverVersion = info.version;
const clientVersion = this.getFrontendVersion();
if (!SemVerRegex.test(serverVersion) || !SemVerRegex.test(clientVersion)) {
return Fail(
FT.SysValidation,
`Not a valid semver: ${serverVersion} or ${clientVersion}`,
);
}
const serverDecoded = serverVersion.split('.');
const clientDecoded = clientVersion.split('.');
if (serverDecoded[0] === '0' || clientDecoded[0] === '0') {
if (serverVersion !== clientVersion) {
return false;
} else {
return true;
}
} else {
return serverDecoded[0] === clientDecoded[0];
}
}
public isLoaded(): boolean {
return this.snapshot.version !== '0.0.0';
}
private async updateInfo(): AsyncFailable<ServerInfo> {
const response = await this.api.get(InfoResponse, '/api/info').result;
if (HasFailed(response)) return response;
this.infoSubject.next(response);
this.infoStorage.set(response);
return response;
}
}