Skip to content

Implement AF-Server Client package for LabVIEW TCP communication#1

Merged
Faragoz merged 4 commits intomainfrom
copilot/add-tcp-client-implementation
Dec 3, 2025
Merged

Implement AF-Server Client package for LabVIEW TCP communication#1
Faragoz merged 4 commits intomainfrom
copilot/add-tcp-client-implementation

Conversation

Copy link

Copilot AI commented Dec 3, 2025

  • Analyze repository structure and requirements
  • Phase 1 (Core):
    • Create package structure (af_server_client/)
    • Create pyproject.toml with dependencies
    • Implement core/config.py - TOML configuration loader
    • Implement core/protocol.py - @lvclass command definitions
    • Implement core/response_handler.py - Request-response correlation
    • Implement core/tcp_client.py - Asyncio TCP client with uvloop
  • Phase 2 (Console):
    • Implement console/widgets.py - StatusPanel widget
    • Implement console/command_parser.py - Parse and validate commands
    • Implement console/commands.py - Command executor and registry
    • Implement console/app.py - Main Textual TUI application
  • Phase 3 (Benchmark):
    • Implement benchmark/metrics.py - Sample, BenchmarkRun classes
    • Implement benchmark/rtt_test.py - Round-trip time benchmarking
    • Implement benchmark/export.py - JSON/CSV/Excel exporters
  • Phase 4 (Integration):
    • Implement psychopy_bridge/shared_client.py - Singleton TCP client
    • Implement psychopy_bridge/launcher.py - Launch PsychoPy experiments
    • Implement psychopy_bridge/subject_gui.py - Subject interface template
  • Phase 5 (CLI & Config):
    • Implement cli.py - CLI entry point
    • Create af_server_config.toml - Example configuration
  • Phase 6 (Testing & CI/CD):
    • Create tests/test_protocol.py
    • Create tests/test_response_handler.py
    • Create tests/test_tcp_client.py
    • Create tests/test_benchmark.py
    • Create tests/test_console.py
    • Create tests/test_config.py
    • Create .github/workflows/ci.yml with explicit permissions
  • Phase 7 (Documentation):
    • Create README.md
  • Run linting (ruff) - Passed
  • Run type checking (mypy) - Passed
  • Run tests - 96 passed
  • Code review - Addressed feedback
  • Security check (CodeQL) - Passed with 0 alerts
  • Integrated real AF-Serializer - Repository now public, tests pass with real package
Original prompt

AF-Server Client Implementation Task

🎯 Project Overview

Develop a modular, low-latency Python TCP client to communicate with a LabVIEW server using AF-Serializer protocol. The client includes a Textual-based interactive console for managing communications, executing commands, and launching PsychoPy interfaces for laboratory experiments with CRIO devices.

📋 Core Requirements

1. Low-Latency TCP Communication

Network Optimizations:

  • Disable Nagle's algorithm: socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  • Set QoS for low latency: socket.setsockopt(socket.IPPROTO_IP, socket.IP_TOS, 0xB8) (DSCP EF)
  • Minimal buffer size for small packets (≤128 bytes typical)
  • Asyncio + uvloop for 2-4x performance improvement
  • Configurable socket timeout for non-blocking operations

Protocol Classes (AF-Serializer):

from af_serializer import lvclass, LVString, LVDouble, LVBoolean

# General protocol wrapper
@lvclass(library='', class_name='Protocol')
class Protocol:
    data: str  # LVString - serialized command data

# Echo command for benchmarking
@lvclass(library='Benchmark', class_name='EchoCommand')
class EchoCommand:
    payload: str  # LVString - variable size payload
    timestamp: float  # LVDouble - client timestamp

# Server response
@lvclass(library='', class_name='Response')
class Response:
    request_id: str  # LVString - correlate with request
    success: bool  # LVBoolean - execution status
    exec_time: float  # LVDouble - server execution time (μs)
    message: str  # LVString - result or error message
2. Request-Response Architecture
Flow:

Client sends command with unique UUID
Server processes and responds with same UUID
Client correlates response using ResponseHandler
Calculate metrics: total_latency = response_time - request_time, network_latency = total_latency - exec_time
Benefits:

✅ Simple correlation with UUIDsBuilt-in execution time trackingDeterministic behavior (every request gets response)
✅ Easy timeout and retry logic
Optional: Fire-and-forget mode for commands not requiring responses

