# adas-core.module.ProxyDevices — Proxy Devices Module

> A **functional module** of the ADAS Core platform.  
> Encapsulates all logic for proxying communication with external hardware devices over HTTP. This module acts as a configurable gateway layer that the Host registers at startup, translating internal requests into authenticated HTTP calls to remote endpoints.

---

## Table of Contents

1. [Overview](#overview)
2. [Responsibilities](#responsibilities)
3. [Project Structure](#project-structure)
4. [Dependencies](#dependencies)
5. [Device Proxy Architecture](#device-proxy-architecture)
6. [ProxyDeviceService Flow](#proxydeviceservice-flow)
7. [Design Rules](#design-rules)

---

## Overview

`adas-core.module.ProxyDevices` is a modular satellite project that provides a **proxy gateway** for interacting with external hardware devices over HTTP. It abstracts the complexity of device authentication, connection management, and response handling behind a uniform `IProxyDevice` contract.

Key characteristics:

- **Modular Monolith Pattern** — Self-contained module with its own device drivers, service orchestration, and configuration model. No other module depends on it directly.
- **Plugin Architecture** — New device types are added by creating a class that implements `IProxyDevice` and naming it `{Type}Device`. The service discovers and instantiates them at runtime via reflection.
- **Digest Authentication Support** — The built-in `HttpDevice` supports HTTP Digest authentication via `NetworkCredential`.
- **Instance Caching** — `ProxyDeviceService` maintains an in-memory cache of initialized device instances to avoid repeated construction and initialization overhead.
- **Dual Operation Modes** — Each device supports both `Process()` (full response) and `Stream()` (response-headers-read) operations.
- **Configuration-Driven** — All devices, their types, and parameters are defined in `ProxyDeviceSettings` bound from `appsettings.json`.

---

## Responsibilities

| Concern | What this project does |
|---------|----------------------|
| **Device Proxying** | Acts as an intermediary between the Host and external HTTP-based devices, shielding the rest of the system from protocol specifics. |
| **Device Lifecycle** | Manages device initialization, caching, and disposal through the `IProxyDevice` contract. |
| **HTTP Communication** | `HttpDevice` performs authenticated and unauthenticated HTTP GET requests with timeout handling. |
| **Digest Authentication** | Supports HTTP Digest auth via `username`, `password`, and optional `domain` parameters. |
| **Reflection-Based Factory** | `ProxyDeviceService` dynamically instantiates device classes by type name at runtime (`{Type}Device`). |
| **Instance Caching** | Caches initialized `IProxyDevice` instances per `deviceId` to minimize repeated setup costs. |
| **Streaming vs Processing** | Offers `Process()` for complete responses and `Stream()` for streaming (headers-first) scenarios. |
| **Error Translation** | Converts `HttpRequestException`, `TaskCanceledException`, and missing-device errors into standardized `HttpResponseMessage` responses. |
| **Configuration Model** | Defines `ProxyDeviceSettings` and `ProxyDevice` as strongly-typed configuration objects bound from the Host's configuration system. |
| **Audit Logging** | Emits audit events for device access and proxy operations via `AuditLogs`. |

---

## Project Structure

```
adas-core.module.ProxyDevices/
├── ProxyDeviceSettings.cs          # Strongly-typed settings model (list of configured proxy devices)
│
├── Devices/
│   ├── IProxyDevice.cs             # Core contract: Initialize, Process, Stream
│   └── HttpDevice.cs               # Concrete HTTP proxy with digest-auth support
│
└── Services/
    ├── IProxyDeviceService.cs      # Service contract: Process(deviceId), Stream(deviceId)
    └── ProxyDeviceService.cs       # Orchestrator: reflection factory, caching, error handling
```

| File | Role |
|------|------|
| `ProxyDeviceSettings.cs` | Configuration root. A `List<ProxyDevice>` bound from `appsettings.json`. Each entry defines `Id`, `Type`, `Enabled`, and `Parameters`. |
| `IProxyDevice.cs` | Interface contract. All proxy devices implement `Initialize(Dictionary)`, `Process()`, and `Stream()`. |
| `HttpDevice.cs` | Concrete proxy for HTTP endpoints. Validates `url`, optional digest auth, performs GET requests, handles timeouts. |
| `IProxyDeviceService.cs` | Application-facing contract. Host controllers depend on this interface, not on module internals. |
| `ProxyDeviceService.cs` | Implementation. Reads settings, looks up devices by `Id`, lazily instantiates and caches drivers, delegates to `Process()` or `Stream()`. |

---

## Dependencies

### Downstream References

This project has **no direct project references** to other ADAS Core projects. It is a completely decoupled satellite module.

| Package | Version | Purpose |
|---------|---------|---------|
| `Microsoft.Extensions.DependencyInjection` | 10.0.8 | DI registration helpers used during Host startup. |
| `Microsoft.Extensions.Hosting` | 10.0.8 | Hosting abstractions for optional background proxy services. |

### Upstream References (projects that depend on this)

| Project | Reason |
|---------|--------|
| `adas-core` (Host) | Registers `IProxyDeviceService` and `ProxyDeviceSettings` at startup. Host controllers invoke `Process()` and `Stream()` through the service interface. |

### NuGet Packages

| Package | Version | Purpose |
|---------|---------|---------|
| `Microsoft.Extensions.DependencyInjection` | 10.0.8 | Service-collection registration helpers. |
| `Microsoft.Extensions.Hosting` | 10.0.8 | Hosting abstractions for background services. |
| `Serilog` | 4.3.1 | Structured logging for timeout and HTTP error events. |
| `AuditLogs` | 1.0.59 | Audit trail emission for device access and proxy operations. |
| `SharpCompress` | 0.49.0 | Available for potential compression pipelines in future device types. |
| `Snappier` | 1.3.1 | Fast compression library for future streaming optimization. |

---

## Device Proxy Architecture

### `IProxyDevice` Contract

```csharp
public interface IProxyDevice
{
    void Initialize(Dictionary<string, object?> deviceParameters);
    Task<HttpResponseMessage> Process();
    Task<HttpResponseMessage> Stream();
}
```

| Member | Purpose |
|--------|---------|
| `Initialize(parameters)` | One-time setup. Validates required keys (`url`), extracts optional keys (`name`, `username`, `password`, `domain`), and marks the device as ready. |
| `Process()` | Performs a full HTTP GET request and returns the complete `HttpResponseMessage`. |
| `Stream()` | Performs an HTTP GET with `HttpCompletionOption.ResponseHeadersRead`, enabling callers to stream the body without buffering. |

### `HttpDevice` — Built-in HTTP Proxy

- **URI Validation** — Requires a non-empty, absolute `url` in parameters. Throws `ArgumentNullException` if missing or invalid.
- **Single Initialization Guard** — Throws `InvalidOperationException` if `Initialize()` is called twice.
- **Optional Digest Auth** — When `username` is provided, sets `HttpClientHandler.Credentials` with `NetworkCredential(username, password, domain)`.
- **Timeout Translation** — Catches `TaskCanceledException` (timeout) and re-throws as `TimeoutException` with a descriptive message.
- **Diagnostics** — Overrides `ToString()` to emit `[HttpDevice] (name uri username password domain)` for logging.

### Adding a New Device Type

1. Create a class in `Devices/` that implements `IProxyDevice`.
2. Name it `{Type}Device` (e.g., `TcpDevice`, `UdpDevice`).
3. Register the type string in `appsettings.json` under `ProxyDeviceSettings`.
4. `ProxyDeviceService` will resolve it automatically via reflection at first use.


## ProxyDeviceService Flow

### Device Resolution & Caching

```
[Host Controller] --> [ProxyDeviceService.Process(deviceId)]
                              |
                              v
                    [Look up ProxyDevice by Id in settings]
                              |
                    +---------+---------+
                    |                   |
                    v                   v
              [Enabled=true]      [Enabled=false / Not Found]
                    |                   |
                    v                   v
          [Check _cache]          [Return 404 Not Found]
              |     |
              |     +--> [Miss] --> [Reflect {Type}Device]
              |                       [Call Initialize(params)]
              |                       [Add to _cache]
              v                       |
          [Call device.Process()] <--+
              |
              v
          [Return HttpResponseMessage]
```

### Key Behaviors

- **Thread-Safe Cache** — The `_cache` dictionary is guarded by a `lock` during read/write to prevent race conditions.
- **Lazy Instantiation** — Devices are created only on first access, not at startup.
- **Graceful Degradation** — If a device is not found, disabled, or throws `HttpRequestException`, the service returns an `HttpResponseMessage` with an appropriate status code rather than crashing.
- **No Dispose Lifecycle** — Cached instances are reused for the lifetime of the service. The Host manages the service scope (typically Singleton).

---

## Design Rules

1. **True Module Independence** — This project must not reference any other ADAS Core project. It communicates with the Host exclusively through its own public interfaces and the .NET configuration/options system.
2. **Configuration-Driven Discovery** — Device types, endpoints, and credentials must come exclusively from `ProxyDeviceSettings` bound to `appsettings.json`. No hardcoded URLs or auth secrets.
3. **Reflection Factory** — New device types are added by convention (`{Type}Device` implementing `IProxyDevice`). No central switch statement needs modification (Open/Closed).
4. **Cache Safety** — The device instance cache is protected by a `lock` during writes. Reads inside the lock are safe because initialization is atomic.
5. **Fail Securely** — Missing or disabled devices return `404 Not Found`. HTTP failures are translated into `HttpResponseMessage` with the original status code. Timeouts become `TimeoutException`.
6. **No Business Logic** — This module handles transport only. Any transformation, validation, or business-rule enforcement belongs in `Application` or the Host.
7. **Lazy Initialization** — Devices are instantiated on first request, not at Host startup. This prevents delaying startup when a remote device is unreachable.
8. **Digest Auth Only** — `HttpDevice` supports HTTP Digest authentication. Basic auth, bearer tokens, or mTLS must be implemented in a separate `IProxyDevice` implementation if needed.
9. **Audit Every Access** — Every `Process()` and `Stream()` call emits an audit event via `AuditLogs` tagging the device ID and outcome.
10. **Singleton Service** — `ProxyDeviceService` is registered as a **Singleton** because it holds cached device instances and settings that are immutable after startup.

---

<p align="center">
  Back to <a href="../README.md">adas-core Root README</a>
</p>
