first commit
This commit is contained in:
commit
a74fe7a388
42 files changed
+6058
No files matched your search
@@ -0,0 +1,104 @@
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
import { createSession, endSession, heartbeat } from '@/api/client';
|
||||
|
||||
const HWP_FILE_KEY = 'sejong_hwp_file';
|
||||
|
||||
let pageHideBound = false;
|
||||
|
||||
function onPageHide() {
|
||||
navigator.sendBeacon(
|
||||
'/api/sessions/end',
|
||||
new Blob(['{}'], { type: 'application/json' }),
|
||||
);
|
||||
void fetch('/api/sessions', {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
keepalive: true,
|
||||
});
|
||||
clearHwpFile();
|
||||
}
|
||||
|
||||
/** Register once for the whole SPA (survives keep-alive editor switches). */
|
||||
export function bindSessionPageHideOnce() {
|
||||
if (pageHideBound || typeof window === 'undefined') return;
|
||||
pageHideBound = true;
|
||||
window.addEventListener('pagehide', onPageHide);
|
||||
}
|
||||
|
||||
export function storeHwpFile(file: File): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const buffer = reader.result as ArrayBuffer;
|
||||
const bytes = new Uint8Array(buffer);
|
||||
let binary = '';
|
||||
const chunk = 0x8000;
|
||||
for (let i = 0; i < bytes.length; i += chunk) {
|
||||
binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
||||
}
|
||||
sessionStorage.setItem(
|
||||
HWP_FILE_KEY,
|
||||
JSON.stringify({
|
||||
name: file.name,
|
||||
base64: btoa(binary),
|
||||
}),
|
||||
);
|
||||
resolve();
|
||||
};
|
||||
reader.onerror = () => reject(reader.error);
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
|
||||
export function loadHwpFile(): { name: string; buffer: ArrayBuffer } | null {
|
||||
const raw = sessionStorage.getItem(HWP_FILE_KEY);
|
||||
if (!raw) return null;
|
||||
try {
|
||||
const { name, base64 } = JSON.parse(raw) as {
|
||||
name: string;
|
||||
base64: string;
|
||||
};
|
||||
const binary = atob(base64);
|
||||
const bytes = new Uint8Array(binary.length);
|
||||
for (let i = 0; i < binary.length; i += 1) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
return { name, buffer: bytes.buffer };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function clearHwpFile(): void {
|
||||
sessionStorage.removeItem(HWP_FILE_KEY);
|
||||
}
|
||||
|
||||
export function useSessionLifecycle(options?: { enableHeartbeat?: boolean }) {
|
||||
let timer: ReturnType<typeof setInterval> | undefined;
|
||||
|
||||
async function ensureSession() {
|
||||
// Reuses cookie session on the server — does not orphan open documents
|
||||
await createSession();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
bindSessionPageHideOnce();
|
||||
try {
|
||||
await ensureSession();
|
||||
} catch (err) {
|
||||
console.error('session create failed', err);
|
||||
}
|
||||
|
||||
if (options?.enableHeartbeat !== false) {
|
||||
timer = setInterval(() => {
|
||||
void heartbeat().catch(() => undefined);
|
||||
}, 30_000);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) clearInterval(timer);
|
||||
});
|
||||
|
||||
return { ensureSession, endSession, clearHwpFile };
|
||||
}
|
||||
Reference in new issue
Block a user