mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-10 01:06:17 +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
|
// 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)
|
* Perform update using GitHub API (ZIP download)
|
||||||
*/
|
*/
|
||||||
@@ -208,6 +266,20 @@ async function performUpdate() {
|
|||||||
console.log('🚀 Microsoft Rewards Bot - Automatic Update')
|
console.log('🚀 Microsoft Rewards Bot - Automatic Update')
|
||||||
console.log('='.repeat(70))
|
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
|
// Step 1: Read user preferences
|
||||||
console.log('\n📋 Reading configuration...')
|
console.log('\n📋 Reading configuration...')
|
||||||
const configData = readJsonConfig([
|
const configData = readJsonConfig([
|
||||||
@@ -324,7 +396,6 @@ async function performUpdate() {
|
|||||||
'LICENSE'
|
'LICENSE'
|
||||||
]
|
]
|
||||||
|
|
||||||
let updatedCount = 0
|
|
||||||
for (const item of itemsToUpdate) {
|
for (const item of itemsToUpdate) {
|
||||||
const srcPath = join(sourceDir, item)
|
const srcPath = join(sourceDir, item)
|
||||||
const destPath = join(process.cwd(), item)
|
const destPath = join(process.cwd(), item)
|
||||||
@@ -350,7 +421,6 @@ async function performUpdate() {
|
|||||||
cpSync(srcPath, destPath)
|
cpSync(srcPath, destPath)
|
||||||
console.log(` ✓ ${item}`)
|
console.log(` ✓ ${item}`)
|
||||||
}
|
}
|
||||||
updatedCount++
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(` ⚠️ Failed to update ${item}: ${err.message}`)
|
console.log(` ⚠️ Failed to update ${item}: ${err.message}`)
|
||||||
}
|
}
|
||||||
@@ -387,24 +457,18 @@ async function performUpdate() {
|
|||||||
rmSync(backupDir, { recursive: true, force: true })
|
rmSync(backupDir, { recursive: true, force: true })
|
||||||
console.log(' ✓ Temporary files removed')
|
console.log(' ✓ Temporary files removed')
|
||||||
|
|
||||||
// Step 9: Check if anything was actually updated
|
// Step 9: Create update marker for bot restart detection
|
||||||
if (updatedCount === 0) {
|
// Version check already confirmed update is needed, so we always create marker here
|
||||||
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
|
|
||||||
const updateMarkerPath = join(process.cwd(), '.update-happened')
|
const updateMarkerPath = join(process.cwd(), '.update-happened')
|
||||||
writeFileSync(updateMarkerPath, JSON.stringify({
|
writeFileSync(updateMarkerPath, JSON.stringify({
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
filesUpdated: updatedCount,
|
fromVersion: versionCheck.localVersion,
|
||||||
|
toVersion: versionCheck.remoteVersion,
|
||||||
method: 'github-api'
|
method: 'github-api'
|
||||||
}, null, 2))
|
}, null, 2))
|
||||||
console.log(' ✓ Update marker created')
|
console.log(' ✓ Update marker created')
|
||||||
|
|
||||||
// Step 11: Install dependencies & rebuild
|
// Step 10: Install dependencies & rebuild
|
||||||
const hasNpm = await which('npm')
|
const hasNpm = await which('npm')
|
||||||
if (!hasNpm) {
|
if (!hasNpm) {
|
||||||
console.log('\n⚠️ npm not found, skipping dependencies and build')
|
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 () => {
|
const bootstrap = async () => {
|
||||||
try {
|
try {
|
||||||
// Check for updates BEFORE initializing and running tasks
|
// Check for updates BEFORE initializing and running tasks
|
||||||
// Anti-loop protection: Track restart attempts
|
const updateMarkerPath = path.join(process.cwd(), '.update-happened')
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we've restarted too many times (3+), something is wrong - skip update
|
try {
|
||||||
if (restartCount >= 3) {
|
const updateResult = await rewardsBot.runAutoUpdate().catch((e) => {
|
||||||
log('main', 'UPDATE', '⚠️ Too many restart attempts detected - skipping update to prevent loop', 'warn')
|
log('main', 'UPDATE', `Auto-update check failed: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
// Clean up counter file
|
return -1
|
||||||
try {
|
})
|
||||||
fs.unlinkSync(restartCounterPath)
|
|
||||||
} catch {
|
if (updateResult === 0) {
|
||||||
// Ignore
|
// Check if update marker exists (created by update.mjs when version changed)
|
||||||
}
|
const updateHappened = fs.existsSync(updateMarkerPath)
|
||||||
} 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
|
|
||||||
})
|
|
||||||
|
|
||||||
if (updateResult === 0) {
|
if (updateHappened) {
|
||||||
const updateMarkerPath = path.join(process.cwd(), '.update-happened')
|
// Read marker for logging
|
||||||
const updateHappened = fs.existsSync(updateMarkerPath)
|
try {
|
||||||
|
const markerContent = fs.readFileSync(updateMarkerPath, 'utf8')
|
||||||
if (updateHappened) {
|
const markerData = JSON.parse(markerContent)
|
||||||
// Remove marker file
|
log('main', 'UPDATE', `✅ Updated ${markerData.fromVersion} → ${markerData.toVersion} - restarting...`, 'log', 'green')
|
||||||
try {
|
} catch {
|
||||||
fs.unlinkSync(updateMarkerPath)
|
log('main', 'UPDATE', '✅ Update successful - restarting...', 'log', 'green')
|
||||||
} 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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()
|
await rewardsBot.initialize()
|
||||||
|
|||||||
Reference in New Issue
Block a user