From 8d19129906e83239180d2c46f02a5a4a62d62ba8 Mon Sep 17 00:00:00 2001 From: mgrimace <55518507+mgrimace@users.noreply.github.com> Date: Sat, 1 Jun 2024 08:50:29 -0400 Subject: [PATCH] Docker: improved env var handling (#113) * Improve env var handling, clarify instructions updateConfig.js will update dist/config.json with any values specified in the docker compose file as environmental variables (env vars). If not specified it will use the default values in src/config.json (the 'usual' place where folks can customize their config). A user can make changes to an env var (e.g., disabling Scroll Random Results), then docker compose up -d to quickly restart the container with the change. * minor update to env vars in table Make sure to change your compose so the updated flattened values work. * TZ handling for cron runs of the script docker logs netsky should now show the proper time zone for script runs that were initiated via cron schedule. --- Dockerfile | 2 +- README.md | 39 ++++++++++++++++++++------------------- compose.yaml | 27 +++------------------------ src/crontab.template | 2 +- src/run_daily.sh | 3 +++ src/updateConfig.js | 41 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 45 deletions(-) create mode 100755 src/updateConfig.js diff --git a/Dockerfile b/Dockerfile index 10e6137..00d5f1f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,4 +37,4 @@ COPY src/crontab.template /etc/cron.d/microsoft-rewards-cron.template RUN touch /var/log/cron.log # Define the command to run your application with cron optionally -CMD sh -c 'echo "$TZ" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata && if [ "$RUN_ON_START" = "true" ]; then npm start; fi && envsubst < /etc/cron.d/microsoft-rewards-cron.template > /etc/cron.d/microsoft-rewards-cron && crontab /etc/cron.d/microsoft-rewards-cron && cron && tail -f /var/log/cron.log' \ No newline at end of file +CMD sh -c 'node src/updateConfig.js && echo "$TZ" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata && if [ "$RUN_ON_START" = "true" ]; then npm start; fi && envsubst < /etc/cron.d/microsoft-rewards-cron.template > /etc/cron.d/microsoft-rewards-cron && crontab /etc/cron.d/microsoft-rewards-cron && cron && tail -f /var/log/cron.log' diff --git a/README.md b/README.md index 7755b53..07eb5e3 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,14 @@ Under development, however mainly for personal use! - If you automate this script, set it to run at least 2 times a day to make sure it picked up all tasks, set `"runOnZeroPoints": false` so it doesn't run when no points are found. ## Docker (Experimental) ## +**Note:** If you had previously built and run the script locally, remove the `/node_modules` and `/dist` from your Microsoft-Rewards-Script folder. + 1. Download the source code -2. Make changes to your `accounts.json` -3. **Headless mode must be enabled when using Docker.** You can do this using the `HEADLESS=true` environmental variable in docker run or docker compose.yaml (see below). Environmental variables are always prioritized over the values in config.json. -4. The container will run scheduled. Customize your schedule using the `CRON_START_TIME` environmental variable. Use [crontab.guru](crontab.guru) if you're unsure how to create a cron schedule. +2. Make changes to your `accounts.json` and `config.json` +3. **Headless mode must be enabled.** You can do this in `config.json` or by using the `HEADLESS=true` environmental variable in docker run or docker compose.yaml (see below). Environmental variables are prioritized over the values in config.json. +4. The container has in-built scheduling. Customize your schedule using the `CRON_START_TIME` environmental variable. Use [crontab.guru](crontab.guru) if you're unsure how to create a cron schedule. 5. **Note:** the container will add between 5 and 50 minutes of randomized variability to your scheduled start times. + ### Option 1: build and run with docker run 1. Build or re-build the container image with: `docker build -t microsoft-rewards-script-docker .` @@ -31,14 +34,12 @@ Under development, however mainly for personal use! docker run --name netsky -d \ -e TZ=America/New_York \ -e HEADLESS=true \ - -e SEARCH_DELAY_MIN=10000 \ - -e SEARCH_DELAY_MAX=20000 \ - -e CLUSTERS=1 \ + -e RUN_ON_START=true \ -e CRON_START_TIME="0 5,11 * * *" \ microsoft-rewards-script-docker ``` - -3. Optionally, change any environmental variables other than `HEADLESS`, which must stay `=true` + +3. Optionally, customize your config by adding any other environmental variables from the table below. 4. You can view logs with `docker logs netsky`. @@ -46,9 +47,9 @@ Under development, however mainly for personal use! 1. A basic docker compose.yaml has been provided. -2. Optionally, change any environmental variables other than `HEADLESS`, which must stay `=true` +2. Optionally, customize your config by adding any other environmental variables from the table below. -3. Build or rebuild and start the container using `docker compose up -d --build` +3. Build and start the container using `docker compose up -d`. 4. You can view logs with `docker logs netsky` @@ -62,17 +63,17 @@ Under development, however mainly for personal use! | runOnZeroPoints | Run the rest of the script if 0 points can be earned | `false` (Will not run on 0 points) | RUN_ON_ZERO_POINTS | | clusters | Amount of instances ran on launch, 1 per account | `1` (Will run 1 account at the time) | CLUSTERS | | saveFingerprint | Re-use the same fingerprint each time | `false` (Will generate a new fingerprint each time) | SAVE_FINGERPRINT | -| workers.doDailySet | Complete daily set items | `true` | WORKERS_DO_DAILY_SET | -| workers.doMorePromotions | Complete promotional items | `true` | WORKERS_DO_MORE_PROMOTIONS | -| workers.doPunchCards | Complete punchcards | `true` | WORKERS_DO_PUNCH_CARDS | -| workers.doDesktopSearch | Complete daily desktop searches | `true` | WORKERS_DO_DESKTOP_SEARCH | -| workers.doMobileSearch | Complete daily mobile searches | `true` | WORKERS_DO_MOBILE_SEARCH | +| workers.doDailySet | Complete daily set items | `true` | DO_DAILY_SET | +| workers.doMorePromotions | Complete promotional items | `true` | DO_MORE_PROMOTIONS | +| workers.doPunchCards | Complete punchcards | `true` | DO_PUNCH_CARDS | +| workers.doDesktopSearch | Complete daily desktop searches | `true` | DO_DESKTOP_SEARCH | +| workers.doMobileSearch | Complete daily mobile searches | `true` | DO_MOBILE_SEARCH | | globalTimeout | The length before the action gets timeout | `30000` (30 seconds) | GLOBAL_TIMEOUT | -| searchSettings.useGeoLocaleQueries | Generate search queries based on your geo-location | `false` (Uses EN-US generated queries) | SEARCH_SETTINGS_USE_GEO_LOCALE_QUERIES | -| scrollRandomResults | Scroll randomly in search results | `true` | SEARCH_SETTINGS_SCROLL_RANDOM_RESULTS | -| searchSettings.clickRandomResults | Visit random website from search result| `true` | SEARCH_SETTINGS_CLICK_RANDOM_RESULTS | +| searchSettings.useGeoLocaleQueries | Generate search queries based on your geo-location | `false` (Uses EN-US generated queries) | USE_GEO_LOCALE_QUERIES | +| scrollRandomResults | Scroll randomly in search results | `true` | SCROLL_RANDOM_RESULTS | +| searchSettings.clickRandomResults | Visit random website from search result| `true` | CLICK_RANDOM_RESULTS | | searchSettings.searchDelay | Minimum and maximum time in miliseconds between search queries | `min: 10000` (10 seconds) `max: 20000` (20 seconds) | SEARCH_DELAY_MIN SEARCH_DELAY_MAX | -| searchSettings.retryMobileSearch | Keep retrying mobile searches until completed (indefinite)| `false` | SEARCH_SETTINGS_RETRY_MOBILE_SEARCH | +| searchSettings.retryMobileSearch | Keep retrying mobile searches until completed (indefinite)| `false` | RETRY_MOBILE_SEARCH | | webhook.enabled | Enable or disable your set webhook | `false` | WEBHOOK_ENABLED | | webhook.url | Your Discord webhook URL | `null` | WEBHOOK_URL="" | | cronStartTime | Scheduled script run-time, *only available for docker implementation* | `0 5,11 * * *` (5:00 am, 11:00 am daily) | CRON_START_TIME="" | diff --git a/compose.yaml b/compose.yaml index 4d5a00f..5484970 100644 --- a/compose.yaml +++ b/compose.yaml @@ -6,29 +6,8 @@ services: - TZ=America/Toronto #change to your local timezone - NODE_ENV=production - HEADLESS=true #do not change - ### the following are optional, you only need to include them if you want to enter a custom value, removing them will use the default values - - BASE_URL=https://rewards.bing.com - - SESSION_PATH=sessions - - RUN_ON_ZERO_POINTS=false - - CLUSTERS=1 - - SAVE_FINGERPRINT=false - - WORKERS_DO_DAILY_SET=true - - WORKERS_DO_MORE_PROMOTIONS=true - - WORKERS_DO_PUNCH_CARDS=true - - WORKERS_DO_DESKTOP_SEARCH=true - - WORKERS_DO_MOBILE_SEARCH=true - - SEARCH_SETTINGS_USE_GEO_LOCALE_QUERIES=false - - SEARCH_SETTINGS_SCROLL_RANDOM_RESULTS=true - - SEARCH_SETTINGS_CLICK_RANDOM_RESULTS=true - - SEARCH_SETTINGS_SEARCH_DELAY_MIN=10000 # Set the search delay longer, e.g. MIN=180000 and MAX=270000 if you live in a region where MS enforces a search cooldown - - SEARCH_SETTINGS_SEARCH_DELAY_MAX=20000 - - SEARCH_SETTINGS_RETRY_MOBILE_SEARCH=true - - WEBHOOK_ENABLED=false - - WEBHOOK_URL= - ### Customize your run schedule, default 5:00 am and 11:00 am, use crontab.guru if you're not sure + ### Customize your run schedule, default 5:00 am and 11:00 am, use crontab.guru for formatting - CRON_START_TIME=0 5,11 * * * - ### Run on start, set as false to only run the script per the cron schedule + ### Run on start, set to false to only run the script per the cron schedule - RUN_ON_START=true - restart: unless-stopped - volumes: - - .:/usr/src/microsoft-rewards-script + restart: unless-stopped \ No newline at end of file diff --git a/src/crontab.template b/src/crontab.template index 16de9ea..f20e8c4 100644 --- a/src/crontab.template +++ b/src/crontab.template @@ -1 +1 @@ -${CRON_START_TIME} /bin/bash /usr/src/microsoft-rewards-script/src/run_daily.sh >> /var/log/cron.log 2>&1 +${CRON_START_TIME} TZ=${TZ} /bin/bash /usr/src/microsoft-rewards-script/src/run_daily.sh >> /var/log/cron.log 2>&1 diff --git a/src/run_daily.sh b/src/run_daily.sh index 15972ed..31656fd 100644 --- a/src/run_daily.sh +++ b/src/run_daily.sh @@ -3,6 +3,9 @@ # Set up environment variables export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin +# Ensure TZ is set +export TZ=${TZ} + # Change directory to the application directory cd /usr/src/microsoft-rewards-script diff --git a/src/updateConfig.js b/src/updateConfig.js new file mode 100755 index 0000000..571866e --- /dev/null +++ b/src/updateConfig.js @@ -0,0 +1,41 @@ +const fs = require('fs'); +const path = require('path'); + +const configPath = path.join(__dirname, '../dist/config.json'); + +// Read the existing config file +const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); + +// Update the config with environment variables if they are set +config.baseURL = process.env.BASE_URL || config.baseURL; +config.sessionPath = process.env.SESSION_PATH || config.sessionPath; +config.headless = process.env.HEADLESS ? process.env.HEADLESS === 'true' : config.headless; +config.runOnZeroPoints = process.env.RUN_ON_ZERO_POINTS ? process.env.RUN_ON_ZERO_POINTS === 'true' : config.runOnZeroPoints; +config.clusters = process.env.CLUSTERS ? parseInt(process.env.CLUSTERS, 10) : config.clusters; +config.saveFingerprint = process.env.SAVE_FINGERPRINT ? process.env.SAVE_FINGERPRINT === 'true' : config.saveFingerprint; +config.globalTimeout = process.env.GLOBAL_TIMEOUT ? parseInt(process.env.GLOBAL_TIMEOUT, 10) : config.globalTimeout; + +config.workers.doDailySet = process.env.DO_DAILY_SET ? process.env.DO_DAILY_SET === 'true' : config.workers.doDailySet; +config.workers.doMorePromotions = process.env.DO_MORE_PROMOTIONS ? process.env.DO_MORE_PROMOTIONS === 'true' : config.workers.doMorePromotions; +config.workers.doPunchCards = process.env.DO_PUNCH_CARDS ? process.env.DO_PUNCH_CARDS === 'true' : config.workers.doPunchCards; +config.workers.doDesktopSearch = process.env.DO_DESKTOP_SEARCH ? process.env.DO_DESKTOP_SEARCH === 'true' : config.workers.doDesktopSearch; +config.workers.doMobileSearch = process.env.DO_MOBILE_SEARCH ? process.env.DO_MOBILE_SEARCH === 'true' : config.workers.doMobileSearch; + +config.searchSettings.useGeoLocaleQueries = process.env.USE_GEO_LOCALE_QUERIES ? process.env.USE_GEO_LOCALE_QUERIES === 'true' : config.searchSettings.useGeoLocaleQueries; +config.searchSettings.scrollRandomResults = process.env.SCROLL_RANDOM_RESULTS ? process.env.SCROLL_RANDOM_RESULTS === 'true' : config.searchSettings.scrollRandomResults; +config.searchSettings.clickRandomResults = process.env.CLICK_RANDOM_RESULTS ? process.env.CLICK_RANDOM_RESULTS === 'true' : config.searchSettings.clickRandomResults; +config.searchSettings.searchDelay.min = process.env.SEARCH_DELAY_MIN ? parseInt(process.env.SEARCH_DELAY_MIN, 10) : config.searchSettings.searchDelay.min; +config.searchSettings.searchDelay.max = process.env.SEARCH_DELAY_MAX ? parseInt(process.env.SEARCH_DELAY_MAX, 10) : config.searchSettings.searchDelay.max; +config.searchSettings.retryMobileSearch = process.env.RETRY_MOBILE_SEARCH ? process.env.RETRY_MOBILE_SEARCH === 'true' : config.searchSettings.retryMobileSearch; + +config.webhook.enabled = process.env.WEBHOOK_ENABLED ? process.env.WEBHOOK_ENABLED === 'true' : config.webhook.enabled; +config.webhook.url = process.env.WEBHOOK_URL || config.webhook.url; + +// Write the updated config back to the file +try { + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + console.log('Config file updated with environment variables'); +} catch (error) { + console.error(`Failed to write updated config file to ${configPath}:`, error); + process.exit(1); +} \ No newline at end of file