storage/fs.js


const fs = require('fs')
const Path = require('path')
const mkdirp = require('mkdirp')
const sanitize = require('sanitize-filename')
const debug = require('debug')('gpgfs.fs-storage')


const IStorage = require('../interface-storage')

/**
 * Local file storage backend
 * @class
 * @implements IStorage
 */
class FsStorage extends IStorage {

  /**
   * @constructor
   * @param {Object} options
   * @param {string} options.path  Path to a `.gpgfs` directory
   * @param {boolean} options.readOnly  Storage open mode
   */
  constructor({path=null, readOnly=false}={}){
    super({readOnly})

    this.basePath = !path ? Path.join(process.cwd(), '.gpgfs') : path

    debug('basePath =', this.basePath)
  }

  async start(){ debug('start') }
  async stop(){ debug('stop') }

  storagePath(path){
    return Path.normalize(
      this.basePath+"/" + Path.dirname(path) + '/'+ sanitize(Path.basename(path))
    )
  }

  get name(){ return 'fs' }

  async fileExists(path){
    this.assertEnabled()
    const result = fs.existsSync( this.storagePath(path) )

    debug("fileExists: ", result, path)
    return result
  }
  
  async readFile(path){
    this.assertEnabled()
    return new Promise((resolve,reject)=>{

      const realPath = this.storagePath(path)

      debug("Reading from file: " + realPath)
      fs.readFile(realPath, 'utf8', (err,data)=>{
        if(err){
          return reject(err)
        }

        resolve(data)
      })

    })
  }

  async writeFile(path, data, options){
    this.assertEnabled()
    if(this.mode!=IStorage.MODE_WRITE){ throw new Error('read only') }

    return new Promise((resolve,reject)=>{

      const realPath = this.storagePath(path)

      debug("Writing file: " + realPath)
      fs.writeFile(realPath, data, options, (err)=>{
        if(err){
          debug('failed to write file - ',path, '\nerror -',err)
          return reject(err)
        }

        debug('wrote file:', path)
        resolve()
      })

    })
  }

  async rmFile(path){ 
    this.assertEnabled()
    const realPath = this.storagePath(path)
    debug('rmFile -', realPath)
    fs.unlinkSync(realPath)
  }

  async readDir(path){
    this.assertEnabled()
    return new Promise((resolve, reject)=>{

      const realPath = this.storagePath(path)
      fs.readdir(realPath, (err, files)=>{
        if(err){
          return reject(err)
        }

        resolve(files)
      })
    })
  }

  async touchDir(path){
    this.assertEnabled()
    return new Promise((resolve, reject) => {
      const realPath = this.storagePath(path)
      debug('touch dir', realPath)
      mkdirp(realPath, (error) => {
        if (error) {
          debug(`failed to mkdirp '${realPath}':`, error)
          return reject(error)
        }
  
        // resolve to adjusted path on success
        resolve(realPath)
      })
    })
  }
}

module.exports = FsStorage