Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Bits.sys.mjs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * This module is used to interact with the Windows BITS component (Background
 * Intelligent Transfer Service). This functionality cannot be used unless on
 * Windows.
 *
 * The reason for this file's existence is that the interfaces in nsIBits.idl
 * are asynchronous, but are unable to use Promises because they are implemented
 * in Rust, which does not yet support Promises. This file functions as a layer
 * between the Rust and the JS that provides access to the functionality
 * provided by nsIBits via Promises rather than callbacks.
 */

import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";

const lazy = {};

// This conditional prevents errors if this file is imported from operating
// systems other than Windows. This is purely for convenient importing, because
// attempting to use anything in this file on platforms other than Windows will
// result in an error.
if (AppConstants.MOZ_BITS_DOWNLOAD) {
  XPCOMUtils.defineLazyServiceGetter(
    lazy,
    "gBits",
    "@mozilla.org/bits;1",
    "nsIBits"
  );
}

// This value exists to mitigate a very unlikely problem: If a BITS method
// catastrophically fails, it may never call its callback. This would result in
// methods in this file returning promises that never resolve. This could, in
// turn, lead to download code hanging altogether rather than being able to
// report errors and utilize fallback mechanisms.
// This problem is mitigated by giving these promises a timeout, the length of
// which will be determined by this value.
const kBitsMethodTimeoutMs = 10 * 60 * 1000; // 10 minutes

/**
 * This class will wrap the errors returned by the nsIBits interface to make
 * them more uniform and more easily consumable.
 *
 * The values of stored by this error type are entirely numeric. This should
 * make them easier to consume with JS and telemetry, but does make them fairly
 * unreadable. nsIBits.idl will need to be referenced to look up what errors
 * the values correspond to.
 *
 * The type of BitsError.code is dependent on the value of BitsError.codeType.
 * It may be null, a number (corresponding to an nsresult or hresult value),
 * a string, or an exception.
 */
export class BitsError extends Error {
  // If codeType == "none", code may be unspecified.
  constructor(type, action, stage, codeType, code) {
    let message =
      `${BitsError.name} {type: ${type}, action: ${action}, ` +
      `stage: ${stage}`;
    switch (codeType) {
      case lazy.gBits.ERROR_CODE_TYPE_NONE:
        code = null;
        message += ", codeType: none}";
        break;
      case lazy.gBits.ERROR_CODE_TYPE_NSRESULT:
        message += `, codeType: nsresult, code: ${code}}`;
        break;
      case lazy.gBits.ERROR_CODE_TYPE_HRESULT:
        message += `, codeType: hresult, code: 0x${BigInt(code >>> 0).toString(
          16
        )}`;
        break;
      case lazy.gBits.ERROR_CODE_TYPE_STRING:
        message += `, codeType: string, code: ${JSON.stringify(code)}}`;
        break;
      case lazy.gBits.ERROR_CODE_TYPE_EXCEPTION:
        message += `, codeType: exception, code: ${code}}`;
        break;
      default:
        message += ", codeType: invalid}";
        break;
    }
    super(message);

    this.type = type;
    this.action = action;
    this.stage = stage;
    this.codeType = codeType;
    this.code = code;
    this.name = this.constructor.name;
    this.succeeded = false;
  }
}

// These specializations exist to make them easier to construct since they may
// need to be constructed outside of this file.
export class BitsVerificationError extends BitsError {
  constructor() {
    super(
      Ci.nsIBits.ERROR_TYPE_VERIFICATION_FAILURE,
      Ci.nsIBits.ERROR_ACTION_NONE,
      Ci.nsIBits.ERROR_STAGE_VERIFICATION,
      Ci.nsIBits.ERROR_CODE_TYPE_NONE
    );
  }
}

export class BitsUnknownError extends BitsError {
  constructor() {
    super(
      Ci.nsIBits.ERROR_TYPE_UNKNOWN,
      Ci.nsIBits.ERROR_ACTION_UNKNOWN,
      Ci.nsIBits.ERROR_STAGE_UNKNOWN,
      Ci.nsIBits.ERROR_CODE_TYPE_NONE
    );
  }
}

