drawio-offline
Version:
diagrams.net desktop
124 lines (114 loc) • 2.83 kB
JavaScript
const fs = require('fs');
const path = require('path');
const { COPYFILE_EXCL } = fs.constants;
function isConflict(origStat, stat)
{
return stat != null && origStat != null && stat.mtimeMs != origStat.mtimeMs;
};
function saveFile(fileObject, data, origStat, overwrite, defEnc, reqId)
{
var retryCount = 0;
var backupCreated = false;
var writeFile = function()
{
if (data == null || data.length == 0)
{
postMessage({error: true, msg: 'empty data', reqId: reqId});
}
else
{
var writeEnc = defEnc || fileObject.encoding;
fs.writeFile(fileObject.path, data, writeEnc,
function (e)
{
if (e)
{
postMessage({error: true, msg: 'saving failed', e: e, reqId: reqId});
}
else
{
fs.stat(fileObject.path, function(e2, stat2)
{
if (e2)
{
postMessage({error: true, msg: 'stat failed', e: e2, reqId: reqId});
}
else
{
// Workaround for possible writing errors is to check the written
// contents of the file and retry 3 times before showing an error
fs.readFile(fileObject.path, writeEnc, (err, writtenData) =>
{
if (data != writtenData)
{
retryCount++;
if (retryCount < 3)
{
writeFile();
}
else
{
postMessage({error: true, msg: 'all saving trials failed', e: e, reqId: reqId});
}
}
else
{
postMessage({success: true, data: {stat: stat2}, reqId: reqId});
if (backupCreated)
{
fs.unlink(fileObject.bkpPath, (err) => {}); //Ignore errors!
}
}
});
}
});
}
});
}
};
function doSaveFile()
{
//Copy file to backup file (after conflict and stat is checked)
fs.copyFile(fileObject.path, fileObject.bkpPath, COPYFILE_EXCL, (err) =>
{
if (!err)
{
backupCreated = true;
}
writeFile();
});
};
if (overwrite)
{
doSaveFile();
}
else
{
//TODO Using stat before write is not recommended, we can check the error code from writeFile
fs.stat(fileObject.path, function(err, stat)
{
if (isConflict(origStat, stat))
{
postMessage({error: true, msg: 'conflict', e: {isConflicted: true}, reqId: reqId});
}
else if (err != null && err.code !== 'ENOENT')
{
postMessage({error: true, msg: 'stat failed', e: err, reqId: reqId});
}
else
{
doSaveFile();
}
});
}
};
//TODO handle reqId better
onmessage = function(e)
{
switch(e.data.action)
{
case 'saveFile':
saveFile(e.data.fileObject, e.data.data, e.data.origStat, e.data.overwrite, e.data.defEnc, e.data.reqId);
break;
};
};