diff --git a/.version b/.version index 420e8937a..28cc11e0c 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -1.2.242 · 2026-02-15 +1.2.244 · 2026-02-15 diff --git a/INSTALL.md b/INSTALL.md index e042ac0fe..99e6fbbb4 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -46,11 +46,12 @@ You will see: ~ Try dmt start ~ ``` -💡 If you don't have `node.js` framework installed, please [read this](./help/NODEJS.md) to learn how to install it in the most maintainable way. +💡 If you don't have `node.js` installed, please [follow this](./help/NODEJS.md). -Node.js is one of the greatest iterative (some would say revolutionary) inventions of recent years, DMT SYSTEM depends on it to function. We further depend on many great libraries that come bundled through DMT install itself. Open source is awesome and powerful. The real global proliferation of great fast software and ubiquitous computing has just barely begun. +DMT SYSTEM depends on it to function. Bun is a faster and more modern alternative to the legendary **node.js** (still here). +We further depend on many great libraries that come bundled through DMT install. Open source is awesome and powerful. -💡 The entire DMT SYSTEM installation is contained inside one directory — `~/.dmt` and there is sometimes `~/.dmt-here` as well for strictly local information saved only on one device. That's it: two directories, never leaving artefacts around your file system. +💡 The entire DMT SYSTEM installation is contained inside one directory — `~/.dmt` and there is also `~/.dmt-here` as well for strictly local information saved only on one device. That's it: two directories, never leaving artefacts around your file system. ## Start the engine @@ -153,7 +154,6 @@ dmt run [run] eclipse 16036 7/2/2022, 1:32:27 PM (+13ms) ∞ dmt-proc is starting in terminal foreground … [run] eclipse 16036 7/2/2022, 1:32:27 PM (+01ms) ∞ OS uptime: 9 days [run] eclipse 16036 7/2/2022, 1:32:27 PM (+02ms) ∞ Starting content server ... -[run] eclipse 16036 7/2/2022, 1:32:27 PM (+05ms) ∞ Initializing ProgramConnectionsAcceptor with public key b26b1fbae57661ee706107262a60e165d58e6efdb3d4f00785939a364270f860 [run] eclipse 16036 7/2/2022, 1:32:27 PM (+02ms) ∞ 💡 Connectome protocol dmt ready. [run] eclipse 16036 7/2/2022, 1:32:27 PM (+00ms) ∞ Starting to load dmt-proc modules ... [run] eclipse 16036 7/2/2022, 1:32:27 PM (+00ms) ∞ Loading player aspect @@ -176,13 +176,11 @@ This allows you to test the new code faster — things you may have added throug Open DMT GUI at `http://localhost:7777` -This GUI helped us iterate quickly and get us to where we are. Now it is being reworked for the next major version, planned for EOY 2022. +This GUI helped us iterate quickly and get us to where we are. Now it is being reworked for the next major version. ## DMT SYSTEM features -DMT SYSTEM has many great features but you can very easily try one of them by disconnecting your wifi. You should get _Internet unreachable_ warning. This is an example of WAN connectivity monitoring feature of DMT SYSTEM. - -For more features, especially when going multi-device please read the [documentation](./DOCS.md) or visit one of our [meetups](https://dmt-system.com/). A lot of functionality is not documented until we test and consolidate it properly as a community and this is the main reason for our regular bi-yearly meetups. +For more features, especially when going multi-device please read the [documentation](./DOCS.md) or visit one of our [meetups](https://dmt-system.com/). A lot of functionality is not documented until we test and consolidate it properly. ## Keep up to date @@ -200,8 +198,6 @@ dmt update user@ip With this DMT SYSTEM core idea you replicate the global DMT ENGINE that you got from source through install to one or more devices that you own or manage. Along with core DMT ENGINE you also pass the replica of your private user directory (`~/.dmt/user`) so that your devices can execute your own customized version of the engine reliably and independently. -Read the documentation for more info on this very powerful aspect. - You can also update all nearby devices with: ``` diff --git a/core/node/aspect-extend/user-engine-load/deviceLoader.js b/core/node/aspect-extend/user-engine-load/deviceLoader.js index bf2084443..80a2d12e7 100644 --- a/core/node/aspect-extend/user-engine-load/deviceLoader.js +++ b/core/node/aspect-extend/user-engine-load/deviceLoader.js @@ -1,3 +1,4 @@ +import fs from 'fs'; import path from 'path'; import { isMainDevice, isMainServer, scan, log, program, devices, dmtUserDir, colors } from 'dmt/common'; @@ -104,5 +105,7 @@ function load(dir, currentNamespace = null) { } export default function init(program, userEnginePath) { - load(DEVICES_DIR); + if (fs.existsSync(DEVICES_DIR)) { + load(DEVICES_DIR); + } } diff --git a/core/node/aspect-meta/connectivity-report/index.js b/core/node/aspect-meta/connectivity-report/index.js deleted file mode 100644 index 5d5722314..000000000 --- a/core/node/aspect-meta/connectivity-report/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import { log, isRPi, isLanServer, loop } from 'dmt/common'; - -const ONE_MINUTE = 60 * 1000; -const ONE_HOUR = 60 * ONE_MINUTE; - -function keep12h(connectivityFailures) { - return connectivityFailures.filter(timestamp => Date.now() - timestamp < 12 * ONE_HOUR); -} - -function shouldCheck() { - return true; -} - -export function init(program) { - if (shouldCheck()) { - const slot = program.slot('connectivityReport'); - - program.on('internet_connection_lost', () => { - const connectivityFailures = keep12h(slot.get('connectivityFailures') || []); - connectivityFailures.push(Date.now()); - slot.update({ count12h: connectivityFailures.length, connectivityFailures }, { announce: false }); - }); - - loop(() => { - const connectivityFailures = keep12h(slot.get('connectivityFailures') || []); - slot.update({ count12h: connectivityFailures.length, connectivityFailures }, { announce: false }); - }, 5 * ONE_MINUTE); - } -} diff --git a/core/node/aspect-meta/connectivity-report/sendPush.js b/core/node/aspect-meta/connectivity-report/sendPush.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/node/aspect-meta/netping/executePing.js b/core/node/aspect-meta/netping/executePing.js deleted file mode 100644 index 109458b9e..000000000 --- a/core/node/aspect-meta/netping/executePing.js +++ /dev/null @@ -1,103 +0,0 @@ -import { log, isDevMachine } from 'dmt/common'; - -import EventEmitter from 'events'; - -import ping from './ping.js'; - -export default class ExecutePing extends EventEmitter { - constructor({ program, target, prefix }) { - super(); - - if (!prefix) { - throw new Error('Specify connectivity store prefix'); - } - - this.program = program; - this.target = target; - - this.isConnected = undefined; - - this.deviceStore = program.slot('device'); - - this.prefix = prefix; - } - - cleanup() { - const connectivityResumed = this.deviceStore.get(`${this.prefix}Resumed`); - const connectivityResumedAt = this.deviceStore.get(`${this.prefix}ResumedAt`); - - if (connectivityResumed && Date.now() - connectivityResumedAt > 10 * 1000) { - this.deviceStore.removeKeys([`${this.prefix}Resumed`, `${this.prefix}ResumedAt`], { announce: false }); - } - } - - reset() { - this.deviceStore.removeKeys([`${this.prefix}Resumed`, `${this.prefix}ResumedAt`, `${this.prefix}Problem`], { announce: false }); - - this.isConnected = undefined; - } - - assumeConnected() { - this.isConnected = true; - } - - ping() { - return new Promise((success, reject) => { - const target = this.target || this.deviceStore.get('gatewayIp'); - - const now = Date.now(); - const temp = Math.random(); - - if (target) { - if (this.program.hasValidIP()) { - ping(target) - .then(() => { - if (this.isConnected == false) { - if (this.deviceStore.get(`${this.prefix}Problem`)) { - const patch = {}; - patch[`${this.prefix}Resumed`] = true; - patch[`${this.prefix}ResumedAt`] = Date.now(); - this.deviceStore.update(patch, { announce: false }); - - this.emit('connection_resumed'); - } - } - - this.deviceStore.removeKey(`${this.prefix}Problem`); - - this.isConnected = true; - - success(); - }) - .catch(e => { - this.connectionLost(e.code); - - success(); - }); - } else { - this.connectionLost(); - success(); - } - } else { - this.connectionLost('router unreachable'); - success(); - } - }); - } - - connectionLost(code) { - this.deviceStore.removeKeys([`${this.prefix}Resumed`, `${this.prefix}ResumedAt`], { announce: false }); - - if (!this.deviceStore.get(`${this.prefix}Problem`)) { - const patch = {}; - patch[`${this.prefix}Problem`] = true; - this.deviceStore.update(patch); - } - - if (this.isConnected) { - this.emit('connection_lost', { code }); - } - - this.isConnected = false; - } -} diff --git a/core/node/aspect-meta/netping/index.js b/core/node/aspect-meta/netping/index.js deleted file mode 100644 index 0f5316d8b..000000000 --- a/core/node/aspect-meta/netping/index.js +++ /dev/null @@ -1,146 +0,0 @@ -import { log, device, apMode, isRPi, isPersonalComputer, isDevMachine, globals } from 'dmt/common'; - -import os from 'os'; - -const BOOT_WAIT_SECONDS = 30; - -import { desktop } from 'dmt/notify'; - -import ExecutePing from './executePing.js'; - -const CLOUDFLARE_DNS = '1.0.0.1'; -const DEFAULT_TTL = 20; -const NOTIFICATION_GROUP_PREFIX = `${device().id}_connectivity`; - -function reportConnectivityOnLan() { - return isRPi() || device().id == 'eclipse'; -} - -function init(program) { - const wanConnectivity = new ExecutePing({ program, target: CLOUDFLARE_DNS, prefix: 'connectivity' }); - - const localConnectivity = new ExecutePing({ program, prefix: 'localConnectivity' }); - - wanConnectivity.on('connection_lost', ({ code }) => { - const color = '#e34042'; - - const prefix = isPersonalComputer() ? '❌' : '✖'; - const noConnectivityMsg = `${prefix} Internet unreachable`; - - program.emit('internet_connection_lost'); - - if (device().id == 'eclipse' || isDevMachine() || !isPersonalComputer()) { - log.red(noConnectivityMsg); - } - - if (reportConnectivityOnLan()) { - program.nearbyNotification({ msg: noConnectivityMsg, ttl: DEFAULT_TTL, color, group: `${NOTIFICATION_GROUP_PREFIX}_unreachable` }); - } else { - desktop.notify(noConnectivityMsg); - } - }); - - localConnectivity.on('connection_lost', ({ code }) => { - const color = '#FF7A2C'; - - const noConnectivityMsg = '✖ Router unreachable'.trim(); - - if (device().id == 'eclipse' || isDevMachine() || !isPersonalComputer()) { - log.red(noConnectivityMsg); - } - - if (reportConnectivityOnLan()) { - program.nearbyNotification({ msg: noConnectivityMsg, ttl: 20, color, group: `${NOTIFICATION_GROUP_PREFIX}_local_connectivity` }); - } else { - desktop.notify(noConnectivityMsg); - } - }); - - wanConnectivity.on('connection_resumed', () => { - const prefix = isPersonalComputer() ? '✅' : '✓'; - const connResumedMsg = `${prefix} Internet connection resumed`; - - // NEW❗ - localConnectivity.assumeConnected(); - - if (device().id == 'eclipse' || isDevMachine() || !isPersonalComputer()) { - log.green(connResumedMsg); - } - - if (reportConnectivityOnLan()) { - program.nearbyNotification({ msg: connResumedMsg, ttl: DEFAULT_TTL, color: '#6BFF74', group: `${NOTIFICATION_GROUP_PREFIX}_resumed` }); - } else { - desktop.notify(connResumedMsg); - } - - program.slot('device').removeKeys(['localConnectivityProblem', 'localConnectivityResumed', 'localConnectivityResumedAt']); - }); - - localConnectivity.on('connection_resumed', () => { - const connResumedMsg = '✓ Router connection resumed'; - - if (device().id == 'eclipse' || isDevMachine() || !isPersonalComputer()) { - log.green(`${connResumedMsg}`); - } - - if (reportConnectivityOnLan()) { - program.nearbyNotification({ msg: connResumedMsg, ttl: 20, color: '#F1A36B', group: `${NOTIFICATION_GROUP_PREFIX}_local_connectivity` }); - } else { - desktop.notify(connResumedMsg); - } - }); - - let wokeAt; - let lastIntervalAt = Date.now(); - - let temp; - let count = 0; - - setTimeout( - () => { - program.on('tick', () => { - temp = Date.now(); - setTimeout(() => { - if (isDevMachine()) { - count += 1; - } - - if (!wokeAt || Date.now() - wokeAt > 5000) { - if (Date.now() - lastIntervalAt <= 2.1 * globals.tickerPeriod) { - localConnectivity.cleanup(); - wanConnectivity.cleanup(); - - if (!apMode()) { - if (os.uptime() > BOOT_WAIT_SECONDS) { - wanConnectivity.ping().then(() => { - if (program.slot('device').get('connectivityProblem')) { - localConnectivity.ping(); - } - }); - } - } - } else { - if (device().id == 'eclipse' || isDevMachine()) { - log.green(`PC Wake up after ${Math.round((Date.now() - lastIntervalAt) / 1000)}s`); - log.magenta('Will start pings in 6s'); - } - - localConnectivity.reset(); - wanConnectivity.reset(); - - wokeAt = Date.now(); - } - } else { - localConnectivity.reset(); - wanConnectivity.reset(); - } - - lastIntervalAt = Date.now(); - }, 500); - }); - }, - isRPi() ? 7000 : 2000 - ); -} - -export { init }; diff --git a/core/node/aspect-meta/netping/ping.js b/core/node/aspect-meta/netping/ping.js deleted file mode 100644 index 805558a4e..000000000 --- a/core/node/aspect-meta/netping/ping.js +++ /dev/null @@ -1,74 +0,0 @@ -import { log, device, colors, globals, isDevMachine, isDevUser, isPersonalComputer } from 'dmt/common'; -import ping from 'nodejs-tcp-ping'; - -const TIMEOUT = 1500; - -const prevAttemptAt = {}; - -const consecutiveUnresolvedTimeouts = {}; - -export default function doPing(target, timeout = TIMEOUT) { - return new Promise((success, reject) => { - const startedAt = Date.now(); - - if (prevAttemptAt[target] && startedAt - prevAttemptAt[target] > 2.1 * globals.tickerPeriod) { - consecutiveUnresolvedTimeouts[target] = 0; - } - - prevAttemptAt[target] = startedAt; - - consecutiveUnresolvedTimeouts[target] = (consecutiveUnresolvedTimeouts[target] || 0) + 1; - if (consecutiveUnresolvedTimeouts[target] >= 3) { - if (isDevUser()) { - log.red(`${target} consecutiveUnresolvedTimeout after ${consecutiveUnresolvedTimeouts[target] - 1}x unresolved promise`); - } - - consecutiveUnresolvedTimeouts[target] = 0; - - const timeoutError = new Error('Timeout'); - timeoutError.code = `${consecutiveUnresolvedTimeouts[target]}x TIMEOUT `; - - reject(timeoutError); - return; - } - - ping - .tcpPing({ - attempts: 5, - host: target, - timeout - }) - .then(results => { - const delay = Date.now() - startedAt; - - if (delay < timeout) { - if (consecutiveUnresolvedTimeouts[target] == 2 && isDevUser()) { - log.green(`⚠️ Ping ${target} anomaly returned to normal (did not reach two consecutive timeouts)`); - } - - consecutiveUnresolvedTimeouts[target] = 0; - - if (results.filter(el => el.ping < timeout).length == 0) { - const timeoutError = new Error('Timeout'); - timeoutError.code = `TIMEOUT ${timeout}ms`; - reject(timeoutError); - } else { - success(results); - } - } else if (isDevUser()) { - log.cyan(`⚠️ Ping ${target} anomaly ignored: delay ${colors.red(delay)}ms > timeout (${timeout})ms`); - log.gray(results); - } - }) - .catch(e => { - const delay = Date.now() - startedAt; - - if (delay < timeout) { - reject(e); - } else if (isDevMachine() || device().id == 'eclipse') { - log.magenta(`⚠️ Ping ${target} anomaly2 ignored: delay ${colors.red(delay)}ms > timeout (${timeout})ms`); - log.red(e); - } - }); - }); -} diff --git a/core/node/controller/processes/dmt-proc.js b/core/node/controller/processes/dmt-proc.js index 80070c53b..0f56c9f2b 100644 --- a/core/node/controller/processes/dmt-proc.js +++ b/core/node/controller/processes/dmt-proc.js @@ -45,10 +45,6 @@ mids.push('content/samba'); mids.push('meta/abc-connect'); -if (isDevUser()) { - mids.push('meta/connectivity-report'); -} - mids.push('meta/replicate'); mids.push('meta/sysinfo'); mids.push('meta/holidays'); diff --git a/core/node/controller/program/boot/retrogradePushMessagesRecovery.js b/core/node/controller/program/boot/retrogradePushMessagesRecovery.js index e1b868a92..4a8faa444 100644 --- a/core/node/controller/program/boot/retrogradePushMessagesRecovery.js +++ b/core/node/controller/program/boot/retrogradePushMessagesRecovery.js @@ -5,7 +5,7 @@ const { ONE_SECOND, ONE_MINUTE, ONE_HOUR, ONE_DAY } = timeutils; const { format } = dateFns; const MAIN_DEVICE_TESTING = false; -const TESTING_LOOKBACK_MINUTES = 30; +const TESTING_LOOKBACK_MINUTES = 10; const INITIAL_DELAY = MAIN_DEVICE_TESTING ? 500 : 3000; diff --git a/core/node/controller/program/interval/checkForLocalOnlyIpAndRebootDevice.js b/core/node/controller/program/interval/checkForLocalOnlyIpAndRebootDevice.js index 69146cdd5..60b6445b3 100644 --- a/core/node/controller/program/interval/checkForLocalOnlyIpAndRebootDevice.js +++ b/core/node/controller/program/interval/checkForLocalOnlyIpAndRebootDevice.js @@ -38,7 +38,7 @@ export default function checkForLocalOnlyIpAndRebootDevice({ program, ip, prevIp const msg = `✓ Device received a valid IP address [ ${colors.gray(prevIp)} → ${ip} ] again.`; log.green(msg); - if (program.isHub() && isDevUser()) { + if (program.isHub()) { setTimeout(() => { push.notify(stripAnsi(msg)); }, 500); diff --git a/core/node/controller/program/program.js b/core/node/controller/program/program.js index e974c2a8c..0c3e15e60 100644 --- a/core/node/controller/program/program.js +++ b/core/node/controller/program/program.js @@ -1,7 +1,7 @@ import EventEmitter from 'events'; import * as dmt from 'dmt/common'; -const { log, colors, colors2 } = dmt; +const { log, colors, colors2, userDef } = dmt; import { desktop, apn, push } from 'dmt/notify'; @@ -147,6 +147,10 @@ class Program extends EventEmitter { this.slot('device').removeKey('isRPi', { announce: false }); } + if (!userDef('pushover')?.pushover?.user) { + log.yellow('⚠️ pushover.def does not exist or is missing user token... you will not receive push messages...'); + } + if (mids.includes('apps')) { if (!this.acceptor.ok()) { log.cyan(`Skipped ${colors.red('dmt/apps')} middleware because ProgramConnectionsAcceptor was not properly initialized`); diff --git a/core/node/notify/lib/node-notifier/package-lock.json b/core/node/notify/lib/node-notifier/package-lock.json index f9e443eb4..7c27b8c3f 100644 --- a/core/node/notify/lib/node-notifier/package-lock.json +++ b/core/node/notify/lib/node-notifier/package-lock.json @@ -10,7 +10,6 @@ "license": "MIT", "dependencies": { "growly": "^1.3.0", - "husky": "^8.0.1", "is-wsl": "^2.2.0", "semver": "^7.3.5", "shellwords": "^0.1.1", @@ -26,6 +25,7 @@ "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", + "husky": "^8.0.1", "jest": "^26.6.3", "lint-staged": "^13.0.3", "nexe": "^4.0.0-beta.19", @@ -4194,9 +4194,9 @@ } }, "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "node_modules/for-in": { @@ -4733,6 +4733,7 @@ "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, "bin": { "husky": "lib/bin.js" }, @@ -13751,9 +13752,9 @@ } }, "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "for-in": { @@ -14168,7 +14169,8 @@ "husky": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==" + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true }, "iconv-lite": { "version": "0.4.24", diff --git a/core/node/notify/lib/node-notifier/pnpm-lock.yaml b/core/node/notify/lib/node-notifier/pnpm-lock.yaml index c353977b0..96de05def 100644 --- a/core/node/notify/lib/node-notifier/pnpm-lock.yaml +++ b/core/node/notify/lib/node-notifier/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: growly: specifier: ^1.3.0 diff --git a/core/node/notify/lib/pushover/sending/notifyHelper.js b/core/node/notify/lib/pushover/sending/notifyHelper.js index cf3a44d33..25e104cb2 100644 --- a/core/node/notify/lib/pushover/sending/notifyHelper.js +++ b/core/node/notify/lib/pushover/sending/notifyHelper.js @@ -36,6 +36,9 @@ function reportError(obj) { export default function notifyHelper(obj, sendingId) { return new Promise((success, reject) => { + if (!getMainUserToken()) { + success(true); + } obj.app = obj.app || dmtApp; const { @@ -75,6 +78,12 @@ export default function notifyHelper(obj, sendingId) { recipient = getPushoverUserApi(); } + if (!recipient) { + log.red('No pushover recipient defined'); + success(true); + return; + } + let client = getPushoverClient(app); if (!client && optionalApp) { diff --git a/core/node/notify/lib2/dailyNotifier.js b/core/node/notify/lib2/dailyNotifier.js index e0ee2a500..672b5b02f 100644 --- a/core/node/notify/lib2/dailyNotifier.js +++ b/core/node/notify/lib2/dailyNotifier.js @@ -111,9 +111,11 @@ class DailyNotifier extends ScopedNotifier { let _isWithin = true; for (const _from of Array(from).flat()) { - const { isWithin } = evaluateTimespan({ date: notificationTime, from: _from, until }); - if (!isWithin) { - _isWithin = false; + for (const _until of Array(until).flat()) { + const { isWithin } = evaluateTimespan({ date: notificationTime, from: _from, until: _until }); + if (!isWithin) { + _isWithin = false; + } } } diff --git a/core/node/notify/lib2/dateNotifier.js b/core/node/notify/lib2/dateNotifier.js index 3c1a54c99..eec2a83a4 100644 --- a/core/node/notify/lib2/dateNotifier.js +++ b/core/node/notify/lib2/dateNotifier.js @@ -398,9 +398,11 @@ class DateNotifier extends ScopedNotifier { let _isWithin = true; for (const _from of Array(from).flat()) { - const { isWithin } = evaluateTimespan({ date: timepoint, from: _from, until }); - if (!isWithin) { - _isWithin = false; + for (const _until of Array(until).flat()) { + const { isWithin } = evaluateTimespan({ date: timepoint, from: _from, until: _until }); + if (!isWithin) { + _isWithin = false; + } } } @@ -430,25 +432,17 @@ class DateNotifier extends ScopedNotifier { const isLastNotification = index === minutesBefore.length - 1; - const brevityTagline = minutesBefore.length >= 2 && min <= 30 && isLastNotification && !isPast; - let _tagline = isNow && msg ? undefined - : `${isNow ? NOW_SYMBOL : CLOCK_SYMBOL}${brevityTagline ? '' : ` ${datetime}`}${ - inTime ? ` ${brevityTagline ? capitalizeFirstLetter(inTime) : `[ ${inTime} ]`}` : '' - }${(!isNow && min <= 30) || isPast ? EXCLAMATION_SYMBOL : ''}`; + : `${isNow ? NOW_SYMBOL : CLOCK_SYMBOL} ${datetime} ${inTime ? `[ ${inTime} ]` : ''}${ + (!isNow && min <= 30) || isPast ? EXCLAMATION_SYMBOL : '' + }`; - if (duration && minutesBefore.length - 1 == index) { + if (duration) { const endTime = addMinutes(timepoint, duration); - const startTimeStr = format(timepoint, 'HH:mm'); const endTimeStr = format(endTime, 'HH:mm'); - _tagline = `${_tagline || ''}${_tagline ? '\n' : ''}${FINISH_SYMBOL} `; - if (brevityTagline) { - _tagline += `${capitalizeFirstLetter(strFrom)} ${startTimeStr} ${strUntil} ${endTimeStr}`; - } else { - _tagline += `${capitalizeFirstLetter(strUntil)} ${endTimeStr}`; - } + _tagline = `${_tagline || ''}${_tagline ? '\n' : ''}${FINISH_SYMBOL} ${capitalizeFirstLetter(strUntil)} ${endTimeStr}`; } const __tagline = isUnspecifiedTime ? undefined : _tagline; diff --git a/core/node/notify/lib2/lib/describeNearTime.js b/core/node/notify/lib2/lib/describeNearTime.js index 4df774f88..c9d424e92 100644 --- a/core/node/notify/lib2/lib/describeNearTime.js +++ b/core/node/notify/lib2/lib/describeNearTime.js @@ -1,6 +1,6 @@ import { timeutils, dateFns, program } from 'dmt/common'; -const { isToday, isTomorrow, format, differenceInMinutes, isSameMinute } = dateFns; +const { isToday: _isToday, isTomorrow, format, differenceInMinutes, isSameMinute } = dateFns; const { formatFutureDistance, prettyTimeAgo } = timeutils; @@ -22,13 +22,19 @@ export default function describeNearTime(_date, { now = new Date() } = {}) { now.setSeconds(0); now.setMilliseconds(0); + const diff = differenceInMinutes(date, now); + + const isSoon = diff <= 180 && diff > 0; + if (isSameMinute(date, now)) { return { datetime: `${capitalizeFirstLetter(strAt)} ${time}`, inTime: strNow, isNow: true }; } + const isToday = _isToday(date); + const timeDescription = () => { - if (isToday(date)) { - return `${strToday} ${strAt} ${time}`; + if (isToday) { + return isSoon ? time : `${strToday} ${strAt} ${time}`; } if (isTomorrow(date)) { @@ -40,15 +46,13 @@ export default function describeNearTime(_date, { now = new Date() } = {}) { return `${d} ${strAt} ${t}`; }; - const diff = differenceInMinutes(date, now); - - if (diff <= 180 && diff > 0) { - return { datetime: timeDescription(), inTime: `${strIn} ${formatFutureDistance(date, { referenceDate: now, lang: program.lang() })}` }; + if (isSoon) { + return { datetime: timeDescription(), isToday, inTime: `${strIn} ${formatFutureDistance(date, { referenceDate: now, lang: program.lang() })}` }; } if (diff < 0) { - return { datetime: timeDescription(), isPast: true, inTime: `${prettyTimeAgo(date, { now })}` }; + return { datetime: timeDescription(), isToday, isPast: true, inTime: `${prettyTimeAgo(date, { now })}` }; } - return { datetime: timeDescription() }; + return { datetime: timeDescription(), isToday }; } diff --git a/core/node/notify/lib2/weeklyNotifier.js b/core/node/notify/lib2/weeklyNotifier.js index d1390c558..ca99c2a4d 100644 --- a/core/node/notify/lib2/weeklyNotifier.js +++ b/core/node/notify/lib2/weeklyNotifier.js @@ -204,11 +204,13 @@ class WeeklyNotifier extends ScopedNotifier { let _isWithin = true; let _isLastDay; for (const _from of Array(from).flat()) { - const { isWithin, isLastDay } = evaluateTimespan({ date: eventTime, from: _from, until }); - if (!isWithin) { - _isWithin = false; + for (const _until of Array(until).flat()) { + const { isWithin, isLastDay } = evaluateTimespan({ date: eventTime, from: _from, until: _until }); + if (!isWithin) { + _isWithin = false; + } + _isLastDay = isLastDay; } - _isLastDay = isLastDay; } if (_isWithin && !this.shouldSkip(eventTime, entry, excludedRanges)) { @@ -238,25 +240,15 @@ class WeeklyNotifier extends ScopedNotifier { const { capitalizeFirstLetter, strFrom, strUntil } = localize(program); - const brevityTagline = !isNow && minutesBefore.length >= 2 && minBefore <= 30 && minutesBefore.length - 1 == index; - let tagline = isNow && msg ? undefined - : `${isNow ? NOW_SYMBOL : CLOCK_SYMBOL}${brevityTagline ? '' : ` ${datetime}`}${ - inTime ? ` ${brevityTagline ? capitalizeFirstLetter(inTime) : `[ ${inTime} ]`}` : '' - }${!isNow && minBefore <= 30 ? EXCLAMATION_SYMBOL : ''}`; + : `${isNow ? NOW_SYMBOL : CLOCK_SYMBOL} ${datetime} ${inTime ? `[ ${inTime} ]` : ''}${!isNow && minBefore <= 30 ? EXCLAMATION_SYMBOL : ''}`; - if (duration && minutesBefore.length - 1 == index) { + if (duration) { const endTime = addMinutes(eventTime, duration); - const startTimeStr = format(eventTime, 'HH:mm'); const endTimeStr = format(endTime, 'HH:mm'); - tagline = `${tagline || ''}${tagline ? '\n' : ''}${FINISH_SYMBOL} `; - if (brevityTagline) { - tagline += `${capitalizeFirstLetter(strFrom)} ${startTimeStr} ${strUntil} ${endTimeStr}`; - } else { - tagline += `${capitalizeFirstLetter(strUntil)} ${endTimeStr}`; - } + tagline = `${tagline || ''}${tagline ? '\n' : ''}${FINISH_SYMBOL} ${capitalizeFirstLetter(strUntil)} ${endTimeStr}`; } const title = `${_title}${lastTag}`; @@ -286,11 +278,13 @@ class WeeklyNotifier extends ScopedNotifier { let _isWithin = true; let _isLastDay; for (const _from of Array(from).flat()) { - const { isWithin, isLastDay } = evaluateTimespan({ date: eventTime, from: _from, until }); - if (!isWithin) { - _isWithin = false; + for (const _until of Array(until).flat()) { + const { isWithin, isLastDay } = evaluateTimespan({ date: eventTime, from: _from, until: _until }); + if (!isWithin) { + _isWithin = false; + } + _isLastDay = isLastDay; } - _isLastDay = isLastDay; } const isLastDay = _isLastDay || this.isLastDaySpecificCheckForWeeklyNotifier(eventTime, entry, excludedRanges); @@ -360,14 +354,19 @@ class WeeklyNotifier extends ScopedNotifier { } isLastDaySpecificCheckForWeeklyNotifier(_eventTime, entry, excludedRanges) { - const { when, from: _from, until } = entry; + const { when, from: _from, until: _until } = entry; let from = _from; + let until = _until; if (Array.isArray(from)) { from = from[0]; } + if (Array.isArray(until)) { + until = until[0]; + } + for (let i = 1; i <= 30; i++) { const eventTime = addDays(_eventTime, i); diff --git a/etc/conf/caddy/Caddyfile b/etc/conf/caddy/Caddyfile new file mode 100644 index 000000000..e24d43ebc --- /dev/null +++ b/etc/conf/caddy/Caddyfile @@ -0,0 +1,25 @@ +# Default site +:80 { + root * /usr/share/caddy + file_server +} + +# HTTPS configuration for zetaseek.com +yourdomain.com { + # Match WebSockets + @websockets { + header Connection *Upgrade* + header Upgrade websocket + path /ws* + } + + # Route WebSockets to 7780, everything else to 7777 + reverse_proxy @websockets 127.0.0.1:7780 + + reverse_proxy 127.0.0.1:7777 + + # Log to the system journal instead of a file to avoid permission issues + log { + output stderr + } +} diff --git a/etc/conf/caddy/DMT_WARNING.txt b/etc/conf/caddy/DMT_WARNING.txt new file mode 100644 index 000000000..d0bc0f70d --- /dev/null +++ b/etc/conf/caddy/DMT_WARNING.txt @@ -0,0 +1,3 @@ +Caddyfile is synced from dmt device. Any manual changes you make will be lost on next dmt update. + +Edit locally (on your PC/mainDevice) at ~/.dmt/devices/[serverDevice]/device/conf/Caddyfile ... diff --git a/etc/cron/root/hourly b/etc/cron/root/hourly old mode 100755 new mode 100644 index b7b3b05ff..05a7907cf --- a/etc/cron/root/hourly +++ b/etc/cron/root/hourly @@ -1,58 +1,2 @@ #!/bin/bash -user="$1" - -if [ -n "$user" ]; then - - CERT_DIR="/home/${user}/.dmt-here/https/zetaseek.com" - - if [ -d "$CERT_DIR" ]; then - - cd "$CERT_DIR" - - if [ -f web.pem ]; then - REPORT=cert_auto_update_report.txt - - echo $(date) > $REPORT - - # if certificate is not expiring soon, don't do anything, just write log - if openssl x509 -checkend 604800 -noout -in web.pem # 604800s == 7 days - then - echo "Certificate is good at least for another week, it expires at:" >> $REPORT - echo $(openssl x509 -enddate -noout -in web.pem | sed 's/notAfter=//') >> $REPORT - else # if certificate is expiring soon, re-fetch it - echo "Certificate has expired or will do so within 7 days!" >> $REPORT - echo "(or is invalid/not found)" >> $REPORT - - curl https://dmt-system.com/cert/zs.pem -o web_cert_next.pem - - if [ -f web_cert_next.pem ]; then - # and check if it was actually updated - if openssl x509 -checkend 604800 -noout -in web_cert_next.pem # 604800s == 7 days - then - echo "" >> $REPORT - echo "fetched new certificate" >> $REPORT - - # we got a new certificate, replace the old one - mv web.pem web_old.pem - mv web_cert_next.pem web.pem - - chown $user:$user web.pem - - # restart lighttpd - # ⚠️ reload does not work when certificates update - it freezes lighttpd :( - echo "restarting lighttpd" >> $REPORT - systemctl restart lighttpd - else - echo "fetched certificate from server but it's still the old one" >> $REPORT - # certificate was not yet updated on server, it is probably the same we have or also expired or expiring soon - rm web_cert_next.pem - fi - else - echo "failed to fetch certificate from server" >> $REPORT - fi - fi - fi - - fi -fi diff --git a/etc/cron/setup_cron b/etc/cron/setup_cron index d7d177978..394660f4b 100755 --- a/etc/cron/setup_cron +++ b/etc/cron/setup_cron @@ -25,5 +25,3 @@ fi (crontab -l ; echo "0 * * * * bash -ic ~/.dmt/etc/cron/hourly") | sort - | uniq - | crontab - (crontab -l ; echo "0 0 * * * bash -ic ~/.dmt/etc/cron/daily") | sort - | uniq - | crontab - -echo -echo "ok" diff --git a/etc/deploy_hooks/oninstall b/etc/deploy_hooks/on_update similarity index 59% rename from etc/deploy_hooks/oninstall rename to etc/deploy_hooks/on_update index 1de18083c..9f260f731 100755 --- a/etc/deploy_hooks/oninstall +++ b/etc/deploy_hooks/on_update @@ -7,10 +7,12 @@ if [ -d "$DMT_NODE_CORE" ]; then DMT_NODEJS_EXEC="node --unhandled-rejections=strict" # use bun if available - if command -v bun >/dev/null 2>&1; then - #printf "✅ Using ${GREEN}bun${NC}\n" - DMT_NODEJS_EXEC="bun --unhandled-rejections=strict" - fi + # if command -v bun >/dev/null 2>&1; then + # #printf "✅ Using ${GREEN}bun${NC}\n" + # DMT_NODEJS_EXEC="node --unhandled-rejections=strict" + # else + # DMT_NODEJS_EXEC="node --unhandled-rejections=strict" + # fi $DMT_NODEJS_EXEC "${DMT_NODE_CORE}/gui/cli/gui.js" reload fi diff --git a/etc/onboot/daemons b/etc/onboot/daemons index 6a5cc5ab5..6c2b34bd0 100755 --- a/etc/onboot/daemons +++ b/etc/onboot/daemons @@ -16,13 +16,12 @@ DMT_NODE_CORE="$HOME/.dmt/core/node" # there are some other places that should be updated if nodejs flags change! find and replace ... DMT_NODEJS_EXEC="node --unhandled-rejections=strict" - -# use bun if available -if command -v bun >/dev/null 2>&1; then - printf "✅ Using ${GREEN}bun${NC}\n" - echo - DMT_NODEJS_EXEC="bun --unhandled-rejections=strict" -fi +# if command -v bun >/dev/null 2>&1; then +# printf "✅ Using ${GREEN}bun${NC}\n" +# DMT_NODEJS_EXEC="node --unhandled-rejections=strict" +# else +# DMT_NODEJS_EXEC="node --unhandled-rejections=strict" +# fi # # dup but ok... function nearby_notify { diff --git a/etc/scripts/lighttpd/install_lighttpd_manual_compile b/etc/scripts/lighttpd/install_lighttpd_manual_compile deleted file mode 100755 index 05a3e7183..000000000 --- a/etc/scripts/lighttpd/install_lighttpd_manual_compile +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash - -# DEFINE COLORS -YELLOW='\033[0;33m' -GREEN='\033[0;32m' -RED='\033[0;31m' -BLUE='\033[0;34m' -CYAN='\e[0;36m' -MAGENTA='\033[0;35m' -GRAY='\e[1;30m' -NC='\033[0m' # No Color - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -function macos { - if [[ $OSTYPE == darwin* ]]; then - return 0 # true - fi - - return 1 # false -} - -if [ "$1" == "-h" ]; then - printf "${YELLOW}Usage:${NC}\n" - printf "${GRAY}[todo]${NC}\n" - exit -fi - -if macos; then - printf "${RED}Can't run on macOS${NC}\n" - exit -fi - -if [ "$EUID" -ne 0 ] - then printf "${RED}Must be root, use ${YELLOW}sudo $0${NC}\n" - exit -fi - -if [ -d /etc/lighttpd ]; then - printf "⚠️ ${YELLOW}Directory ${WHITE}/etc/lighttpd ${YELLOW}already exists.${NC}\n" - exit -fi - -function latest_tag { - local latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`) - git checkout $latest_tag -} - -mkdir -p ~/Install - -cd ~/Install - -if [ ! -d lighttpd ]; then - git clone https://git.lighttpd.net/lighttpd/lighttpd1.4.git lighttpd -fi - -cd lighttpd - -latest_tag - -sudo apt-get update -sudo apt-get -y build-dep lighttpd - -./autogen.sh - -./configure --prefix=/usr --with-openssl # default prefix is into /usr/local -# https://www.cyberciti.biz/tips/installing-and-configuring-lighttpd-webserver-howto.html -# todo - test this and see if these dirs are created, then don't create them manually below -# --datadir=/usr/share \ -# --localstatedir=/var \ - -make - -make install - -if [ -f /usr/sbin/lighttpd ]; then - echo - printf "${GREEN}✓ Installed lighttpd ${CYAN}$(/usr/sbin/lighttpd -v)${NC}\n" - echo -else - printf "⚠️ ${RED}Failed to install ${YELLOW}lighttpd${NC}.${NC}\n" - exit -fi - -cp "${DIR}/lighttpd.service" /etc/systemd/system - -systemctl enable lighttpd - -mkdir -p /var/log/lighttpd/ -chown www-data:www-data /var/log/lighttpd/ - -mkdir -p /var/cache/lighttpd/uploads -chown www-data:www-data /var/cache/lighttpd/uploads - -mkdir -p /var/cache/lighttpd/compress -chown www-data:www-data /var/cache/lighttpd/compress - -mkdir -p /usr/share/lighttpd - -cp ~/Install/lighttpd/doc/scripts/create-mime.conf.pl /usr/share/lighttpd - -cp "${DIR}/use-ipv6.pl" /usr/share/lighttpd - -if [ -f /etc/lighttpd/lighttpd.conf ]; then - printf "⚠️ ${YELLOW}Not overwriting /etc/lighttpd/lighttpd.conf ! ${NC}\n" -else - mkdir -p /etc/lighttpd - cp "${DIR}/lighttpd.conf" /etc/lighttpd -fi - -mkdir -p /var/www - -chown www-data:www-data /var/www - -if [ ! -f /var/www/index.html ]; then - echo "OK" > /var/www/index.html - chown www-data:www-data /var/www/index.html -fi - -sudo systemctl start lighttpd diff --git a/etc/scripts/lighttpd/lighttpd.conf b/etc/scripts/lighttpd/lighttpd.conf deleted file mode 100644 index 87e257a89..000000000 --- a/etc/scripts/lighttpd/lighttpd.conf +++ /dev/null @@ -1,37 +0,0 @@ -server.modules = ( - "mod_access", - "mod_alias", - "mod_proxy", - "mod_openssl", - "mod_compress", - "mod_redirect", -) - -server.document-root = "/var/www" -server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) -server.errorlog = "/var/log/lighttpd/error.log" -server.pid-file = "/var/run/lighttpd.pid" -server.username = "www-data" -server.groupname = "www-data" -server.port = 80 - -index-file.names = ( "index.php", "index.html", "index.shtml", "index.lighttpd.html" ) -url.access-deny = ( "~", ".inc" ) -static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" ) - -compress.cache-dir = "/var/cache/lighttpd/compress/" -compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" ) - -# default listening port for IPv6 falls back to the IPv4 port -include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port -include_shell "/usr/share/lighttpd/create-mime.conf.pl" -#include_shell "/usr/share/lighttpd/include-conf-enabled.pl" -#include_shell "/usr/share/lighttpd/create-mime.assign.pl" - -# redirect -$HTTP["host"] =~ "^www\.(.*)$" { - url.redirect = ( - "^/(.*)" => "http://%1/$1", - ) -} - diff --git a/etc/scripts/lighttpd/lighttpd.service b/etc/scripts/lighttpd/lighttpd.service deleted file mode 100644 index e92b160cb..000000000 --- a/etc/scripts/lighttpd/lighttpd.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Lighttpd Daemon -After=network.target - -[Service] -Type=simple -ExecStartPre=/usr/sbin/lighttpd -tt -f /etc/lighttpd/lighttpd.conf -ExecStart=/usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf -Restart=on-failure - -[Install] -WantedBy=multi-user.target diff --git a/etc/scripts/lighttpd/use-ipv6.pl b/etc/scripts/lighttpd/use-ipv6.pl deleted file mode 100755 index 3de52126f..000000000 --- a/etc/scripts/lighttpd/use-ipv6.pl +++ /dev/null @@ -1,12 +0,0 @@ -#! /usr/bin/perl -w - -use Socket; -use strict; - -my $sock; -my $PORT = 80; -$PORT = $ARGV[0] if $ARGV[0] and $ARGV[0] >= 0 and $ARGV[0] <= 65535; - -if (socket($sock, AF_INET6, SOCK_STREAM, 0)) { - print qq/\$SERVER["socket"] == "[::]:$PORT" { }\n/; -} diff --git a/etc/scripts/lighttpd/zeta.conf b/etc/scripts/lighttpd/zeta.conf deleted file mode 100644 index 9be055206..000000000 --- a/etc/scripts/lighttpd/zeta.conf +++ /dev/null @@ -1,81 +0,0 @@ -server.modules = ( - "mod_access", - "mod_alias", - "mod_proxy", - "mod_openssl", - "mod_compress", - "mod_redirect", -) - -server.document-root = "/var/www" -server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) -server.errorlog = "/var/log/lighttpd/error.log" -server.pid-file = "/var/run/lighttpd.pid" -server.username = "www-data" -server.groupname = "www-data" -server.port = 80 - -index-file.names = ( "index.php", "index.html", "index.shtml", "index.lighttpd.html" ) -url.access-deny = ( "~", ".inc" ) -static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" ) - -compress.cache-dir = "/var/cache/lighttpd/compress/" -compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" ) - -# default listening port for IPv6 falls back to the IPv4 port -include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port -include_shell "/usr/share/lighttpd/create-mime.conf.pl" -#include_shell "/usr/share/lighttpd/include-conf-enabled.pl" -#include_shell "/usr/share/lighttpd/create-mime.assign.pl" - -# redirect -$HTTP["host"] =~ "^www\.(.*)$" { - url.redirect = ( - "^/(.*)" => "http://%1/$1", - ) -} - -# --------------------------------- -# *.zetaseek.com -# --------------------------------- -$HTTP["host"] =~ "[subdomain].zetaseek.com$" { - $SERVER["socket"] == ":443" { - ssl.engine = "enable" - ssl.pemfile = "/home/[user]/.dmt-here/https/zetaseek.com/web.pem" # Combined Certificate - # ssl.ca-file = "/home/[user]/.dmt/user/https/zetaseek.com/chain.pem" # Root CA (probably not needed, included in the former!) - server.name = "zetaseek.com" # Domain Name OR Virtual Host Name - server.document-root = "/home/[user]/.dmt/apps/dmt-search/gui" # Document Root - #server.errorlog = "/var/log/lighttpd/web.itzgeek.com_error.log" - #accesslog.filename = "/var/log/lighttpd/web.itzgeek.com_access.log" - } - - $HTTP["scheme"] == "http" { - $HTTP["host"] =~ ".*" { - url.redirect = (".*" => "https://%0$0") - } - } - - $HTTP["url"] =~ "^/ws" { - proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "7780" ) ) ) - proxy.header = ( "upgrade" => "enable" ) - } - - $HTTP["url"] =~ "^/file" { - proxy.server = ( "" => ( - ( "host" => "127.0.0.1", "port" => 7777 ) - ) ) - } - - $HTTP["url"] =~ "^/swarm" { - proxy.header = ("map-urlpath" => ( "/swarm" => "" )) - proxy.server = ( "" => ( - ( "host" => "127.0.0.1", "port" => 8888 ) - ) ) - } - - # only used on zetaseek.com device to serve peers.txt -- NOT ANYMORE! - # alias.url = ( "/public" => "/home/[user]/.dmt/user/devices/zeta/public" ) - - # not actually used when not https - server.document-root = "/home/[user]/.dmt/apps/dmt-search" -} diff --git a/etc/scripts/prepare_apps_and_user_engine/prepare_apps b/etc/scripts/prepare_apps_and_user_engine/prepare_apps index 6d934b611..338b6c732 100755 --- a/etc/scripts/prepare_apps_and_user_engine/prepare_apps +++ b/etc/scripts/prepare_apps_and_user_engine/prepare_apps @@ -11,7 +11,15 @@ function install_node_modules { if [ -f $LOCK_FILE ]; then rm $LOCK_FILE fi + npm install + + # we don't do it if bun is not yet installed + # but when it is then next dmt proc re/start will do this correctly + # if command -v bun >/dev/null 2>&1; then + # bun install + # fi + cd "$cwd" } diff --git a/help/BUN.md b/help/BUN.md new file mode 100644 index 000000000..c88d4290c --- /dev/null +++ b/help/BUN.md @@ -0,0 +1,19 @@ +## Bun is a fast JavaScript runtime, package manager, bundler, and test runner. + +**Linux** (Debian, Raspbian etc.) / **macOS** / **Windows 10 Ubuntu shell**: + +You can install [Bun](https://bun.com/) (faster and more modern node.js alternative) like this: + +``` +curl -fsSL https://bun.sh/install | bash +``` + +Then use command: + +```bash +bun +``` + +(maybe you'll need to reload the shell first) + +to check that it worked. diff --git a/help/NODEJS.md b/help/NODEJS.md index 977281808..905e378b3 100644 --- a/help/NODEJS.md +++ b/help/NODEJS.md @@ -1,19 +1,22 @@ -## node.js requirement +## Node.js **Linux** (Debian, Raspbian etc.) / **macOS** / **Windows 10 Ubuntu shell**: -`node.js >= v16.13.0` +You can install [node.js](https://bun.com/): -You can install `node.js` via [n](https://github.com/tj/n) which makes upgrading node.js easier. Install `n`: +1. ``` -curl -L https://git.io/n-install | bash +curl -fsSL https://fnm.vercel.app/install | bash ``` -Then use command: +2. Restart your terminal (or run `source ~/.bashrc`). -```bash -n +3. ``` +fnm install --lts +``` + +4. Verify: `node -v` -to manage `node.js` versions. +`v25.6.1` etc. diff --git a/help/SETUP_SERVER2.md b/help/SETUP_SERVER2.md index 5f475046d..61854a7c3 100644 --- a/help/SETUP_SERVER2.md +++ b/help/SETUP_SERVER2.md @@ -10,25 +10,15 @@ If you want to start with your local device (Personal Computer), [FOLLOW PART ON You can then continue with this guide. Any order actually works, depending on your preferences and priorities. -## Get your own fully independent public Search Node - -A `dmt-proc` instance which is publicly accessible (has public IP) is nicknamed **Zeta node**. - 🔎 Here is one example of such [Zeta node](https://zetaseek.com). There are others as well. Visit [DMT SYSTEM](https://dmt-system.com) website for some more background info. **DMT Search** is one of the main apps running on DMT SYSTEM. Zeta nodes expose this search interface by default. Installation takes around ⏱️**10 min** in optimal scenario and a few minutes more if you're doing it for the first time. -Along the way you learn the basics about **servers**. In near future the smartest people will want to run their own servers for many purposes. - -It is not that hard and we help you because we are searching for great people to learn from them as well. - -We give you software and knowledge how to set it up, you collect interesting links, decide to share some and we all benefit. - ### Prerequisites -**Get a fresh** Debian/Ubuntu linux server** (from [DigitalOcean](https://www.digitalocean.com/)?) and ⚙️ [SET IT UP](./SERVER_SETUP.md) (⏱️ **5 min**) +**Get a fresh** Debian/Ubuntu linux server (from [DigitalOcean](https://www.digitalocean.com/)?) and ⚙️ [SET IT UP](./SERVER_SETUP.md) (⏱️ **5 min**) --- @@ -43,8 +33,8 @@ ssh user@ip continue with setup: ```bash -sudo apt-get update -sudo apt-get -y install git +sudo apt update +sudo apt install -y git ``` ### Get DMT ENGINE @@ -57,22 +47,21 @@ Install (everything stays neatly inside the `~/.dmt` directory): ```bash git clone https://github.com/uniqpath/dmt.git ~/.dmt -cd ~/.dmt -./install +cd ~/.dmt && ./install source ~/.bashrc ``` (ignore the `node.js is not installed` message for now). -### Setup the search node +### Automatic setup ⏱️ **3 min** ```bash -zeta_setup +dmt_setup_server ``` -Remember to logout and login if you get this error: `zeta_setup: command not found`. +Remember to logout and login if you get this error: `setup_dmt_server: command not found`. The correct **welcome screen** indicating that the script is ready to run looks like this: @@ -86,57 +75,68 @@ The correct **welcome screen** indicating that the script is ready to run looks You should now be able to open `http://server_ip:7777/dmt-search`. -There will be nothing in your search engine though so try this next: +### Configure timezone on the server -```bash -ssh username@ip +Set it to the same zone as your local computer. -mkdir Files && cd $_ -echo "something" > my_test_file.txt +See available timezones: +```bash +timedatectl list-timezones | grep Europe ``` -And then try entering **test file** search query into the box on your new DMT SEARCH ENGINE. +Set the timezone: +```bash +sudo timedatectl set-timezone Europe/Paris +``` -You will see the test result like this: +Check that it worked: -