/**
 * Returns a timer object. If the timer expires, reject will be called with
 * a BitsError error. The timer's cancel method should be called if the promise
 * resolves or rejects without the timeout expiring.
 */
function makeTimeout(reject, errorAction) {
  let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  timer.initWithCallback(
    () => {
      let error = new BitsError(
        lazy.gBits.ERROR_TYPE_METHOD_TIMEOUT,
        errorAction,
        lazy.gBits.ERROR_STAGE_UNKNOWN,
        lazy.gBits.ERROR_CODE_TYPE_NONE
      );
      reject(error);
    },
    kBitsMethodTimeoutMs,
    Ci.nsITimer.TYPE_ONE_SHOT
  );
  return timer;
}

/**
 * This function does all of the wrapping and error handling for an async
 * BitsRequest method. This allows the implementations for those methods to
 * simply call this function with a closure that executes appropriate
 * nsIBitsRequest method.
 *
 * Specifically, this function takes an nsBitsErrorAction and a function.
 * The nsBitsErrorAction will be used when constructing a BitsError, if the
 * wrapper encounters an error.
 * The function will be passed the callback function that should be passed to
 * the nsIBitsRequest method.
 */
async function requestPromise(errorAction, actionFn) {
  return new Promise((resolve, reject) => {
    let timer = makeTimeout(reject, errorAction);

    let callback = {
      QueryInterface: ChromeUtils.generateQI(["nsIBitsCallback"]),
      success() {
        timer.cancel();
        resolve();
      },
      failure(type, action, stage) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_NONE
        );
        reject(error);
      },
      failureNsresult(type, action, stage, code) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_NSRESULT,
          code
        );
        reject(error);
      },
      failureHresult(type, action, stage, code) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_HRESULT,
          code
        );
        reject(error);
      },
      failureString(type, action, stage, message) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_STRING,
          message
        );
        reject(error);
      },
    };

    try {
      actionFn(callback);
    } catch (e) {
      let error = new BitsError(
        lazy.gBits.ERROR_TYPE_METHOD_THREW,
        errorAction,
        lazy.gBits.ERROR_STAGE_PRETASK,
        lazy.gBits.ERROR_CODE_TYPE_EXCEPTION,
        e
      );
      reject(error);
    }
  });
}

/**
 * This class is a wrapper around nsIBitsRequest that converts functions taking
 * callbacks to asynchronous functions. This class implements nsIRequest.
 *
 * Note that once the request has been shutdown, calling methods on it will
 * cause an exception to be thrown. The request will be shutdown automatically
 * when the BITS job is successfully completed or cancelled. If the request is
 * no longer needed, but the transfer is still in progress, the shutdown method
 * should be called manually to prevent memory leaks.
 * Getter methods (except loadGroup and loadFlags) should continue to be
 * accessible, even after shutdown.
 */
export class BitsRequest {
  constructor(request) {
    this._request = request;
    this._request.QueryInterface(Ci.nsIBitsRequest);
  }

  /**
   * This function releases the Rust request that backs this wrapper. Calling
   * any method on this request after calling release will result in a BitsError
   * being thrown.
   *
   * This step is important, because otherwise a cycle exists that the cycle
   * collector doesn't know about. To break this cycle, either the Rust request
   * needs to let go of the observer, or the JS request wrapper needs to let go
   * of the Rust request (which is what we do here).
   *
   * Once there is support for cycle collection of cycles that extend through
   * Rust, this function may no longer be necessary.
   */
  shutdown() {
    if (this.hasShutdown) {
      return;
    }
    // Cache some values before we shut down so they are still available
    this._name = this._request.name;
    this._status = this._request.status;
    this._bitsId = this._request.bitsId;
    this._transferError = this._request.transferError;

    this._request = null;
  }

  /**
   * Allows consumers to determine if this request has been shutdown.
   */
  get hasShutdown() {
    return !this._request;
  }

