import { defineStore } from 'pinia' import { request } from './socket.service' import { useCommonStore } from './common.store' import { useRedisStateStore } from './redis-state.store' import { useSettingsStore } from './settings.store' import { useI18nStore } from './i18n.store' import { useOverlayStore } from './overlay.store' import { navigateTo } from './navigation.store' import { parseRedisInfo } from './redis-parser' // --- Event bus for component communication --- type Callback = (...args: any[]) => void type VoidCallback = () => void const cmdListeners: Record> = {} export function onCommandEvent(event: string, cb: Callback): VoidCallback { if (!cmdListeners[event]) cmdListeners[event] = new Set() cmdListeners[event].add(cb) return () => { cmdListeners[event].delete(cb) } } export function emitCommand(event: string, data?: any) { cmdListeners[event]?.forEach(cb => cb(data)) } let lastRefreshAt = 0 export const useMainCommandStore = defineStore('mainCommand', () => { async function connect(conn: any) { const cloned = JSON.parse(JSON.stringify(conn)) const settings = useSettingsStore() const overlay = useOverlayStore() const common = useCommonStore() try { const dbStorageKey = settings.getStorageKeyCurrentDatabase(cloned.id) let db: string | undefined try { db = localStorage.getItem(dbStorageKey) ?? undefined } catch {} if (cloned.askAuth === true) { try { const a = await common.askAuth() cloned.username = a.username || undefined cloned.password = a.password || undefined } catch { return } } const i18n = useI18nStore() overlay.show({ message: i18n.strings?.title?.connectingRedis }) useRedisStateStore().connectionState = 'connecting' const response = await request({ action: 'connection/connect', payload: { connection: cloned, db }, }) const redisState = useRedisStateStore() const databaseIndexes: number[] = [] let idx = 0 while (idx < response.databases) databaseIndexes.push(idx++) const commands: string[] = [] Object.keys(response.commands ?? {}).forEach(k => commands.push(response.commands[k][0])) commands.sort() const modules = Array.isArray(response.modules) ? response.modules : [] redisState.page = 1 redisState.monitor = false redisState.dbsize = response.dbsize redisState.databaseIndexes = databaseIndexes redisState.connection = cloned redisState.commands = commands redisState.commandsMeta = response.commandsMeta ?? {} redisState.modules = modules redisState.hasReJSON = modules.some((m: any) => m.name === 'ReJSON') redisState.hasRediSearch = modules.some((m: any) => m.name === 'search') redisState.hasTimeSeries = modules.some((m: any) => m.name === 'timeseries' || m.name === 'Timeseries') redisState.hasBloom = modules.some((m: any) => m.name === 'bf') common.loadRedisInfoResponse({ response }) try { localStorage.setItem(settings.connectInfoStorageKey, JSON.stringify(cloned)) } catch {} useRedisStateStore().connectionState = 'connected' } catch (error) { const settings = useSettingsStore() try { localStorage.removeItem(settings.connectInfoStorageKey) } catch {} const rs = useRedisStateStore() rs.connection = undefined rs.connectionState = 'none' common.generalHandleError(error) } finally { overlay.hide() } } async function selectDatabase(dbIndex: number) { const redisState = useRedisStateStore() const settings = useSettingsStore() redisState.currentDatabase = dbIndex redisState.page = 1 redisState.redisChanged = true try { await request({ action: 'redis/console', payload: { command: `select ${dbIndex}` } }) const i18n = useI18nStore() const s = i18n.strings const fn = s?.status?.dbChanged const msg = typeof fn === 'function' ? fn({ db: dbIndex }) : '' const common = useCommonStore() if (msg) common.toast(msg) // Persist const storageKey = settings.getStorageKeyCurrentDatabase(redisState.connection?.id) if (storageKey) try { localStorage.setItem(storageKey, String(dbIndex)) } catch {} await refresh({ force: true }) } catch (e) { useCommonStore().generalHandleError(e) } } async function save() { try { const response = await request({ action: 'redis/save' }) const info = parseRedisInfo(response.info) const redisState = useRedisStateStore() redisState.info = info const i18n = useI18nStore() const s = i18n.strings useCommonStore().toast(s?.status?.savedRedis) } catch (e) { useCommonStore().generalHandleError(e) } } async function statistics() { try { navigateTo('database.statistics') await refresh({ force: true }) } catch (e) { useCommonStore().generalHandleError(e) } } async function refresh(options: { withoutParent?: boolean; force?: boolean } = {}) { const now = Date.now() if (!options.force && now - lastRefreshAt < 2000) return lastRefreshAt = now try { const redisState = useRedisStateStore() const settings = useSettingsStore() const payload: any = {} const searchValue = redisState.search if (!settings.searchClientSide && typeof searchValue === 'string' && searchValue.length > 0) { payload.match = settings.searchStartsWith ? searchValue + '*' : '*' + searchValue + '*' } const response = await request({ action: 'redis/refresh', payload }) redisState.dbsize = response.dbsize redisState.redisChanged = true useCommonStore().loadRedisInfoResponse({ response }) emitCommand('tree-refresh') if (!options.withoutParent) emitCommand('refresh-key') } catch (e) { useCommonStore().generalHandleError(e) } } async function disconnect() { const redisState = useRedisStateStore() const settings = useSettingsStore() try { localStorage.removeItem(settings.connectInfoStorageKey) } catch {} redisState.connection = undefined redisState.connectionState = 'none' redisState.redisConnections = {} redisState.monitor = false try { await request({ action: 'connection/disconnect', payload: { connectionId: redisState.connection?.id }, }) } catch {} navigateTo('settings') } function addKey(options: { event: Event; node?: any }) { options.event.stopPropagation() emitCommand('key-new', options) } function getCurrentDatabase(): number { const redisState = useRedisStateStore() const settings = useSettingsStore() let db: any = redisState.currentDatabase if (db === undefined) { const storageKey = settings.getStorageKeyCurrentDatabase(redisState.connection?.id) if (storageKey) try { db = localStorage.getItem(storageKey) } catch {} } return Number(db ?? 0) } function setCurrentDatabase(value: number) { const redisState = useRedisStateStore() const settings = useSettingsStore() redisState.currentDatabase = value const storageKey = settings.getStorageKeyCurrentDatabase(redisState.connection?.id) if (storageKey) try { localStorage.setItem(storageKey, String(value)) } catch {} } return { connect, selectDatabase, save, statistics, refresh, disconnect, addKey, getCurrentDatabase, setCurrentDatabase, } })