Rework device and folder service to have public obseravble

to accomaccommodatemodate many subscribers without re-requesting data
from the API
This commit is contained in:
Jesse Lucas 2020-04-10 22:06:27 -04:00
parent 24a637e9e6
commit ae776ff8df
6 changed files with 129 additions and 97 deletions

View File

@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild, Input } from '@angular/core'; import { Component, OnInit, ViewChild, Input, Type } from '@angular/core';
import Folder from '../../folder' import Folder from '../../folder'
import { FolderService } from 'src/app/services/folder.service'; import { FolderService } from 'src/app/services/folder.service';
import { DonutChartComponent } from '../donut-chart/donut-chart.component'; import { DonutChartComponent } from '../donut-chart/donut-chart.component';
@ -6,6 +6,7 @@ import { DeviceService } from 'src/app/services/device.service';
import Device from 'src/app/device'; import Device from 'src/app/device';
import { StType } from '../../type'; import { StType } from '../../type';
import { FilterService } from 'src/app/services/filter.service'; import { FilterService } from 'src/app/services/filter.service';
import { Observable } from 'rxjs';
export interface ChartItemState { export interface ChartItemState {
@ -27,12 +28,12 @@ export class ChartComponent implements OnInit {
chartID: string; chartID: string;
states: ChartItemState[] = []; states: ChartItemState[] = [];
private service: any; private observer: Observable<any>;
private activeChartState: ChartItemState; private activeChartState: ChartItemState;
constructor( constructor(
private folderService: FolderService, private folderService: FolderService,
private deviceServce: DeviceService, private deviceService: DeviceService,
private filterService: FilterService, private filterService: FilterService,
) { } ) { }
@ -60,19 +61,19 @@ export class ChartComponent implements OnInit {
case StType.Folder: case StType.Folder:
this.title = "Folders"; this.title = "Folders";
this.chartID = 'foldersChart'; this.chartID = 'foldersChart';
this.service = this.folderService; this.observer = this.folderService.folderAdded$;
break; break;
case StType.Device: case StType.Device:
this.title = "Devices"; this.title = "Devices";
this.chartID = 'devicesChart'; this.chartID = 'devicesChart';
this.service = this.deviceServce; this.observer = this.deviceService.deviceAdded$;
break; break;
} }
} }
ngAfterViewInit() { ngAfterViewInit() {
let totalCount: number = 0; let totalCount: number = 0;
this.service.getEach().subscribe( this.observer.subscribe(
t => { t => {
// Count the number of folders and set chart // Count the number of folders and set chart
totalCount++; totalCount++;

View File

@ -14,6 +14,8 @@ import { MatProgressBar } from '@angular/material/progress-bar';
import { MessageService } from '../services/message.service'; import { MessageService } from '../services/message.service';
import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { DialogComponent } from '../dialog/dialog.component'; import { DialogComponent } from '../dialog/dialog.component';
import { FolderService } from '../services/folder.service';
import { DeviceService } from '../services/device.service';
@Component({ @Component({
selector: 'app-dashboard', selector: 'app-dashboard',
@ -64,16 +66,21 @@ export class DashboardComponent implements OnInit, AfterViewInit {
constructor( constructor(
private systemConfigService: SystemConfigService, private systemConfigService: SystemConfigService,
private folderService: FolderService,
private deviceService: DeviceService,
private progressService: ProgressService, private progressService: ProgressService,
private messageService: MessageService, private messageService: MessageService,
public dialog: MatDialog public dialog: MatDialog
) { } ) { }
ngOnInit() { ngOnInit() {
// Request data from Rest API
this.systemConfigService.getSystemConfig().subscribe( this.systemConfigService.getSystemConfig().subscribe(
x => console.log('Observer got a next value: ' + x), _ => {
err => console.error('Observer got an error: ' + err), // Request devices and folders for charts and lists
() => console.log('Observer got a complete notification') this.folderService.requestFolders();
this.deviceService.requestDevices();
}
); );
} }

View File

@ -8,6 +8,7 @@ import { SystemConfigService } from '../../services/system-config.service';
import { FilterService } from 'src/app/services/filter.service'; import { FilterService } from 'src/app/services/filter.service';
import { StType } from 'src/app/type'; import { StType } from 'src/app/type';
import { MatInput } from '@angular/material/input'; import { MatInput } from '@angular/material/input';
import { DeviceService } from 'src/app/services/device.service';
@Component({ @Component({
selector: 'app-device-list', selector: 'app-device-list',
@ -22,10 +23,10 @@ export class DeviceListComponent implements AfterViewInit, OnInit, OnDestroy {
dataSource: MatTableDataSource<Device>; dataSource: MatTableDataSource<Device>;
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['id', 'name', 'state']; displayedColumns = ['id', 'name', 'state', 'folders'];
constructor( constructor(
private systemConfigService: SystemConfigService, private deviceService: DeviceService,
private filterService: FilterService, private filterService: FilterService,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
) { }; ) { };
@ -41,9 +42,19 @@ export class DeviceListComponent implements AfterViewInit, OnInit, OnDestroy {
this.dataSource = new MatTableDataSource(); this.dataSource = new MatTableDataSource();
this.dataSource.data = []; this.dataSource.data = [];
this.systemConfigService.getDevices().subscribe( // Replace all data when requests are finished
data => { this.deviceService.devicesUpdated$.subscribe(
this.dataSource.data = data; devices => {
this.dataSource.data = devices;
}
);
// Add device as they come in
let devices: Device[] = [];
this.deviceService.deviceAdded$.subscribe(
device => {
devices.push(device);
this.dataSource.data = devices;
} }
); );
} }

View File

@ -25,7 +25,7 @@ export class FolderListComponent implements AfterViewInit, OnInit, OnDestroy {
displayedColumns = ['id', 'label', 'path', 'state']; displayedColumns = ['id', 'label', 'path', 'state'];
constructor( constructor(
private systemConfigService: SystemConfigService, private folderService: FolderService,
private filterService: FilterService, private filterService: FilterService,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
) { ) {
@ -41,11 +41,21 @@ export class FolderListComponent implements AfterViewInit, OnInit, OnDestroy {
this.dataSource = new MatTableDataSource(); this.dataSource = new MatTableDataSource();
this.dataSource.data = []; this.dataSource.data = [];
this.systemConfigService.getFolders().subscribe( // Replace all data when requests are finished
data => { this.folderService.foldersUpdated$.subscribe(
this.dataSource.data = data; folders => {
this.dataSource.data = folders;
} }
); );
// Add device as they come in
let folders: Folder[] = [];
this.folderService.folderAdded$.subscribe(
folder => {
folders.push(folder);
this.dataSource.data = folders;
}
);;
} }
ngAfterViewInit() { ngAfterViewInit() {

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import Device from '../device'; import Device from '../device';
import { Observable, Subscriber } from 'rxjs'; import { Observable, Subscriber, ReplaySubject, Subject } from 'rxjs';
import { SystemConfigService } from './system-config.service'; import { SystemConfigService } from './system-config.service';
import { SystemConnectionsService } from './system-connections.service'; import { SystemConnectionsService } from './system-connections.service';
import { DbCompletionService } from './db-completion.service'; import { DbCompletionService } from './db-completion.service';
@ -15,7 +15,12 @@ import { StType } from '../type';
export class DeviceService { export class DeviceService {
private devices: Device[]; private devices: Device[];
private sysConns: SystemConnections; private sysConns: SystemConnections;
thisDevice: Device; private devicesSubject: ReplaySubject<Device[]> = new ReplaySubject(1);
devicesUpdated$ = this.devicesSubject.asObservable();
private thisDevice: Device;
private deviceAddedSource = new Subject<Device>();
deviceAdded$ = this.deviceAddedSource.asObservable();
constructor( constructor(
private systemConfigService: SystemConfigService, private systemConfigService: SystemConfigService,
@ -25,10 +30,12 @@ export class DeviceService {
private progressService: ProgressService, private progressService: ProgressService,
) { } ) { }
getDeviceStatusInOrder(observer: Subscriber<Device>, startIndex: number) { getDeviceStatusInOrder(startIndex: number) {
// Return if there aren't any device at the index // Return if there aren't any device at the index
if (startIndex >= (this.devices.length)) { if (startIndex >= (this.devices.length)) {
observer.complete(); this.devicesSubject.next(this.devices);
// this.devicesSubject.complete();
// this.deviceAddedSource.complete();
return; return;
} }
const device: Device = this.devices[startIndex]; const device: Device = this.devices[startIndex];
@ -53,76 +60,73 @@ export class DeviceService {
Device.recalcCompletion(device); Device.recalcCompletion(device);
device.stateType = Device.getStateType(device); device.stateType = Device.getStateType(device);
device.state = Device.stateTypeToString(device.stateType); device.state = Device.stateTypeToString(device.stateType);
observer.next(device);
this.deviceAddedSource.next(device);
this.progressService.addToProgress(1); this.progressService.addToProgress(1);
// recursively get the status of the next device // recursively get the status of the next device
this.getDeviceStatusInOrder(observer, startIndex); this.getDeviceStatusInOrder(startIndex);
}); });
} }
/** /**
* getEach() returns each device * getEach() returns each device
*/ */
getEach(): Observable<Device> { requestDevices() {
const deviceObservable: Observable<Device> = new Observable((observer) => { this.systemConfigService.getDevices().subscribe(
// TODO return devices if cached devices => {
this.devices = devices;
this.systemConfigService.getDevices().subscribe( // First check to see which device is local 'thisDevice'
devices => { this.systemStatusService.getSystemStatus().subscribe(
this.devices = devices; status => {
this.devices.forEach(device => {
if (device.deviceID === status.myID) {
// TODO Determine if it should ignore thisDevice
this.thisDevice = device;
}
});
// First check to see which device is local 'thisDevice' // Check folder devices to see if the device is used
this.systemStatusService.getSystemStatus().subscribe( this.systemConfigService.getFolders().subscribe(
status => { folders => {
this.devices.forEach(device => { // Loop through all folder devices to see if the device is used
if (device.deviceID === status.myID) { this.devices.forEach(device => {
// TODO Determine if it should ignore thisDevice // Alloc array if needed
this.thisDevice = device; if (!device.folders) {
} device.folders = [];
}); device.folderNames = [];
}
// Check folder devices to see if the device is used folders.forEach(folder => {
this.systemConfigService.getFolders().subscribe( folder.devices.forEach(fdevice => {
folders => { if (device.deviceID === fdevice.deviceID) {
// Loop through all folder devices to see if the device is used // The device is used by a folder
this.devices.forEach(device => { device.used = true;
// Alloc array if needed
if (!device.folders) {
device.folders = [];
}
folders.forEach(folder => { // Add a reference to the folder to the device
folder.devices.forEach(fdevice => { device.folders.push(folder);
if (device.deviceID === fdevice.deviceID) {
// The device is used by a folder
device.used = true;
// Add a reference to the folder to the device // Add string folder name
device.folders.push(folder); device.folderNames.push(folder.label);
} }
});
}); });
}); });
// See if the connection is connected or undefined
this.systemConnectionsService.getSystemConnections().subscribe(
c => {
this.sysConns = c;
// Synchronously get the status of each device
this.getDeviceStatusInOrder(observer, 0);
}
);
}); });
}
) // See if the connection is connected or undefined
}, this.systemConnectionsService.getSystemConnections().subscribe(
err => { console.log("getEach error!", err) }, c => {
() => { console.log("getEach complete!") } this.sysConns = c;
);
}); // Synchronously get the status of each device
return deviceObservable this.getDeviceStatusInOrder(0);
}
);
});
}
)
}
);
} }
} }

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { SystemConfigService } from './system-config.service'; import { SystemConfigService } from './system-config.service';
import { Observable, Subscriber } from 'rxjs'; import { Observable, Subscriber, Subject, ReplaySubject } from 'rxjs';
import Folder from '../folder'; import Folder from '../folder';
import { DbStatusService } from './db-status.service'; import { DbStatusService } from './db-status.service';
import { ProgressService } from './progress.service'; import { ProgressService } from './progress.service';
@ -12,6 +12,10 @@ import { StType } from '../type';
}) })
export class FolderService { export class FolderService {
private folders: Folder[]; private folders: Folder[];
private foldersSubject: ReplaySubject<Folder[]> = new ReplaySubject(1);
foldersUpdated$ = this.foldersSubject.asObservable();
private folderAddedSource = new Subject<Folder>();
folderAdded$ = this.folderAddedSource.asObservable();
constructor( constructor(
private systemConfigService: SystemConfigService, private systemConfigService: SystemConfigService,
@ -20,10 +24,11 @@ export class FolderService {
private progressService: ProgressService, private progressService: ProgressService,
) { } ) { }
getFolderStatusInOrder(observer: Subscriber<Folder>, startIndex: number) { getFolderStatusInOrder(startIndex: number) {
// Return if there aren't any folders at the index // Return if there aren't any folders at the index
if (startIndex >= (this.folders.length)) { if (startIndex >= (this.folders.length)) {
observer.complete(); this.foldersSubject.next(this.folders);
// this.folderAddedSource.complete();
return; return;
} }
const folder: Folder = this.folders[startIndex]; const folder: Folder = this.folders[startIndex];
@ -37,37 +42,31 @@ export class FolderService {
folder.completion = c; folder.completion = c;
folder.stateType = Folder.getStateType(folder); folder.stateType = Folder.getStateType(folder);
folder.state = Folder.stateTypeToString(folder.stateType); folder.state = Folder.stateTypeToString(folder.stateType);
observer.next(folder);
this.folderAddedSource.next(folder);
this.progressService.addToProgress(1); this.progressService.addToProgress(1);
// recursively get the status of the next folder // recursively get the status of the next folder
this.getFolderStatusInOrder(observer, startIndex); this.getFolderStatusInOrder(startIndex);
}); });
} }
); );
} }
/** /**
* getEach() returns each folder and uses db status service to * requestFolders() requests each folder and uses db status service to
* set all their statuses and db completion service to find * set all their statuses and db completion service to find
* completion * completion in order. Updating folderAdded$ and foldersUpdate$
* observers
*/ */
getEach(): Observable<Folder> { requestFolders() {
// TODO return this.folders if cached this.systemConfigService.getFolders().subscribe(
folders => {
this.folders = folders;
const folderObservable: Observable<Folder> = new Observable((observer) => { // Synchronously get the status of each folder
this.systemConfigService.getFolders().subscribe( this.getFolderStatusInOrder(0);
folders => { }
this.folders = folders; );
// Synchronously get the status of each folder
this.getFolderStatusInOrder(observer, 0);
},
err => { console.log("getEach error!", err) },
() => { console.log("getEach complete!") }
);
});
return folderObservable;
} }
} }