digitalfabrik/integreat-app

View on GitHub
native/ios/Integreat/fetcher/FetchResultCollector.swift

Summary

Maintainability
A
25 mins
Test Coverage
import Foundation
import os

class FetchResultCollector {
  var fetchResults = [String : FetchResult]()
  var resultQueue = DispatchQueue(label: "FetchResultQueue")

  var emitter: RCTEventEmitter
  var resolve: RCTPromiseResolveBlock
  var reject: RCTPromiseRejectBlock
  var expectedFetchCount: Int
  var hasListeners: Bool

  init(emitter: RCTEventEmitter, expectedFetchCount: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
    self.emitter = emitter
    self.resolve = resolve
    self.reject = reject
    self.expectedFetchCount = expectedFetchCount
    self.hasListeners = false
  }

  func failed(url: String, targetFile: URL, message: String) {
    resultQueue.async {
      self.fetchResults[targetFile.path] = FetchResult(url: url, lastUpdate: Date(), alreadyExisted: false, errorMessage: message)
      
      os_log("[%d/%d] Failed to download %s: %s", type: .info, self.currentFetchCount(), self.expectedFetchCount, url, message);
      
      self.sendProgress()
      self.tryToResolve()
    }
  }

  func fetched(url: String, targetFile: URL) {
    success(url: url, targetFile: targetFile, alreadyExisted: false);
  }

  func alreadyExists(url: String, targetFile: URL) {
    success(url: url, targetFile: targetFile, alreadyExisted: true);
  }

  func success(url: String, targetFile: URL, alreadyExisted: Bool) {
    resultQueue.async {
      self.fetchResults[targetFile.path] = FetchResult(url: url, lastUpdate: Date(),alreadyExisted: alreadyExisted, errorMessage: nil)

      os_log("[%d/%d] Downloaded a file: %s", type: .info, self.currentFetchCount(), self.expectedFetchCount, url);

      self.sendProgress();
      self.tryToResolve();
    }
  }

  func currentFetchCount() -> Int {
    return fetchResults.count
  }

  func tryToResolve() {
    if (currentFetchCount() != expectedFetchCount) {
      return;
    }

    var resolveValue = [String : [String : String]]()

    for (filePath, result) in fetchResults {
      var fetchResult = [String : String]()
      let dateTime = result.lastUpdate

      fetchResult["url"] = result.url

      if (result.alreadyExisted) {
        fetchResult["lastUpdate"] = dateTime.iso8601
      }

      if (result.errorMessage != nil) {
        fetchResult["errorMessage"] = result.errorMessage
      }

      resolveValue[filePath] = fetchResult
    }

    os_log("Resolving promise", type: .info)
    resolve(resolveValue)
  }

  // Will be called when this module's first listener is added.
  func startObserving() {
    hasListeners = true;
  }

  // Will be called when this module's last listener is removed, or on dealloc.
  func stopObserving() {
    hasListeners = false;
  }

  func sendProgress() {
    if (hasListeners) {
      emitter.sendEvent(withName: "progress", body: Double(fetchResults.count) / Double(expectedFetchCount))
    }
  }
}