refactor: remove session expiry, add syncWithOpenCode
- Remove expireInactive and startExpiryLoop - Add syncWithOpenCode() to prune orphaned sessions - Add logging for session map file path and load count
This commit is contained in:
parent
01bf23543a
commit
7db5bc6989
|
|
@ -36,8 +36,6 @@ async function runPlugin(ctx: any, options: any, sdkClient?: any) {
|
||||||
|
|
||||||
log(`Configuration loaded`)
|
log(`Configuration loaded`)
|
||||||
|
|
||||||
const sessionRetentionMs = 30 * 60 * 1000
|
|
||||||
|
|
||||||
const matrix = new MatrixBotClient(options)
|
const matrix = new MatrixBotClient(options)
|
||||||
const sessionManager = new SessionManager(options.rateLimitSeconds || 5)
|
const sessionManager = new SessionManager(options.rateLimitSeconds || 5)
|
||||||
|
|
||||||
|
|
@ -289,10 +287,7 @@ async function runPlugin(ctx: any, options: any, sdkClient?: any) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Session expiry loop
|
// Start Matrix client
|
||||||
expiryInterval = sessionManager.startExpiryLoop(sessionRetentionMs)
|
|
||||||
|
|
||||||
// V2 Storage - defensive access
|
|
||||||
if (isV2 && ctx?.storage) {
|
if (isV2 && ctx?.storage) {
|
||||||
await ctx.storage.set("matrix/plugin_version", "1.0.0")
|
await ctx.storage.set("matrix/plugin_version", "1.0.0")
|
||||||
await ctx.storage.set("matrix/started_at", new Date().toISOString())
|
await ctx.storage.set("matrix/started_at", new Date().toISOString())
|
||||||
|
|
@ -306,7 +301,6 @@ async function runPlugin(ctx: any, options: any, sdkClient?: any) {
|
||||||
cleanup = () => {
|
cleanup = () => {
|
||||||
log("Plugin cleaning up...")
|
log("Plugin cleaning up...")
|
||||||
eventController.abort()
|
eventController.abort()
|
||||||
if (expiryInterval) clearInterval(expiryInterval)
|
|
||||||
matrix.stop()
|
matrix.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ export function encodeSessionId(matrixRoomId: string, threadRootId: string): str
|
||||||
}
|
}
|
||||||
|
|
||||||
const SESSION_MAP_FILE = path.join(process.env.HOME || "/tmp", ".opencode-matrix-sessions.json")
|
const SESSION_MAP_FILE = path.join(process.env.HOME || "/tmp", ".opencode-matrix-sessions.json")
|
||||||
|
console.log(`[SessionManager] SESSION_MAP_FILE=${SESSION_MAP_FILE}`)
|
||||||
|
|
||||||
interface SessionMapEntry {
|
interface SessionMapEntry {
|
||||||
matrixRoomId: string
|
matrixRoomId: string
|
||||||
|
|
@ -37,15 +38,18 @@ function loadSessionMap(): Map<string, SessionMapEntry> {
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(SESSION_MAP_FILE)) {
|
if (fs.existsSync(SESSION_MAP_FILE)) {
|
||||||
const data = JSON.parse(fs.readFileSync(SESSION_MAP_FILE, "utf-8"))
|
const data = JSON.parse(fs.readFileSync(SESSION_MAP_FILE, "utf-8"))
|
||||||
|
console.log(`[SessionManager] Loaded ${data.length} sessions from ${SESSION_MAP_FILE}`)
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
for (const entry of data) {
|
for (const entry of data) {
|
||||||
const key = `${entry.matrixRoomId}::${entry.threadRootId}`
|
const key = `${entry.matrixRoomId}::${entry.threadRootId}`
|
||||||
result.set(key, entry)
|
result.set(key, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`[SessionManager] File not found: ${SESSION_MAP_FILE}`)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ignore
|
console.log(`[SessionManager] Error loading: ${e}`)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
@ -166,25 +170,6 @@ export class SessionManager {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
expireInactive(maxAgeMs: number): void {
|
|
||||||
const now = Date.now()
|
|
||||||
for (const [sessionId, session] of this.sessions) {
|
|
||||||
if (now - session.lastActivity > maxAgeMs) {
|
|
||||||
const key = sessionId
|
|
||||||
this.sessions.delete(key)
|
|
||||||
this.persistentMap.delete(key)
|
|
||||||
this.activeQueries.delete(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveSessionMap(this.persistentMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
startExpiryLoop(maxAgeMs: number, intervalMs: number = 60000): NodeJS.Timeout {
|
|
||||||
return setInterval(() => {
|
|
||||||
this.expireInactive(maxAgeMs)
|
|
||||||
}, intervalMs)
|
|
||||||
}
|
|
||||||
|
|
||||||
saveSession(matrixRoomId: string, threadRootId: string, opencodeSessionId: string): void {
|
saveSession(matrixRoomId: string, threadRootId: string, opencodeSessionId: string): void {
|
||||||
const key = this.getSessionKey(matrixRoomId, threadRootId)
|
const key = this.getSessionKey(matrixRoomId, threadRootId)
|
||||||
const session = this.sessions.get(key)
|
const session = this.sessions.get(key)
|
||||||
|
|
@ -202,4 +187,21 @@ export class SessionManager {
|
||||||
saveSessionMap(this.persistentMap)
|
saveSessionMap(this.persistentMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncWithOpenCode(openCodeSessionIds: Set<string>): void {
|
||||||
|
const toDelete: string[] = []
|
||||||
|
for (const [, entry] of this.persistentMap) {
|
||||||
|
if (!openCodeSessionIds.has(entry.opencodeSessionId)) {
|
||||||
|
toDelete.push(`${entry.matrixRoomId}::${entry.threadRootId}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const key of toDelete) {
|
||||||
|
this.persistentMap.delete(key)
|
||||||
|
this.sessions.delete(key)
|
||||||
|
this.activeQueries.delete(key)
|
||||||
|
}
|
||||||
|
if (toDelete.length > 0) {
|
||||||
|
saveSessionMap(this.persistentMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue