123 lines
4.1 KiB
TypeScript
123 lines
4.1 KiB
TypeScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import { app } from 'electron'
|
|
|
|
export interface MySqlVersion {
|
|
id: string
|
|
version: string
|
|
cycle: string
|
|
url: string
|
|
status: 'available' | 'downloading' | 'installed'
|
|
progress: number
|
|
description?: string
|
|
}
|
|
|
|
export class MySqlManagerService {
|
|
private versions: MySqlVersion[] = []
|
|
private binDir: string
|
|
private catalogPath: string
|
|
|
|
constructor() {
|
|
this.binDir = path.join(app.getPath('userData'), 'bin')
|
|
this.catalogPath = path.join(app.getAppPath(), 'src/main/resources/mysql_catalog.json')
|
|
if (!fs.existsSync(this.catalogPath)) {
|
|
this.catalogPath = path.join(process.cwd(), 'src/main/resources/mysql_catalog.json')
|
|
}
|
|
this.init()
|
|
}
|
|
|
|
private async init() {
|
|
if (!fs.existsSync(this.binDir)) {
|
|
fs.mkdirSync(this.binDir, { recursive: true })
|
|
}
|
|
}
|
|
|
|
async fetchAvailableVersions(): Promise<MySqlVersion[]> {
|
|
console.log('Loading MySQL versions from local catalog:', this.catalogPath)
|
|
try {
|
|
if (!fs.existsSync(this.catalogPath)) {
|
|
console.error('MySQL Catalog not found at:', this.catalogPath)
|
|
return this.versions
|
|
}
|
|
|
|
const rawData = fs.readFileSync(this.catalogPath, 'utf8')
|
|
const catalog = JSON.parse(rawData)
|
|
const releases = catalog.mysql_release_catalog.releases as any[]
|
|
|
|
const dynamicVersions: MySqlVersion[] = releases.map(v => {
|
|
const version = v.version
|
|
const cycle = v.series
|
|
|
|
// Extract MAJOR.MINOR (e.g. 8.0 from 8.0.40)
|
|
const versionParts = version.split('.')
|
|
const majorMinor = `${versionParts[0]}.${versionParts[1]}`
|
|
|
|
// Working CDN Pattern: https://cdn.mysql.com/archives/mysql-MAJOR.MINOR/mysql-VERSION-winx64.zip
|
|
const url = `https://cdn.mysql.com/archives/mysql-${majorMinor}/mysql-${version}-winx64.zip`
|
|
|
|
return {
|
|
id: `mysql-${version}`,
|
|
version,
|
|
cycle,
|
|
url,
|
|
status: 'available',
|
|
progress: 0,
|
|
description: v.status
|
|
}
|
|
})
|
|
|
|
this.updateVersionsList(dynamicVersions)
|
|
return this.versions
|
|
} catch (e: any) {
|
|
console.error('Failed to load MySQL catalog:', e.message)
|
|
return this.versions
|
|
}
|
|
}
|
|
|
|
private updateVersionsList(newList: MySqlVersion[]) {
|
|
this.versions = newList.map(dv => {
|
|
const current = this.versions.find(cv => cv.id === dv.id)
|
|
if (current && current.status === 'downloading') return current
|
|
return dv
|
|
}).sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true, sensitivity: 'base' }))
|
|
|
|
this.refreshInstalledStatus()
|
|
}
|
|
|
|
private refreshInstalledStatus() {
|
|
this.versions = this.versions.map(v => {
|
|
const targetDir = path.join(this.binDir, v.id)
|
|
const possiblePaths = [
|
|
path.join(targetDir, 'bin', 'mysqld.exe'),
|
|
path.join(targetDir, `mysql-${v.version}-winx64`, 'bin', 'mysqld.exe')
|
|
]
|
|
|
|
const isInstalled = possiblePaths.some(p => fs.existsSync(p))
|
|
|
|
if (isInstalled) {
|
|
return { ...v, status: 'installed', progress: 100 }
|
|
}
|
|
return v
|
|
})
|
|
}
|
|
|
|
async getVersions(): Promise<MySqlVersion[]> {
|
|
if (this.versions.length === 0) {
|
|
await this.fetchAvailableVersions()
|
|
} else {
|
|
this.refreshInstalledStatus()
|
|
}
|
|
return this.versions
|
|
}
|
|
|
|
updateProgress(id: string, progress: number, status: MySqlVersion['status'] = 'downloading') {
|
|
const version = this.versions.find(v => v.id === id)
|
|
if (version) {
|
|
version.progress = progress
|
|
version.status = status
|
|
}
|
|
}
|
|
}
|
|
|
|
export const mySqlManagerService = new MySqlManagerService()
|