better transfer progress (#2350)

* better transfer progress

* frontend for calculating transfer size

* fixes from testing

* improve internal api

---------

Co-authored-by: Matt Hill <mattnine@protonmail.com>
This commit is contained in:
Aiden McClelland
2023-07-13 19:40:53 -06:00
committed by GitHub
parent cc0e525dc5
commit 2c07cf50fa
8 changed files with 203 additions and 149 deletions

View File

@@ -2,15 +2,12 @@
<ion-grid>
<ion-row class="ion-align-items-center">
<ion-col class="ion-text-center">
<ion-card
*ngIf="{ decimal: progress$ | async } as progress"
color="dark"
>
<ion-card *ngIf="progress$ | async as progress" color="dark">
<ion-card-header>
<ion-card-title>Initializing StartOS</ion-card-title>
<div class="center-wrapper">
<ion-card-subtitle *ngIf="progress.decimal as decimal">
Progress: {{ (decimal * 100).toFixed(0)}}%
<ion-card-subtitle>
{{ progress.transferred | toMessage }}
</ion-card-subtitle>
</div>
</ion-card-header>
@@ -18,16 +15,22 @@
<ion-card-content class="ion-margin">
<ion-progress-bar
color="tertiary"
style="
max-width: 700px;
margin: auto;
padding-bottom: 20px;
margin-bottom: 40px;
"
[type]="progress.decimal && progress.decimal < 1 ? 'determinate' : 'indeterminate'"
[value]="progress.decimal || 0"
style="max-width: 700px; margin: auto; margin-bottom: 36px"
[type]="progress.transferred && progress.transferred < 1 ? 'determinate' : 'indeterminate'"
[value]="progress.transferred || 0"
></ion-progress-bar>
<p>{{ progress.decimal | toMessage }}</p>
<p>
<ng-container *ngIf="progress.totalBytes as total">
<ng-container
*ngIf="progress.transferred as transferred; else calculating"
>
Progress: {{ (transferred * 100).toFixed() }}%
</ng-container>
<ng-template #calculating>
{{ (progress.totalBytes / 1073741824).toFixed(2) }} GB
</ng-template>
</ng-container>
</p>
</ion-card-content>
</ion-card>
</ion-col>

View File

@@ -2,6 +2,14 @@ import { Component } from '@angular/core'
import { NavController } from '@ionic/angular'
import { StateService } from 'src/app/services/state.service'
import { Pipe, PipeTransform } from '@angular/core'
import { BehaviorSubject } from 'rxjs'
import { ApiService } from 'src/app/services/api/api.service'
import { ErrorToastService, pauseFor } from '@start9labs/shared'
type Progress = {
totalBytes: number | null
transferred: number
}
@Component({
selector: 'app-loading',
@@ -9,23 +17,49 @@ import { Pipe, PipeTransform } from '@angular/core'
styleUrls: ['loading.page.scss'],
})
export class LoadingPage {
readonly progress$ = this.stateService.dataProgress$
readonly progress$ = new BehaviorSubject<Progress>({
totalBytes: null,
transferred: 0,
})
constructor(
private readonly stateService: StateService,
private readonly navCtrl: NavController,
private readonly api: ApiService,
private readonly errorToastService: ErrorToastService,
) {}
ngOnInit() {
this.stateService.pollDataTransferProgress()
const progSub = this.stateService.dataCompletionSubject$.subscribe(
async complete => {
if (complete) {
progSub.unsubscribe()
await this.navCtrl.navigateForward(`/success`)
}
},
)
this.poll()
}
async poll() {
try {
const progress = await this.api.getStatus()
if (!progress) return
const {
'total-bytes': totalBytes,
'bytes-transferred': bytesTransferred,
} = progress
this.progress$.next({
totalBytes,
transferred: totalBytes ? bytesTransferred / totalBytes : 0,
})
if (progress.complete) {
this.navCtrl.navigateForward(`/success`)
this.progress$.complete()
return
}
await pauseFor(250)
setTimeout(() => this.poll(), 0) // prevent call stack from growing
} catch (e: any) {
this.errorToastService.present(e)
}
}
}
@@ -41,7 +75,7 @@ export class ToMessagePipe implements PipeTransform {
}
if (!progress) {
return 'Preparing data. This can take a while'
return 'Calculating size'
} else if (progress < 1) {
return 'Copying data'
} else {

View File

@@ -17,8 +17,6 @@ let tries: number
export class MockApiService extends ApiService {
async getStatus() {
const restoreOrMigrate = true
const total = 4
await pauseFor(1000)
if (tries === undefined) {
@@ -27,7 +25,9 @@ export class MockApiService extends ApiService {
}
tries++
const progress = tries - 1
const total = tries <= 4 ? tries * 268435456 : 1073741824
const progress = tries > 4 ? (tries - 4) * 268435456 : 0
return {
'bytes-transferred': restoreOrMigrate ? progress : 0,

View File

@@ -1,7 +1,5 @@
import { Injectable } from '@angular/core'
import { BehaviorSubject } from 'rxjs'
import { ApiService, RecoverySource } from './api/api.service'
import { pauseFor, ErrorToastService } from '@start9labs/shared'
@Injectable({
providedIn: 'root',
@@ -12,47 +10,7 @@ export class StateService {
recoverySource?: RecoverySource
recoveryPassword?: string
dataTransferProgress?: {
bytesTransferred: number
totalBytes: number | null
complete: boolean
}
dataProgress$ = new BehaviorSubject<number>(0)
dataCompletionSubject$ = new BehaviorSubject(false)
constructor(
private readonly api: ApiService,
private readonly errorToastService: ErrorToastService,
) {}
async pollDataTransferProgress() {
await pauseFor(500)
if (this.dataTransferProgress?.complete) {
this.dataCompletionSubject$.next(true)
return
}
try {
const progress = await this.api.getStatus()
if (!progress) return
this.dataTransferProgress = {
bytesTransferred: progress['bytes-transferred'],
totalBytes: progress['total-bytes'],
complete: progress.complete,
}
if (this.dataTransferProgress.totalBytes) {
this.dataProgress$.next(
this.dataTransferProgress.bytesTransferred /
this.dataTransferProgress.totalBytes,
)
}
} catch (e: any) {
this.errorToastService.present(e)
}
setTimeout(() => this.pollDataTransferProgress(), 0) // prevent call stack from growing
}
constructor(private readonly api: ApiService) {}
async importDrive(guid: string, password: string): Promise<void> {
await this.api.attach({