  /**
   * This is the nsIRequest implementation. Since this._request is an
   * nsIRequest, these functions just call the corresponding method on it.
   *
   * Note that nsIBitsRequest does not yet properly implement load groups or
   * load flags. This class will still forward those calls, but they will have
   * not succeed.
   */
  get name() {
    if (!this._request) {
      return this._name;
    }
    return this._request.name;
  }
  isPending() {
    if (!this._request) {
      return false;
    }
    return this._request.isPending();
  }
  get status() {
    if (!this._request) {
      return this._status;
    }
    return this._request.status;
  }
  cancel(status) {
    return this.cancelAsync(status);
  }
  suspend() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_SUSPEND,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    return this._request.suspend();
  }
  resume() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_RESUME,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    return this._request.resume();
  }
  get loadGroup() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_NONE,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    return this._request.loadGroup;
  }
  set loadGroup(group) {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_NONE,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    this._request.loadGroup = group;
  }
  get loadFlags() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_NONE,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    return this._request.loadFlags;
  }
  set loadFlags(flags) {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_NONE,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    this._request.loadFlags = flags;
  }

  /**
   * This function wraps nsIBitsRequest::bitsId.
   */
  get bitsId() {
    if (!this._request) {
      return this._bitsId;
    }
    return this._request.bitsId;
  }

  /**
   * This function wraps nsIBitsRequest::transferError.
   *
   * Instead of simply returning the nsBitsErrorType value, however, it returns
   * a BitsError object, or null.
   */
  get transferError() {
    let result;
    if (this._request) {
      result = this._request.transferError;
    } else {
      result = this._transferError;
    }
    if (result == Ci.nsIBits.ERROR_TYPE_SUCCESS) {
      return null;
    }
    return new BitsError(
      result,
      Ci.nsIBits.ERROR_ACTION_NONE,
      Ci.nsIBits.ERROR_STAGE_MONITOR,
      Ci.nsIBits.ERROR_CODE_TYPE_NONE
    );
  }

  /**
   * This function wraps nsIBitsRequest::changeMonitorInterval.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   */
  async changeMonitorInterval(monitorIntervalMs) {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_CHANGE_MONITOR_INTERVAL,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    let action = lazy.gBits.ERROR_ACTION_CHANGE_MONITOR_INTERVAL;
    return requestPromise(action, callback => {
      this._request.changeMonitorInterval(monitorIntervalMs, callback);
    });
  }

  /**
   * This function wraps nsIBitsRequest::cancelAsync.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   *
   * Adds a default status of NS_ERROR_ABORT if one is not provided.
   */
  async cancelAsync(status) {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_CANCEL,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    if (status === undefined) {
      status = Cr.NS_ERROR_ABORT;
    }
    let action = lazy.gBits.ERROR_ACTION_CANCEL;
    return requestPromise(action, callback => {
      this._request.cancelAsync(status, callback);
    }).then(() => this.shutdown());
  }

  /**
   * This function wraps nsIBitsRequest::setPriorityHigh.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   */
  async setPriorityHigh() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_SET_PRIORITY,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    let action = lazy.gBits.ERROR_ACTION_SET_PRIORITY;
    return requestPromise(action, callback => {
      this._request.setPriorityHigh(callback);
    });
  }

  /**
   * This function wraps nsIBitsRequest::setPriorityLow.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   */
  async setPriorityLow() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_SET_PRIORITY,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    let action = lazy.gBits.ERROR_ACTION_SET_PRIORITY;
    return requestPromise(action, callback => {
      this._request.setPriorityLow(callback);
    });
  }

  /**
   * This function wraps nsIBitsRequest::setNoProgressTimeout.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   */
  async setNoProgressTimeout(timeoutSecs) {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_SET_NO_PROGRESS_TIMEOUT,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    let action = lazy.gBits.ERROR_ACTION_SET_NO_PROGRESS_TIMEOUT;
    return requestPromise(action, callback => {
      this._request.setNoProgressTimeout(timeoutSecs, callback);
    });
  }

  /**
   * This function wraps nsIBitsRequest::complete.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   */
  async complete() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_COMPLETE,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    let action = lazy.gBits.ERROR_ACTION_COMPLETE;
    return requestPromise(action, callback => {
      this._request.complete(callback);
    }).then(() => this.shutdown());
  }

  /**
   * This function wraps nsIBitsRequest::suspendAsync.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   */
  async suspendAsync() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_SUSPEND,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    let action = lazy.gBits.ERROR_ACTION_SUSPEND;
    return requestPromise(action, callback => {
      this._request.suspendAsync(callback);
    });
  }

  /**
   * This function wraps nsIBitsRequest::resumeAsync.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with no data, or rejects with a BitsError.
   */
  async resumeAsync() {
    if (!this._request) {
      throw new BitsError(
        Ci.nsIBits.ERROR_TYPE_USE_AFTER_REQUEST_SHUTDOWN,
        Ci.nsIBits.ERROR_ACTION_RESUME,
        Ci.nsIBits.ERROR_STAGE_PRETASK,
        Ci.nsIBits.ERROR_CODE_TYPE_NONE
      );
    }
    let action = lazy.gBits.ERROR_ACTION_RESUME;
    return requestPromise(action, callback => {
      this._request.resumeAsync(callback);
    });
  }
}

