2019-01-19 21:55:06 +01:00
|
|
|
import { Injectable } from '@angular/core';
|
|
|
|
|
|
|
|
import { Observable, Subject } from 'rxjs';
|
|
|
|
|
|
|
|
import { NotifyService } from '../core-services/notify.service';
|
|
|
|
import { OperatorService } from '../core-services/operator.service';
|
|
|
|
|
|
|
|
interface CountUserRequest {
|
|
|
|
token: string;
|
|
|
|
}
|
|
|
|
|
2019-03-26 12:29:08 +01:00
|
|
|
export interface CountUserData {
|
2019-01-19 21:55:06 +01:00
|
|
|
userId: number;
|
2019-03-26 12:29:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
interface CountUserResponse extends CountUserRequest {
|
|
|
|
data: CountUserData;
|
2019-01-19 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const REQUEST_NAME = 'count-user-request';
|
|
|
|
const RESPONSE_NAME = 'count-user-response';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Provides functionality to count users with notify.
|
|
|
|
* Sends requests to all active instances, which (hopefully) respond to this message.
|
|
|
|
* Here, the answers will be collected and aggegated.
|
|
|
|
*/
|
|
|
|
@Injectable({
|
|
|
|
providedIn: 'root'
|
|
|
|
})
|
2019-02-08 17:24:32 +01:00
|
|
|
export class CountUsersService {
|
2019-03-26 12:29:08 +01:00
|
|
|
private activeCounts: { [token: string]: Subject<CountUserData> } = {};
|
2019-01-19 21:55:06 +01:00
|
|
|
|
|
|
|
private currentUserId: number;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets up all listeners
|
|
|
|
*
|
|
|
|
* @param notifyService
|
|
|
|
* @param operator
|
|
|
|
*/
|
2019-07-01 11:23:33 +02:00
|
|
|
public constructor(private notifyService: NotifyService, operator: OperatorService) {
|
2019-01-19 21:55:06 +01:00
|
|
|
// Listen for requests to send an answer.
|
|
|
|
this.notifyService.getMessageObservable<CountUserRequest>(REQUEST_NAME).subscribe(request => {
|
|
|
|
if (request.content.token) {
|
2019-03-26 12:29:08 +01:00
|
|
|
this.notifyService.sendToChannels<CountUserResponse>(
|
2019-01-19 21:55:06 +01:00
|
|
|
RESPONSE_NAME,
|
|
|
|
{
|
|
|
|
token: request.content.token,
|
2019-03-26 12:29:08 +01:00
|
|
|
data: {
|
2020-03-25 12:18:57 +01:00
|
|
|
userId: this.currentUserId
|
2019-03-26 12:29:08 +01:00
|
|
|
}
|
2019-01-19 21:55:06 +01:00
|
|
|
},
|
|
|
|
request.senderChannelName
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Listen for responses and distribute them through `activeCounts`
|
|
|
|
this.notifyService.getMessageObservable<CountUserResponse>(RESPONSE_NAME).subscribe(response => {
|
2019-03-26 12:29:08 +01:00
|
|
|
if (response.content.data && response.content.token && this.activeCounts[response.content.token]) {
|
|
|
|
this.activeCounts[response.content.token].next(response.content.data);
|
2019-01-19 21:55:06 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Look for the current user.
|
2019-02-01 13:56:08 +01:00
|
|
|
operator.getUserObservable().subscribe(user => (this.currentUserId = user ? user.id : null));
|
2019-01-19 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns a generated track token to keep track of the counting.
|
|
|
|
*/
|
|
|
|
private generateTrackToken(): string {
|
|
|
|
let token = '';
|
|
|
|
const characters = '0123456789abcdef';
|
|
|
|
for (let i = 0; i < 32; i++) {
|
|
|
|
token += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
|
|
}
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Starts the counting process
|
|
|
|
*
|
|
|
|
* @returns a tuple: the first entry is a token, which can be used to stop the
|
|
|
|
* counting with `stopCounting`. The second entry is an observable, where all user
|
|
|
|
* ids will be published.
|
|
|
|
*/
|
2019-03-26 12:29:08 +01:00
|
|
|
public countUsers(): [string, Observable<CountUserData>] {
|
2019-01-19 21:55:06 +01:00
|
|
|
const trackToken = this.generateTrackToken();
|
2019-03-26 12:29:08 +01:00
|
|
|
const subject = new Subject<CountUserData>();
|
2019-01-19 21:55:06 +01:00
|
|
|
this.activeCounts[trackToken] = subject;
|
|
|
|
this.notifyService.sendToAllUsers<CountUserRequest>(REQUEST_NAME, {
|
|
|
|
token: trackToken
|
|
|
|
});
|
|
|
|
return [trackToken, this.activeCounts[trackToken].asObservable()];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stops an active counting by the provided token
|
|
|
|
*
|
|
|
|
* @param token The count to stop
|
|
|
|
*/
|
|
|
|
public stopCounting(trackToken: string): void {
|
|
|
|
if (this.activeCounts[trackToken]) {
|
|
|
|
this.activeCounts[trackToken].complete();
|
|
|
|
delete this.activeCounts[trackToken];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|