diff --git a/src/Logic/ImageProviders/ImageUploadManager.ts b/src/Logic/ImageProviders/ImageUploadManager.ts index a39f88c061..7a0e3b1607 100644 --- a/src/Logic/ImageProviders/ImageUploadManager.ts +++ b/src/Logic/ImageProviders/ImageUploadManager.ts @@ -3,7 +3,7 @@ import LinkImageAction from "../Osm/Actions/LinkImageAction" import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore" import { NoteId, OsmId, OsmTags } from "../../Models/OsmFeature" import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" -import { Store, UIEventSource } from "../UIEventSource" +import { Store, Stores, UIEventSource } from "../UIEventSource" import { OsmConnection } from "../Osm/OsmConnection" import { Changes } from "../Osm/Changes" import Translations from "../../UI/i18n/Translations" @@ -80,6 +80,10 @@ export class ImageUploadManager { this._changes = changes this._gps = gpsLocation this._reportError = reportError + Stores.Chronic(5 * 60000).addCallback(() => { + // If images failed to upload: attempt to reupload + this.uploadQueue() + }) } public async canBeUploaded(file: File): Promise { @@ -166,16 +170,26 @@ export class ImageUploadManager { if (this.uploadingAll) { return } - const queue = this._queue.imagesInQueue.data ?? [] + let queue = this._queue.imagesInQueue.data ?? [] if (queue.length === 0) { return } console.log("Checking image upload queue and uploading if needed") this.uploadingAll = true try { + queue = [...queue] while (queue.length > 0) { - const currentItem = queue[0] - await this.handleQueueItem(currentItem) + const currentItem = queue.shift() + if(!currentItem){ + continue + } + const uploadOk = await this.handleQueueItem(currentItem) + if(uploadOk){ + this._queue.delete(currentItem) + }else{ + // Our local 'queue' is a copy where we've removed the failed item from + // A next attempt to 'uploadQueue' will retry the upload + } } } catch (e) { console.error("Error while handling the queue:", e) @@ -192,14 +206,11 @@ export class ImageUploadManager { * - Applies the action to the correct element * - indicates failure * - * Modifies the queue: if the upload is successfull, deletes the item from the queue - * @private + * Will _not_ modify the queue: if the upload is successful, deletes the item from the queue. + * @returns true if successful (and the item should be deleted from the queue), false if something failed */ - private async handleQueueItem(args: ImageUploadArguments): Promise { + private async handleQueueItem(args: NonNullable): Promise { console.log("Handling queue item", args.blob.name, args) - if (!args) { - return - } this._isUploading.set(args.featureId) let result: UploadResult = undefined @@ -221,7 +232,7 @@ export class ImageUploadManager { if (result === undefined) { this._fails.data.push(args) this._fails.ping() - return + return false } let properties: UIEventSource> = this._featureProperties.getStore( args.featureId @@ -239,34 +250,33 @@ export class ImageUploadManager { osmConnection: this._osmConnection, }) } - } else { - if (properties === undefined) { - const downloaded = await new OsmObjectDownloader( - this._osmConnection.Backend(), - this._changes - ).DownloadObjectAsync(args.featureId) - if (downloaded === "deleted") { - this._queue.delete(args) - return - } - this._featureProperties.trackFeature(downloaded.asGeoJson()) - properties = this._featureProperties.getStore(args.featureId) - } - const action = new LinkImageAction( - args.featureId, - result.key, - result.value, - properties, - { - theme: args.layoutId ?? properties?.data?.["_orig_theme"] ?? this._theme.id, - changeType: "add-image", - } - ) - await this._changes.applyAction(action) - await this._changes.flushChanges("Image upload completed") + return true } - - this._queue.delete(args) + if (properties === undefined) { + const downloaded = await new OsmObjectDownloader( + this._osmConnection.Backend(), + this._changes, + ).DownloadObjectAsync(args.featureId) + if (downloaded === "deleted") { + this._queue.delete(args) + return + } + this._featureProperties.trackFeature(downloaded.asGeoJson()) + properties = this._featureProperties.getStore(args.featureId) + } + const action = new LinkImageAction( + args.featureId, + result.key, + result.value, + properties, + { + theme: args.layoutId ?? properties?.data?.["_orig_theme"] ?? this._theme.id, + changeType: "add-image", + }, + ) + await this._changes.applyAction(action) + await this._changes.flushChanges("Image upload completed") + return true } /**