"use strict";var t=this&&this.__awaiter||function(t,e,i,o){return new(i||(i=Promise))((function(s,a){function l(t){try{r(o.next(t))}catch(t){a(t)}}function c(t){try{r(o.throw(t))}catch(t){a(t)}}function r(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(l,c)}r((o=o.apply(t,e||[])).next())}))},e=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.FileLock=void 0;const i=e(require("path")),o=e(require("graceful-fs")),s=require("../../config"),a=require("./types"),l=e(require("process")),c=e(require("../../log")),r=require("signal-exit"),u=require("../../util"),h=require("../../util/sleep");class n{constructor(){this._lockFilePath="",this._options=a.defaultOptions}lock(e){return t(this,void 0,void 0,(function*(){if(!this.isEnable())return;(0,r.onExit)((()=>{this.unlock()})),c.default.debug("",`start lock, pid: ${l.default.pid}`),this._options=Object.assign(Object.assign({},this._options),e);const t=e?e.filePath:"";this._lockFilePath=t?i.default.resolve(t):i.default.join(s.config.getProjectRoot(),n.LOCK_FILE_NAME),this._options.stale=Math.max(this._options.stale||0,2e3),this._options.update=this._options.update?this._options.update:this._options.stale/2,this._options.update=Math.max(Math.min(this._options.update,this._options.stale/2),1e3),this._options.retryInterval=Math.max(this._options.retryInterval||0,100),yield this.acquireLock(),this._lock={lockfilePath:this._lockFilePath,mtime:Date.now(),options:this._options,lastUpdate:Date.now()},this.updateLock(this._options)}))}unlock(){if(this.isEnable()&&this.acquiredLock())return this.clearTimeout(),this.removeLock()}acquireLock(){return t(this,void 0,void 0,(function*(){c.default.debug("",`start acquireLock, pid: ${l.default.pid}`);try{yield o.default.promises.mkdir(this._lockFilePath),c.default.debug("",`acquireLock succeed, pid: ${l.default.pid}`)}catch(t){if("EEXIST"!==t.code)throw t;try{const t=yield o.default.promises.stat(this._lockFilePath);this.isLockStale(t)?(this.removeLock(),yield(0,h.sleep)(this._options.retryInterval),yield this.acquireLock()):(yield(0,h.sleep)(this._options.retryInterval),yield this.acquireLock())}catch(t){if(t){if("ENOENT"===t.code)return yield(0,h.sleep)(this._options.retryInterval),void(yield this.acquireLock());throw t}}}}))}isLockStale(t){return t.mtime.getTime()<Date.now()-this._options.stale}clearTimeout(){this._lock&&(this._lock.updateTimeout&&clearTimeout(this._lock.updateTimeout),this._lock.released=!0)}removeLock(){try{u.FsBlockingUtil.rmDirSync(this._lockFilePath),c.default.debug("",`removeLock succeed, filepath: ${this._lockFilePath}.`)}catch(t){if("ENOENT"!==t.code)throw t}}updateLock(e){c.default.debug("",`start updateLock, pid: ${l.default.pid}`),this._lock.updateDelay=this._lock.updateDelay||e.update,this._lock.updateTimeout=setTimeout((()=>t(this,void 0,void 0,(function*(){c.default.debug("","start update lock..."),this._lock.updateTimeout=null;try{const t=yield o.default.promises.stat(this._lockFilePath);if(!this.isMtimeOurs(t))return c.default.debug("",`ECOMPROMISED, stat.mtime: ${t.mtime.getTime()}, _lock.mtime:${this._lock.mtime}`),this.setLockAsCompromised(Object.assign(new Error("Unable to update filelock within the stale threshold"),{code:"ECOMPROMISED"}));const i=Date.now();try{if(yield o.default.promises.utimes(this._lockFilePath,new Date(i),new Date(i)),this._lock.released)return;this._lock.mtime=i,this._lock.lastUpdate=Date.now(),this._lock.updateDelay=null,c.default.debug("","end update lock..."),this.updateLock(e)}catch(t){const i=this._lock.lastUpdate+this._options.stale<Date.now();return"ENOENT"===t.code||i?this.setLockAsCompromised(Object.assign(t,{code:"ECOMPROMISED"})):(this._lock.updateDelay=1e3,this.updateLock(e))}}catch(t){const i=this._lock.lastUpdate+e.stale<Date.now();return"ENOENT"===t.code||i?this.setLockAsCompromised(Object.assign(t,{code:"ECOMPROMISED"})):(this._lock.updateDelay=1e3,this.updateLock(e))}}))),this._lock.updateDelay),this._lock.updateTimeout.unref&&this._lock.updateTimeout.unref()}setLockAsCompromised(t){this._lock.released=!0,this._lock.updateTimeout&&clearTimeout(this._lock.updateTimeout),this._options.onErrorCallBack&&this._options.onErrorCallBack(t)}acquiredLock(){return!!this._lock}isEnable(){return s.config.get(s.types.ENABLE_CROSS_PROCESS_LOCK)}isMtimeOurs(t){return Math.abs(this._lock.mtime-t.mtime.getTime())<=1e3}}exports.FileLock=n,n.LOCK_FILE_NAME="oh-lock.lock";