BitsRequest.prototype.QueryInterface = ChromeUtils.generateQI(["nsIRequest"]);

/**
 * This function does all of the wrapping and error handling for an async
 * Bits Service method. This allows the implementations for those methods to
 * simply call this function with a closure that executes appropriate
 * nsIBits method.
 *
 * Specifically, this function takes an nsBitsErrorAction, an optional observer,
 * and a function.
 * The nsBitsErrorAction will be used when constructing a BitsError, if the
 * wrapper encounters an error.
 * The observer should be the one that the caller passed to the Bits Interface
 * method. It will be wrapped so that its methods are passed a BitsRequest
 * rather than an nsIBitsRequest.
 * The function will be passed the callback function and the wrapped observer,
 * both of which should be passed to the nsIBitsRequest method.
 */
async function servicePromise(errorAction, observer, actionFn) {
  return new Promise((resolve, reject) => {
    let isProgressEventSink = false;
    if (observer) {
      try {
        observer.QueryInterface(Ci.nsIRequestObserver);
      } catch (e) {
        let error = new BitsError(
          lazy.gBits.ERROR_TYPE_INVALID_ARGUMENT,
          errorAction,
          lazy.gBits.ERROR_STAGE_PRETASK,
          lazy.gBits.ERROR_CODE_TYPE_EXCEPTION,
          e
        );
        reject(error);
        return;
      }
      try {
        observer.QueryInterface(Ci.nsIProgressEventSink);
        isProgressEventSink = true;
      } catch (e) {}
    }

    // Check if we are not late in creating new requests.
    if (
      Services &&
      Services.startup &&
      Services.startup.isInOrBeyondShutdownPhase(
        Ci.nsIAppStartup.SHUTDOWN_PHASE_APPSHUTDOWNCONFIRMED
      )
    ) {
      let error = new BitsError(
        lazy.gBits.ERROR_TYPE_BROWSER_SHUTTING_DOWN,
        errorAction,
        lazy.gBits.ERROR_STAGE_PRETASK,
        lazy.gBits.ERROR_CODE_TYPE_NONE
      );
      reject(error);
      return;
    }

    // This will be set to the BitsRequest (wrapping the nsIBitsRequest), once
    // it is available. This prevents a new wrapper from having to be made every
    // time an observer function is called.
    let wrappedRequest;

    let wrappedObserver = {
      onStartRequest: function wrappedObserver_onStartRequest(request) {
        if (observer) {
          if (!wrappedRequest) {
            wrappedRequest = new BitsRequest(request);
          }
          observer.onStartRequest(wrappedRequest);
        }
      },
      onStopRequest: function wrappedObserver_onStopRequest(request, status) {
        if (observer) {
          if (!wrappedRequest) {
            wrappedRequest = new BitsRequest(request);
          }
          observer.onStopRequest(wrappedRequest, status);
        }
      },
      onProgress: function wrappedObserver_onProgress(
        request,
        progress,
        progressMax
      ) {
        if (observer && isProgressEventSink) {
          if (!wrappedRequest) {
            wrappedRequest = new BitsRequest(request);
          }
          observer.onProgress(wrappedRequest, progress, progressMax);
        }
      },
      onStatus: function wrappedObserver_onStatus(request, status, statusArg) {
        if (observer && isProgressEventSink) {
          if (!wrappedRequest) {
            wrappedRequest = new BitsRequest(request);
          }
          observer.onStatus(wrappedRequest, status, statusArg);
        }
      },
      QueryInterface: ChromeUtils.generateQI([
        "nsIRequestObserver",
        "nsIProgressEventSink",
      ]),
    };

    let timer = makeTimeout(reject, errorAction);
    let callback = {
      QueryInterface: ChromeUtils.generateQI(["nsIBitsNewRequestCallback"]),
      success(request) {
        timer.cancel();
        if (!wrappedRequest) {
          wrappedRequest = new BitsRequest(request);
        }
        resolve(wrappedRequest);
      },
      failure(type, action, stage) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_NONE
        );
        reject(error);
      },
      failureNsresult(type, action, stage, code) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_NSRESULT,
          code
        );
        reject(error);
      },
      failureHresult(type, action, stage, code) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_HRESULT,
          code
        );
        reject(error);
      },
      failureString(type, action, stage, message) {
        timer.cancel();
        let error = new BitsError(
          type,
          action,
          stage,
          lazy.gBits.ERROR_CODE_TYPE_STRING,
          message
        );
        reject(error);
      },
    };

    try {
      actionFn(wrappedObserver, callback);
    } catch (e) {
      let error = new BitsError(
        lazy.gBits.ERROR_TYPE_METHOD_THREW,
        errorAction,
        lazy.gBits.ERROR_STAGE_PRETASK,
        lazy.gBits.ERROR_CODE_TYPE_EXCEPTION,
        e
      );
      reject(error);
    }
  });
}

