mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-09 17:06:15 +00:00
feat: Add version check before updates to enhance update process and prevent unnecessary restarts
This commit is contained in:
@@ -200,6 +200,64 @@ async function extractZip(zipPath, destDir) {
|
||||
// MAIN UPDATE LOGIC
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Check if update is available by comparing versions
|
||||
*/
|
||||
async function checkVersion() {
|
||||
try {
|
||||
// Read local version
|
||||
const localPkgPath = join(process.cwd(), 'package.json')
|
||||
if (!existsSync(localPkgPath)) {
|
||||
console.log('⚠️ Could not find local package.json')
|
||||
return { updateAvailable: false, localVersion: 'unknown', remoteVersion: 'unknown' }
|
||||
}
|
||||
|
||||
const localPkg = JSON.parse(readFileSync(localPkgPath, 'utf8'))
|
||||
const localVersion = localPkg.version
|
||||
|
||||
// Fetch remote version from GitHub
|
||||
const repoOwner = 'Obsidian-wtf'
|
||||
const repoName = 'Microsoft-Rewards-Bot'
|
||||
const branch = 'main'
|
||||
const pkgUrl = `https://raw.githubusercontent.com/${repoOwner}/${repoName}/refs/heads/${branch}/package.json`
|
||||
|
||||
console.log('🔍 Checking for updates...')
|
||||
console.log(` Local version: ${localVersion}`)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
httpsGet(pkgUrl, (res) => {
|
||||
if (res.statusCode !== 200) {
|
||||
console.log(` ⚠️ Could not check remote version (HTTP ${res.statusCode})`)
|
||||
resolve({ updateAvailable: false, localVersion, remoteVersion: 'unknown' })
|
||||
return
|
||||
}
|
||||
|
||||
let data = ''
|
||||
res.on('data', chunk => data += chunk)
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const remotePkg = JSON.parse(data)
|
||||
const remoteVersion = remotePkg.version
|
||||
console.log(` Remote version: ${remoteVersion}`)
|
||||
|
||||
const updateAvailable = localVersion !== remoteVersion
|
||||
resolve({ updateAvailable, localVersion, remoteVersion })
|
||||
} catch (err) {
|
||||
console.log(` ⚠️ Could not parse remote package.json: ${err.message}`)
|
||||
resolve({ updateAvailable: false, localVersion, remoteVersion: 'unknown' })
|
||||
}
|
||||
})
|
||||
}).on('error', (err) => {
|
||||
console.log(` ⚠️ Network error: ${err.message}`)
|
||||
resolve({ updateAvailable: false, localVersion, remoteVersion: 'unknown' })
|
||||
})
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(`⚠️ Version check failed: ${err.message}`)
|
||||
return { updateAvailable: false, localVersion: 'unknown', remoteVersion: 'unknown' }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform update using GitHub API (ZIP download)
|
||||
*/
|
||||
@@ -208,6 +266,20 @@ async function performUpdate() {
|
||||
console.log('🚀 Microsoft Rewards Bot - Automatic Update')
|
||||
console.log('='.repeat(70))
|
||||
|
||||
// Step 0: Check if update is needed by comparing versions
|
||||
const versionCheck = await checkVersion()
|
||||
|
||||
if (!versionCheck.updateAvailable) {
|
||||
console.log('\n✅ Already up to date!')
|
||||
console.log(` Current version: ${versionCheck.localVersion}`)
|
||||
console.log('='.repeat(70) + '\n')
|
||||
return 0 // Exit without creating update marker
|
||||
}
|
||||
|
||||
console.log('\n📥 New version available!')
|
||||
console.log(` ${versionCheck.localVersion} → ${versionCheck.remoteVersion}`)
|
||||
console.log(' Starting update process...\n')
|
||||
|
||||
// Step 1: Read user preferences
|
||||
console.log('\n📋 Reading configuration...')
|
||||
const configData = readJsonConfig([
|
||||
@@ -324,7 +396,6 @@ async function performUpdate() {
|
||||
'LICENSE'
|
||||
]
|
||||
|
||||
let updatedCount = 0
|
||||
for (const item of itemsToUpdate) {
|
||||
const srcPath = join(sourceDir, item)
|
||||
const destPath = join(process.cwd(), item)
|
||||
@@ -350,7 +421,6 @@ async function performUpdate() {
|
||||
cpSync(srcPath, destPath)
|
||||
console.log(` ✓ ${item}`)
|
||||
}
|
||||
updatedCount++
|
||||
} catch (err) {
|
||||
console.log(` ⚠️ Failed to update ${item}: ${err.message}`)
|
||||
}
|
||||
@@ -387,24 +457,18 @@ async function performUpdate() {
|
||||
rmSync(backupDir, { recursive: true, force: true })
|
||||
console.log(' ✓ Temporary files removed')
|
||||
|
||||
// Step 9: Check if anything was actually updated
|
||||
if (updatedCount === 0) {
|
||||
console.log('\n✅ Already up to date!')
|
||||
console.log('='.repeat(70) + '\n')
|
||||
// No update marker - bot won't restart
|
||||
return 0
|
||||
}
|
||||
|
||||
// Step 10: Create update marker for bot restart detection
|
||||
// Step 9: Create update marker for bot restart detection
|
||||
// Version check already confirmed update is needed, so we always create marker here
|
||||
const updateMarkerPath = join(process.cwd(), '.update-happened')
|
||||
writeFileSync(updateMarkerPath, JSON.stringify({
|
||||
timestamp: new Date().toISOString(),
|
||||
filesUpdated: updatedCount,
|
||||
fromVersion: versionCheck.localVersion,
|
||||
toVersion: versionCheck.remoteVersion,
|
||||
method: 'github-api'
|
||||
}, null, 2))
|
||||
console.log(' ✓ Update marker created')
|
||||
|
||||
// Step 11: Install dependencies & rebuild
|
||||
// Step 10: Install dependencies & rebuild
|
||||
const hasNpm = await which('npm')
|
||||
if (!hasNpm) {
|
||||
console.log('\n⚠️ npm not found, skipping dependencies and build')
|
||||
|
||||
106
src/index.ts
106
src/index.ts
@@ -946,79 +946,49 @@ async function main(): Promise<void> {
|
||||
const bootstrap = async () => {
|
||||
try {
|
||||
// Check for updates BEFORE initializing and running tasks
|
||||
// Anti-loop protection: Track restart attempts
|
||||
const restartCounterPath = path.join(process.cwd(), '.update-restart-count')
|
||||
let restartCount = 0
|
||||
if (fs.existsSync(restartCounterPath)) {
|
||||
try {
|
||||
const content = fs.readFileSync(restartCounterPath, 'utf8')
|
||||
restartCount = parseInt(content, 10) || 0
|
||||
} catch {
|
||||
restartCount = 0
|
||||
}
|
||||
}
|
||||
const updateMarkerPath = path.join(process.cwd(), '.update-happened')
|
||||
|
||||
// If we've restarted too many times (3+), something is wrong - skip update
|
||||
if (restartCount >= 3) {
|
||||
log('main', 'UPDATE', '⚠️ Too many restart attempts detected - skipping update to prevent loop', 'warn')
|
||||
// Clean up counter file
|
||||
try {
|
||||
fs.unlinkSync(restartCounterPath)
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const updateResult = await rewardsBot.runAutoUpdate().catch((e) => {
|
||||
log('main', 'UPDATE', `Auto-update check failed: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||
return -1
|
||||
})
|
||||
try {
|
||||
const updateResult = await rewardsBot.runAutoUpdate().catch((e) => {
|
||||
log('main', 'UPDATE', `Auto-update check failed: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||
return -1
|
||||
})
|
||||
|
||||
if (updateResult === 0) {
|
||||
// Check if update marker exists (created by update.mjs when version changed)
|
||||
const updateHappened = fs.existsSync(updateMarkerPath)
|
||||
|
||||
if (updateResult === 0) {
|
||||
const updateMarkerPath = path.join(process.cwd(), '.update-happened')
|
||||
const updateHappened = fs.existsSync(updateMarkerPath)
|
||||
|
||||
if (updateHappened) {
|
||||
// Remove marker file
|
||||
try {
|
||||
fs.unlinkSync(updateMarkerPath)
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
|
||||
// Increment restart counter
|
||||
restartCount++
|
||||
try {
|
||||
fs.writeFileSync(restartCounterPath, String(restartCount))
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
log('main', 'UPDATE', `✅ Update successful - restarting with new version (attempt ${restartCount}/3)...`, 'log', 'green')
|
||||
|
||||
// Restart the process with the same arguments
|
||||
const { spawn } = await import('child_process')
|
||||
const child = spawn(process.execPath, process.argv.slice(1), {
|
||||
detached: true,
|
||||
stdio: 'inherit'
|
||||
})
|
||||
child.unref()
|
||||
process.exit(0)
|
||||
} else {
|
||||
log('main', 'UPDATE', 'Already up to date, continuing with bot execution')
|
||||
// Clean restart counter on successful non-update run
|
||||
try {
|
||||
if (fs.existsSync(restartCounterPath)) {
|
||||
fs.unlinkSync(restartCounterPath)
|
||||
}
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
if (updateHappened) {
|
||||
// Read marker for logging
|
||||
try {
|
||||
const markerContent = fs.readFileSync(updateMarkerPath, 'utf8')
|
||||
const markerData = JSON.parse(markerContent)
|
||||
log('main', 'UPDATE', `✅ Updated ${markerData.fromVersion} → ${markerData.toVersion} - restarting...`, 'log', 'green')
|
||||
} catch {
|
||||
log('main', 'UPDATE', '✅ Update successful - restarting...', 'log', 'green')
|
||||
}
|
||||
|
||||
// Remove marker file
|
||||
try {
|
||||
fs.unlinkSync(updateMarkerPath)
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
|
||||
// Restart the process with the same arguments
|
||||
const { spawn } = await import('child_process')
|
||||
const child = spawn(process.execPath, process.argv.slice(1), {
|
||||
detached: true,
|
||||
stdio: 'inherit'
|
||||
})
|
||||
child.unref()
|
||||
process.exit(0)
|
||||
} else {
|
||||
log('main', 'UPDATE', 'Already up to date, continuing with bot execution')
|
||||
}
|
||||
} catch (updateError) {
|
||||
log('main', 'UPDATE', `Update check failed (continuing): ${updateError instanceof Error ? updateError.message : String(updateError)}`, 'warn')
|
||||
}
|
||||
} catch (updateError) {
|
||||
log('main', 'UPDATE', `Update check failed (continuing): ${updateError instanceof Error ? updateError.message : String(updateError)}`, 'warn')
|
||||
}
|
||||
|
||||
await rewardsBot.initialize()
|
||||
|
||||
Reference in New Issue
Block a user