refactor: restructure project layout
- Move main process to electron/main/ - Move preload to electron/preload/ - Add shared types in electron/shared/ - Split redis-service into modular redis/ directory - Flatten renderer to src/ (remove src/renderer/ nesting) - Update electron.vite.config.ts paths - Update tsconfig paths - Output to electron-dist/
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
// src/main/redis/connection.ts
|
||||
// Redis 连接管理
|
||||
import Redis, { RedisOptions } from 'ioredis'
|
||||
import type { ConnectionOptions } from '../../shared/types'
|
||||
|
||||
export type RedisClient = Redis
|
||||
|
||||
const clients = new Map<string, RedisClient>()
|
||||
|
||||
function buildRedisOptions(opts: ConnectionOptions): RedisOptions {
|
||||
const options: RedisOptions = {
|
||||
host: opts.host,
|
||||
port: opts.port,
|
||||
username: opts.username || undefined,
|
||||
password: opts.password || undefined,
|
||||
stringNumbers: true,
|
||||
enableReadyCheck: true,
|
||||
family: 0,
|
||||
connectTimeout: 10000,
|
||||
retryStrategy(times: number) {
|
||||
if (times > 3) return null
|
||||
return Math.min(times * 200, 1000)
|
||||
},
|
||||
maxRetriesPerRequest: 3,
|
||||
}
|
||||
|
||||
if (opts.tls) {
|
||||
options.tls = {
|
||||
rejectUnauthorized: false,
|
||||
checkServerIdentity: () => undefined,
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
export function getClient(id: string): RedisClient | undefined {
|
||||
return clients.get(id)
|
||||
}
|
||||
|
||||
export function isClientConnected(id: string): boolean {
|
||||
const client = clients.get(id)
|
||||
return client?.status === 'ready'
|
||||
}
|
||||
|
||||
export async function connect(id: string, opts: ConnectionOptions): Promise<void> {
|
||||
if (clients.has(id)) {
|
||||
await disconnect(id)
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const redis = new Redis(buildRedisOptions(opts))
|
||||
|
||||
redis.once('ready', () => {
|
||||
clients.set(id, redis)
|
||||
resolve()
|
||||
})
|
||||
|
||||
redis.once('error', (err: Error) => {
|
||||
redis.disconnect()
|
||||
reject(err)
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
if (!clients.has(id)) {
|
||||
redis.disconnect()
|
||||
reject(new Error('连接超时,请检查主机和端口'))
|
||||
}
|
||||
}, 12000)
|
||||
})
|
||||
}
|
||||
|
||||
export async function disconnect(id: string): Promise<void> {
|
||||
const client = clients.get(id)
|
||||
if (client) {
|
||||
client.disconnect()
|
||||
clients.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
export function disconnectAll(): void {
|
||||
for (const [id] of clients) {
|
||||
disconnect(id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// src/main/redis/hash.ts
|
||||
// Hash 操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function getHashFields(
|
||||
id: string, key: string, cursor: string, count: number
|
||||
): Promise<{ cursor: string; fields: [string, string][] }> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
const [nextCursor, raw] = await client.hscan(key, cursor, 'COUNT', count)
|
||||
const fields: [string, string][] = []
|
||||
for (let i = 0; i < raw.length; i += 2) {
|
||||
fields.push([raw[i], raw[i + 1]])
|
||||
}
|
||||
return { cursor: nextCursor, fields }
|
||||
}
|
||||
|
||||
export async function setHashField(
|
||||
id: string, key: string, field: string, value: string
|
||||
): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
await client.hset(key, field, value)
|
||||
}
|
||||
|
||||
export async function deleteHashField(id: string, key: string, field: string): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
await client.hdel(key, field)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// src/main/redis/index.ts
|
||||
// Redis 服务统一导出
|
||||
export * from './connection'
|
||||
export * from './keys'
|
||||
export * from './string'
|
||||
export * from './hash'
|
||||
export * from './list'
|
||||
export * from './set'
|
||||
export * from './zset'
|
||||
export * from './stream'
|
||||
export * from './server'
|
||||
@@ -0,0 +1,73 @@
|
||||
// src/main/redis/keys.ts
|
||||
// Key 操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function getKeyType(id: string, key: string): Promise<string> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.type(key)
|
||||
}
|
||||
|
||||
export async function getKeyTTL(id: string, key: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.ttl(key)
|
||||
}
|
||||
|
||||
export async function deleteKey(id: string, key: string): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
await client.del(key)
|
||||
}
|
||||
|
||||
export async function setKeyTTL(id: string, key: string, ttl: number): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
if (ttl < 0) {
|
||||
await client.persist(key)
|
||||
} else {
|
||||
await client.expire(key, ttl)
|
||||
}
|
||||
}
|
||||
|
||||
export async function renameKey(id: string, oldKey: string, newKey: string): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
await client.rename(oldKey, newKey)
|
||||
}
|
||||
|
||||
export async function existsKey(id: string, key: string): Promise<boolean> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return (await client.exists(key)) === 1
|
||||
}
|
||||
|
||||
export async function batchDelete(id: string, keys: string[]): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
if (keys.length === 0) return 0
|
||||
const pipeline = client.pipeline()
|
||||
for (const key of keys) {
|
||||
pipeline.del(key)
|
||||
}
|
||||
const results = await pipeline.exec()
|
||||
return results?.filter(([err]) => !err).length ?? 0
|
||||
}
|
||||
|
||||
export async function memoryUsage(id: string, key: string): Promise<number | null> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.memory('USAGE', key) as Promise<number | null>
|
||||
}
|
||||
|
||||
export async function scanKeys(
|
||||
id: string,
|
||||
cursor: string,
|
||||
pattern: string,
|
||||
count: number
|
||||
): Promise<{ cursor: string; keys: string[] }> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
const [nextCursor, keys] = await client.scan(cursor, 'MATCH', pattern, 'COUNT', count)
|
||||
return { cursor: nextCursor, keys }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// src/main/redis/list.ts
|
||||
// List 操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function listRange(id: string, key: string, start: number, stop: number): Promise<string[]> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.lrange(key, start, stop)
|
||||
}
|
||||
|
||||
export async function listLength(id: string, key: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.llen(key)
|
||||
}
|
||||
|
||||
export async function listPush(id: string, key: string, ...values: string[]): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.rpush(key, ...values)
|
||||
}
|
||||
|
||||
export async function listSet(id: string, key: string, index: number, value: string): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
await client.lset(key, index, value)
|
||||
}
|
||||
|
||||
export async function listRemove(id: string, key: string, count: number, value: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.lrem(key, count, value)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// src/main/redis/server.ts
|
||||
// 服务器操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function execute(id: string, command: string, args: string[]): Promise<unknown> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.call(command, ...args)
|
||||
}
|
||||
|
||||
export async function getServerInfo(id: string): Promise<string> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.info() as Promise<string>
|
||||
}
|
||||
|
||||
export async function selectDb(id: string, db: number): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
await client.select(db)
|
||||
}
|
||||
|
||||
export async function dbSize(id: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.dbsize() as Promise<number>
|
||||
}
|
||||
|
||||
export async function ping(id: string): Promise<string> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.ping()
|
||||
}
|
||||
|
||||
export async function slowLogGet(id: string, count: number): Promise<any[]> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.slowlog('GET', count) as Promise<any[]>
|
||||
}
|
||||
|
||||
export async function slowLogLen(id: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.slowlog('LEN') as Promise<number>
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// src/main/redis/set.ts
|
||||
// Set 操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function setMembers(id: string, key: string): Promise<string[]> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.smembers(key)
|
||||
}
|
||||
|
||||
export async function setSize(id: string, key: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.scard(key)
|
||||
}
|
||||
|
||||
export async function setAdd(id: string, key: string, ...members: string[]): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.sadd(key, ...members)
|
||||
}
|
||||
|
||||
export async function setRemove(id: string, key: string, ...members: string[]): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.srem(key, ...members)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// src/main/redis/stream.ts
|
||||
// Stream 操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function streamInfo(id: string, key: string): Promise<any> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.xinfo('STREAM', key)
|
||||
}
|
||||
|
||||
export async function streamRange(
|
||||
id: string, key: string, start: string, end: string, count: number
|
||||
): Promise<any[]> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.xrange(key, start, end, 'COUNT', count)
|
||||
}
|
||||
|
||||
export async function streamAdd(
|
||||
id: string, key: string, streamId: string, fieldValues: string[]
|
||||
): Promise<string | null> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.xadd(key, streamId, ...fieldValues)
|
||||
}
|
||||
|
||||
export async function streamTrim(id: string, key: string, maxLen: number): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.xtrim(key, 'MAXLEN', maxLen)
|
||||
}
|
||||
|
||||
export async function streamDel(id: string, key: string, ...ids: string[]): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.xdel(key, ...ids)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// src/main/redis/string.ts
|
||||
// String 操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function getStringValue(id: string, key: string): Promise<string | null> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.get(key)
|
||||
}
|
||||
|
||||
export async function setStringValue(id: string, key: string, value: string): Promise<void> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
await client.set(key, value)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// src/main/redis/zset.ts
|
||||
// Sorted Set 操作
|
||||
import { getClient } from './connection'
|
||||
|
||||
export async function zsetRange(id: string, key: string, start: number, stop: number, withScores: boolean): Promise<string[]> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
if (withScores) return client.zrange(key, start, stop, 'WITHSCORES')
|
||||
return client.zrange(key, start, stop)
|
||||
}
|
||||
|
||||
export async function zsetSize(id: string, key: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.zcard(key)
|
||||
}
|
||||
|
||||
export async function zsetAdd(id: string, key: string, score: number, member: string): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.zadd(key, score, member)
|
||||
}
|
||||
|
||||
export async function zsetRemove(id: string, key: string, ...members: string[]): Promise<number> {
|
||||
const client = getClient(id)
|
||||
if (!client) throw new Error(`Client ${id} not found`)
|
||||
return client.zrem(key, ...members)
|
||||
}
|
||||
Reference in New Issue
Block a user