3. Package Structure
Code
af_server_client/
├── __init__. py
├── core/
│   ├── __init__.py
│   ├── tcp_client.py          # Asyncio TCP client with uvloop
│   ├── protocol.py             # @lvclass command definitions
│   ├── response_handler.py     # Request-response correlation
│   └── config.py               # TOML configuration loader
├── console/
│   ├── __init__.py
│   ├── app.py                  # Main Textual TUI application
│   ├── commands. py             # Command executor and registry
│   ├── widgets. py              # StatusPanel, LogViewer
│   └── command_parser. py       # Parse and validate commands
├── benchmark/
│   ├── __init__.py
│   ├── rtt_test.py             # Round-trip time benchmarking
│   ├── metrics.py              # Sample, BenchmarkRun classes
│   └── export.py               # JSON/CSV/Excel exporters
├── psychopy_bridge/
│   ├── __init__.py
│   ├── launcher.py             # Launch PsychoPy experiments
│   ├── subject_gui.py          # Subject interface (buttons/sliders)
│   └── shared_client.py        # Singleton TCP client
├── cli.py                       # CLI entry point
├── tests/
│   ├── test_tcp_client.py
│   ├── test_serialization.py
│   ├── test_benchmark.py
│   ├── test_console.py
│   └── test_response_handler.py
├── pyproject.toml               # Package metadata & dependencies
├── README.md                    # Documentation
├── af_server_config.toml        # Example configuration
└── . github/
    └── workflows/
        └── ci.yml               # GitHub Actions CI/CD
4. Interactive Console (Textual TUI)
Command Set:

connect <host> <port> - Establish TCP connection with retry logic
disconnect - Gracefully close connection
status - Display connection state, avg latency, pending requests, error count
send <command> [args...] - Send custom command to server
benchmark [iterations] [sizes...] - Run RTT benchmark (default: 10 iterations, sizes 0-8192 bytes)
launch-psychopy <experiment> - Start PsychoPy experiment in subprocess
config show - Display current configuration
config set <key> <value> - Update config and persist to TOML
config reload - Reload configuration from file
export <format> <filename> - Export benchmark data (json/csv/excel)
clear - Clear console log
help [command] - Show help for specific command or all
UI Components:

Header: App title and connection status
StatusPanel (top, 5 lines):
Connection: ✓ Connected to 127.0.0.1:2001 orDisconnected
Latency: Avg: 2.3ms | P95: 4.1ms | P99: 5.8ms
Requests: Pending: 0 | Completed: 1523 | Failed: 2
Uptime: Session: 00:15:43
RichLog (main area): Colored, timestamped log with markup support
Input (bottom): Command input with history navigation (↑/↓)
Footer: Keybindings (Ctrl+C: Quit, Ctrl+L: Clear)
Features:

Non-blocking async command execution
Command history (up to 100 entries)
Autocomplete suggestions
Real-time log updates from TCP event...

</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

Copilot AI self-assigned this Dec 3, 2025
Copilot AI and others added 2 commits December 3, 2025 11:50
… and benchmarking

Co-authored-by: Faragoz <62692906+Faragoz@users.noreply.github.com>
Co-authored-by: Faragoz <62692906+Faragoz@users.noreply.github.com>
Copilot AI changed the title [WIP] Add modular low-latency Python TCP client Implement AF-Server Client package for LabVIEW TCP communication Dec 3, 2025
Copilot AI requested a review from Faragoz December 3, 2025 12:02
@Faragoz
Copy link
Owner

Faragoz commented Dec 3, 2025

@copilot Acabé de poner el repositorio de AF-Serializer como publico, integralo y prueba si funciona con el codigo proporcionado.

Co-authored-by: Faragoz <62692906+Faragoz@users.noreply.github.com>
Copy link
Author

Copilot AI commented Dec 3, 2025

@copilot Acabé de poner el repositorio de AF-Serializer como publico, integralo y prueba si funciona con el codigo proporcionado.

Integrado y probado. AF-Serializer funciona correctamente con el código:

  • pip install git+https://github.com/Faragoz/AF-Serializer.git
  • Serialización de Protocol, EchoCommand, Response ✅
  • 96 tests pasando con el paquete real ✅
  • Corregida compatibilidad con uvloop

Commit: ee65be5

@Faragoz Faragoz marked this pull request as ready for review December 3, 2025 12:19
Copilot AI review requested due to automatic review settings December 3, 2025 12:19
@Faragoz Faragoz merged commit 453ef34 into main Dec 3, 2025
6 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a comprehensive AF-Server Client package for low-latency TCP communication with LabVIEW servers using the AF-Serializer protocol. The implementation follows a well-structured, modular architecture with multiple phases completed including core functionality, console UI, benchmarking, PsychoPy integration, and comprehensive testing.

