Skip to content

Commit 66d13ff

Browse files
committed
merged websocket_fix.
- fixes connection issues in production mode - disables vite minifying
1 parent 3370514 commit 66d13ff

File tree

6 files changed

+63
-43
lines changed

6 files changed

+63
-43
lines changed

Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ FROM deps AS prod
6666

6767
WORKDIR /repo
6868
COPY --from=deps /repo /repo
69-
COPY --chown=beetle:beetle . .
69+
COPY --chown=beetle:beetle . .
7070
RUN chmod +x ./entrypoint.sh
7171

7272
WORKDIR /repo/frontend
73+
RUN rm -rf node_modules
74+
RUN rm -rf dist
75+
RUN rm -rf .pnpm-store
7376
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
7477
pnpm install
7578
RUN pnpm run build

backend/beets_flask/inbox.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
from beets_flask.logger import log
1717
from beets_flask.config import config
1818
from beets_flask.routes.sse import update_client_view
19-
from beets_flask.disk import all_album_folders, album_folders_from_track_paths
19+
from beets_flask.disk import (
20+
all_album_folders,
21+
album_folders_from_track_paths,
22+
path_to_dict,
23+
)
2024

2125

2226
# ------------------------------------------------------------------------------------ #

entrypoint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ done
3535
redis-cli FLUSHALL
3636

3737
# we need to run with one worker for socketio to work (but need at lesat threads for SSEs)
38-
gunicorn --worker-class eventlet -w 1 --threads 32 --bind 0.0.0.0:5001 'main:create_app()'
38+
gunicorn --worker-class eventlet -w 1 --threads 32 --timeout 300 --bind 0.0.0.0:5001 'main:create_app()'

frontend/src/components/common/hooks/useSocket.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const useSocket = (
3030
const url: string =
3131
import.meta.env.MODE === "development"
3232
? `ws://localhost:5001/${namespace}`
33-
: namespace;
33+
: `/${namespace}`;
3434

3535
const [socket, setSocket] = useState<Socket | null>(null);
3636
const [isConnected, setIsConnected] = useState(false);
@@ -94,7 +94,9 @@ const STATUS_URL =
9494
import.meta.env.MODE === "development" ? "ws://localhost:5001/status" : "/status";
9595

9696
const statusSocket = io(STATUS_URL, {
97-
autoConnect: true,
97+
// Setting autoConnect to true causes issues in production mode.
98+
// Seems the connection is attempted before dependencies are ready.
99+
autoConnect: false,
98100
transports: ["websocket"],
99101
});
100102

frontend/src/components/frontpage/terminal.tsx

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,17 @@ const xTermTheme = {
3535

3636
export function Terminal(props: HtmlHTMLAttributes<HTMLDivElement>) {
3737
const ref = useRef<HTMLDivElement>(null);
38-
const { term, resetTerm } = useTerminalContext();
38+
const { term, resetTerm, socket } = useTerminalContext();
3939

4040
// we have to recreate the terminal on every mount of the component.
4141
// not sure why we cannot restore.
4242
useEffect(resetTerm, [resetTerm]);
4343

44-
// resetting term also retriggers this guy:
44+
// resetting term also retriggers this guy.
45+
// having socket as a dependencies should make sure we retrigger when
46+
// the if socket had connection issues.
4547
useEffect(() => {
46-
if (!ref.current || !term) return;
48+
if (!ref.current || !term || !socket) return;
4749
const ele = ref.current;
4850
function copyPasteHandler(e: KeyboardEvent) {
4951
if (!term) return false;
@@ -83,23 +85,19 @@ export function Terminal(props: HtmlHTMLAttributes<HTMLDivElement>) {
8385
const fitAddon = new xTermFitAddon();
8486
term.loadAddon(fitAddon);
8587
term.open(ele);
88+
term.focus();
8689
fitAddon.fit();
87-
console.log(term.rows);
8890

89-
// Resize on window resize
9091
const resizeObserver = new ResizeObserver(() => {
9192
fitAddon.fit();
9293
});
9394
resizeObserver.observe(ele);
9495

95-
// On visibility change rerender terminal
96-
console.log("Term mounted");
9796
return () => {
98-
// term.dispose();
97+
term.dispose();
9998
if (ele) resizeObserver.unobserve(ele);
100-
console.log("Term unmounted");
10199
};
102-
}, [term]);
100+
}, [term, ref, socket]);
103101

104102
return <div ref={ref} {...props} />;
105103
}
@@ -139,12 +137,45 @@ export function TerminalContextProvider({ children }: { children: React.ReactNod
139137
});
140138
}, []);
141139

