Skip to content

Commit b12af1b

Browse files
authored
CFFI Integration (#20)
* remove unnecessary files * add qlcp library submodule * readd timestamps to logging * migrate protocol to cffi * update readme for protocol changes * switch to cmake shared libs option * cffi api mode * fix missing build script * remove missing dev dependencies requirement from dockerfiles * improve cffi build caching * improve protocol binding interface * fix file name in build script * improved typing for packet decode return * clean up tcp packet handler * remove need for extra library header * fix ctl-qlcp-lib commit hash * fix header size in python + warning * remove hardcoded dependency on header size * extract reused built components to scripts * assert header size compiled properly * extract UDP fast path type checking to peek_packet_type * decoding optimization * apply PR review changes * remove peek_packet_type * consistent naming in protocol decode * clarify usage of makefile * fix non-data packet ignore case
1 parent a476cdb commit b12af1b

21 files changed

Lines changed: 869 additions & 1999 deletions

.dockerignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.github
22
.venv
33
.vscode
4-
media
4+
media
5+
qlcp/build

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ configs/
66
.claude/
77
recordings/
88

9+
libqretprop/_protocol
10+
libqretprop/_lib
11+
912
*.egg-info

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "qlcp"]
2+
path = qlcp
3+
url = https://github.com/Queens-Rocket-Engineering-Team/ctl-qlcp-lib

Dockerfile.mockdevice

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Stage 1: Build libqlcp.so from C source
2+
FROM python:3.13-alpine3.22@sha256:ab45bd32143151fe060d48218b91df43a289166e72ec7877823b1c972580bed3 AS qlcp-builder
3+
4+
RUN apk add --no-cache gcc musl-dev cmake make
5+
6+
COPY qlcp/ /build/qlcp/
7+
WORKDIR /build/qlcp/build
8+
9+
RUN cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON && \
10+
cmake --build . --target qlcp
11+
12+
# Stage 2: Compile cffi Python extension against libqlcp.so
13+
FROM python:3.13-alpine3.22@sha256:ab45bd32143151fe060d48218b91df43a289166e72ec7877823b1c972580bed3 AS cffi-builder
14+
15+
RUN apk add --no-cache gcc musl-dev
16+
17+
COPY --from=ghcr.io/astral-sh/uv@sha256:9a23023be68b2ed09750ae636228e903a54a05ea56ed03a934d00fe9fbeded4b /uv /uvx /bin/
18+
19+
WORKDIR /app
20+
21+
COPY --from=qlcp-builder /build/qlcp/build/libqlcp.so /app/libqretprop/_lib/libqlcp.so
22+
23+
RUN --mount=type=cache,target=/root/.cache/uv \
24+
--mount=type=bind,source=uv.lock,target=uv.lock \
25+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
26+
uv sync --no-install-project --no-dev
27+
28+
COPY qlcp/include/ /app/qlcp/include/
29+
COPY scripts/build_qlcp.py /app/scripts/build_qlcp.py
30+
COPY libqretprop/__init__.py /app/libqretprop/__init__.py
31+
COPY scripts/expand_qlcp_header.sh /app/scripts/expand_qlcp_header.sh
32+
33+
RUN sh /app/scripts/expand_qlcp_header.sh /app/qlcp/include/qlcp_lib.h /app/libqretprop/_lib/qlcp_lib_expanded.h
34+
35+
RUN mkdir -p /app/libqretprop/_protocol && \
36+
uv run python scripts/build_qlcp.py
37+
38+
# Stage 3: Final runtime image
39+
FROM python:3.13-alpine3.22@sha256:ab45bd32143151fe060d48218b91df43a289166e72ec7877823b1c972580bed3
40+
41+
COPY --from=ghcr.io/astral-sh/uv@sha256:9a23023be68b2ed09750ae636228e903a54a05ea56ed03a934d00fe9fbeded4b /uv /uvx /bin/
42+
WORKDIR /app
43+
44+
COPY --from=qlcp-builder /build/qlcp/build/libqlcp.so /app/libqretprop/_lib/libqlcp.so
45+
COPY --from=cffi-builder /app/libqretprop/_protocol/ /app/libqretprop/_protocol/
46+
47+
RUN --mount=type=cache,target=/root/.cache/uv \
48+
--mount=type=bind,source=uv.lock,target=uv.lock \
49+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
50+
uv sync --no-install-project --no-dev
51+
52+
ADD . /app
53+
54+
RUN --mount=type=cache,target=/root/.cache/uv \
55+
uv sync --no-dev
56+
57+
CMD ["uv", "run", "--no-dev", "mock_device"]

