Files
multiphp/src/main/services/MySqlManagerService.ts
T

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()