export var Bits = {
  /**
   * This function wraps nsIBits::initialized.
   */
  get initialized() {
    return lazy.gBits.initialized;
  },

  /**
   * This function wraps nsIBits::init.
   */
  init(jobName, savePathPrefix, monitorTimeoutMs) {
    return lazy.gBits.init(jobName, savePathPrefix, monitorTimeoutMs);
  },

  /**
   * This function wraps nsIBits::startDownload.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with a BitsRequest (which is also an
   * nsIRequest), or rejects with a BitsError.
   */
  async startDownload(
    downloadURL,
    saveRelPath,
    proxy,
    noProgressTimeoutSecs,
    monitorIntervalMs,
    customHeaders,
    observer,
    context
  ) {
    let action = lazy.gBits.ERROR_ACTION_START_DOWNLOAD;
    return servicePromise(action, observer, (wrappedObserver, callback) => {
      lazy.gBits.startDownload(
        downloadURL,
        saveRelPath,
        proxy,
        noProgressTimeoutSecs,
        monitorIntervalMs,
        customHeaders,
        wrappedObserver,
        context,
        callback
      );
    });
  },

  /**
   * This function wraps nsIBits::monitorDownload.
   *
   * Instead of taking a callback, the function is asynchronous.
   * This method either resolves with a BitsRequest (which is also an
   * nsIRequest), or rejects with a BitsError.
   */
  async monitorDownload(id, monitorIntervalMs, observer, context) {
    let action = lazy.gBits.ERROR_ACTION_MONITOR_DOWNLOAD;
    return servicePromise(action, observer, (wrappedObserver, callback) => {
      lazy.gBits.monitorDownload(
        id,
        monitorIntervalMs,
        wrappedObserver,
        context,
        callback
      );
    });
  },
};

[ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge