opusdev/vector-similarity-api
1
1'use strict'2 3const EE = require('events').EventEmitter4const cons = require('constants')5const fs = require('fs')6 7module.exports = (f, options, cb) => {8 if (typeof options === 'function')9 cb = options, options = {}10 11 const p = new Promise((res, rej) => {12 new Touch(validOpts(options, f, null))13 .on('done', res).on('error', rej)14 })15 16 return cb ? p.then(res => cb(null, res), cb) : p17}18 19module.exports.sync = module.exports.touchSync = (f, options) =>20 (new TouchSync(validOpts(options, f, null)), undefined)21 22module.exports.ftouch = (fd, options, cb) => {23 if (typeof options === 'function')24 cb = options, options = {}25 26 const p = new Promise((res, rej) => {27 new Touch(validOpts(options, null, fd))28 .on('done', res).on('error', rej)29 })30 31 return cb ? p.then(res => cb(null, res), cb) : p32}33 34module.exports.ftouchSync = (fd, opt) =>35 (new TouchSync(validOpts(opt, null, fd)), undefined)36 37const validOpts = (options, path, fd) => {38 options = Object.create(options || {})39 options.fd = fd40 options.path = path41 42 // {mtime: true}, {ctime: true}43 // If set to something else, then treat as epoch ms value44 const now = new Date(options.time || Date.now()).getTime() / 100045 if (!options.atime && !options.mtime)46 options.atime = options.mtime = now47 else {48 if (true === options.atime)49 options.atime = now50 51 if (true === options.mtime)52 options.mtime = now53 }54 55 let oflags = 056 if (!options.force)57 oflags = oflags | cons.O_RDWR58 59 if (!options.nocreate)60 oflags = oflags | cons.O_CREAT61 62 options.oflags = oflags63 return options64}65 66class Touch extends EE {67 constructor (options) {68 super(options)69 this.fd = options.fd70 this.path = options.path71 this.atime = options.atime72 this.mtime = options.mtime73 this.ref = options.ref74 this.nocreate = !!options.nocreate75 this.force = !!options.force76 this.closeAfter = options.closeAfter77 this.oflags = options.oflags78 this.options = options79 80 if (typeof this.fd !== 'number') {81 this.closeAfter = true82 this.open()83 } else84 this.onopen(null, this.fd)85 }86 87 emit (ev, data) {88 // we only emit when either done or erroring89 // in both cases, need to close90 this.close()91 return super.emit(ev, data)92 }93 94 close () {95 if (typeof this.fd === 'number' && this.closeAfter)96 fs.close(this.fd, () => {})97 }98 99 open () {100 fs.open(this.path, this.oflags, (er, fd) => this.onopen(er, fd))101 }102 103 onopen (er, fd) {104 if (er) {105 if (er.code === 'EISDIR')106 this.onopen(null, null)107 else if (er.code === 'ENOENT' && this.nocreate)108 this.emit('done')109 else110 this.emit('error', er)111 } else {112 this.fd = fd113 if (this.ref)114 this.statref()115 else if (!this.atime || !this.mtime)116 this.fstat()117 else118 this.futimes()119 }120 }121 122 statref () {123 fs.stat(this.ref, (er, st) => {124 if (er)125 this.emit('error', er)126 else127 this.onstatref(st)128 })129 }130 131 onstatref (st) {132 this.atime = this.atime && st.atime.getTime()/1000133 this.mtime = this.mtime && st.mtime.getTime()/1000134 if (!this.atime || !this.mtime)135 this.fstat()136 else137 this.futimes()138 }139 140 fstat () {141 const stat = this.fd ? 'fstat' : 'stat'142 const target = this.fd || this.path143 fs[stat](target, (er, st) => {144 if (er)145 this.emit('error', er)146 else147 this.onfstat(st)148 })149 }150 151 onfstat (st) {152 if (typeof this.atime !== 'number')153 this.atime = st.atime.getTime()/1000154 155 if (typeof this.mtime !== 'number')156 this.mtime = st.mtime.getTime()/1000157 158 this.futimes()159 }160 161 futimes () {162 const utimes = this.fd ? 'futimes' : 'utimes'163 const target = this.fd || this.path164 fs[utimes](target, ''+this.atime, ''+this.mtime, er => {165 if (er)166 this.emit('error', er)167 else168 this.emit('done')169 })170 }171}172 173class TouchSync extends Touch {174 open () {175 try {176 this.onopen(null, fs.openSync(this.path, this.oflags))177 } catch (er) {178 this.onopen(er)179 }180 }181 182 statref () {183 let threw = true184 try {185 this.onstatref(fs.statSync(this.ref))186 threw = false187 } finally {188 if (threw)189 this.close()190 }191 }192 193 fstat () {194 let threw = true195 const stat = this.fd ? 'fstatSync' : 'statSync'196 const target = this.fd || this.path197 try {198 this.onfstat(fs[stat](target))199 threw = false200 } finally {201 if (threw)202 this.close()203 }204 }205 206 futimes () {207 let threw = true208 const utimes = this.fd ? 'futimesSync' : 'utimesSync'209 const target = this.fd || this.path210 try {211 fs[utimes](target, this.atime, this.mtime)212 threw = false213 } finally {214 if (threw)215 this.close()216 }217 this.emit('done')218 }219 220 close () {221 if (typeof this.fd === 'number' && this.closeAfter)222 try { fs.closeSync(this.fd) } catch (er) {}223 }224}225 