So I am trying to make my sftp folder synced with a local folder using nodejs. That means that they both always have the same files and also get updated based on which one is newer. The Problem I have with my script is that it is always uploading the folders and files even if I haven’t changed anything. Maybe the date is different?
const fs = require('fs');
const path = require('path');
const Client = require('ssh2-sftp-client');
const SFTP_CONFIG = {
host: '123456',
username: 'user',
password: '1234',
port: 22,
remotePath: '/',
localPath: './content',
syncInterval: 10000,
};
const sftp = new Client();
async function syncFiles() {
try {
await sftp.connect(SFTP_CONFIG);
await syncDirectory(SFTP_CONFIG.remotePath, SFTP_CONFIG.localPath);
setInterval(async () => {
await syncDirectory(SFTP_CONFIG.remotePath, SFTP_CONFIG.localPath);
}, SFTP_CONFIG.syncInterval);
} catch (err) {
console.error('Error:', err);
}
}
async function syncDirectory(remotePath, localPath) {
try {
const remoteFiles = await sftp.list(remotePath);
const localFiles = await getLocalFiles(localPath);
// Download new or modified files from the remote server
for (const remoteFile of remoteFiles) {
const localFile = localFiles.find((f) => f.name === remoteFile.name);
if (!localFile || remoteFile.modifyTime > localFile.modifyTime) {
const remoteFilePath = path.posix.join(remotePath, remoteFile.name);
const localFilePath = path.join(localPath, remoteFile.name);
if (remoteFile.type === 'd') {
await downloadDirectory(remoteFilePath, localFilePath);
} else {
await downloadFile(remoteFilePath, localFilePath);
}
} else if (remoteFile.modifyTime < localFile.modifyTime) {
const remoteFilePath = path.posix.join(remotePath, remoteFile.name);
const localFilePath = path.join(localPath, remoteFile.name);
if (localFile.type === 'd') {
await uploadDirectory(localFilePath, remoteFilePath);
} else {
await uploadFile(localFilePath, remoteFilePath);
}
}
}
// Upload new or modified files to the remote server
for (const localFile of localFiles) {
const remoteFile = remoteFiles.find((f) => f.name === localFile.name);
if (!remoteFile || localFile.modifyTime > remoteFile.modifyTime) {
const remoteFilePath = path.posix.join(remotePath, localFile.name);
const localFilePath = path.join(localPath, localFile.name);
if (localFile.type === 'd') {
await uploadDirectory(localFilePath, remoteFilePath);
} else {
await uploadFile(localFilePath, remoteFilePath);
}
}
}
} catch (err) {
console.error('Error syncing directory:', err);
}
}
async function downloadFile(remotePath, localPath) {
try {
await sftp.fastGet(remotePath, localPath);
console.log(`Downloaded ${remotePath} to ${localPath}`);
} catch (err) {
console.error('Error downloading file:', err);
}
}
async function downloadDirectory(remotePath, localPath) {
try {
await fs.promises.mkdir(localPath, { recursive: true });
const remoteFiles = await sftp.list(remotePath);
for (const remoteFile of remoteFiles) {
const fileName = remoteFile.name;
const remoteFilePath = path.posix.join(remotePath, fileName);
const localFilePath = path.join(localPath, fileName);
if (remoteFile.type === 'd') {
await downloadDirectory(remoteFilePath, localFilePath);
} else {
await downloadFile(remoteFilePath, localFilePath);
}
}
} catch (err) {
console.error('Error downloading directory:', err);
}
}
async function uploadFile(localPath, remotePath) {
try {
await sftp.fastPut(localPath, remotePath);
console.log(`Uploaded ${localPath} to ${remotePath}`);
} catch (err) {
console.error('Error uploading file:', err);
}
}
async function uploadDirectory(localPath, remotePath) {
try {
await sftp.mkdir(remotePath, true);
console.log(`Uploaded ${localPath} to ${remotePath}`);
const localFiles = await getLocalFiles(localPath);
for (const localFile of localFiles) {
const fileName = localFile.name;
const localFilePath = path.join(localPath, fileName);
const remoteFilePath = path.posix.join(remotePath, fileName);
if (localFile.type === 'd') {
await uploadDirectory(localFilePath, remoteFilePath);
} else {
await uploadFile(localFilePath, remoteFilePath);
}
}
} catch (err) {
console.error('Error uploading directory:', err);
}
}
async function getLocalFiles(dirPath) {
try {
const files = await fs.promises.readdir(dirPath, { withFileTypes: true });
return Promise.all(
files.map(async (file) => {
const filePath = path.join(dirPath, file.name);
const stats = await fs.promises.stat(filePath);
return { name: file.name, modifyTime: stats.mtimeMs, type: file.isDirectory() ? 'd' : 'f' };
})
);
} catch (err) {
if (err.code === 'ENOENT') {
console.error(`Local path "${dirPath}" does not exist.`);
return [];
} else {
console.error('Error reading local directory:', err);
throw err;
}
}
}
syncFiles();