mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-10 17:26:17 +00:00
feat: Add Docker environment detection and update mode configuration; enhance update process for Docker and host systems
This commit is contained in:
@@ -196,6 +196,69 @@ async function extractZip(zipPath, destDir) {
|
|||||||
throw new Error('No extraction tool found (unzip, tar, or PowerShell required)')
|
throw new Error('No extraction tool found (unzip, tar, or PowerShell required)')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// ENVIRONMENT DETECTION
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if running inside a Docker container
|
||||||
|
* Checks multiple indicators for accuracy
|
||||||
|
*/
|
||||||
|
function isDocker() {
|
||||||
|
try {
|
||||||
|
// Method 1: Check for /.dockerenv file (most reliable)
|
||||||
|
if (existsSync('/.dockerenv')) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method 2: Check /proc/1/cgroup for docker
|
||||||
|
if (existsSync('/proc/1/cgroup')) {
|
||||||
|
const cgroupContent = readFileSync('/proc/1/cgroup', 'utf8')
|
||||||
|
if (cgroupContent.includes('docker') || cgroupContent.includes('/kubepods/')) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method 3: Check environment variables
|
||||||
|
if (process.env.DOCKER === 'true' ||
|
||||||
|
process.env.CONTAINER === 'docker' ||
|
||||||
|
process.env.KUBERNETES_SERVICE_HOST) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method 4: Check /proc/self/mountinfo for overlay filesystem
|
||||||
|
if (existsSync('/proc/self/mountinfo')) {
|
||||||
|
const mountinfo = readFileSync('/proc/self/mountinfo', 'utf8')
|
||||||
|
if (mountinfo.includes('docker') || mountinfo.includes('overlay')) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
} catch {
|
||||||
|
// If any error occurs (e.g., on Windows), assume not Docker
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine update mode based on config and environment
|
||||||
|
*/
|
||||||
|
function getUpdateMode(configData) {
|
||||||
|
const dockerMode = configData?.update?.dockerMode || 'auto'
|
||||||
|
|
||||||
|
if (dockerMode === 'force-docker') {
|
||||||
|
return 'docker'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dockerMode === 'force-host') {
|
||||||
|
return 'host'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-detect
|
||||||
|
return isDocker() ? 'docker' : 'host'
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// MAIN UPDATE LOGIC
|
// MAIN UPDATE LOGIC
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -281,10 +344,7 @@ async function performUpdate() {
|
|||||||
return 0 // Exit without creating update marker
|
return 0 // Exit without creating update marker
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`\n📦 Update available: ${versionCheck.localVersion} → ${versionCheck.remoteVersion}`)
|
// Step 0.5: Detect environment and determine update mode
|
||||||
console.log('⏳ Updating... (this may take a moment)\n')
|
|
||||||
|
|
||||||
// Step 1: Read user preferences (silent)
|
|
||||||
const configData = readJsonConfig([
|
const configData = readJsonConfig([
|
||||||
'src/config.jsonc',
|
'src/config.jsonc',
|
||||||
'config.jsonc',
|
'config.jsonc',
|
||||||
@@ -292,6 +352,14 @@ async function performUpdate() {
|
|||||||
'config.json'
|
'config.json'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const updateMode = getUpdateMode(configData)
|
||||||
|
const envIcon = updateMode === 'docker' ? '🐳' : '💻'
|
||||||
|
|
||||||
|
console.log(`\n📦 Update available: ${versionCheck.localVersion} → ${versionCheck.remoteVersion}`)
|
||||||
|
console.log(`${envIcon} Environment: ${updateMode === 'docker' ? 'Docker container' : 'Host system'}`)
|
||||||
|
console.log('⏳ Updating... (this may take a moment)\n')
|
||||||
|
|
||||||
|
// Step 1: Read user preferences (silent)
|
||||||
const userConfig = {
|
const userConfig = {
|
||||||
autoUpdateConfig: configData?.update?.autoUpdateConfig ?? false,
|
autoUpdateConfig: configData?.update?.autoUpdateConfig ?? false,
|
||||||
autoUpdateAccounts: configData?.update?.autoUpdateAccounts ?? false
|
autoUpdateAccounts: configData?.update?.autoUpdateAccounts ?? false
|
||||||
@@ -570,9 +638,19 @@ async function performUpdate() {
|
|||||||
rmSync(rollbackDir, { recursive: true, force: true })
|
rmSync(rollbackDir, { recursive: true, force: true })
|
||||||
|
|
||||||
console.log(`\n✅ Updated successfully! (${versionCheck.localVersion} → ${versionCheck.remoteVersion})`)
|
console.log(`\n✅ Updated successfully! (${versionCheck.localVersion} → ${versionCheck.remoteVersion})`)
|
||||||
console.log('🔄 Restarting...\n')
|
|
||||||
|
|
||||||
|
// Different behavior for Docker vs Host
|
||||||
|
if (updateMode === 'docker') {
|
||||||
|
console.log('<27> Docker mode: Update complete')
|
||||||
|
console.log(' Container will restart automatically if configured\n')
|
||||||
|
// In Docker, don't restart - let orchestrator handle it
|
||||||
|
// Just exit cleanly so Docker can restart the container
|
||||||
return 0
|
return 0
|
||||||
|
} else {
|
||||||
|
console.log('<27>🔄 Restarting in same process...\n')
|
||||||
|
// In host mode, signal restart needed
|
||||||
|
return 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
@@ -170,7 +170,7 @@
|
|||||||
"update": {
|
"update": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"method": "github-api",
|
"method": "github-api",
|
||||||
"docker": false,
|
"dockerMode": "auto", // "auto" = detect automatically, "force-docker" = always use Docker mode, "force-host" = never use Docker mode
|
||||||
"scriptPath": "setup/update/update.mjs",
|
"scriptPath": "setup/update/update.mjs",
|
||||||
"autoUpdateConfig": true,
|
"autoUpdateConfig": true,
|
||||||
"autoUpdateAccounts": false
|
"autoUpdateAccounts": false
|
||||||
|
|||||||
35
src/index.ts
35
src/index.ts
@@ -943,10 +943,38 @@ async function main(): Promise<void> {
|
|||||||
process.exit(code)
|
process.exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if running in Docker container
|
||||||
|
*/
|
||||||
|
const isDockerEnvironment = (): boolean => {
|
||||||
|
try {
|
||||||
|
// Check /.dockerenv file
|
||||||
|
if (fs.existsSync('/.dockerenv')) return true
|
||||||
|
|
||||||
|
// Check /proc/1/cgroup
|
||||||
|
if (fs.existsSync('/proc/1/cgroup')) {
|
||||||
|
const content = fs.readFileSync('/proc/1/cgroup', 'utf8')
|
||||||
|
if (content.includes('docker') || content.includes('/kubepods/')) return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check environment variables
|
||||||
|
if (process.env.DOCKER === 'true' ||
|
||||||
|
process.env.CONTAINER === 'docker' ||
|
||||||
|
process.env.KUBERNETES_SERVICE_HOST) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const bootstrap = async () => {
|
const bootstrap = async () => {
|
||||||
try {
|
try {
|
||||||
// Check for updates BEFORE initializing and running tasks
|
// Check for updates BEFORE initializing and running tasks
|
||||||
const updateMarkerPath = path.join(process.cwd(), '.update-happened')
|
const updateMarkerPath = path.join(process.cwd(), '.update-happened')
|
||||||
|
const isDocker = isDockerEnvironment()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const updateResult = await rewardsBot.runAutoUpdate().catch((e) => {
|
const updateResult = await rewardsBot.runAutoUpdate().catch((e) => {
|
||||||
@@ -966,6 +994,12 @@ async function main(): Promise<void> {
|
|||||||
// Ignore cleanup errors
|
// Ignore cleanup errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDocker) {
|
||||||
|
// Docker mode: exit cleanly to let container restart
|
||||||
|
log('main', 'UPDATE', 'Update complete - exiting for container restart', 'log', 'green')
|
||||||
|
process.exit(0)
|
||||||
|
} else {
|
||||||
|
// Host mode: reload in same process
|
||||||
// Clear Node's require cache to reload updated modules
|
// Clear Node's require cache to reload updated modules
|
||||||
Object.keys(require.cache).forEach(key => {
|
Object.keys(require.cache).forEach(key => {
|
||||||
// Only clear cache for project files, not node_modules
|
// Only clear cache for project files, not node_modules
|
||||||
@@ -985,6 +1019,7 @@ async function main(): Promise<void> {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (updateError) {
|
} catch (updateError) {
|
||||||
log('main', 'UPDATE', `Update check failed (continuing): ${updateError instanceof Error ? updateError.message : String(updateError)}`, 'warn')
|
log('main', 'UPDATE', `Update check failed (continuing): ${updateError instanceof Error ? updateError.message : String(updateError)}`, 'warn')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user