{"size": 2176, "ext": "js", "max_stars_repo_path": "lib/backends/backend.js", "max_stars_repo_name": "jjeff/pecans", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "lib/backends/backend.js", "max_issues_repo_name": "jjeff/pecans", "max_issues_repo_issues_event_min_datetime": "2021-11-14T21:41:51.000Z", "max_issues_repo_issues_event_max_datetime": "2021-11-14T21:41:51.000Z", "max_forks_repo_path": "lib/backends/backend.js", "max_forks_repo_name": "jjeff/pecans", "max_forks_repo_forks_event_min_datetime": "2021-09-12T19:39:50.000Z", "max_forks_repo_forks_event_max_datetime": "2021-09-12T19:39:50.000Z"}
{"max_stars_count": null, "max_issues_count": 1, "max_forks_count": 1, "avg_line_length": 25.0114942529, "max_line_length": 75, "alphanum_fraction": 0.5983455882}
import util from "util";
import path from "path";
import os from "os";
import destroy from "destroy";
import LRU from "lru-diskcache";
import streamRes from "stream-res";
import { Buffer } from "buffer";

const streamResAsync = util.promisify(streamRes);

export class Backend {
  constructor(pecans, opts = {}) {
    const defaults = {
      // Folder to cache assets
      cache: path.resolve(os.tmpdir(), "pecans"),
      // Cache configuration
      cacheMax: 500 * 1024 * 1024,
      cacheMaxAge: 60 * 60 * 1000,
    };
    this.cacheId = 0;
    this.pecans = pecans;
    this.opts = Object.assign({}, defaults, opts);

    // Create cache
    this.cache = LRU(opts.cache, {
      max: opts.cacheMax,
      maxAge: opts.cacheMaxAge,
    });
  }

  // New release? clear cache
  onRelease() {
    this.cacheId++;
  }
  // Initialize the backend
  async init() {
    this.cache.init();
  }
  // List all releases for this repository
  releases() {}

  // Return stream for an asset, serving out of the LRU cache if available.
  async serveAsset(asset, req, res) {
    const cacheKey = asset.id;
    res.header("Content-Length", asset.size);
    res.attachment(asset.filename);
    // fill cache if empty
    if (!this.cache.has(cacheKey)) {
      const stream = await this.getAssetStream(asset);
      // Cache the stream
      await this.cache.set(cacheKey, stream);
    }
    const stream = await this.cache.getStream(cacheKey);
    return streamResAsync(res, stream);
  }
  // Return stream for an asset
  async getAssetStream(asset) {
    throw Error("Abstract Method");
  }

  // Return stream for an asset
  async readAsset(asset) {
    const response = await this.getAssetStream(asset);
    return new Promise((resolve, reject) => {
      let output = Buffer.alloc(0);

      function cleanup() {
        destroy(response);
        response.removeAllListeners();
      }

      response
        .on("data", (buf) => {
          output = Buffer.concat([output, buf]);
        })
        .on("error", (err) => {
          cleanup();
          reject(err);
        })
        .on("end", () => {
          cleanup();
          resolve(output);
        });
    });
  }
}
