test some stuff

This commit is contained in:
rubikscraft
2022-09-13 00:13:49 +02:00
parent 35c8000589
commit 9e9753a530
3 changed files with 187 additions and 4 deletions

View File

@@ -3,7 +3,7 @@ import { ConfigService } from '@nestjs/config';
import {
ParseBool,
ParseInt,
ParseString,
ParseString
} from 'picsur-shared/dist/util/parse-simple';
import { EnvPrefix } from '../config.static';
@@ -16,8 +16,15 @@ export class HostConfigService {
this.logger.log('Verbose: ' + this.isVerbose());
this.logger.log('Host: ' + this.getHost());
this.logger.log('Port: ' + this.getPort());
this.logger.log('Demo: ' + this.isDemo());
this.logger.log('Demo Interval: ' + this.getDemoInterval() / 1000 + 's');
if (this.isDemo()) {
this.logger.log('Running in demo mode');
this.logger.log('Demo Interval: ' + this.getDemoInterval() / 1000 + 's');
}
if (!this.isTelemetry()) {
this.logger.log('Telemetry disabled');
}
}
public getHost(): string {
@@ -47,6 +54,10 @@ export class HostConfigService {
return ParseBool(this.configService.get(`${EnvPrefix}VERBOSE`), false);
}
public isTelemetry() {
return ParseBool(this.configService.get(`${EnvPrefix}TELEMETRY`), true);
}
public getVersion() {
return ParseString(this.configService.get(`npm_package_version`), '0.0.0');
}

View File

@@ -5,11 +5,12 @@ import {
ActivatedRoute,
NavigationEnd,
NavigationError,
Router,
Router
} from '@angular/router';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { RouteTransitionAnimations } from './app.animation';
import { PRouteData } from './models/dto/picsur-routes.dto';
import { UmamiService } from './services/tracking/umami.service';
import { BootstrapService } from './util/bootstrap.service';
@Component({
@@ -33,6 +34,7 @@ export class AppComponent implements OnInit {
private readonly router: Router,
private readonly activatedRoute: ActivatedRoute,
private readonly bootstrapService: BootstrapService,
private readonly umami: UmamiService,
) {}
public getRouteAnimData() {

View File

@@ -0,0 +1,170 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { LOCATION, NAVIGATOR, WINDOW } from '@ng-web-apis/common';
import { Logger } from '../logger/logger.service';
type UmamiCollectType = 'pageview' | 'event';
interface UmamiBasePayload {
website: string;
hostname: string;
screen: string;
language: string;
url: string;
}
interface UmamiPayload {
pageview: UmamiBasePayload & {
referer: string;
};
event: UmamiBasePayload & {
event_name: string;
event_data?: string;
};
}
type FunctionOnly<O> = {
[K in keyof O]: O[K] extends (...args: any) => any ? O[K] : never;
};
const hook = <T, FT extends FunctionOnly<T>, M extends keyof FT>(
self: FT,
method: M,
callback: (...args: Parameters<FT[M]>) => any,
): FT[M] => {
const orig = self[method];
return ((...args: Parameters<FT[M]>) => {
callback(...args);
return orig.apply(self, args);
}) as FT[M];
};
@Injectable({
providedIn: 'root',
})
export class UmamiService {
private readonly logger = new Logger(UmamiService.name);
private doNotTrack = false;
private SITE_ID = '8dd2491e-1984-4f22-9f41-ca880e630ffe';
private REPORT_URL = 'http://localhost:3000/api/collect';
private umami_cache: string = '';
constructor(
@Inject(WINDOW) private readonly window: Window,
@Inject(DOCUMENT) private readonly document: Document,
@Inject(NAVIGATOR) private readonly navigator: Navigator,
@Inject(LOCATION) private readonly location: Location,
) {
//this.doNotTrack =
// this.navigator.doNotTrack === '1' || this.navigator.doNotTrack === 'yes';
if (this.doNotTrack) this.logger.warn('Do not track is enabled');
this.setup();
}
private async setup() {
if (this.doNotTrack) return;
const { history } = this.window;
history.pushState = hook(history, 'pushState', this.handlePush.bind(this));
history.replaceState = hook(
history,
'replaceState',
this.handlePush.bind(this),
);
const update = async () => {
if (document.readyState !== 'complete') return;
await this.trackView();
};
document.addEventListener('readystatechange', update, true);
await update();
}
public async sendEvent(event: string, data?: string) {
if (this.doNotTrack) return;
return await this.trackEvent(event, data);
}
private async handlePush(
data: any,
unused: string,
url?: string | URL | null,
) {
if (!url) return;
let currentUrl = this.currentUrl;
const referrer = currentUrl;
const newUrl = url.toString();
if (newUrl.substring(0, 4) === 'http') {
currentUrl = '/' + newUrl.split('/').splice(3).join('/');
} else {
currentUrl = newUrl;
}
if (currentUrl === referrer) return;
return await this.trackView(currentUrl, referrer);
}
private getPayload(): UmamiBasePayload {
const { hostname } = this.location;
const screen = `${this.window.screen.width}x${this.window.screen.height}`;
const { language } = this.navigator;
return {
website: this.SITE_ID,
hostname,
screen,
language,
url: this.currentUrl,
};
}
private async collect<T extends UmamiCollectType>(
type: T,
payload: UmamiPayload[T],
) {
return this.window
.fetch(this.REPORT_URL, {
method: 'POST',
body: JSON.stringify({ type, payload }),
headers: {
'Content-Type': 'application/json',
['x-umami-cache']: this.umami_cache,
},
})
.then((res) => res.text())
.then((text) => (this.umami_cache = text));
}
private async trackView(url?: string, referrer?: string) {
url = url || this.currentUrl;
referrer = referrer ?? this.document.referrer;
return this.collect('pageview', {
...this.getPayload(),
url,
referer: referrer,
});
}
private async trackEvent(event: string, data?: string) {
return this.collect('event', {
...this.getPayload(),
event_name: event,
event_data: data,
});
}
private get currentUrl() {
return this.location.pathname + this.location.search;
}
}