Metadata-Version: 2.4
Name: easy-asocket
Version: 0.1.0
Summary: A user-friendly asynchronous socket wrapper with a simple communication protocol, currently available for Python and C++.
Author-email: Red Elephant <redelephant@foxmail.com>
License-Expression: MIT
Keywords: image,annotation,labeling,gui
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Provides-Extra: dev

# easy-asocket

A user-friendly asynchronous socket wrapper with a simple communication protocol, currently available for Python and C++.

## Features

- **Asynchronous I/O**: Built on Python's `asyncio` for high-performance network communication
- **Simple Protocol**: Lightweight application-layer protocol with CRC16 checksum validation
- **Request-Response Pattern**: Built-in support for request-response communication with automatic message ID management
- **Multi-Client Server**: Server can handle multiple concurrent client connections
- **Cross-Language Support**: Available for both Python and C++

## Installation

```bash
pip install easy-asocket
```

## Quick Start

### Server Example

```python
import asyncio
from easy_asocket import SocketServer, SimpleProtocol

def on_request(pkg: SimpleProtocol, client_id: int):
    """Callback function to handle received requests"""
    print(f'Received data from client {client_id}:')
    print(f'  Message ID: {pkg.get_msgid()}')
    print(f'  CMD: {pkg.get_cmd()}')
    print(f'  Data: {pkg.get_data()}')
    
    # Create and send response
    resp = SimpleProtocol()
    resp.set_msgid(pkg.get_msgid())  # Use same message ID
    resp.set_cmd(pkg.get_cmd())      # Use same command
    resp.set_data(b'Response data')  # Set response data
    
    # Send response asynchronously
    asyncio.create_task(server.response(resp, client_id))

async def main():
    server = SocketServer(22334)
    server.set_request_callback(on_request)
    await server.start()

if __name__ == "__main__":
    asyncio.run(main())
```

### Client Example

```python
import asyncio
import easy_asocket as eas

def on_request(pkg: eas.SimpleProtocol):
    """Callback function to handle received requests from server"""
    print(f"Received request:")
    print(f"  Message ID: {pkg.get_msgid()}")
    print(f"  CMD: {pkg.get_cmd()}")
    print(f"  Data: {pkg.get_data()}")

async def main():
    client = eas.SocketClient("127.0.0.1", 22334)
    
    # Set callback to handle received requests
    client.set_request_callback(on_request)
    
    # Connect to server
    await client.connect()
    
    # Send a request and wait for response
    pkg = eas.SimpleProtocol()
    pkg.set_cmd(0x0001)
    pkg.set_data(b'Hello, Server!')
    
    success, response = await client.request(pkg, expect_response=True, timeout=5.0)
    if success:
        print(f"Response received: {response.get_data()}")
    
    # Keep connection alive
    await asyncio.sleep(3600)  # Keep running for 1 hour

if __name__ == "__main__":
    asyncio.run(main())
```

## API Reference

### SocketServer

Server class for accepting multiple client connections.

#### Methods

- `__init__(port: int)`: Initialize server on specified port
- `set_request_callback(callback: Callable[[SimpleProtocol, int], None])`: Set callback function to handle incoming requests. The callback receives the protocol package and client ID.
- `async start()`: Start the server and begin accepting connections
- `async stop()`: Stop the server and close all connections
- `async response(pkg: SimpleProtocol, client_id: int)`: Send a response to a specific client
- `async request(pkg: SimpleProtocol, client_id: int, expect_response: bool = False, timeout: float = 5.0)`: Send a request to a specific client

### SocketClient

Client class for connecting to a server.

#### Methods

- `__init__(host: str, port: int)`: Initialize client with server address
- `set_request_callback(callback: Callable[[SimpleProtocol], None])`: Set callback function to handle incoming requests from server
- `async connect()`: Connect to the server
- `async disconnect()`: Disconnect from the server
- `async request(pkg: SimpleProtocol, expect_response: bool = False, timeout: float = 5.0) -> Tuple[bool, SimpleProtocol]`: Send a request. Returns `(success, response)` tuple.
- `async response(pkg: SimpleProtocol)`: Send a response

### SimpleProtocol

Protocol class for encoding and decoding messages.

#### Methods

- `set_msgid(msg_id: int)`: Set message ID
- `get_msgid() -> int`: Get message ID
- `set_cmd(cmd: int)`: Set command code
- `get_cmd() -> int`: Get command code
- `set_direction(direction: int)`: Set direction (DIRECTION_REQUEST or DIRECTION_RESPONSE)
- `get_direction() -> int`: Get direction
- `set_data(data: bytes)`: Set data payload
- `get_data() -> bytes`: Get data payload (reference)
- `get_data_copy() -> bytes`: Get data payload (copy)
- `encode() -> bytes`: Encode protocol data into byte array
- `decode(data: bytes) -> bool`: Decode byte array into protocol data. Returns `True` if successful.

#### Constants

- `DIRECTION_REQUEST = 0x00`: Request direction
- `DIRECTION_RESPONSE = 0x01`: Response direction

## Protocol Format

The SimpleProtocol uses the following structure:

```
[Header(2)][Direction(1)][MessageID(2)][Length(4)][CMD(2)][Data(N)][CRC16(2)][Footer(2)]
```

- **Header**: `0xAA 0x55`
- **Direction**: `0x00` (request) or `0x01` (response)
- **MessageID**: 16-bit unsigned integer
- **Length**: 32-bit unsigned integer (data length)
- **CMD**: 16-bit unsigned integer (command code)
- **Data**: Variable length byte array
- **CRC16**: 16-bit CRC checksum
- **Footer**: `0x55 0xAA`

## C++ Support

The library also provides C++ headers and implementation files. To get the C++ include directory path:

```bash
easy-asocket-cppdir
```

This will print the path to the C++ headers directory, which you can use in your CMake configuration.

### Dependencies

The C++ implementation requires **Boost.Asio** library. Make sure you have Boost installed on your system before using the C++ headers.

#### Installing Boost

**Ubuntu/Debian:**
```bash
sudo apt-get install libboost-all-dev
```

**macOS (using Homebrew):**
```bash
brew install boost
```

**Windows (using vcpkg):**
```bash
vcpkg install boost-asio
```

#### CMake Configuration

When using CMake, you can find Boost and link against it:

```cmake
find_package(Boost REQUIRED COMPONENTS system)
target_link_libraries(your_target PRIVATE Boost::system)
```

## License

MIT License

## Author

Red Elephant (redelephant@foxmail.com)