Dockerfile.server

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,58 @@
1+
# Stage 1: Build libqlcp.so from C source
2+
FROM python:3.13-alpine3.22@sha256:ab45bd32143151fe060d48218b91df43a289166e72ec7877823b1c972580bed3 AS qlcp-builder
3+
4+
RUN apk add --no-cache gcc musl-dev cmake make
5+
6+
COPY qlcp/ /build/qlcp/
7+
WORKDIR /build/qlcp/build
8+
9+
RUN cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON && \
10+
cmake --build . --target qlcp
11+
12+
# Stage 2: Compile cffi Python extension against libqlcp.so
13+
FROM python:3.13-alpine3.22@sha256:ab45bd32143151fe060d48218b91df43a289166e72ec7877823b1c972580bed3 AS cffi-builder
14+
15+
RUN apk add --no-cache gcc musl-dev
16+
17+
COPY --from=ghcr.io/astral-sh/uv@sha256:9a23023be68b2ed09750ae636228e903a54a05ea56ed03a934d00fe9fbeded4b /uv /uvx /bin/
18+
19+
WORKDIR /app
20+
21+
COPY --from=qlcp-builder /build/qlcp/build/libqlcp.so /app/libqretprop/_lib/libqlcp.so
22+
23+
RUN --mount=type=cache,target=/root/.cache/uv \
24+
--mount=type=bind,source=uv.lock,target=uv.lock \
25+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
26+
uv sync --no-install-project --no-dev
27+
28+
# Only copy what _build_qlcp.py needs — insulates cffi build from unrelated changes
29+
COPY qlcp/include/ /app/qlcp/include/
30+
COPY scripts/build_qlcp.py /app/scripts/build_qlcp.py
31+
COPY libqretprop/__init__.py /app/libqretprop/__init__.py
32+
COPY scripts/expand_qlcp_header.sh /app/scripts/expand_qlcp_header.sh
33+
34+
RUN sh /app/scripts/expand_qlcp_header.sh /app/qlcp/include/qlcp_lib.h /app/libqretprop/_lib/qlcp_lib_expanded.h
35+
36+
RUN mkdir -p /app/libqretprop/_protocol && \
37+
uv run python scripts/build_qlcp.py
38+
39+
# Stage 3: Final runtime image
140
FROM python:3.13-alpine3.22@sha256:ab45bd32143151fe060d48218b91df43a289166e72ec7877823b1c972580bed3
241

3-
# Install uv
442
COPY --from=ghcr.io/astral-sh/uv@sha256:9a23023be68b2ed09750ae636228e903a54a05ea56ed03a934d00fe9fbeded4b /uv /uvx /bin/
543
WORKDIR /app
644

7-
# Use host dependencies by default during development to improve build times
45+
COPY --from=qlcp-builder /build/qlcp/build/libqlcp.so /app/libqretprop/_lib/libqlcp.so
46+
COPY --from=cffi-builder /app/libqretprop/_protocol/ /app/libqretprop/_protocol/
47+
848
RUN --mount=type=cache,target=/root/.cache/uv \
949
--mount=type=bind,source=uv.lock,target=uv.lock \
1050
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
1151
uv sync --no-install-project --no-dev
1252

13-
# Copy the project into the image
1453
ADD . /app
1554

16-
# Sync the project
1755
RUN --mount=type=cache,target=/root/.cache/uv \
1856
uv sync --no-dev
1957

20-
CMD ["uv", "run", "--no-dev", "start_server"]
58+
CMD ["uv", "run", "--no-dev", "start_server"]

Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.PHONY: build-qlcp build-protocol
2+
3+
build-qlcp:
4+
cmake -S qlcp -B qlcp/build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release
5+
cmake --build qlcp/build --target qlcp
6+
mkdir -p libqretprop/_lib
7+
cp qlcp/build/libqlcp.so libqretprop/_lib/libqlcp.so
8+
sh scripts/expand_qlcp_header.sh qlcp/include/qlcp_lib.h libqretprop/_lib/qlcp_lib_expanded.h
9+
10+
build-protocol: build-qlcp
11+
uv run python scripts/build_qlcp.py

0 commit comments

Comments
 (0)