Spaces:
Sleeping
Sleeping
File size: 5,484 Bytes
4cadbaf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const events_1 = require("events");
const sha1_1 = __importDefault(require("sha1"));
const diff = __importStar(require("diff"));
const asyncCall_1 = __importDefault(require("./asyncCall"));
class FileProxy extends events_1.EventEmitter {
constructor(filePath) {
super();
this.alive = true;
this.filePath = filePath;
//console.log("File proxy created:", filePath);
if (!fs_1.default.existsSync(filePath))
throw new Error(`file not exist: ${filePath}`);
asyncCall_1.default(fs_1.default.stat, filePath)
.then(stats => {
this.diskTimestamp = stats.mtime.getTime();
this.timestamp = this.diskTimestamp;
return asyncCall_1.default(fs_1.default.readFile, filePath);
})
.then(buffer => {
this.content = buffer.toString();
this.fullSync();
});
this.fileListener = (current) => __awaiter(this, void 0, void 0, function* () {
this.diskTimestamp = current.mtime.getTime();
this.timestamp = this.diskTimestamp;
const buffer = yield asyncCall_1.default(fs_1.default.readFile, filePath);
if (!buffer) {
this.emit("error", { description: "file reading failed" });
return;
}
const newContent = buffer.toString();
const newHash = sha1_1.default(newContent);
if (newHash !== this.hash) {
const patch = diff.createPatch(filePath, this.content, newContent);
this.emit("increase", {
timestamp: this.timestamp,
fromHash: this.hash,
toHash: newHash,
patch,
});
this.content = newContent;
}
});
fs_1.default.watchFile(filePath, this.fileListener);
this.keepWriteFile();
}
dispose() {
this.alive = false;
if (this.fileListener)
fs_1.default.unwatchFile(this.filePath, this.fileListener);
}
makeWritePromise() {
return new Promise(resolve => this.writeFile = resolve);
}
keepWriteFile() {
return __awaiter(this, void 0, void 0, function* () {
let writeSignal = this.makeWritePromise();
while (this.alive) {
yield writeSignal;
writeSignal = this.makeWritePromise();
//console.debug("keepWriteFile:", this.timestamp, this.diskTimestamp);
if (this.timestamp > this.diskTimestamp) {
yield asyncCall_1.default(fs_1.default.writeFile, this.filePath, this.content);
}
}
});
}
get hash() {
return sha1_1.default(this.content);
}
fullSync() {
this.emit("fullSync", {
timestamp: this.timestamp,
content: this.content,
hash: this.hash,
});
}
increase({ timestamp, fromHash, toHash, patch }) {
if (this.hash !== fromHash) {
if (this.timestamp > timestamp)
// web content is out of date
this.fullSync();
else
console.warn("[FileProxy] disk file content is behind increase base:", this.timestamp, timestamp);
}
else {
this.content = diff.applyPatch(this.content, patch);
this.timestamp = timestamp;
console.assert(this.hash === toHash, "[FileProxy] verify failed:", this.hash, toHash, this.content);
// trigger file writing
this.writeFile();
}
}
}
exports.default = FileProxy;
;
|