#!/usr/bin/env node var { Client } = require('undici'); var { parseArgs } = require('node:util'); var { values, positionals } = parseArgs({ options: { help: { type: 'boolean' } }, allowPositionals: true, }); var help = `Usage: webtimediff Calculate system clock difference between this host and a web server. --help display this help and exit `; if (values.help || positionals.length != 1) { console.log(help); return; } function sleep(ms) { return new Promise((res, rej) => setTimeout(_ => res(), ms)); } ((async function(url) { var conn = new Client(url.origin, { pipelining: 1000, headersTimeout: 10e3, bodyTimeout: 10e3, }); let step = 20; let end = 2000; let errors = []; let resps = []; let firstRemoteTime = undefined; let foundChange = undefined; let reqtempl = { method: "OPTIONS", path: url.pathname + url.search, headers: { "user-agent": "webtimediff" }, blocking: false, idempotent: true, } await conn.request(reqtempl); for (let i = 0; (!foundChange) && i < end; i += step) { if (errors.length > 0) break; let date = new Date(); let ii=i; let res = conn.request(reqtempl).then(e => ( e.date = new Date(e.headers.date), firstRemoteTime = firstRemoteTime ?? e.date, e.madeAt = date, e.doneAt = new Date(), foundChange = foundChange ?? ((firstRemoteTime && (firstRemoteTime.getTime() != e.date.getTime())) ? { remoteTime: e.date.getTime()/1000, beginTime: e.madeAt.getTime()/1000, endTime: e.doneAt.getTime()/1000, } : foundChange), e)); res.catch(e => errors.push(res)); resps.push(res); if (i + step < end) await sleep(step); } if (errors.length > 0) await Promise.all(errors); Promise.all(resps).catch(e => {}); if (!foundChange) { throw new Error("The remote clock does not work."); } let firstReq = [await (resps[0])].map(res => ({ remoteTime: res.date.getTime()/1000, beginTime: res.madeAt.getTime()/1000, endTime: res.doneAt.getTime()/1000, }))[0]; let reqEnds = (foundChange.endTime - firstReq.endTime); let reqBegins = (foundChange.beginTime - firstReq.beginTime) let lag = reqEnds / reqBegins; if (!(lag < 1.08)) { console.error("WARNING: Big Lag (" +reqEnds+ "s / " +reqBegins+ "s) detected, reported result may be inaccurate."); } let diff = (foundChange.remoteTime - (foundChange.beginTime + foundChange.endTime) / 2); console.log("remote_time = local_time "+(diff < 0 ? "-" : "+")+" " + Math.abs(Math.round(diff*1000)/1000)+ " s"); process.exit(); })(new URL(positionals[0])))