@ariya/berkala
Advanced tools
Comparing version 1.2.1 to 1.3.0
117
index.js
@@ -5,3 +5,2 @@ #!/usr/bin/env node | ||
const os = require('os'); | ||
const child_process = require('child_process'); | ||
@@ -12,5 +11,5 @@ const manifest = require('./package.json'); | ||
const Bree = require('bree'); | ||
const which = require('which'); | ||
const say = require('say'); | ||
const pal = require('./src/pal'); | ||
const CONFIG_FILENAME = 'berkala.yml'; | ||
@@ -40,2 +39,11 @@ | ||
sign-of-life: | ||
interval: every 30 minutes | ||
steps: | ||
- print: Pings | ||
- run: | | ||
ping -c 3 google.com | ||
ping -c 5 bing.com | ||
timeout-minutes: 2 | ||
weekend-exercise: | ||
@@ -66,3 +74,8 @@ cron: 0 9 * * 6 # every 9 morning on Saturday | ||
if (answer === 'Y' || answer === 'YES') { | ||
fs.writeFileSync(CONFIG_FILENAME, SAMPLE_CONFIG.trim(), 'utf-8'); | ||
let conf = SAMPLE_CONFIG.trim(); | ||
if (os.type() === 'Windows_NT') { | ||
// ping on Window does not support "-c" | ||
conf = conf.replace(/ping -c/gi, 'ping -n'); | ||
} | ||
fs.writeFileSync(CONFIG_FILENAME, conf, 'utf-8'); | ||
return yaml.load(SAMPLE_CONFIG); | ||
@@ -86,80 +99,2 @@ } else { | ||
/** | ||
* Escape a string for PowerShell. | ||
* @param {string} str | ||
* @return {string} | ||
*/ | ||
function psEscape(str) { | ||
let result = ''; | ||
for (let i = 0; i < str.length; i++) { | ||
const ch = str[i]; | ||
if (ch.charCodeAt(0) === 39) { | ||
// single quote, escape it with another single quote | ||
result += ch; | ||
} | ||
result += ch; | ||
} | ||
return result; | ||
} | ||
/** | ||
* Send a desktop notification | ||
* @param {string} title | ||
* @param {string} message | ||
*/ | ||
function platformNotify(title, message) { | ||
if (os.type() === 'Linux') { | ||
const resolved = which.sync('notify-send', { nothrow: true }); | ||
if (resolved) { | ||
child_process.spawnSync('notify-send', ['-a', 'Berkala', title, message]); | ||
} else { | ||
console.error('notify: unable to locate notify-send'); | ||
console.log(title + ':', message); | ||
} | ||
} else if (os.type() === 'Darwin') { | ||
const command = `display notification "${message}" with title "Berkala" subtitle "${title}"`; | ||
child_process.spawnSync('osascript', ['-e', command]); | ||
} else if (os.type() === 'Windows_NT') { | ||
const script = ` | ||
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null; | ||
$templateType = [Windows.UI.Notifications.ToastTemplateType]::ToastText02; | ||
$template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($templateType); | ||
$template.SelectSingleNode(\"//text[@id=1]\").InnerText = '${psEscape(title)}'; | ||
$template.SelectSingleNode(\"//text[@id=2]\").InnerText = '${psEscape(message)}'; | ||
$toast = [Windows.UI.Notifications.ToastNotification]::new($template); | ||
$notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('Berkala'); | ||
$notifier.Show($toast);`; | ||
child_process.execSync(script, { shell: 'powershell.exe' }); | ||
} else { | ||
// FIXME what's this system? | ||
console.log(title, message); | ||
} | ||
} | ||
/** | ||
* Convert text to audible speech | ||
* @param {string} message | ||
*/ | ||
function platformSay(message) { | ||
if (os.type() === 'Linux') { | ||
const resolved = which.sync('festival', { nothrow: true }); | ||
if (resolved) { | ||
say.speak(message); | ||
} else { | ||
console.error('say: unable to locate Festival'); | ||
platformNotify('Berkala', message); | ||
} | ||
} else if (os.type() === 'Windows_NT') { | ||
// TODO: check for Powershell first | ||
say.speak(psEscape(message)); | ||
} else if (os.type() === 'Darwin') { | ||
say.speak(message, 'Samantha'); // Siri's voice | ||
} else { | ||
// unsupported | ||
console.error('say: unsupport system', os.type()); | ||
platformNotify('Berkala', message); | ||
} | ||
} | ||
function workerMessageHandler(workerData) { | ||
@@ -173,6 +108,6 @@ const workerMsg = workerData.message; | ||
const { title, message } = workerMsg; | ||
platformNotify(title, message); | ||
pal.notify(title, message); | ||
} else if (duty === 'say') { | ||
const { message } = workerMsg; | ||
platformSay(message); | ||
pal.say(message); | ||
} | ||
@@ -186,2 +121,3 @@ } | ||
function runTask() { | ||
const child_process = require('child_process'); | ||
const { workerData, parentPort } = require('worker_threads'); | ||
@@ -201,2 +137,15 @@ | ||
parentPort.postMessage({ duty: 'say', message: step.say }); | ||
} else if (step.run) { | ||
const command = step.run; | ||
const cwd = step['working-directory'] || process.cwd(); | ||
const timeoutMinutes = step['timeout-minutes'] || 3; | ||
const timeout = 60 * 1000 * timeoutMinutes; | ||
const options = { cwd, timeout }; | ||
try { | ||
child_process.execSync(command, options); | ||
} catch (e) { | ||
const { errno, stderr } = e; | ||
const msg = stderr ? stderr.toString() : e.toString(); | ||
console.error(`run error: ${errno} ${msg}`); | ||
} | ||
} else { | ||
@@ -203,0 +152,0 @@ console.error('Unknown step', step); |
{ | ||
"name": "@ariya/berkala", | ||
"version": "1.2.1", | ||
"version": "1.3.0", | ||
"description": "Run scheduled tasks", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -34,2 +34,8 @@ # Berkala | ||
sign-of-life: | ||
interval: every 2 hours | ||
steps: | ||
- run: ping -c 7 google.com | ||
timeout-minutes: 2 | ||
weekend-exercise: | ||
@@ -53,6 +59,53 @@ cron: 0 9 * * 6 # every 9 morning on Saturday | ||
<details><summary><code>print</code>: displays a message to the standard output</summary></details> | ||
<details><summary><code>run</code>: executes a shell command</summary> | ||
Example: | ||
```yaml | ||
sign-of-life: | ||
interval: every 30 minutes | ||
steps: | ||
- run: ping -c 7 google.com | ||
``` | ||
Optionally, `timeout-minutes` can be used to limit the execution time and `working-directory` can be used to set the directory to start the execution from. | ||
Another example: | ||
```yaml | ||
sys-resource: | ||
interval: every 2 hours | ||
steps: | ||
- run: | | ||
date >> resources.log | ||
top | head -n 4 >> resources.log | ||
timeout-minutes: 3 | ||
working-directory: /var/log | ||
``` | ||
</details> | ||
<details><summary><code>print</code>: displays a message to the standard output</summary> | ||
Example: | ||
```yaml | ||
morning: | ||
interval: at 7:00am | ||
steps: | ||
- print: Good morning! | ||
``` | ||
</details> | ||
<details><summary><code>notify</code>: sends a desktop notification</summary> | ||
Optionally, `title` can be used to set the notification title. | ||
Example: | ||
```yaml | ||
mahlzeit: | ||
interval: at 11:58am | ||
steps: | ||
- notify: It's lunch time very soon | ||
title: Yummy | ||
``` | ||
The notification is supported on the following system: | ||
@@ -68,2 +121,10 @@ | ||
Example: | ||
```yaml | ||
vaya-con-dios: | ||
interval: 0 17 * * 1-5 # every workday late afternoon | ||
steps: | ||
- say: Time to go home | ||
``` | ||
The text-to-speech conversion is supported on the following system: | ||
@@ -70,0 +131,0 @@ |
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
20898
11
256
157
4
2