MapComplete/src/Logic/ImageProviders/EmergencyImageBackup.ts

112 lines
3.8 KiB
TypeScript

import { IdbLocalStorage } from "../Web/IdbLocalStorage"
import { Store, UIEventSource } from "../UIEventSource"
import ThemeViewState from "../../Models/ThemeViewState"
import LinkImageAction from "../Osm/Actions/LinkImageAction"
import { WithImageState } from "../../Models/ThemeViewState/WithImageState"
export interface FailedImageArgs {
readonly featureId: string,
readonly author: string,
readonly blob: File,
readonly targetKey: string | undefined,
readonly noblur: boolean,
readonly ignoreGps: boolean,
readonly lastGpsLocation: GeolocationCoordinates,
readonly layoutId: string
readonly date: number
}
export default class EmergencyImageBackup {
public static readonly singleton = new EmergencyImageBackup()
private readonly _failedImages: UIEventSource<FailedImageArgs[]>
public readonly failedImages: Store<FailedImageArgs[]>
private readonly _isUploading: UIEventSource<boolean> = new UIEventSource(false)
public readonly isUploading: Store<boolean> = this._isUploading
private constructor() {
this._failedImages = IdbLocalStorage.Get<FailedImageArgs[]>("failed-images-backup", { defaultValue: [] })
this.failedImages = this._failedImages
}
public addFailedImage(args: FailedImageArgs) {
this._failedImages.data.push(args)
this._failedImages.ping()
}
public delete(img: FailedImageArgs) {
const index = this._failedImages.data.indexOf(img)
if (index < 0) {
return
}
this._failedImages.data.splice(index, 1)
this._failedImages.ping()
}
/**
* Retries uploading the given image
* Returns 'true' if the image got correctly uploaded and linked (or upload is no longer necessary, e.g. deleted iem)
* @param state
* @param i
*/
public async retryUploading(state: ThemeViewState, i: FailedImageArgs): Promise<boolean> {
this._isUploading.set(true)
try {
const feature = await state.osmObjectDownloader.DownloadObjectAsync(i.featureId)
if (feature === "deleted") {
return true
}
const asGeojson = feature.asGeoJson()
const uploadResult = await state.imageUploadManager.uploadImageWithLicense(
i.featureId,
i.author,
i.blob,
i.targetKey,
i.noblur,
asGeojson,
{
ignoreGps: i.ignoreGps,
noBackup: true,// Don't save this _again_
overwriteGps: i.lastGpsLocation
}
)
if (!uploadResult) {
// Upload failed again
return false
}
state.featureProperties.trackFeature(asGeojson)
const properties = state.featureProperties.getStore(i.featureId)
// Upload successful, time to link this to the image
const action = new LinkImageAction(
i.featureId,
uploadResult.key,
uploadResult.value,
properties,
{
theme: i.layoutId,
changeType: "add-image"
}
)
await state.changes.applyAction(action)
await state.changes.flushChanges("delayed image upload link")
this.delete(i)
return true
} finally {
this._isUploading.set(false)
}
}
public async retryAll(state: WithImageState) {
for (const img of [...this._failedImages.data]) {
await this.retryUploading(state, img)
/*this._isUploading.setData(true)
await Utils.waitFor(2000)
this._isUploading.set(false)*/
}
}
}