Merge pull request #4540 from FinnStutzenstein/trackFirefoxIssues

Track storage fallbacks via count users
This commit is contained in:
Finn Stutzenstein 2019-04-01 08:49:55 +02:00 committed by GitHub
commit 55c162809c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 16 deletions

View File

@ -66,7 +66,7 @@ export class CustomIndexedDBDatabase extends IndexedDBDatabase {
} else { } else {
// Storing the database connection for further access // Storing the database connection for further access
this.database.next(db); this.database.next(db);
this.storageLock.OK(); this.storageLock.OK(true);
} }
}, },
() => { () => {
@ -80,7 +80,7 @@ export class CustomIndexedDBDatabase extends IndexedDBDatabase {
public setFallback(prefix: string): void { public setFallback(prefix: string): void {
console.log('uses localStorage as IndexedDB fallback!'); console.log('uses localStorage as IndexedDB fallback!');
super.setFallback(prefix); super.setFallback(prefix);
this.storageLock.OK(); this.storageLock.OK(false);
} }
} }

View File

@ -9,16 +9,22 @@ import { Injectable } from '@angular/core';
export class StoragelockService { export class StoragelockService {
private lock: Promise<void>; private lock: Promise<void>;
private resolve: () => void; private resolve: () => void;
private _indexedDBUsed = false;
public get promise(): Promise<void> { public get promise(): Promise<void> {
return this.lock; return this.lock;
} }
public get indexedDBUsed(): boolean {
return this._indexedDBUsed;
}
public constructor() { public constructor() {
this.lock = new Promise<void>(resolve => (this.resolve = resolve)); this.lock = new Promise<void>(resolve => (this.resolve = resolve));
} }
public OK(): void { public OK(indexedDBUsed: boolean): void {
this._indexedDBUsed = indexedDBUsed;
this.resolve(); this.resolve();
} }
} }

View File

@ -4,13 +4,19 @@ import { Observable, Subject } from 'rxjs';
import { NotifyService } from '../core-services/notify.service'; import { NotifyService } from '../core-services/notify.service';
import { OperatorService } from '../core-services/operator.service'; import { OperatorService } from '../core-services/operator.service';
import { StoragelockService } from '../local-storage/storagelock.service';
interface CountUserRequest { interface CountUserRequest {
token: string; token: string;
} }
interface CountUserResponse extends CountUserRequest { export interface CountUserData {
userId: number; userId: number;
usesIndexedDB: boolean;
}
interface CountUserResponse extends CountUserRequest {
data: CountUserData;
} }
const REQUEST_NAME = 'count-user-request'; const REQUEST_NAME = 'count-user-request';
@ -25,7 +31,7 @@ const RESPONSE_NAME = 'count-user-response';
providedIn: 'root' providedIn: 'root'
}) })
export class CountUsersService { export class CountUsersService {
private activeCounts: { [token: string]: Subject<number> } = {}; private activeCounts: { [token: string]: Subject<CountUserData> } = {};
private currentUserId: number; private currentUserId: number;
@ -35,15 +41,22 @@ export class CountUsersService {
* @param notifyService * @param notifyService
* @param operator * @param operator
*/ */
public constructor(private notifyService: NotifyService, operator: OperatorService) { public constructor(
private notifyService: NotifyService,
operator: OperatorService,
storageLockService: StoragelockService
) {
// Listen for requests to send an answer. // Listen for requests to send an answer.
this.notifyService.getMessageObservable<CountUserRequest>(REQUEST_NAME).subscribe(request => { this.notifyService.getMessageObservable<CountUserRequest>(REQUEST_NAME).subscribe(request => {
if (request.content.token) { if (request.content.token) {
this.notifyService.sendToChannels( this.notifyService.sendToChannels<CountUserResponse>(
RESPONSE_NAME, RESPONSE_NAME,
{ {
token: request.content.token, token: request.content.token,
userId: this.currentUserId data: {
userId: this.currentUserId,
usesIndexedDB: storageLockService.indexedDBUsed
}
}, },
request.senderChannelName request.senderChannelName
); );
@ -52,8 +65,8 @@ export class CountUsersService {
// Listen for responses and distribute them through `activeCounts` // Listen for responses and distribute them through `activeCounts`
this.notifyService.getMessageObservable<CountUserResponse>(RESPONSE_NAME).subscribe(response => { this.notifyService.getMessageObservable<CountUserResponse>(RESPONSE_NAME).subscribe(response => {
if (response.content.userId && response.content.token && this.activeCounts[response.content.token]) { if (response.content.data && response.content.token && this.activeCounts[response.content.token]) {
this.activeCounts[response.content.token].next(response.content.userId); this.activeCounts[response.content.token].next(response.content.data);
} }
}); });
@ -80,9 +93,9 @@ export class CountUsersService {
* counting with `stopCounting`. The second entry is an observable, where all user * counting with `stopCounting`. The second entry is an observable, where all user
* ids will be published. * ids will be published.
*/ */
public countUsers(): [string, Observable<number>] { public countUsers(): [string, Observable<CountUserData>] {
const trackToken = this.generateTrackToken(); const trackToken = this.generateTrackToken();
const subject = new Subject<number>(); const subject = new Subject<CountUserData>();
this.activeCounts[trackToken] = subject; this.activeCounts[trackToken] = subject;
this.notifyService.sendToAllUsers<CountUserRequest>(REQUEST_NAME, { this.notifyService.sendToAllUsers<CountUserRequest>(REQUEST_NAME, {
token: trackToken token: trackToken

View File

@ -8,6 +8,8 @@
<div *ngIf="stats"> <div *ngIf="stats">
<p> <p>
{{ userIds().length }} <span translate>active users</span> {{ userIds().length }} <span translate>active users</span>
({{ stats.usesIndexedDB }} <span translate>with indexedDB</span>,
{{ stats.activeUserHandles-stats.usesIndexedDB }} <span translate>with local storage</span>)
({{ stats.activeUserHandles }} <span translate>connections</span>) ({{ stats.activeUserHandles }} <span translate>connections</span>)
</p> </p>
<h3 translate>Groups</h3> <h3 translate>Groups</h3>

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CountUsersService } from 'app/core/ui-services/count-users.service'; import { CountUsersService, CountUserData } from 'app/core/ui-services/count-users.service';
import { Observable, BehaviorSubject } from 'rxjs'; import { Observable, BehaviorSubject } from 'rxjs';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
@ -9,6 +9,7 @@ import { UserRepositoryService } from 'app/core/repositories/users/user-reposito
*/ */
export interface CountUserStatistics { export interface CountUserStatistics {
activeUserHandles: number; activeUserHandles: number;
usesIndexedDB: number;
activeUsers: { activeUsers: {
[id: number]: number; [id: number]: number;
}; };
@ -42,25 +43,31 @@ export class CountUsersStatisticsService {
*/ */
public countUsers(): [string, Observable<CountUserStatistics>] { public countUsers(): [string, Observable<CountUserStatistics>] {
let token: string; let token: string;
let userIdObservable: Observable<number>; let userDataObservable: Observable<CountUserData>;
// Start counting // Start counting
// TODO: maybe we shold bet the observable bofore the actual countig was // TODO: maybe we shold bet the observable bofore the actual countig was
// started. We might miss some user ids. // started. We might miss some user ids.
[token, userIdObservable] = this.countUserService.countUsers(); [token, userDataObservable] = this.countUserService.countUsers();
this.runningCounts[token] = new BehaviorSubject<CountUserStatistics>({ this.runningCounts[token] = new BehaviorSubject<CountUserStatistics>({
activeUserHandles: 0, activeUserHandles: 0,
usesIndexedDB: 0,
activeUsers: {}, activeUsers: {},
groups: {} groups: {}
}); });
// subscribe to responses // subscribe to responses
userIdObservable.subscribe(userId => { userDataObservable.subscribe(data => {
const userId = !!data.userId ? data.userId : 0;
const stats = this.runningCounts[token].getValue(); const stats = this.runningCounts[token].getValue();
const user = this.userRepo.getViewModel(userId); const user = this.userRepo.getViewModel(userId);
// Add to user stats // Add to user stats
stats.activeUserHandles++; stats.activeUserHandles++;
if (data.usesIndexedDB) {
stats.usesIndexedDB++;
}
if (!stats.activeUsers[userId]) { if (!stats.activeUsers[userId]) {
stats.activeUsers[userId] = 0; stats.activeUsers[userId] = 0;
} }