text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   *
   * @format
   *
   */
  
  "use strict";
  
  const HttpError = require("./HttpError");
  const NetworkError = require("./NetworkError");
  
  const http = require("http");
  const https = require("https");
  const url = require("url");
  const zlib = require("zlib");
  
  const ZLIB_OPTIONS = {
    level: 9
  };
  
  class HttpStore {
    constructor(options) {
      const uri = url.parse(options.endpoint);
      const module = uri.protocol === "http:" ? http : https;
  
      const agentConfig = {
        family: options.family,
        keepAlive: true,
        keepAliveMsecs: options.timeout || 5000,
        maxSockets: 64,
        maxFreeSockets: 64
      };
  
      if (!uri.hostname || !uri.pathname) {
        throw new TypeError("Invalid endpoint: " + options.endpoint);
      }
  
      this._module = module;
      this._timeout = options.timeout || 5000;
  
      this._host = uri.hostname;
      this._path = uri.pathname;
      this._port = +uri.port;
  
      this._getAgent = new module.Agent(agentConfig);
      this._setAgent = new module.Agent(agentConfig);
    }
  
    get(key) {
      return new Promise((resolve, reject) => {
        const options = {
          agent: this._getAgent,
          host: this._host,
          method: "GET",
          path: this._path + "/" + key.toString("hex"),
          port: this._port,
          timeout: this._timeout
        };
  
        const req = this._module.request(options, res => {
          const code = res.statusCode;
          let data = "";
  
          if (code === 404) {
            res.resume();
            resolve(null);
  
            return;
          } else if (code !== 200) {
            res.resume();
            reject(new HttpError("HTTP error: " + code, code));
  
            return;
          }
  
          const gunzipped = res.pipe(zlib.createGunzip());
  
          gunzipped.on("data", chunk => {
            data += chunk.toString();
          });
  
          gunzipped.on("error", err => {
            reject(err);
          });
  
          gunzipped.on("end", () => {
            try {
              resolve(JSON.parse(data));
            } catch (err) {
              reject(err);
            }
          });
  
          res.on("error", err => gunzipped.emit("error", err));
        });
  
        req.on("error", err => {
          reject(new NetworkError(err.message, err.code));
        });
  
        req.end();
      });
    }
  
    set(key, value) {
      return new Promise((resolve, reject) => {
        const gzip = zlib.createGzip(ZLIB_OPTIONS);
  
        const options = {
          agent: this._setAgent,
          host: this._host,
          method: "PUT",
          path: this._path + "/" + key.toString("hex"),
          port: this._port,
          timeout: this._timeout
        };
  
        const req = this._module.request(options, res => {
          res.on("error", err => {
            reject(err);
          });
  
          res.on("end", () => {
            resolve();
          });
  
          // Consume all the data from the response without processing it.
          res.resume();
        });
  
        gzip.pipe(req);
        gzip.end(JSON.stringify(value) || "null");
      });
    }
  
    clear() {
      // Not implemented.
    }
  }
  HttpStore.HttpError = HttpError;
  HttpStore.NetworkError = NetworkError;
  
  module.exports = HttpStore;
  