<commit_before>'use strict';

import { Service } from 'components/fxos-mvc/dist/mvc';

import FoxboxSettings from './foxbox-settings';
import FoxboxDb from './foxbox-db';

// The delay after which a request is considered failed.
const REQUEST_TIMEOUT = 5000;

/**
 * Request a JSON from a specified URL.
 *
 * @param {string} url The URL to send the request to.
 * @param {string} method The HTTP method (defaults to "GET").
 * @param {Object} body An object of key/value.
 * @return {Promise}
 */
const loadJSON = function(url, method = 'GET', body = undefined) {
  method = method.toUpperCase();

  let req = {
    method,
    headers: {
      'Accept': 'application/json'
    },
    cache: 'no-store'
  };

  if (body !== undefined) {
    req.body = JSON.stringify(body);
  }
  if (method === 'GET' || method === 'HEAD') {
    delete req.body;
  }

  // Workaround to catch network failures.
  return new Promise((resolve, reject) => {
    let hasTimedOut = false;
    const timeout = setTimeout(() => {
      hasTimedOut = true;
      reject(new Error('Request timed out'));
    }, REQUEST_TIMEOUT);

    fetch(url, req)
      .then(response => {
        if (hasTimedOut) {
          return;
        }

        clearTimeout(timeout);
        return resolve(response.json());
      });
  });
};

export default class Foxbox extends Service {
  constructor() {
    super();
    this.settings = new FoxboxSettings();
    this.db = new FoxboxDb();
  }

  init() {
    return this.db.init();
  }

  get origin() {
    return `${this.settings.scheme}://${this.settings.hostname}:${this.settings.port}`;
  }

  /**
   * Retrieve the list of the services available.
   *
   * @return {Promise} A promise that resolves with an array of objects.
   */
  getServices() {
    return new Promise((resolve, reject) => {
      loadJSON(`${this.origin}/services/list.json`)
        .then(services => {
          // Let's remove the dummy services here.
          services = services.filter(service => service.name !== 'dummy service');

          const promises =
            services.map(service => loadJSON(`http://localhost:3000/services/${service.id}/state`, 'GET'));
          Promise.all(promises)
            .then(states => {
              services.forEach((service, id) => service.state = states[id]);

              // Clear the services db.
              this.db.clearServices()
                .then(() => {
                  // Populate the db with the latest services.
                  services.forEach(service => {
                    this.db.setService(service);
                  });
                });

              return resolve(services);
            });
        });
    });
  }

  /**
   * Change the state of a service.
   *
   * @param {string} id The ID of the service.
   * @param {Object} state An object containing pairs of key/value.
   * @return {Promise}
   */
  changeServiceState(id, state) {
    return new Promise((resolve, reject) => {
      loadJSON(`${this.origin}/services/${id}/state`, 'PUT', state)
        .then(response => {
          if (!response || !response.result || response.result !== 'success') {
            return reject(new Error(`The action couldn't be performed.`));
          }

          return resolve();
        });
    });
  }

  getTags() {
    return this.db.getTags.apply(this.db, arguments);
  }

  getService() {
    // Get data from the DB so we get the attributes, the state and the tags.
    return this.db.getService.apply(this.db, arguments);
  }

  setService() {
    return this.db.setService.apply(this.db, arguments);
  }

  setTag() {
    return this.db.setTag.apply(this.db, arguments);
  }
}<commit_msg>Use the Request and Headers constructors<commit_after>/* global Request, Headers */

'use strict';

import { Service } from 'components/fxos-mvc/dist/mvc';

import FoxboxSettings from './foxbox-settings';
import FoxboxDb from './foxbox-db';

// The delay after which a request is considered failed.
const REQUEST_TIMEOUT = 5000;

/**
 * Request a JSON from a specified URL.
 *
 * @param {string} url The URL to send the request to.
 * @param {string} method The HTTP method (defaults to "GET").
 * @param {Object} body An object of key/value.
 * @return {Promise}
 */
const loadJSON = function(url, method = 'GET', body = undefined) {
  method = method.toUpperCase();
  if (method === 'GET' || method === 'HEAD') {
    body = undefined;
  }

  let req = new Request(url, {
    method,
    headers: new Headers({
      'Accept': 'application/json'
    }),
    cache: 'no-store',
    body: JSON.stringify(body)
  });

  // Workaround to catch network failures.
  return new Promise((resolve, reject) => {
    let hasTimedOut = false;
    const timeout = setTimeout(() => {
      hasTimedOut = true;
      reject(new TypeError('Request timed out'));
    }, REQUEST_TIMEOUT);

    fetch(req)
      .then(res => {
        if (hasTimedOut) {
          return;
        }

        clearTimeout(timeout);

        if (res.ok) {
          return resolve(res.json());
        } else {
          throw new TypeError(`The response returned a ${res.status} HTTP status code.`);
        }
      });
  });
};

export default class Foxbox extends Service {
  constructor() {
    super();
    this.settings = new FoxboxSettings();
    this.db = new FoxboxDb();
  }

  init() {
    return this.db.init();
  }

  get origin() {
    return `${this.settings.scheme}://${this.settings.hostname}:${this.settings.port}`;
  }

  /**
   * Retrieve the list of the services available.
   *
   * @return {Promise} A promise that resolves with an array of objects.
   */
  getServices() {
    return new Promise((resolve, reject) => {
      loadJSON(`${this.origin}/services/list.json`)
        .then(services => {
          // Let's remove the dummy services here.
          services = services.filter(service => service.name !== 'dummy service');

          const promises =
            services.map(service => loadJSON(`http://localhost:3000/services/${service.id}/state`, 'GET'));
          Promise.all(promises)
            .then(states => {
              services.forEach((service, id) => service.state = states[id]);

              // Clear the services db.
              this.db.clearServices()
                .then(() => {
                  // Populate the db with the latest services.
                  services.forEach(service => {
                    this.db.setService(service);
                  });
                });

              return resolve(services);
            });
        });
    });
  }

  /**
   * Change the state of a service.
   *
   * @param {string} id The ID of the service.
   * @param {Object} state An object containing pairs of key/value.
   * @return {Promise}
   */
  changeServiceState(id, state) {
    return new Promise((resolve, reject) => {
      loadJSON(`${this.origin}/services/${id}/state`, 'PUT', state)
        .then(res => {
          if (!res || !res.result || res.result !== 'success') {
            return reject(new Error(`The action couldn't be performed.`));
          }

          return resolve();
        });
    });
  }

  getTags() {
    return this.db.getTags.apply(this.db, arguments);
  }

  getService() {
    // Get data from the DB so we get the attributes, the state and the tags.
    return this.db.getService.apply(this.db, arguments);
  }

  setService() {
    return this.db.setService.apply(this.db, arguments);
  }

  setTag() {
    return this.db.setTag.apply(this.db, arguments);
  }
}
{'fraction_non_alphanumeric': 0.1457306513920341, 'fraction_numerical': 0.002131344078859731, 'mean_word_length': 2.2445980985306826, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4185355', 'n_tokens_mistral': 2214, 'n_tokens_neox': 2159, 'n_words': 594}