Key Changes:

  • Asyncio-based TCP client with low-latency optimizations (TCP_NODELAY, QoS, uvloop)
  • Request-response architecture with UUID correlation and metrics tracking
  • Interactive Textual TUI console with real-time status monitoring and command execution
  • RTT benchmarking system with JSON/CSV/Excel export capabilities
  • PsychoPy integration for laboratory experiments with singleton client pattern
  • Mock AF-Serializer implementation for testing when the real package is unavailable
  • Comprehensive test suite with 96 passing tests

Reviewed changes

Copilot reviewed 35 out of 36 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
af_server_client/core/tcp_client.py Implements asyncio TCP client with low-latency optimizations; contains minor bugs with exception naming and uninitialized attribute
af_server_client/core/response_handler.py Manages request-response correlation with UUID tracking and metrics calculation
af_server_client/core/protocol.py Defines AF-Serializer protocol classes for commands and responses
af_server_client/core/config.py TOML-based configuration management with hot-reload support
af_server_client/console/app.py Main Textual TUI application with status panels and command execution
af_server_client/console/commands.py Command executor with registry pattern for console commands
af_server_client/console/command_parser.py Parses and validates console commands with history support
af_server_client/console/widgets.py Custom Textual widgets for status and progress display
af_server_client/benchmark/rtt_test.py RTT benchmarking implementation with progress callbacks
af_server_client/benchmark/metrics.py Data classes for benchmark samples and statistics
af_server_client/benchmark/export.py Export functionality for JSON/CSV/Excel formats
af_server_client/psychopy_bridge/shared_client.py Singleton pattern for shared TCP client; has lock initialization issue
af_server_client/psychopy_bridge/launcher.py Subprocess launcher for PsychoPy experiments
af_server_client/psychopy_bridge/subject_gui.py PsychoPy-based subject interface with buttons and sliders
af_server_client/cli.py CLI entry point with argparse configuration; minor style issue
af_server_client/_mock/af_serializer.py Mock implementation for testing without real AF-Serializer package
tests/*.py Comprehensive test suite covering all major components
pyproject.toml Package configuration with dependencies and build settings
af_server_config.toml Example configuration file with all available settings
.github/workflows/ci.yml CI pipeline with linting, type checking, and testing
README.md Comprehensive documentation with usage examples and API reference

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


except asyncio.TimeoutError as e:
sock.close()
raise ConnectionError(f"Connection timed out to {target_host}:{target_port}") from e
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing format string parameter. The test expects the error message to include "timed out", but the ConnectionError is raised with just a format string placeholder without the actual host/port values being formatted in.

Copilot uses AI. Check for mistakes.
"""Base exception for TCP client errors."""


class ConnectionError(TCPClientError):
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name ConnectionError conflicts with Python's built-in ConnectionError exception. This shadowing can cause confusion and potential bugs when trying to catch the built-in exception. Consider renaming to TCPConnectionError or ClientConnectionError.

Suggested change
class ConnectionError(TCPClientError):
class TCPConnectionError(TCPClientError):

Copilot uses AI. Check for mistakes.
self.reader, self.writer = await asyncio.open_connection(sock=sock)
self.connected = True
self._connection_time = time.time()
self._reconnect_attempts = 0
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _reconnect_attempts attribute is set but never defined in __init__. This will cause an AttributeError if the attribute is accessed elsewhere in the code. Either add this to __init__ or remove the assignment if it's unused.

Copilot uses AI. Check for mistakes.
_instance: Optional["SharedClient"] = None
_client: Optional["TCPClient"] = None
_config: Optional["Config"] = None
_lock = asyncio.Lock()
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class-level asyncio.Lock() is created at module import time, which may cause issues if the event loop hasn't been initialized yet. Consider creating the lock lazily on first access or within an async context to avoid potential RuntimeError: no running event loop errors.

Copilot uses AI. Check for mistakes.

if TYPE_CHECKING:
from af_server_client.core.config import Config

Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing blank line before function definition according to PEP 8 style guidelines.

Suggested change

Copilot uses AI. Check for mistakes.
license = {text = "MIT"}

dependencies = [
"af-serializer @ git+https://github.com/Faragoz/AF-Serializer.git",
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency af-serializer @ git+https://github.com/Faragoz/AF-Serializer.git is a VCS URL without a pinned commit/tag, creating a supply-chain risk: upstream changes (or repo compromise) can silently alter installed code and execute during install/import. Pin to an immutable reference or a published package to ensure integrity, e.g.

# Pin to a specific commit SHA
"af-serializer @ git+https://github.com/Faragoz/AF-Serializer.git@<commit_sha>"

# Prefer published versions on PyPI with version constraints
"af-serializer==<version>"
Suggested change
"af-serializer @ git+https://github.com/Faragoz/AF-Serializer.git",
"af-serializer @ git+https://github.com/Faragoz/AF-Serializer.git@<commit_sha>",

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants