refactor: remove Redis dependency and related code
This commit is contained in:
@@ -9,7 +9,15 @@ import {
|
||||
} from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
import { ApiError, api, getToken, login, logout, setToken } from "../api";
|
||||
import {
|
||||
ApiError,
|
||||
api,
|
||||
buildSocketUrl,
|
||||
getToken,
|
||||
login,
|
||||
logout,
|
||||
setToken,
|
||||
} from "../api";
|
||||
import type {
|
||||
AddonExample,
|
||||
DockerService,
|
||||
@@ -181,11 +189,15 @@ export function useControlPlane() {
|
||||
const selectedExampleId = ref("");
|
||||
const draft = reactive<ProxyDraft>(createDefaultDraft());
|
||||
const loadedPort = ref<number | null>(null);
|
||||
const loadedDraftJson = ref("");
|
||||
const loadedCode = ref(draft.code);
|
||||
const wizardOpen = ref(false);
|
||||
const wizardMode = ref<"create" | "edit">("create");
|
||||
const wizardStep = ref(0);
|
||||
const logsCleared = ref(false);
|
||||
let noticeTimer: number | null = null;
|
||||
let logPollTimer: number | null = null;
|
||||
let logSocket: WebSocket | null = null;
|
||||
let logReconnectTimer: number | null = null;
|
||||
let syncingRoute = false;
|
||||
|
||||
const selectedProxy = computed(() =>
|
||||
@@ -437,14 +449,32 @@ export function useControlPlane() {
|
||||
);
|
||||
|
||||
const codeLineCount = computed(() => draft.code.split("\n").length);
|
||||
const scriptDirty = computed(() => draft.code !== loadedCode.value);
|
||||
const draftDirty = computed(
|
||||
() => serializeDraft(draft) !== loadedDraftJson.value,
|
||||
);
|
||||
const canSaveScript = computed(
|
||||
() =>
|
||||
!loading.value &&
|
||||
Boolean(selectedProxy.value) &&
|
||||
scriptDirty.value,
|
||||
);
|
||||
|
||||
watch(
|
||||
[selectedPort, proxies],
|
||||
([port]) => {
|
||||
if (port === null || port === loadedPort.value) return;
|
||||
if (port === null) return;
|
||||
const proxy = proxies.value.find((item) => item.proxy_port === port);
|
||||
if (!proxy) return;
|
||||
hydrateDraft(proxy);
|
||||
|
||||
if (port !== loadedPort.value) {
|
||||
hydrateDraft(proxy);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wizardOpen.value && !draftDirty.value) {
|
||||
hydrateDraft(proxy);
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
@@ -489,23 +519,17 @@ export function useControlPlane() {
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
watch(selectedProxy, (proxy) => {
|
||||
if (!proxy) return;
|
||||
if (!wizardOpen.value) {
|
||||
hydrateDraft(proxy);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
[selectedPort, token, logsPaused],
|
||||
([port, authToken, paused]) => {
|
||||
stopLogPolling();
|
||||
([port, authToken, paused], [previousPort]) => {
|
||||
if (port !== previousPort) {
|
||||
logs.value = "";
|
||||
logFilter.value = "";
|
||||
logsCleared.value = false;
|
||||
}
|
||||
stopLogStream();
|
||||
if (!authToken || port === null || paused) return;
|
||||
void syncLogs(true);
|
||||
if (typeof window === "undefined") return;
|
||||
logPollTimer = window.setInterval(() => {
|
||||
void syncLogs(true);
|
||||
}, 2000);
|
||||
void openLogStream(port);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
@@ -572,10 +596,14 @@ export function useControlPlane() {
|
||||
health.value = null;
|
||||
logs.value = "";
|
||||
logFilter.value = "";
|
||||
Object.assign(
|
||||
draft,
|
||||
createDefaultDraft(nextPort(), examples.value[0]?.code ?? draft.code),
|
||||
logsCleared.value = false;
|
||||
const nextDraft = createDefaultDraft(
|
||||
nextPort(),
|
||||
examples.value[0]?.code ?? draft.code,
|
||||
);
|
||||
Object.assign(draft, nextDraft);
|
||||
loadedDraftJson.value = serializeDraft(nextDraft);
|
||||
loadedCode.value = nextDraft.code;
|
||||
if (announce) {
|
||||
notice.value = "Draft created.";
|
||||
}
|
||||
@@ -681,6 +709,19 @@ export function useControlPlane() {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveScript() {
|
||||
const proxy = selectedProxy.value;
|
||||
if (!proxy) return;
|
||||
|
||||
await run(async () => {
|
||||
const saved = await api.updateProxy(proxy.proxy_port, {
|
||||
code: draft.code,
|
||||
});
|
||||
syncLoadedCode(saved.code);
|
||||
await refreshAll();
|
||||
}, "Script saved");
|
||||
}
|
||||
|
||||
async function removeProxy() {
|
||||
const proxy = selectedProxy.value;
|
||||
if (!proxy) return;
|
||||
@@ -726,7 +767,9 @@ export function useControlPlane() {
|
||||
const proxy = selectedProxy.value;
|
||||
if (!proxy) return;
|
||||
try {
|
||||
logs.value = (await api.logs(proxy.proxy_port)).log;
|
||||
if (!logsCleared.value) {
|
||||
logs.value = (await api.logs(proxy.proxy_port)).log;
|
||||
}
|
||||
} catch (err) {
|
||||
if (!silent) {
|
||||
error.value = err instanceof Error ? err.message : String(err);
|
||||
@@ -734,6 +777,81 @@ export function useControlPlane() {
|
||||
}
|
||||
}
|
||||
|
||||
async function openLogStream(proxyPort: number) {
|
||||
if (!logsCleared.value) {
|
||||
await syncLogs(true);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof window === "undefined" ||
|
||||
!token.value ||
|
||||
logsPaused.value ||
|
||||
selectedPort.value !== proxyPort
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const socket = new WebSocket(buildSocketUrl(`/proxy/${proxyPort}/logs/ws`));
|
||||
logSocket = socket;
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
if (socket !== logSocket) return;
|
||||
const frame = parseLogFrame(event.data);
|
||||
if (frame === null) return;
|
||||
if (frame.type === "snapshot") {
|
||||
if (logsCleared.value) return;
|
||||
logs.value = frame.log;
|
||||
return;
|
||||
}
|
||||
logs.value += frame.log;
|
||||
};
|
||||
|
||||
socket.onclose = (event) => {
|
||||
if (socket !== logSocket) return;
|
||||
logSocket = null;
|
||||
|
||||
if (event.code === 4401) {
|
||||
clearSession("Session expired. Sign in again.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!token.value ||
|
||||
logsPaused.value ||
|
||||
selectedPort.value !== proxyPort ||
|
||||
event.code === 1000
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleLogReconnect(proxyPort);
|
||||
};
|
||||
}
|
||||
|
||||
function parseLogFrame(raw: string) {
|
||||
try {
|
||||
const payload = JSON.parse(raw);
|
||||
if (
|
||||
(payload.type === "snapshot" || payload.type === "append") &&
|
||||
typeof payload.log === "string"
|
||||
) {
|
||||
return payload as { type: "snapshot" | "append"; log: string };
|
||||
}
|
||||
} catch {
|
||||
return { type: "append", log: raw } as const;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function scheduleLogReconnect(proxyPort: number) {
|
||||
if (typeof window === "undefined" || logReconnectTimer !== null) return;
|
||||
logReconnectTimer = window.setTimeout(() => {
|
||||
logReconnectTimer = null;
|
||||
if (!token.value || logsPaused.value || selectedPort.value !== proxyPort) return;
|
||||
void openLogStream(proxyPort);
|
||||
}, 1200);
|
||||
}
|
||||
|
||||
async function saveCurrentAsExample() {
|
||||
const name = customExampleName.value.trim();
|
||||
if (!name) {
|
||||
@@ -852,41 +970,63 @@ export function useControlPlane() {
|
||||
|
||||
function clearLogs() {
|
||||
logs.value = "";
|
||||
logsCleared.value = true;
|
||||
}
|
||||
|
||||
function cleanDraft(): ProxyDraft {
|
||||
return draftPayload(draft);
|
||||
}
|
||||
|
||||
function hydrateDraft(proxy: ProxyDocument) {
|
||||
const nextDraft = draftPayload(proxy);
|
||||
Object.assign(draft, nextDraft);
|
||||
loadedPort.value = proxy.proxy_port;
|
||||
loadedDraftJson.value = serializeDraft(nextDraft);
|
||||
loadedCode.value = nextDraft.code;
|
||||
health.value = null;
|
||||
logs.value = "";
|
||||
}
|
||||
|
||||
function syncLoadedCode(code: string) {
|
||||
loadedCode.value = code;
|
||||
|
||||
const baseline = loadedDraftJson.value
|
||||
? (JSON.parse(loadedDraftJson.value) as ProxyDraft)
|
||||
: cleanDraft();
|
||||
baseline.code = code;
|
||||
loadedDraftJson.value = serializeDraft(baseline);
|
||||
}
|
||||
|
||||
function draftPayload(value: ProxyDraft | ProxyDocument): ProxyDraft {
|
||||
return JSON.parse(
|
||||
JSON.stringify({
|
||||
proxy_port: draft.proxy_port,
|
||||
name: draft.name,
|
||||
code: draft.code,
|
||||
mode: draft.mode,
|
||||
mode_spec: draft.mode_spec || null,
|
||||
protocol: draft.protocol,
|
||||
listen_host: draft.listen_host,
|
||||
mitm_options: draft.mitm_options,
|
||||
proxy_port: value.proxy_port,
|
||||
name: value.name,
|
||||
code: value.code,
|
||||
mode: value.mode,
|
||||
mode_spec: value.mode_spec || null,
|
||||
protocol: value.protocol,
|
||||
listen_host: value.listen_host,
|
||||
mitm_options: value.mitm_options,
|
||||
healthcheck: {
|
||||
...draft.healthcheck,
|
||||
expected_status: draft.healthcheck.expected_status || null,
|
||||
protocol: draft.healthcheck.protocol || null,
|
||||
...value.healthcheck,
|
||||
expected_status: value.healthcheck.expected_status || null,
|
||||
protocol: value.healthcheck.protocol || null,
|
||||
},
|
||||
service: {
|
||||
host: draft.service.host,
|
||||
port: draft.service.port,
|
||||
bind_host: draft.service.bind_host || null,
|
||||
name: draft.service.name || null,
|
||||
folder: draft.service.folder || null,
|
||||
upstream_port: draft.service.upstream_port || null,
|
||||
host: value.service.host,
|
||||
port: value.service.port,
|
||||
bind_host: value.service.bind_host || null,
|
||||
name: value.service.name || null,
|
||||
folder: value.service.folder || null,
|
||||
upstream_port: value.service.upstream_port || null,
|
||||
},
|
||||
}),
|
||||
) as ProxyDraft;
|
||||
}
|
||||
|
||||
function hydrateDraft(proxy: ProxyDocument) {
|
||||
Object.assign(draft, JSON.parse(JSON.stringify(proxy)) as ProxyDraft);
|
||||
loadedPort.value = proxy.proxy_port;
|
||||
health.value = null;
|
||||
logs.value = "";
|
||||
function serializeDraft(value: ProxyDraft | ProxyDocument) {
|
||||
return JSON.stringify(draftPayload(value));
|
||||
}
|
||||
|
||||
function bindingsFor(service: DockerService) {
|
||||
@@ -964,7 +1104,7 @@ export function useControlPlane() {
|
||||
}
|
||||
|
||||
function clearSession(message = "") {
|
||||
stopLogPolling();
|
||||
stopLogStream();
|
||||
setToken(null);
|
||||
token.value = null;
|
||||
proxies.value = [];
|
||||
@@ -976,18 +1116,26 @@ export function useControlPlane() {
|
||||
health.value = null;
|
||||
logs.value = "";
|
||||
logFilter.value = "";
|
||||
logsCleared.value = false;
|
||||
wizardOpen.value = false;
|
||||
wizardStep.value = 0;
|
||||
wizardMode.value = "create";
|
||||
Object.assign(draft, createDefaultDraft());
|
||||
loadedDraftJson.value = serializeDraft(draft);
|
||||
loadedCode.value = draft.code;
|
||||
authMessage.value = message;
|
||||
void router.replace({ path: "/proxies", query: {} });
|
||||
}
|
||||
|
||||
function stopLogPolling() {
|
||||
if (typeof window === "undefined" || logPollTimer === null) return;
|
||||
window.clearInterval(logPollTimer);
|
||||
logPollTimer = null;
|
||||
function stopLogStream() {
|
||||
if (typeof window !== "undefined" && logReconnectTimer !== null) {
|
||||
window.clearTimeout(logReconnectTimer);
|
||||
logReconnectTimer = null;
|
||||
}
|
||||
if (logSocket === null) return;
|
||||
logSocket.onclose = null;
|
||||
logSocket.close();
|
||||
logSocket = null;
|
||||
}
|
||||
|
||||
return proxyRefs({
|
||||
@@ -1001,6 +1149,7 @@ export function useControlPlane() {
|
||||
clearLogs,
|
||||
closeWizard,
|
||||
codeLineCount,
|
||||
canSaveScript,
|
||||
filteredLogs,
|
||||
logFilter,
|
||||
logsPaused,
|
||||
@@ -1036,6 +1185,7 @@ export function useControlPlane() {
|
||||
runtimeAction,
|
||||
saveCurrentAsExample,
|
||||
saveProxy,
|
||||
saveScript,
|
||||
selectExample,
|
||||
selectedExample,
|
||||
selectedOption,
|
||||
@@ -1044,6 +1194,7 @@ export function useControlPlane() {
|
||||
selectOption,
|
||||
serviceEntries,
|
||||
services,
|
||||
scriptDirty,
|
||||
setOption,
|
||||
signIn,
|
||||
signOut,
|
||||
|
||||
Reference in New Issue
Block a user