#!/usr/bin/env node /* eslint-env es2020 */ const API_URL = process.env.API_URL; const API_KEY = process.env.API_KEY; const VERBOSE = !!process.env.VERBOSE; async function main() { const config = await fetchConfig(); const devicesStatus = await fetchDevicesStatus(); const connectionsStatus = await fetchConnections(); for (const {deviceID, name} of config.devices) { const {connected} = connectionsStatus.connections[deviceID]; const {lastSeen: lastSeenString} = devicesStatus[deviceID]; const lastSeenDate = new Date(lastSeenString); const {completion, needItems} = await fetchCompletion(deviceID); //console.log(name, await fetchCompletion(deviceID)); checkDevice({name, connected, lastSeenDate, completion, needItems}); } } async function checkDevice({name, connected, lastSeenDate, completion, needItems}) { if (VERBOSE) { console.error('checkDevice', {name, connected, lastSeenDate, completion, needItems}); } if (lastSeenDate.getTime() === 0 || connected) { return; } if (lastSeenDate < newDateDays(-10)) { console.log(`Alert! '${name}' has been missing since ` + lastSeenDate.toISOString().replace(/T.*/, '')); } if (needItems > 0 || completion < 100) { console.log(`Alert! '${name}' is out of sync! ` + `${Math.round(completion)}%, missing ${needItems} files.`); } } function newDateDays(days) { return new Date(Date.now() + days * 24 * 3600 * 1000); } async function fetchConfig() { const response = await fetchSyncthing('/rest/config'); await assertResponseOk(response); return response.json(); } async function fetchDevicesStatus() { const response = await fetchSyncthing('/rest/stats/device'); await assertResponseOk(response); return response.json(); } async function fetchConnections() { const response = await fetchSyncthing('/rest/system/connections'); await assertResponseOk(response); return response.json(); } async function fetchCompletion(deviceID) { const response = await fetchSyncthing(`/rest/db/completion?device=${deviceID}`); await assertResponseOk(response); return response.json(); } async function fetchSyncthing(path) { return fetch(`${API_URL}${path}`, { headers: { 'X-API-Key': API_KEY, } }); } async function assertResponseOk(response) { if (response.ok) { return; } throw new Error( 'Response error! ' + response.status + ' ' + response.statusText + ' -- ' + (await response.text()) ); } main().catch((err) => { console.error('Exiting due to error!', err); process.exit(1); });