58 lines
1.7 KiB
JavaScript
58 lines
1.7 KiB
JavaScript
import crypto from "node:crypto";
|
|
export class SessionRegistry {
|
|
ttlMs;
|
|
bindings = new Map();
|
|
constructor(ttlSeconds) {
|
|
this.ttlMs = ttlSeconds * 1000;
|
|
}
|
|
upsert(context, sessionId) {
|
|
const binding = {
|
|
clientSessionId: context.clientSessionId,
|
|
sessionId,
|
|
lastUsedAt: Date.now(),
|
|
};
|
|
this.bindings.set(this.makeKey(context), binding);
|
|
return binding;
|
|
}
|
|
get(context) {
|
|
const key = this.makeKey(context);
|
|
const binding = this.bindings.get(key);
|
|
if (!binding) {
|
|
return null;
|
|
}
|
|
if (Date.now() - binding.lastUsedAt > this.ttlMs) {
|
|
this.bindings.delete(key);
|
|
return null;
|
|
}
|
|
binding.lastUsedAt = Date.now();
|
|
return binding;
|
|
}
|
|
count() {
|
|
this.evictExpired();
|
|
return this.bindings.size;
|
|
}
|
|
evictExpired() {
|
|
const expired = [];
|
|
const now = Date.now();
|
|
for (const [key, binding] of this.bindings.entries()) {
|
|
if (now - binding.lastUsedAt > this.ttlMs) {
|
|
expired.push(binding.sessionId);
|
|
this.bindings.delete(key);
|
|
}
|
|
}
|
|
return expired;
|
|
}
|
|
makeKey(context) {
|
|
// 会话隔离不能只看前端 session_id;同一浏览器会话切换用户或项目时必须映射到不同 opencode session。
|
|
const digest = crypto
|
|
.createHash("sha256")
|
|
.update([
|
|
context.clientSessionId,
|
|
context.accessToken ?? "",
|
|
context.projectId ?? "",
|
|
].join("|"))
|
|
.digest("hex");
|
|
return digest;
|
|
}
|
|
}
|