merge: MEM-1/2/3 event listener leak cleanup (resolved session.store.ts conflict)
This commit is contained in:
commit
625a4500bc
@ -88,7 +88,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted, onBeforeUnmount } from "vue";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { useSessionStore, type Session } from "@/stores/session.store";
|
import { useSessionStore, type Session } from "@/stores/session.store";
|
||||||
import { useConnectionStore } from "@/stores/connection.store";
|
import { useConnectionStore } from "@/stores/connection.store";
|
||||||
@ -151,16 +151,10 @@ function closeMenuTab(): void {
|
|||||||
if (session) sessionStore.closeSession(session.id);
|
if (session) sessionStore.closeSession(session.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for reattach events from detached windows
|
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
listen<{ sessionId: string; name: string; protocol: string }>("session:reattach", (event) => {
|
import type { UnlistenFn } from "@tauri-apps/api/event";
|
||||||
const { sessionId } = event.payload;
|
|
||||||
const session = sessionStore.sessions.find(s => s.id === sessionId);
|
let unlistenReattach: UnlistenFn | null = null;
|
||||||
if (session) {
|
|
||||||
session.active = true;
|
|
||||||
sessionStore.activateSession(sessionId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
@ -168,6 +162,19 @@ onMounted(async () => {
|
|||||||
} catch {
|
} catch {
|
||||||
availableShells.value = [];
|
availableShells.value = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unlistenReattach = await listen<{ sessionId: string; name: string; protocol: string }>("session:reattach", (event) => {
|
||||||
|
const { sessionId } = event.payload;
|
||||||
|
const session = sessionStore.sessions.find(s => s.id === sessionId);
|
||||||
|
if (session) {
|
||||||
|
session.active = true;
|
||||||
|
sessionStore.activateSession(sessionId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
unlistenReattach?.();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Drag-and-drop tab reordering
|
// Drag-and-drop tab reordering
|
||||||
|
|||||||
@ -195,6 +195,7 @@ export function useRdp(): UseRdpReturn {
|
|||||||
const clipboardSync = ref(false);
|
const clipboardSync = ref(false);
|
||||||
|
|
||||||
let animFrameId: number | null = null;
|
let animFrameId: number | null = null;
|
||||||
|
let unlistenFrame: (() => void) | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the current frame from the Rust RDP backend.
|
* Fetch the current frame from the Rust RDP backend.
|
||||||
@ -315,8 +316,7 @@ export function useRdp(): UseRdpReturn {
|
|||||||
listen(`rdp:frame:${sessionId}`, () => {
|
listen(`rdp:frame:${sessionId}`, () => {
|
||||||
onFrameReady();
|
onFrameReady();
|
||||||
}).then((unlisten) => {
|
}).then((unlisten) => {
|
||||||
// Store unlisten so we can clean up
|
unlistenFrame = unlisten;
|
||||||
(canvas as any).__wraith_unlisten = unlisten;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -332,6 +332,10 @@ export function useRdp(): UseRdpReturn {
|
|||||||
cancelAnimationFrame(animFrameId);
|
cancelAnimationFrame(animFrameId);
|
||||||
animFrameId = null;
|
animFrameId = null;
|
||||||
}
|
}
|
||||||
|
if (unlistenFrame !== null) {
|
||||||
|
unlistenFrame();
|
||||||
|
unlistenFrame = null;
|
||||||
|
}
|
||||||
connected.value = false;
|
connected.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { defineStore } from "pinia";
|
|||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
|
import type { UnlistenFn } from "@tauri-apps/api/event";
|
||||||
import { useConnectionStore } from "@/stores/connection.store";
|
import { useConnectionStore } from "@/stores/connection.store";
|
||||||
import type { ThemeDefinition } from "@/components/common/ThemePicker.vue";
|
import type { ThemeDefinition } from "@/components/common/ThemePicker.vue";
|
||||||
|
|
||||||
@ -39,10 +40,14 @@ export const useSessionStore = defineStore("session", () => {
|
|||||||
|
|
||||||
const sessionCount = computed(() => sessions.value.length);
|
const sessionCount = computed(() => sessions.value.length);
|
||||||
|
|
||||||
|
const sessionUnlisteners = new Map<string, Array<UnlistenFn>>();
|
||||||
|
|
||||||
// Listen for backend close/exit events to update session status
|
// Listen for backend close/exit events to update session status
|
||||||
function setupStatusListeners(sessionId: string): void {
|
async function setupStatusListeners(sessionId: string): Promise<void> {
|
||||||
listen(`ssh:close:${sessionId}`, () => markDisconnected(sessionId));
|
const unlisteners: UnlistenFn[] = [];
|
||||||
listen(`ssh:exit:${sessionId}`, () => markDisconnected(sessionId));
|
unlisteners.push(await listen(`ssh:close:${sessionId}`, () => markDisconnected(sessionId)));
|
||||||
|
unlisteners.push(await listen(`ssh:exit:${sessionId}`, () => markDisconnected(sessionId)));
|
||||||
|
sessionUnlisteners.set(sessionId, unlisteners);
|
||||||
}
|
}
|
||||||
|
|
||||||
function markDisconnected(sessionId: string): void {
|
function markDisconnected(sessionId: string): void {
|
||||||
@ -92,6 +97,12 @@ export const useSessionStore = defineStore("session", () => {
|
|||||||
console.error("Failed to disconnect session:", err);
|
console.error("Failed to disconnect session:", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unlisteners = sessionUnlisteners.get(id);
|
||||||
|
if (unlisteners) {
|
||||||
|
unlisteners.forEach((fn) => fn());
|
||||||
|
sessionUnlisteners.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
sessions.value.splice(idx, 1);
|
sessions.value.splice(idx, 1);
|
||||||
|
|
||||||
if (activeSessionId.value === id) {
|
if (activeSessionId.value === id) {
|
||||||
@ -325,7 +336,8 @@ export const useSessionStore = defineStore("session", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Listen for PTY close
|
// Listen for PTY close
|
||||||
listen(`pty:close:${sessionId}`, () => markDisconnected(sessionId));
|
const unlistenPty = await listen(`pty:close:${sessionId}`, () => markDisconnected(sessionId));
|
||||||
|
sessionUnlisteners.set(sessionId, [unlistenPty]);
|
||||||
|
|
||||||
activeSessionId.value = sessionId;
|
activeSessionId.value = sessionId;
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user