2023-10-19 21:41:01 +02:00
|
|
|
import {
|
|
|
|
BehaviorSubject,
|
|
|
|
Subject,
|
|
|
|
combineLatestWith,
|
|
|
|
map,
|
|
|
|
distinctUntilChanged,
|
|
|
|
shareReplay,
|
|
|
|
} from "rxjs";
|
|
|
|
|
|
|
|
import { AccountInfo, InternalAccountService } from "../../auth/abstractions/account.service";
|
2023-06-06 22:34:53 +02:00
|
|
|
import { LogService } from "../../platform/abstractions/log.service";
|
|
|
|
import { MessagingService } from "../../platform/abstractions/messaging.service";
|
2023-10-19 21:41:01 +02:00
|
|
|
import { UserId } from "../../types/guid";
|
|
|
|
import { AuthenticationStatus } from "../enums/authentication-status";
|
2022-07-29 21:49:58 +02:00
|
|
|
|
2022-10-18 22:02:11 +02:00
|
|
|
export class AccountServiceImplementation implements InternalAccountService {
|
2023-10-19 21:41:01 +02:00
|
|
|
private accounts = new BehaviorSubject<Record<UserId, AccountInfo>>({});
|
|
|
|
private activeAccountId = new BehaviorSubject<UserId | undefined>(undefined);
|
|
|
|
private lock = new Subject<UserId>();
|
|
|
|
private logout = new Subject<UserId>();
|
|
|
|
|
|
|
|
accounts$ = this.accounts.asObservable();
|
|
|
|
activeAccount$ = this.activeAccountId.pipe(
|
|
|
|
combineLatestWith(this.accounts$),
|
|
|
|
map(([id, accounts]) => (id ? { id, ...accounts[id] } : undefined)),
|
|
|
|
distinctUntilChanged(),
|
|
|
|
shareReplay({ bufferSize: 1, refCount: false })
|
|
|
|
);
|
|
|
|
accountLock$ = this.lock.asObservable();
|
|
|
|
accountLogout$ = this.logout.asObservable();
|
2022-10-18 22:02:11 +02:00
|
|
|
constructor(private messagingService: MessagingService, private logService: LogService) {}
|
2022-07-29 21:49:58 +02:00
|
|
|
|
2023-10-19 21:41:01 +02:00
|
|
|
addAccount(userId: UserId, accountData: AccountInfo): void {
|
|
|
|
this.accounts.value[userId] = accountData;
|
|
|
|
this.accounts.next(this.accounts.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
setAccountName(userId: UserId, name: string): void {
|
|
|
|
this.setAccountInfo(userId, { ...this.accounts.value[userId], name });
|
|
|
|
}
|
|
|
|
|
|
|
|
setAccountEmail(userId: UserId, email: string): void {
|
|
|
|
this.setAccountInfo(userId, { ...this.accounts.value[userId], email });
|
|
|
|
}
|
|
|
|
|
|
|
|
setAccountStatus(userId: UserId, status: AuthenticationStatus): void {
|
|
|
|
this.setAccountInfo(userId, { ...this.accounts.value[userId], status });
|
|
|
|
|
|
|
|
if (status === AuthenticationStatus.LoggedOut) {
|
|
|
|
this.logout.next(userId);
|
|
|
|
} else if (status === AuthenticationStatus.Locked) {
|
|
|
|
this.lock.next(userId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switchAccount(userId: UserId) {
|
|
|
|
if (userId == null) {
|
|
|
|
// indicates no account is active
|
|
|
|
this.activeAccountId.next(undefined);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.accounts.value[userId] == null) {
|
|
|
|
throw new Error("Account does not exist");
|
|
|
|
}
|
|
|
|
this.activeAccountId.next(userId);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: update to use our own account status settings. Requires inverting direction of state service accounts flow
|
2022-10-18 22:02:11 +02:00
|
|
|
async delete(): Promise<void> {
|
2022-07-29 21:49:58 +02:00
|
|
|
try {
|
2023-10-19 21:41:01 +02:00
|
|
|
this.messagingService?.send("logout");
|
2022-07-29 21:49:58 +02:00
|
|
|
} catch (e) {
|
|
|
|
this.logService.error(e);
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
2023-10-19 21:41:01 +02:00
|
|
|
|
|
|
|
private setAccountInfo(userId: UserId, accountInfo: AccountInfo) {
|
|
|
|
if (this.accounts.value[userId] == null) {
|
|
|
|
throw new Error("Account does not exist");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Avoid unnecessary updates
|
|
|
|
// TODO: Faster comparison, maybe include a hash on the objects?
|
|
|
|
if (JSON.stringify(this.accounts.value[userId]) === JSON.stringify(accountInfo)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.accounts.value[userId] = accountInfo;
|
|
|
|
this.accounts.next(this.accounts.value);
|
|
|
|
}
|
2022-07-29 21:49:58 +02:00
|
|
|
}
|