+
+## Project background
+
+**DMT SYSTEM** is a flexible, early adopters framework for making your life better and easier. We do this by telling computers what to do for us. Each computer runs a customized **dmt process** and executes needed tasks every second of every day so we don't have to. Our brains want Big Picture, not technical details.
+
+# SERVER SETUP (part TWO)
+
+If you want to start with your local device (Personal Computer), [FOLLOW PART ONE](./SETUP_DEVICE.md) first.
+
+You can then continue with this guide. Any order actually works, depending on your preferences and priorities.
+
+🔎 Here is one example of such [Zeta node](https://zetaseek.com). There are others as well. Visit [DMT SYSTEM](https://dmt-system.com) website for some more background info.
+
+**DMT Search** is one of the main apps running on DMT SYSTEM. Zeta nodes expose this search interface by default.
+
+Installation takes around ⏱️**10 min** in optimal scenario and a few minutes more if you're doing it for the first time.
+
+### Prerequisites
+
+**Get a fresh** Debian/Ubuntu linux server (from [DigitalOcean](https://www.digitalocean.com/)?) and ⚙️ [SET IT UP](./SERVER_SETUP.md) (⏱️ **5 min**)
+
+---
+
+### Login to your server
+
+Now login to your **⚡new remote computer⚡** with your *non-root username*:
+
+```bash
+ssh user@ip
+```
+
+ continue with setup:
+
+```bash
+sudo apt update
+sudo apt install -y git
+```
+
+### Get DMT ENGINE
+
+⏱️ **2 min**
+
+This is the 🚂 **engine** that runs our node and connects to other network nodes.
+
+Install (everything stays neatly inside the `~/.dmt` directory):
+
+```bash
+git clone https://github.com/uniqpath/dmt.git ~/.dmt
+cd ~/.dmt && ./install
+source ~/.bashrc
+```
+
+(ignore the `node.js is not installed` message for now).
+
+### Automatic setup
+
+⏱️ **3 min**
+
+```bash
+setup_dmt_server
+```
+
+Remember to logout and login if you get this error: `setup_dmt_server: command not found`.
+
+The correct **welcome screen** indicating that the script is ready to run looks like this:
+
+
+
+✨**That's it**, follow the instructions on screen 👣 🐇. A few minutes later:
+
+
