homelab/services/device-inventory/src/common/protocol.h
Dan V 69113c1ea7 feat: richer hardware discovery — CPU cache/voltage, memory type/bandwidth/part-no, GPU discovery
- CPU: max speed, bus MHz, L1/L2/L3 cache (from sysfs), voltage, socket type; /proc/cpuinfo fallback for non-root
- Memory sticks: DDR type, form factor, part number, rank, data width, theoretical bandwidth
- GPU: new part type discovered via lspci + /sys/class/drm + nvidia-smi; shows VRAM and display outputs
- discover-only tree updated to show all new fields

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-01 01:20:33 +02:00

192 lines
8.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <sstream>
#include <string>
#include <vector>
// ─────────────────────────────────────────────────────────────────────────────
// Network
// ─────────────────────────────────────────────────────────────────────────────
constexpr uint16_t DEFAULT_PORT = 9876;
// ─────────────────────────────────────────────────────────────────────────────
// Wire-format separators
// ─────────────────────────────────────────────────────────────────────────────
// FS (field separator) SOH 0x01 splits top-level tokens in a command line
constexpr char FS = '\x01';
// LS (list separator) used to encode lists inside a single field value
// e.g. ip_addresses field: "192.168.1.2/24\x02fe80::1/64"
constexpr char LS = '\x02';
// ─────────────────────────────────────────────────────────────────────────────
// Wire format
//
// Client → Server (one line per request):
// COMMAND<FS>arg1<FS>arg2…<newline>
//
// Server → Client:
// OK<newline>
// <data-row-line><newline> ← 0 or more rows
// END<newline>
// or
// ERR <message><newline>
//
// Key-value part commands:
// ADD_PART <type><FS>server_id<FS><int><FS>key1<FS>val1<FS>key2<FS>val2…
// UPSERT_PART <type><FS>server_id<FS><int><FS>key1<FS>val1…
// (insert or update matching an existing part by serial/mac)
// EDIT_PART <part_id><FS>key1<FS>val1<FS>key2<FS>val2…
// REMOVE_PART <part_id>
// LIST_PARTS <server_id> [optional: <FS><type>]
// GET_PART <part_id>
//
// List field values are encoded as val1<LS>val2<LS>val3
// (empty string encodes an empty list)
//
// Null / absent optional fields are sent as the literal string "NULL"
// ─────────────────────────────────────────────────────────────────────────────
// Server management
constexpr const char* CMD_ADD_SERVER = "ADD_SERVER";
constexpr const char* CMD_LIST_SERVERS = "LIST_SERVERS";
constexpr const char* CMD_EDIT_SERVER = "EDIT_SERVER";
constexpr const char* CMD_REMOVE_SERVER = "REMOVE_SERVER";
// Part type (label) management
constexpr const char* CMD_ADD_PART_TYPE = "ADD_PART_TYPE";
constexpr const char* CMD_LIST_PART_TYPES = "LIST_PART_TYPES";
constexpr const char* CMD_EDIT_PART_TYPE = "EDIT_PART_TYPE";
constexpr const char* CMD_REMOVE_PART_TYPE = "REMOVE_PART_TYPE";
// Typed part management
constexpr const char* CMD_ADD_PART = "ADD_PART";
constexpr const char* CMD_UPSERT_PART = "UPSERT_PART"; // for discovery
constexpr const char* CMD_EDIT_PART = "EDIT_PART";
constexpr const char* CMD_REMOVE_PART = "REMOVE_PART";
constexpr const char* CMD_LIST_PARTS = "LIST_PARTS";
constexpr const char* CMD_GET_PART = "GET_PART";
// Response sentinels
constexpr const char* RESP_OK = "OK";
constexpr const char* RESP_ERR = "ERR";
constexpr const char* RESP_END = "END";
// ─────────────────────────────────────────────────────────────────────────────
// Field keys for each specialized part type
// (shared between client serializer and server deserializer)
// ─────────────────────────────────────────────────────────────────────────────
// PartBase common keys
constexpr const char* K_SERIAL = "serial";
constexpr const char* K_LAST_UPDATED = "last_updated";
// Natural keys for deduplication when serial is absent
constexpr const char* K_LOCATOR = "locator"; // DIMM locator for memory
constexpr const char* K_SOCKET = "socket_designation"; // CPU socket label
constexpr const char* K_DEVICE_NAME = "device_name"; // block device name (sda, nvme0n1…)
// MemoryStick
constexpr const char* K_SPEED_MHZ = "speed_mhz";
constexpr const char* K_SIZE_MB = "size_mb";
constexpr const char* K_MANUFACTURER = "manufacturer";
constexpr const char* K_CHANNEL_CONFIG = "channel_config";
constexpr const char* K_OTHER_INFO = "other_info";
// MemorySlot
constexpr const char* K_ALLOWED_SPEED = "allowed_speed_mhz";
constexpr const char* K_ALLOWED_SIZE = "allowed_size_mb";
constexpr const char* K_INSTALLED_STICK = "installed_stick_id";
// CPU
constexpr const char* K_NAME = "name";
constexpr const char* K_SPEED_GHZ = "speed_ghz";
constexpr const char* K_CORES = "cores";
constexpr const char* K_THREADS = "threads";
// CPU extended
constexpr const char* K_MAX_SPEED_GHZ = "max_speed_ghz";
constexpr const char* K_BUS_MHZ = "bus_speed_mhz";
constexpr const char* K_CACHE_L1_KB = "cache_l1_kb";
constexpr const char* K_CACHE_L2_KB = "cache_l2_kb";
constexpr const char* K_CACHE_L3_KB = "cache_l3_kb";
constexpr const char* K_VOLTAGE_V = "voltage_v";
constexpr const char* K_SOCKET_TYPE = "socket_type";
// CPUSlot
constexpr const char* K_FORM_FACTOR = "form_factor";
constexpr const char* K_INSTALLED_CPU = "installed_cpu_id";
// Disk
constexpr const char* K_MODEL = "model";
constexpr const char* K_GENERATION = "generation";
constexpr const char* K_CONN_TYPE = "connection_type";
constexpr const char* K_CONN_SPEED = "connection_speed_mbps";
constexpr const char* K_DISK_SPEED = "disk_speed_mbps";
constexpr const char* K_DISK_SIZE = "disk_size_gb";
constexpr const char* K_DISK_TYPE = "disk_type";
constexpr const char* K_AGE_YEARS = "age_years";
constexpr const char* K_PARTITION_IDS = "partition_ids"; // LS-separated
constexpr const char* K_PARTITION_SIZES = "partition_sizes_gb"; // LS-separated
constexpr const char* K_VM_HOSTNAMES = "vm_hostnames"; // LS-separated
constexpr const char* K_VM_SERVER_IDS = "vm_server_ids"; // LS-separated
// NetworkCard
constexpr const char* K_AGE_YEARS_NIC = "age_years"; // same key, different struct
constexpr const char* K_SPEED_MBPS = "connection_speed_mbps";
constexpr const char* K_MAC = "mac_address";
constexpr const char* K_IPS = "ip_addresses"; // LS-separated
constexpr const char* K_DHCP = "dhcp";
// MemoryStick extended
constexpr const char* K_MEM_TYPE = "memory_type";
constexpr const char* K_PART_NUMBER = "part_number";
constexpr const char* K_RANK = "rank";
constexpr const char* K_DATA_WIDTH = "data_width_bits";
constexpr const char* K_BANDWIDTH_MBPS = "bandwidth_mbps";
// GPU
constexpr const char* K_VRAM_MB = "vram_mb";
constexpr const char* K_GPU_BANDWIDTH_MBPS = "gpu_bandwidth_mbps";
constexpr const char* K_DISPLAY_OUTPUTS = "display_outputs";
// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────
inline std::vector<std::string> split(const std::string& s, char delim) {
std::vector<std::string> parts;
std::stringstream ss(s);
std::string token;
while (std::getline(ss, token, delim))
parts.push_back(token);
return parts;
}
inline std::string join(const std::vector<std::string>& v, char delim) {
std::string out;
for (size_t i = 0; i < v.size(); ++i) {
if (i) out += delim;
out += v[i];
}
return out;
}
inline std::string join_u64(const std::vector<uint64_t>& v, char delim) {
std::string out;
for (size_t i = 0; i < v.size(); ++i) {
if (i) out += delim;
out += std::to_string(v[i]);
}
return out;
}
inline std::string join_u32(const std::vector<uint32_t>& v, char delim) {
std::string out;
for (size_t i = 0; i < v.size(); ++i) {
if (i) out += delim;
out += std::to_string(v[i]);
}
return out;
}