142-
useEffect(resetTerm, [resetTerm]);
140+
// useEffect(resetTerm, [resetTerm]);
141+
142+
const onCursorUpdate = useCallback(
143+
(data: { x: number; y: number }) => {
144+
if (!term) return;
145+
// xterm uses 1-based indexing
146+
// console.log("Cursor update", data);
147+
term.write(`\x1b[${data.y + 1};${data.x + 1}H`);
148+
},
149+
[term]
150+
);
151+
152+
const onOutput = useCallback(
153+
(data: { output: string[] }) => {
154+
if (!term) return;
155+
// term!.clear(); seems to be preferred from the documentation,
156+
// but it leaves the prompt on the first line in place - which we here do not want
157+
// ideally we would directly access the buffer.
158+
// console.log("ptyOutput", data);
159+
term.reset();
160+
data.output.forEach((line, index) => {
161+
if (index < data.output.length - 1) {
162+
term.writeln(line);
163+
} else {
164+
// Workaround: strip all trailing whitespaces except for one
165+
// not a perfect fix (one wrong space remains when backspacing)
166+
const stripped_line = line.replace(/\s+$/, " ");
167+
term.write(stripped_line);
168+
}
169+
});
170+
},
171+
[term]
172+
);
143173

144174
// Attach socket handler
145175
useEffect(() => {
146176
if (!term || !isConnected || !socket) return;
147177

178+
// spaces are needed to clear out the longer "Connecting..."
148179
term.writeln("\rConnected! ");
149180

150181
const onInput = term.onData((data) => {
@@ -156,33 +187,10 @@ export function TerminalContextProvider({ children }: { children: React.ReactNod
156187
});
157188

158189
const onResize = term.onResize(({ cols, rows }) => {
159-
// console.log(`Terminal was resized to ${cols} cols and ${rows} rows.`);
190+
console.log(`Terminal was resized to ${cols} cols and ${rows} rows.`);
160191
socket.emit("ptyResize", { cols, rows: rows });
161192
});
162193

163-
function onOutput(data: { output: string[] }) {
164-
// term!.clear(); seems to be preferred from the documentation,
165-
// but it leaves the prompt on the first line in place - which we here do not want
166-
// ideally we would directly access the buffer.
167-
// console.log("ptyOutput", data);
168-
term!.reset();
169-
data.output.forEach((line, index) => {
170-
if (index < data.output.length - 1) {
171-
term!.writeln(line);
172-
} else {
173-
// Workaround: strip all trailing whitespaces except for one
174-
// not a perfect fix (one wrong space remains when backspacing)
175-
const stripped_line = line.replace(/\s+$/, " ");
176-
term!.write(stripped_line);
177-
}
178-
});
179-
}
180-
181-
function onCursorUpdate(data: { x: number; y: number }) {
182-
// xterm uses 1-based indexing
183-
term!.write(`\x1b[${data.y + 1};${data.x + 1}H`);
184-
}
185-
186194
socket.on("ptyOutput", onOutput);
187195
socket.on("ptyCursorPosition", onCursorUpdate);
188196

@@ -197,7 +205,7 @@ export function TerminalContextProvider({ children }: { children: React.ReactNod
197205
socket.off("ptyOutput", onOutput);
198206
socket.off("ptyCursorPosition", onCursorUpdate);
199207
};
200-
}, [isConnected, term, socket]);
208+
}, [isConnected, term, socket, onOutput, onCursorUpdate]);
201209

202210
// make first responder directly after opening
203211
useEffect(() => {
@@ -211,7 +219,6 @@ export function TerminalContextProvider({ children }: { children: React.ReactNod
211219
console.error("No socket available");
212220
return;
213221
}
214-
215222
socket.emit("ptyInput", { input: t });
216223
}
217224

@@ -220,7 +227,6 @@ export function TerminalContextProvider({ children }: { children: React.ReactNod
220227
console.error("No socket available");
221228
return;
222229
}
223-
224230
socket.emit("ptyInput", { input: "\x15" });
225231
}
226232

frontend/vite.config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,9 @@ import svgr from "vite-plugin-svgr";
66
// https://vitejs.dev/config/
77
export default defineConfig({
88
plugins: [tsconfigPaths(), react(), TanStackRouterVite(), svgr()],
9+
// not minifying helped when debugging in production mode
10+
// we can enable this again when the code base is a bit more mature.
11+
build: {
12+
minify: false,
13+
},
914
});

0 commit comments

Comments
 (0)