From a160c5331a53eca772250405c687fdfb2ee70a4e Mon Sep 17 00:00:00 2001 From: Chris Veilleux Date: Mon, 22 Oct 2018 21:44:21 -0500 Subject: [PATCH] new service for all skill add/remove logic --- .../src/app/skills/install.service.ts | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 market/frontend/v1/market-ui/src/app/skills/install.service.ts diff --git a/market/frontend/v1/market-ui/src/app/skills/install.service.ts b/market/frontend/v1/market-ui/src/app/skills/install.service.ts new file mode 100644 index 00000000..621cbe7c --- /dev/null +++ b/market/frontend/v1/market-ui/src/app/skills/install.service.ts @@ -0,0 +1,140 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, Subject } from "rxjs"; +import { AvailableSkill, SkillDetail } from "./skills.service"; + +type InstallStatus = 'failed' | 'installed' | 'installing' | 'uninstalling'; + +export interface SkillInstallStatus { + [key: string]: InstallStatus; +} + +export interface FailureReason { + [key: string]: string; +} + +export interface Installations { + failureReasons: FailureReason; + installStatuses: SkillInstallStatus; +} + +// const inProgressStatuses = ['installing', 'uninstalling', 'failed']; +const inProgressStatuses = ['installing', 'uninstalling']; +const installStatusUrl = '/api/skill/installations'; +const installUrl = '/api/skill/install'; +const uninstallUrl = '/api/skill/uninstall'; + +@Injectable({ + providedIn: 'root' +}) +export class InstallService { + public failureReasons: FailureReason; + public installStatuses = new Subject(); + public newInstallStatuses: SkillInstallStatus; + private prevInstallStatuses: SkillInstallStatus; + public statusNotifications = new Subject(); + + constructor(private http: HttpClient) { } + + getSkillInstallations() { + this.http.get(installStatusUrl).subscribe( + (installations) => { + this.newInstallStatuses = installations.installStatuses; + this.failureReasons = installations.failureReasons; + this.applyInstallStatusChanges(); + this.checkInstallationsInProgress(); + } + ) + } + + applyInstallStatusChanges() { + if (this.prevInstallStatuses) { + Object.keys(this.newInstallStatuses).forEach( + () => this.compareStatuses + ); + } + this.prevInstallStatuses = this.newInstallStatuses; + this.installStatuses.next(this.newInstallStatuses); + } + + compareStatuses(skillName: string) { + let prevSkillStatus = this.prevInstallStatuses[skillName]; + let newSkillStatus = this.newInstallStatuses[skillName]; + let statusNotifications: SkillInstallStatus = {}; + + switch (prevSkillStatus) { + case ('installing'): { + if (['installed', 'failed'].includes(newSkillStatus)) { + statusNotifications[skillName] = newSkillStatus; + } else { + this.newInstallStatuses[skillName] = prevSkillStatus; + } + break; + } + case ('uninstalling'): { + if (!newSkillStatus || newSkillStatus === 'failed') { + statusNotifications[skillName] = newSkillStatus; + } else { + this.newInstallStatuses[skillName] = prevSkillStatus; + } + break; + } + case ('failed'): { + if (!newSkillStatus || newSkillStatus != 'installed') { + statusNotifications[skillName] = newSkillStatus; + } else { + this.newInstallStatuses[skillName] = prevSkillStatus; + } + break; + } + } + + if (statusNotifications) { + this.statusNotifications.next(statusNotifications) + } + + } + + getSkillInstallStatus( + skill: AvailableSkill | SkillDetail, + installStatuses: SkillInstallStatus + ) { + let installStatus: string; + + if (skill.isSystemSkill) { + installStatus = 'system'; + } else { + installStatus = installStatuses[skill.name]; + } + + return installStatus; + } + + /** Poll at an interval to check the status of install/uninstall requests + * + * We want to avoid polling if we don't need it. Only poll if waiting for + * the result of a requested install/uninstall. + */ + checkInstallationsInProgress() { + let inProgress = Object.values(this.installStatuses).filter( + (installStatus) => inProgressStatuses.includes(installStatus) + ); + if (inProgress.length > 0) { + setTimeout(() => {this.getSkillInstallations();}, 10000); + } + } + + installSkill(skill: AvailableSkill): Observable { + return this.http.put( + installUrl, + {skill_name: skill.name} + ) + } + + uninstallSkill(skill: AvailableSkill): Observable { + return this.http.put( + uninstallUrl, + {skill_name: skill.name} + ) + } +}