Initial idea
This commit is contained in:
57
CMSCore.sln
Normal file
57
CMSCore.sln
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anscloud-common", "anscloud-common\anscloud-common.vcxproj", "{B1A2C3D4-0001-4000-8000-000000000001}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anscloud-device", "anscloud-device\anscloud-device.vcxproj", "{B1A2C3D4-0001-4000-8000-000000000002}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anscloud-gateway", "anscloud-gateway\anscloud-gateway.vcxproj", "{B1A2C3D4-0001-4000-8000-000000000003}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-device", "test-device\test-device.vcxproj", "{B1A2C3D4-0001-4000-8000-000000000004}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test-gateway", "test-gateway\test-gateway.vcxproj", "{B1A2C3D4-0001-4000-8000-000000000005}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{F0000000-0000-4000-8000-000000000001}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F0000000-0000-4000-8000-000000000002}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B1A2C3D4-0001-4000-8000-000000000001}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000001}.Debug|x64.Build.0 = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000001}.Release|x64.ActiveCfg = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000001}.Release|x64.Build.0 = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000002}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000002}.Debug|x64.Build.0 = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000002}.Release|x64.ActiveCfg = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000002}.Release|x64.Build.0 = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000003}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000003}.Debug|x64.Build.0 = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000003}.Release|x64.ActiveCfg = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000003}.Release|x64.Build.0 = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000004}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000004}.Debug|x64.Build.0 = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000004}.Release|x64.ActiveCfg = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000004}.Release|x64.Build.0 = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000005}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000005}.Debug|x64.Build.0 = Debug|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000005}.Release|x64.ActiveCfg = Release|x64
|
||||
{B1A2C3D4-0001-4000-8000-000000000005}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{B1A2C3D4-0001-4000-8000-000000000001} = {F0000000-0000-4000-8000-000000000001}
|
||||
{B1A2C3D4-0001-4000-8000-000000000002} = {F0000000-0000-4000-8000-000000000001}
|
||||
{B1A2C3D4-0001-4000-8000-000000000003} = {F0000000-0000-4000-8000-000000000001}
|
||||
{B1A2C3D4-0001-4000-8000-000000000004} = {F0000000-0000-4000-8000-000000000002}
|
||||
{B1A2C3D4-0001-4000-8000-000000000005} = {F0000000-0000-4000-8000-000000000002}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
247
_gen_src_01.py
Normal file
247
_gen_src_01.py
Normal file
@@ -0,0 +1,247 @@
|
||||
import os
|
||||
R = r"C:\Projects\CMSCore"
|
||||
def w(rel, txt):
|
||||
p = os.path.join(R, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8", newline="\r\n") as f:
|
||||
f.write(txt.lstrip("\n"))
|
||||
print(f" OK: {rel}")
|
||||
|
||||
# ============================================================================
|
||||
# 1. anscloud-common/include/anscloud/common/types.h
|
||||
# ============================================================================
|
||||
w("anscloud-common/include/anscloud/common/types.h", r'''#pragma once
|
||||
// ==========================================================================
|
||||
// ANSCloud SDK - Common Types
|
||||
// ANSCENTER Pty Ltd - Cloud Messaging Protocol Types
|
||||
// ==========================================================================
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Protocol version
|
||||
// --------------------------------------------------------------------------
|
||||
constexpr const char* PROTOCOL_VERSION = "1.0.0";
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Exchange names (must match RabbitMQ broker topology)
|
||||
// --------------------------------------------------------------------------
|
||||
namespace exchange {
|
||||
constexpr const char* DEVICE_TELEMETRY = "ex.device.telemetry";
|
||||
constexpr const char* DEVICE_STATUS = "ex.device.status";
|
||||
constexpr const char* DEVICE_EVENTS = "ex.device.events";
|
||||
constexpr const char* COMMAND = "ex.command";
|
||||
constexpr const char* COMMAND_RESPONSE = "ex.command.response";
|
||||
constexpr const char* BROADCAST = "ex.broadcast";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Queue name builders
|
||||
// --------------------------------------------------------------------------
|
||||
namespace queue {
|
||||
inline std::string device_command(const std::string& device_id) { return "q.cmd." + device_id; }
|
||||
inline std::string device_broadcast(const std::string& device_id){ return "q.broadcast." + device_id; }
|
||||
// Gateway-side queues (shared)
|
||||
constexpr const char* TELEMETRY_INGEST = "q.telemetry.ingest";
|
||||
constexpr const char* EVENTS_PROCESSOR = "q.events.processor";
|
||||
constexpr const char* STATUS_TRACKER = "q.status.tracker";
|
||||
constexpr const char* COMMAND_RESPONSES = "q.command.responses";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Device Status
|
||||
// --------------------------------------------------------------------------
|
||||
enum class DeviceStatus {
|
||||
Unknown = 0,
|
||||
Online,
|
||||
Offline,
|
||||
Connecting,
|
||||
Error
|
||||
};
|
||||
const char* to_string(DeviceStatus s);
|
||||
DeviceStatus device_status_from_string(const std::string& s);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Command Types
|
||||
// --------------------------------------------------------------------------
|
||||
enum class CommandType {
|
||||
Custom = 0,
|
||||
GetSystemInfo,
|
||||
GetConfig,
|
||||
SetConfig,
|
||||
GetCameraList,
|
||||
AddCamera,
|
||||
RemoveCamera,
|
||||
UpdateCamera,
|
||||
GetCameraSnapshot,
|
||||
StartStream,
|
||||
StopStream,
|
||||
RestartService,
|
||||
RebootDevice,
|
||||
UpdateFirmware,
|
||||
RunDiagnostics,
|
||||
GetLogs,
|
||||
SetSchedule,
|
||||
GetSchedule
|
||||
};
|
||||
const char* to_string(CommandType t);
|
||||
CommandType command_type_from_string(const std::string& s);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Event Types
|
||||
// --------------------------------------------------------------------------
|
||||
enum class EventType {
|
||||
Custom = 0,
|
||||
Alert,
|
||||
DetectionLPR,
|
||||
DetectionFace,
|
||||
DetectionObject,
|
||||
DetectionMotion,
|
||||
LineCrossing,
|
||||
Intrusion,
|
||||
Loitering,
|
||||
CameraDisconnected,
|
||||
CameraReconnected,
|
||||
StorageWarning,
|
||||
SystemError
|
||||
};
|
||||
const char* to_string(EventType t);
|
||||
EventType event_type_from_string(const std::string& s);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Command Status
|
||||
// --------------------------------------------------------------------------
|
||||
enum class CommandStatus {
|
||||
Success = 0,
|
||||
Failed,
|
||||
Timeout,
|
||||
Rejected,
|
||||
Pending,
|
||||
PartialSuccess
|
||||
};
|
||||
const char* to_string(CommandStatus s);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Data structures
|
||||
// --------------------------------------------------------------------------
|
||||
struct SystemMetrics {
|
||||
double cpu_usage_percent = 0.0;
|
||||
double ram_usage_percent = 0.0;
|
||||
uint64_t ram_total_mb = 0;
|
||||
uint64_t ram_used_mb = 0;
|
||||
double gpu_usage_percent = 0.0;
|
||||
double gpu_memory_percent = 0.0;
|
||||
double gpu_temperature_c = 0.0;
|
||||
double disk_usage_percent = 0.0;
|
||||
uint64_t disk_total_gb = 0;
|
||||
uint64_t disk_used_gb = 0;
|
||||
double cpu_temperature_c = 0.0;
|
||||
uint32_t process_count = 0;
|
||||
double network_rx_mbps = 0.0;
|
||||
double network_tx_mbps = 0.0;
|
||||
};
|
||||
|
||||
struct CameraInfo {
|
||||
std::string camera_id;
|
||||
std::string name;
|
||||
std::string rtsp_url;
|
||||
std::string status; // "online", "offline", "error"
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
double fps = 0.0;
|
||||
std::string codec;
|
||||
std::string ai_models; // comma-separated model names
|
||||
bool recording = false;
|
||||
};
|
||||
|
||||
struct InferenceMetrics {
|
||||
uint32_t active_models = 0;
|
||||
double avg_latency_ms = 0.0;
|
||||
double total_fps = 0.0;
|
||||
uint64_t total_detections = 0;
|
||||
};
|
||||
|
||||
struct Heartbeat {
|
||||
std::string device_id;
|
||||
std::string timestamp; // ISO 8601
|
||||
DeviceStatus status = DeviceStatus::Online;
|
||||
uint64_t uptime_seconds = 0;
|
||||
std::string firmware_version;
|
||||
std::string ansvis_version;
|
||||
};
|
||||
|
||||
struct DeviceTelemetry {
|
||||
std::string device_id;
|
||||
std::string timestamp;
|
||||
SystemMetrics metrics;
|
||||
std::vector<CameraInfo> cameras;
|
||||
InferenceMetrics inference;
|
||||
};
|
||||
|
||||
struct Command {
|
||||
std::string command_id; // UUID
|
||||
std::string device_id; // target device
|
||||
CommandType type = CommandType::Custom;
|
||||
std::string type_name; // string name for Custom commands
|
||||
std::string params_json; // JSON string with command parameters
|
||||
std::string correlation_id; // for RPC matching
|
||||
std::string reply_to; // reply queue/routing key
|
||||
int timeout_seconds = 30;
|
||||
std::string timestamp;
|
||||
};
|
||||
|
||||
struct CommandResponse {
|
||||
std::string command_id;
|
||||
std::string device_id;
|
||||
CommandStatus status = CommandStatus::Success;
|
||||
std::string result_json; // JSON string with results
|
||||
std::string error_message;
|
||||
std::string correlation_id;
|
||||
double execution_time_ms = 0.0;
|
||||
std::string timestamp;
|
||||
};
|
||||
|
||||
struct DeviceEvent {
|
||||
std::string event_id; // UUID
|
||||
std::string device_id;
|
||||
EventType type = EventType::Custom;
|
||||
std::string type_name;
|
||||
std::string camera_id; // optional, which camera
|
||||
std::string data_json; // event payload
|
||||
std::string thumbnail_base64;// optional snapshot
|
||||
std::string timestamp;
|
||||
int severity = 0; // 0=info, 1=warning, 2=critical
|
||||
};
|
||||
|
||||
struct DeviceStatusMessage {
|
||||
std::string device_id;
|
||||
DeviceStatus status = DeviceStatus::Unknown;
|
||||
std::string timestamp;
|
||||
std::string firmware_version;
|
||||
std::string ansvis_version;
|
||||
std::string ip_address;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Callback types
|
||||
// --------------------------------------------------------------------------
|
||||
using CommandCallback = std::function<CommandResponse(const Command&)>;
|
||||
using TelemetryCallback = std::function<void(const DeviceTelemetry&)>;
|
||||
using HeartbeatCallback = std::function<void(const Heartbeat&)>;
|
||||
using EventCallback = std::function<void(const DeviceEvent&)>;
|
||||
using StatusCallback = std::function<void(const DeviceStatusMessage&)>;
|
||||
using ConnectionCallback = std::function<void(bool connected, const std::string& info)>;
|
||||
using ErrorCallback = std::function<void(int code, const std::string& message)>;
|
||||
using BroadcastCallback = std::function<void(const std::string& message_json)>;
|
||||
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
print(" [1/15] types.h done")
|
||||
288
_gen_src_02.py
Normal file
288
_gen_src_02.py
Normal file
@@ -0,0 +1,288 @@
|
||||
import os
|
||||
R = r"C:\Projects\CMSCore"
|
||||
def w(rel, txt):
|
||||
p = os.path.join(R, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8", newline="\r\n") as f:
|
||||
f.write(txt.lstrip("\n"))
|
||||
print(f" OK: {rel}")
|
||||
|
||||
# ============================================================================
|
||||
# 2. i_message_broker.h - Abstract interface (your existing RabbitMQ API plugs in)
|
||||
# ============================================================================
|
||||
w("anscloud-common/include/anscloud/common/i_message_broker.h", r'''#pragma once
|
||||
// ==========================================================================
|
||||
// ANSCloud SDK - Abstract Message Broker Interface
|
||||
//
|
||||
// Your existing RabbitMQ C++ API implements this interface.
|
||||
// The SDK never depends on rabbitmq-c directly.
|
||||
// ==========================================================================
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
// Callback when a message is received on a consumer
|
||||
using MessageReceivedFn = std::function<void(
|
||||
const std::string& consumer_tag,
|
||||
const std::string& exchange,
|
||||
const std::string& routing_key,
|
||||
const std::string& correlation_id,
|
||||
const std::string& reply_to,
|
||||
const std::string& body
|
||||
)>;
|
||||
|
||||
// Callback for connection state changes
|
||||
using BrokerConnectionFn = std::function<void(bool connected, const std::string& info)>;
|
||||
|
||||
// Callback for errors
|
||||
using BrokerErrorFn = std::function<void(int code, const std::string& message)>;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// IMessageBroker - Abstract interface for AMQP operations
|
||||
//
|
||||
// Implement this by wrapping your existing RabbitMQ C++ API.
|
||||
// Both DeviceAgent and GatewayAgent receive an IMessageBroker* at configure().
|
||||
// --------------------------------------------------------------------------
|
||||
class IMessageBroker {
|
||||
public:
|
||||
virtual ~IMessageBroker() = default;
|
||||
|
||||
// --- Connection lifecycle ---
|
||||
virtual bool connect() = 0;
|
||||
virtual void disconnect() = 0;
|
||||
virtual bool is_connected() const = 0;
|
||||
|
||||
// --- Topology declaration ---
|
||||
virtual bool declare_exchange(
|
||||
const std::string& exchange_name,
|
||||
const std::string& type = "topic", // "topic", "direct", "fanout"
|
||||
bool durable = true
|
||||
) = 0;
|
||||
|
||||
virtual bool declare_queue(
|
||||
const std::string& queue_name,
|
||||
bool durable = true,
|
||||
bool exclusive = false,
|
||||
bool auto_delete = false
|
||||
) = 0;
|
||||
|
||||
virtual bool bind_queue(
|
||||
const std::string& queue_name,
|
||||
const std::string& exchange_name,
|
||||
const std::string& routing_key
|
||||
) = 0;
|
||||
|
||||
// --- Publishing ---
|
||||
virtual bool publish(
|
||||
const std::string& exchange,
|
||||
const std::string& routing_key,
|
||||
const std::string& body,
|
||||
const std::string& correlation_id = "",
|
||||
const std::string& reply_to = "",
|
||||
bool persistent = true
|
||||
) = 0;
|
||||
|
||||
// --- Consuming ---
|
||||
// Start consuming from a queue. Returns consumer tag (or empty on failure).
|
||||
virtual std::string start_consuming(
|
||||
const std::string& queue_name,
|
||||
MessageReceivedFn on_message
|
||||
) = 0;
|
||||
|
||||
// Cancel a consumer by tag.
|
||||
virtual bool cancel_consumer(const std::string& consumer_tag) = 0;
|
||||
|
||||
// Process pending messages (call from your event loop).
|
||||
// timeout_ms: max time to block waiting for messages (0 = non-blocking).
|
||||
// Returns number of messages processed.
|
||||
virtual int process_messages(uint32_t timeout_ms = 100) = 0;
|
||||
|
||||
// --- Connection callbacks ---
|
||||
virtual void on_connected(BrokerConnectionFn fn) = 0;
|
||||
virtual void on_error(BrokerErrorFn fn) = 0;
|
||||
};
|
||||
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
# ============================================================================
|
||||
# 3. json_serializer.h
|
||||
# ============================================================================
|
||||
w("anscloud-common/include/anscloud/common/json_serializer.h", r'''#pragma once
|
||||
// ==========================================================================
|
||||
// ANSCloud SDK - JSON Serialization
|
||||
// Uses nlohmann/json (or simple manual serialization for now)
|
||||
// ==========================================================================
|
||||
|
||||
#include <anscloud/common/types.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace anscloud {
|
||||
namespace json {
|
||||
|
||||
// --- Serialize to JSON string ---
|
||||
std::string serialize(const Heartbeat& hb);
|
||||
std::string serialize(const DeviceTelemetry& tel);
|
||||
std::string serialize(const SystemMetrics& m);
|
||||
std::string serialize(const Command& cmd);
|
||||
std::string serialize(const CommandResponse& resp);
|
||||
std::string serialize(const DeviceEvent& evt);
|
||||
std::string serialize(const DeviceStatusMessage& status);
|
||||
std::string serialize(const CameraInfo& cam);
|
||||
std::string serialize(const std::vector<CameraInfo>& cams);
|
||||
std::string serialize(const InferenceMetrics& inf);
|
||||
|
||||
// --- Deserialize from JSON string ---
|
||||
Heartbeat deserialize_heartbeat(const std::string& json);
|
||||
DeviceTelemetry deserialize_telemetry(const std::string& json);
|
||||
SystemMetrics deserialize_metrics(const std::string& json);
|
||||
Command deserialize_command(const std::string& json);
|
||||
CommandResponse deserialize_response(const std::string& json);
|
||||
DeviceEvent deserialize_event(const std::string& json);
|
||||
DeviceStatusMessage deserialize_status_message(const std::string& json);
|
||||
CameraInfo deserialize_camera(const std::string& json);
|
||||
std::vector<CameraInfo> deserialize_camera_list(const std::string& json);
|
||||
|
||||
// --- Utilities ---
|
||||
std::string now_iso8601();
|
||||
std::string generate_uuid();
|
||||
|
||||
} // namespace json
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
# ============================================================================
|
||||
# 4. types.cpp
|
||||
# ============================================================================
|
||||
w("anscloud-common/src/types.cpp", r'''#include <anscloud/common/types.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
// --- DeviceStatus ---
|
||||
const char* to_string(DeviceStatus s) {
|
||||
switch (s) {
|
||||
case DeviceStatus::Online: return "online";
|
||||
case DeviceStatus::Offline: return "offline";
|
||||
case DeviceStatus::Connecting: return "connecting";
|
||||
case DeviceStatus::Error: return "error";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
DeviceStatus device_status_from_string(const std::string& s) {
|
||||
static const std::unordered_map<std::string, DeviceStatus> m = {
|
||||
{"online", DeviceStatus::Online}, {"offline", DeviceStatus::Offline},
|
||||
{"connecting", DeviceStatus::Connecting}, {"error", DeviceStatus::Error}
|
||||
};
|
||||
auto it = m.find(s);
|
||||
return it != m.end() ? it->second : DeviceStatus::Unknown;
|
||||
}
|
||||
|
||||
// --- CommandType ---
|
||||
const char* to_string(CommandType t) {
|
||||
switch (t) {
|
||||
case CommandType::GetSystemInfo: return "get_system_info";
|
||||
case CommandType::GetConfig: return "get_config";
|
||||
case CommandType::SetConfig: return "set_config";
|
||||
case CommandType::GetCameraList: return "get_camera_list";
|
||||
case CommandType::AddCamera: return "add_camera";
|
||||
case CommandType::RemoveCamera: return "remove_camera";
|
||||
case CommandType::UpdateCamera: return "update_camera";
|
||||
case CommandType::GetCameraSnapshot:return "get_camera_snapshot";
|
||||
case CommandType::StartStream: return "start_stream";
|
||||
case CommandType::StopStream: return "stop_stream";
|
||||
case CommandType::RestartService: return "restart_service";
|
||||
case CommandType::RebootDevice: return "reboot_device";
|
||||
case CommandType::UpdateFirmware: return "update_firmware";
|
||||
case CommandType::RunDiagnostics: return "run_diagnostics";
|
||||
case CommandType::GetLogs: return "get_logs";
|
||||
case CommandType::SetSchedule: return "set_schedule";
|
||||
case CommandType::GetSchedule: return "get_schedule";
|
||||
default: return "custom";
|
||||
}
|
||||
}
|
||||
|
||||
CommandType command_type_from_string(const std::string& s) {
|
||||
static const std::unordered_map<std::string, CommandType> m = {
|
||||
{"get_system_info", CommandType::GetSystemInfo},
|
||||
{"get_config", CommandType::GetConfig},
|
||||
{"set_config", CommandType::SetConfig},
|
||||
{"get_camera_list", CommandType::GetCameraList},
|
||||
{"add_camera", CommandType::AddCamera},
|
||||
{"remove_camera", CommandType::RemoveCamera},
|
||||
{"update_camera", CommandType::UpdateCamera},
|
||||
{"get_camera_snapshot", CommandType::GetCameraSnapshot},
|
||||
{"start_stream", CommandType::StartStream},
|
||||
{"stop_stream", CommandType::StopStream},
|
||||
{"restart_service", CommandType::RestartService},
|
||||
{"reboot_device", CommandType::RebootDevice},
|
||||
{"update_firmware", CommandType::UpdateFirmware},
|
||||
{"run_diagnostics", CommandType::RunDiagnostics},
|
||||
{"get_logs", CommandType::GetLogs},
|
||||
{"set_schedule", CommandType::SetSchedule},
|
||||
{"get_schedule", CommandType::GetSchedule}
|
||||
};
|
||||
auto it = m.find(s);
|
||||
return it != m.end() ? it->second : CommandType::Custom;
|
||||
}
|
||||
|
||||
// --- EventType ---
|
||||
const char* to_string(EventType t) {
|
||||
switch (t) {
|
||||
case EventType::Alert: return "alert";
|
||||
case EventType::DetectionLPR: return "detection_lpr";
|
||||
case EventType::DetectionFace: return "detection_face";
|
||||
case EventType::DetectionObject: return "detection_object";
|
||||
case EventType::DetectionMotion: return "detection_motion";
|
||||
case EventType::LineCrossing: return "line_crossing";
|
||||
case EventType::Intrusion: return "intrusion";
|
||||
case EventType::Loitering: return "loitering";
|
||||
case EventType::CameraDisconnected: return "camera_disconnected";
|
||||
case EventType::CameraReconnected: return "camera_reconnected";
|
||||
case EventType::StorageWarning: return "storage_warning";
|
||||
case EventType::SystemError: return "system_error";
|
||||
default: return "custom";
|
||||
}
|
||||
}
|
||||
|
||||
EventType event_type_from_string(const std::string& s) {
|
||||
static const std::unordered_map<std::string, EventType> m = {
|
||||
{"alert", EventType::Alert},
|
||||
{"detection_lpr", EventType::DetectionLPR},
|
||||
{"detection_face", EventType::DetectionFace},
|
||||
{"detection_object", EventType::DetectionObject},
|
||||
{"detection_motion", EventType::DetectionMotion},
|
||||
{"line_crossing", EventType::LineCrossing},
|
||||
{"intrusion", EventType::Intrusion},
|
||||
{"loitering", EventType::Loitering},
|
||||
{"camera_disconnected", EventType::CameraDisconnected},
|
||||
{"camera_reconnected", EventType::CameraReconnected},
|
||||
{"storage_warning", EventType::StorageWarning},
|
||||
{"system_error", EventType::SystemError}
|
||||
};
|
||||
auto it = m.find(s);
|
||||
return it != m.end() ? it->second : EventType::Custom;
|
||||
}
|
||||
|
||||
// --- CommandStatus ---
|
||||
const char* to_string(CommandStatus s) {
|
||||
switch (s) {
|
||||
case CommandStatus::Success: return "success";
|
||||
case CommandStatus::Failed: return "failed";
|
||||
case CommandStatus::Timeout: return "timeout";
|
||||
case CommandStatus::Rejected: return "rejected";
|
||||
case CommandStatus::Pending: return "pending";
|
||||
case CommandStatus::PartialSuccess: return "partial_success";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
print(" [2-4] i_message_broker.h, json_serializer.h, types.cpp done")
|
||||
207
_gen_src_03.py
Normal file
207
_gen_src_03.py
Normal file
@@ -0,0 +1,207 @@
|
||||
import os
|
||||
R = r"C:\Projects\CMSCore"
|
||||
def w(rel, txt):
|
||||
p = os.path.join(R, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8", newline="\r\n") as f:
|
||||
f.write(txt.lstrip("\n"))
|
||||
print(f" OK: {rel}")
|
||||
|
||||
# ============================================================================
|
||||
# 5. json_serializer.cpp (simple manual JSON - no nlohmann dependency yet)
|
||||
# ============================================================================
|
||||
w("anscloud-common/src/json_serializer.cpp", r'''#include <anscloud/common/json_serializer.h>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <ctime>
|
||||
|
||||
// ==========================================================================
|
||||
// Minimal JSON builder/parser (no external dependency).
|
||||
// Replace with nlohmann/json when you add it via NuGet/vcpkg.
|
||||
// ==========================================================================
|
||||
|
||||
namespace anscloud {
|
||||
namespace json {
|
||||
|
||||
// ---- Utilities ----
|
||||
|
||||
std::string now_iso8601() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto t = std::chrono::system_clock::to_time_t(now);
|
||||
struct tm buf;
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&buf, &t);
|
||||
#else
|
||||
gmtime_r(&t, &buf);
|
||||
#endif
|
||||
std::ostringstream ss;
|
||||
ss << std::put_time(&buf, "%Y-%m-%dT%H:%M:%SZ");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string generate_uuid() {
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
static std::uniform_int_distribution<uint32_t> dist(0, 0xFFFFFFFF);
|
||||
auto hex = [](uint32_t v, int digits) {
|
||||
std::ostringstream s;
|
||||
s << std::hex << std::setfill('0') << std::setw(digits) << v;
|
||||
return s.str();
|
||||
};
|
||||
uint32_t a = dist(gen), b = dist(gen), c = dist(gen), d = dist(gen);
|
||||
return hex(a, 8) + "-" + hex(b >> 16, 4) + "-4" + hex((b & 0xFFF), 3)
|
||||
+ "-" + hex(0x8000 | (c & 0x3FFF), 4) + "-" + hex(d, 8) + hex(c >> 16, 4);
|
||||
}
|
||||
|
||||
// Simple JSON escape
|
||||
static std::string esc(const std::string& s) {
|
||||
std::string r;
|
||||
r.reserve(s.size() + 8);
|
||||
for (char c : s) {
|
||||
switch (c) {
|
||||
case '"': r += "\\\""; break;
|
||||
case '\\': r += "\\\\"; break;
|
||||
case '\n': r += "\\n"; break;
|
||||
case '\r': r += "\\r"; break;
|
||||
case '\t': r += "\\t"; break;
|
||||
default: r += c;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Helper macros for building JSON
|
||||
#define JS_STR(k, v) "\"" k "\":\"" + esc(v) + "\""
|
||||
#define JS_NUM(k, v) "\"" k "\":" + std::to_string(v)
|
||||
#define JS_BOOL(k, v) "\"" k "\":" + std::string((v) ? "true" : "false")
|
||||
|
||||
// ---- Serialize implementations ----
|
||||
|
||||
std::string serialize(const SystemMetrics& m) {
|
||||
return "{" + JS_NUM("cpu_usage_percent", m.cpu_usage_percent) + ","
|
||||
+ JS_NUM("ram_usage_percent", m.ram_usage_percent) + ","
|
||||
+ JS_NUM("ram_total_mb", m.ram_total_mb) + ","
|
||||
+ JS_NUM("ram_used_mb", m.ram_used_mb) + ","
|
||||
+ JS_NUM("gpu_usage_percent", m.gpu_usage_percent) + ","
|
||||
+ JS_NUM("gpu_memory_percent", m.gpu_memory_percent) + ","
|
||||
+ JS_NUM("gpu_temperature_c", m.gpu_temperature_c) + ","
|
||||
+ JS_NUM("disk_usage_percent", m.disk_usage_percent) + ","
|
||||
+ JS_NUM("disk_total_gb", m.disk_total_gb) + ","
|
||||
+ JS_NUM("disk_used_gb", m.disk_used_gb) + ","
|
||||
+ JS_NUM("cpu_temperature_c", m.cpu_temperature_c) + ","
|
||||
+ JS_NUM("process_count", m.process_count) + ","
|
||||
+ JS_NUM("network_rx_mbps", m.network_rx_mbps) + ","
|
||||
+ JS_NUM("network_tx_mbps", m.network_tx_mbps) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const CameraInfo& cam) {
|
||||
return "{" + JS_STR("camera_id", cam.camera_id) + ","
|
||||
+ JS_STR("name", cam.name) + ","
|
||||
+ JS_STR("rtsp_url", cam.rtsp_url) + ","
|
||||
+ JS_STR("status", cam.status) + ","
|
||||
+ JS_NUM("width", cam.width) + ","
|
||||
+ JS_NUM("height", cam.height) + ","
|
||||
+ JS_NUM("fps", cam.fps) + ","
|
||||
+ JS_STR("codec", cam.codec) + ","
|
||||
+ JS_STR("ai_models", cam.ai_models) + ","
|
||||
+ JS_BOOL("recording", cam.recording) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const std::vector<CameraInfo>& cams) {
|
||||
std::string r = "[";
|
||||
for (size_t i = 0; i < cams.size(); ++i) {
|
||||
if (i > 0) r += ",";
|
||||
r += serialize(cams[i]);
|
||||
}
|
||||
return r + "]";
|
||||
}
|
||||
|
||||
std::string serialize(const InferenceMetrics& inf) {
|
||||
return "{" + JS_NUM("active_models", inf.active_models) + ","
|
||||
+ JS_NUM("avg_latency_ms", inf.avg_latency_ms) + ","
|
||||
+ JS_NUM("total_fps", inf.total_fps) + ","
|
||||
+ JS_NUM("total_detections", inf.total_detections) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const Heartbeat& hb) {
|
||||
return "{" + JS_STR("device_id", hb.device_id) + ","
|
||||
+ JS_STR("timestamp", hb.timestamp) + ","
|
||||
+ JS_STR("status", to_string(hb.status)) + ","
|
||||
+ JS_NUM("uptime_seconds", hb.uptime_seconds) + ","
|
||||
+ JS_STR("firmware_version", hb.firmware_version) + ","
|
||||
+ JS_STR("ansvis_version", hb.ansvis_version) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const DeviceTelemetry& tel) {
|
||||
return "{" + JS_STR("device_id", tel.device_id) + ","
|
||||
+ JS_STR("timestamp", tel.timestamp) + ","
|
||||
+ "\"metrics\":" + serialize(tel.metrics) + ","
|
||||
+ "\"cameras\":" + serialize(tel.cameras) + ","
|
||||
+ "\"inference\":" + serialize(tel.inference) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const Command& cmd) {
|
||||
return "{" + JS_STR("command_id", cmd.command_id) + ","
|
||||
+ JS_STR("device_id", cmd.device_id) + ","
|
||||
+ JS_STR("type", to_string(cmd.type)) + ","
|
||||
+ JS_STR("type_name", cmd.type_name) + ","
|
||||
+ "\"params\":" + (cmd.params_json.empty() ? "{}" : cmd.params_json) + ","
|
||||
+ JS_STR("correlation_id", cmd.correlation_id) + ","
|
||||
+ JS_STR("reply_to", cmd.reply_to) + ","
|
||||
+ JS_NUM("timeout_seconds", cmd.timeout_seconds) + ","
|
||||
+ JS_STR("timestamp", cmd.timestamp) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const CommandResponse& r) {
|
||||
return "{" + JS_STR("command_id", r.command_id) + ","
|
||||
+ JS_STR("device_id", r.device_id) + ","
|
||||
+ JS_STR("status", to_string(r.status)) + ","
|
||||
+ "\"result\":" + (r.result_json.empty() ? "{}" : r.result_json) + ","
|
||||
+ JS_STR("error_message", r.error_message) + ","
|
||||
+ JS_STR("correlation_id", r.correlation_id) + ","
|
||||
+ JS_NUM("execution_time_ms", r.execution_time_ms) + ","
|
||||
+ JS_STR("timestamp", r.timestamp) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const DeviceEvent& e) {
|
||||
return "{" + JS_STR("event_id", e.event_id) + ","
|
||||
+ JS_STR("device_id", e.device_id) + ","
|
||||
+ JS_STR("type", to_string(e.type)) + ","
|
||||
+ JS_STR("type_name", e.type_name) + ","
|
||||
+ JS_STR("camera_id", e.camera_id) + ","
|
||||
+ "\"data\":" + (e.data_json.empty() ? "{}" : e.data_json) + ","
|
||||
+ JS_STR("timestamp", e.timestamp) + ","
|
||||
+ JS_NUM("severity", e.severity) + "}";
|
||||
}
|
||||
|
||||
std::string serialize(const DeviceStatusMessage& s) {
|
||||
return "{" + JS_STR("device_id", s.device_id) + ","
|
||||
+ JS_STR("status", to_string(s.status)) + ","
|
||||
+ JS_STR("timestamp", s.timestamp) + ","
|
||||
+ JS_STR("firmware_version", s.firmware_version) + ","
|
||||
+ JS_STR("ansvis_version", s.ansvis_version) + ","
|
||||
+ JS_STR("ip_address", s.ip_address) + ","
|
||||
+ JS_STR("message", s.message) + "}";
|
||||
}
|
||||
|
||||
// ---- Deserialize stubs (TODO: implement with proper JSON parser) ----
|
||||
// For now these return default-constructed objects.
|
||||
// Replace with nlohmann/json parsing when ready.
|
||||
|
||||
Heartbeat deserialize_heartbeat(const std::string&) { return {}; }
|
||||
DeviceTelemetry deserialize_telemetry(const std::string&) { return {}; }
|
||||
SystemMetrics deserialize_metrics(const std::string&) { return {}; }
|
||||
Command deserialize_command(const std::string&) { return {}; }
|
||||
CommandResponse deserialize_response(const std::string&) { return {}; }
|
||||
DeviceEvent deserialize_event(const std::string&) { return {}; }
|
||||
DeviceStatusMessage deserialize_status_message(const std::string&) { return {}; }
|
||||
CameraInfo deserialize_camera(const std::string&) { return {}; }
|
||||
std::vector<CameraInfo> deserialize_camera_list(const std::string&){ return {}; }
|
||||
|
||||
} // namespace json
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
print(" [5] json_serializer.cpp done")
|
||||
195
_gen_src_04.py
Normal file
195
_gen_src_04.py
Normal file
@@ -0,0 +1,195 @@
|
||||
import os
|
||||
R = r"C:\Projects\CMSCore"
|
||||
def w(rel, txt):
|
||||
p = os.path.join(R, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8", newline="\r\n") as f:
|
||||
f.write(txt.lstrip("\n"))
|
||||
print(f" OK: {rel}")
|
||||
|
||||
# ============================================================================
|
||||
# 6. device_agent.h
|
||||
# ============================================================================
|
||||
w("anscloud-device/include/anscloud/device/device_agent.h", r'''#pragma once
|
||||
// ==========================================================================
|
||||
// ANSCloud SDK - Device Agent (AIBOX side)
|
||||
//
|
||||
// Manages the full device lifecycle:
|
||||
// - Connects to broker via IMessageBroker (your existing RabbitMQ API)
|
||||
// - Declares device queues, binds to exchanges
|
||||
// - Listens for commands, dispatches to your CommandHandler
|
||||
// - Publishes heartbeat, telemetry, events, status
|
||||
// - Background threads for timers and message processing
|
||||
// ==========================================================================
|
||||
|
||||
#include <anscloud/common/types.h>
|
||||
#include <anscloud/common/i_message_broker.h>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Configuration
|
||||
// --------------------------------------------------------------------------
|
||||
struct DeviceAgentConfig {
|
||||
std::string device_id;
|
||||
std::string firmware_version;
|
||||
std::string ansvis_version;
|
||||
std::string local_ansvis_api; // e.g. "http://127.0.0.1:8080"
|
||||
|
||||
// Telemetry intervals (seconds)
|
||||
int heartbeat_interval_sec = 30;
|
||||
int metrics_interval_sec = 60;
|
||||
|
||||
// Logging
|
||||
bool verbose_logging = false;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Provider callbacks - your application implements these
|
||||
// --------------------------------------------------------------------------
|
||||
using MetricsProvider = std::function<SystemMetrics()>;
|
||||
using CameraListProvider = std::function<std::vector<CameraInfo>()>;
|
||||
using InferenceProvider = std::function<InferenceMetrics()>;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Agent status info
|
||||
// --------------------------------------------------------------------------
|
||||
struct DeviceAgentStatus {
|
||||
bool connected = false;
|
||||
bool running = false;
|
||||
uint64_t uptime_seconds = 0;
|
||||
uint64_t commands_received = 0;
|
||||
uint64_t commands_executed = 0;
|
||||
uint64_t heartbeats_sent = 0;
|
||||
uint64_t telemetry_sent = 0;
|
||||
uint64_t events_sent = 0;
|
||||
uint64_t reconnect_count = 0;
|
||||
std::string last_error;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// DeviceAgent
|
||||
// --------------------------------------------------------------------------
|
||||
class DeviceAgent {
|
||||
public:
|
||||
DeviceAgent();
|
||||
~DeviceAgent();
|
||||
|
||||
// Non-copyable
|
||||
DeviceAgent(const DeviceAgent&) = delete;
|
||||
DeviceAgent& operator=(const DeviceAgent&) = delete;
|
||||
|
||||
// --- Setup ---
|
||||
// Pass YOUR existing RabbitMQ API instance (already configured with host/port/credentials).
|
||||
// DeviceAgent does NOT own the broker - you manage its lifetime.
|
||||
void configure(IMessageBroker* broker, const DeviceAgentConfig& config);
|
||||
|
||||
// --- Provider registration ---
|
||||
void set_command_handler(CommandCallback handler);
|
||||
void set_metrics_provider(MetricsProvider provider);
|
||||
void set_camera_list_provider(CameraListProvider provider);
|
||||
void set_inference_provider(InferenceProvider provider);
|
||||
|
||||
// --- Lifecycle ---
|
||||
bool start(); // NON-BLOCKING: connects, declares topology, starts background threads
|
||||
void stop(); // Publishes offline status, stops threads, disconnects
|
||||
|
||||
bool is_running() const;
|
||||
bool is_connected() const;
|
||||
|
||||
// --- Manual publishing ---
|
||||
bool publish_event(const DeviceEvent& evt);
|
||||
bool publish_telemetry(); // gathers from providers and publishes
|
||||
bool send_heartbeat();
|
||||
bool send_metrics();
|
||||
|
||||
// --- Callbacks ---
|
||||
void on_connection_changed(ConnectionCallback cb);
|
||||
void on_error(ErrorCallback cb);
|
||||
void on_broadcast(BroadcastCallback cb);
|
||||
|
||||
// --- Status ---
|
||||
DeviceAgentStatus get_status() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
# ============================================================================
|
||||
# 7. device_agent_c.h (C API for FFI)
|
||||
# ============================================================================
|
||||
w("anscloud-device/include/anscloud/device/device_agent_c.h", r'''#pragma once
|
||||
// ==========================================================================
|
||||
// ANSCloud SDK - Device Agent C API (for FFI: Go, Python, C#, etc.)
|
||||
// ==========================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Opaque handle
|
||||
typedef void* AnsDeviceHandle;
|
||||
|
||||
// C callback types
|
||||
typedef const char* (*AnsDeviceCmdHandlerFn)(
|
||||
void* user_data,
|
||||
const char* command_json // full Command as JSON
|
||||
); // returns CommandResponse as JSON (caller frees with ansdevice_free_string)
|
||||
|
||||
typedef void (*AnsDeviceConnectionFn)(void* user_data, bool connected, const char* info);
|
||||
typedef void (*AnsDeviceErrorFn)(void* user_data, int code, const char* message);
|
||||
typedef void (*AnsDeviceBroadcastFn)(void* user_data, const char* message_json);
|
||||
|
||||
// --- Lifecycle ---
|
||||
AnsDeviceHandle ansdevice_create(void);
|
||||
void ansdevice_destroy(AnsDeviceHandle h);
|
||||
|
||||
// Configure: broker_ptr is your IMessageBroker* cast to void*
|
||||
bool ansdevice_configure(AnsDeviceHandle h, void* broker_ptr, const char* config_json);
|
||||
|
||||
// --- Handlers ---
|
||||
void ansdevice_set_command_handler(AnsDeviceHandle h, AnsDeviceCmdHandlerFn fn, void* user_data);
|
||||
void ansdevice_on_connection_changed(AnsDeviceHandle h, AnsDeviceConnectionFn fn, void* user_data);
|
||||
void ansdevice_on_error(AnsDeviceHandle h, AnsDeviceErrorFn fn, void* user_data);
|
||||
void ansdevice_on_broadcast(AnsDeviceHandle h, AnsDeviceBroadcastFn fn, void* user_data);
|
||||
|
||||
// --- Lifecycle ---
|
||||
bool ansdevice_start(AnsDeviceHandle h);
|
||||
void ansdevice_stop(AnsDeviceHandle h);
|
||||
bool ansdevice_is_running(AnsDeviceHandle h);
|
||||
bool ansdevice_is_connected(AnsDeviceHandle h);
|
||||
|
||||
// --- Publishing ---
|
||||
bool ansdevice_publish_event(AnsDeviceHandle h, const char* event_json);
|
||||
bool ansdevice_send_heartbeat(AnsDeviceHandle h);
|
||||
bool ansdevice_send_metrics(AnsDeviceHandle h);
|
||||
|
||||
// --- Status ---
|
||||
const char* ansdevice_get_status(AnsDeviceHandle h); // returns JSON, free with ansdevice_free_string
|
||||
|
||||
// --- Memory ---
|
||||
void ansdevice_free_string(const char* str);
|
||||
|
||||
// --- Version ---
|
||||
const char* ansdevice_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
''')
|
||||
|
||||
print(" [6-7] device_agent.h, device_agent_c.h done")
|
||||
336
_gen_src_05.py
Normal file
336
_gen_src_05.py
Normal file
@@ -0,0 +1,336 @@
|
||||
import os
|
||||
R = r"C:\Projects\CMSCore"
|
||||
def w(rel, txt):
|
||||
p = os.path.join(R, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8", newline="\r\n") as f:
|
||||
f.write(txt.lstrip("\n"))
|
||||
print(f" OK: {rel}")
|
||||
|
||||
# ============================================================================
|
||||
# 8. device_agent.cpp
|
||||
# ============================================================================
|
||||
w("anscloud-device/src/device_agent.cpp", r'''#include <anscloud/device/device_agent.h>
|
||||
#include <anscloud/common/json_serializer.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
// ==========================================================================
|
||||
// DeviceAgent::Impl (PIMPL)
|
||||
// ==========================================================================
|
||||
struct DeviceAgent::Impl {
|
||||
IMessageBroker* broker = nullptr;
|
||||
DeviceAgentConfig config;
|
||||
|
||||
// Callbacks
|
||||
CommandCallback cmd_handler;
|
||||
MetricsProvider metrics_provider;
|
||||
CameraListProvider camera_provider;
|
||||
InferenceProvider inference_provider;
|
||||
ConnectionCallback connection_cb;
|
||||
ErrorCallback error_cb;
|
||||
BroadcastCallback broadcast_cb;
|
||||
|
||||
// State
|
||||
std::atomic<bool> running{false};
|
||||
std::atomic<bool> connected{false};
|
||||
std::chrono::steady_clock::time_point start_time;
|
||||
|
||||
// Stats
|
||||
std::atomic<uint64_t> commands_received{0};
|
||||
std::atomic<uint64_t> commands_executed{0};
|
||||
std::atomic<uint64_t> heartbeats_sent{0};
|
||||
std::atomic<uint64_t> telemetry_sent{0};
|
||||
std::atomic<uint64_t> events_sent{0};
|
||||
std::atomic<uint64_t> reconnect_count{0};
|
||||
std::string last_error;
|
||||
mutable std::mutex error_mutex;
|
||||
|
||||
// Threads
|
||||
std::thread message_thread;
|
||||
std::thread heartbeat_thread;
|
||||
std::thread metrics_thread;
|
||||
|
||||
// Consumer tags
|
||||
std::string cmd_consumer_tag;
|
||||
std::string broadcast_consumer_tag;
|
||||
|
||||
void set_error(const std::string& err) {
|
||||
std::lock_guard<std::mutex> lk(error_mutex);
|
||||
last_error = err;
|
||||
if (error_cb) error_cb(-1, err);
|
||||
}
|
||||
|
||||
void log(const std::string& msg) {
|
||||
if (config.verbose_logging) {
|
||||
std::cout << "[DeviceAgent:" << config.device_id << "] " << msg << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Boot sequence ---
|
||||
bool boot() {
|
||||
log("Boot: connecting to broker...");
|
||||
|
||||
if (!broker->is_connected()) {
|
||||
if (!broker->connect()) {
|
||||
set_error("Failed to connect to broker");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
connected = true;
|
||||
log("Boot: connected.");
|
||||
|
||||
// Declare exchanges (idempotent)
|
||||
broker->declare_exchange(exchange::DEVICE_TELEMETRY, "topic");
|
||||
broker->declare_exchange(exchange::DEVICE_STATUS, "topic");
|
||||
broker->declare_exchange(exchange::DEVICE_EVENTS, "topic");
|
||||
broker->declare_exchange(exchange::COMMAND, "topic");
|
||||
broker->declare_exchange(exchange::COMMAND_RESPONSE, "topic");
|
||||
broker->declare_exchange(exchange::BROADCAST, "fanout");
|
||||
log("Boot: exchanges declared.");
|
||||
|
||||
// Declare device command queue
|
||||
std::string cmd_q = queue::device_command(config.device_id);
|
||||
broker->declare_queue(cmd_q, true, false, false);
|
||||
broker->bind_queue(cmd_q, exchange::COMMAND, config.device_id);
|
||||
log("Boot: command queue " + cmd_q + " bound.");
|
||||
|
||||
// Start consuming commands
|
||||
cmd_consumer_tag = broker->start_consuming(cmd_q,
|
||||
[this](const std::string&, const std::string&, const std::string&,
|
||||
const std::string& corr_id, const std::string&, const std::string& body)
|
||||
{
|
||||
handle_command(body, corr_id);
|
||||
});
|
||||
|
||||
// Declare broadcast queue
|
||||
std::string bcast_q = queue::device_broadcast(config.device_id);
|
||||
broker->declare_queue(bcast_q, false, true, true); // exclusive, auto-delete
|
||||
broker->bind_queue(bcast_q, exchange::BROADCAST, "");
|
||||
broadcast_consumer_tag = broker->start_consuming(bcast_q,
|
||||
[this](const std::string&, const std::string&, const std::string&,
|
||||
const std::string&, const std::string&, const std::string& body)
|
||||
{
|
||||
if (broadcast_cb) broadcast_cb(body);
|
||||
});
|
||||
log("Boot: consumers started.");
|
||||
|
||||
// Publish online status
|
||||
publish_status(DeviceStatus::Online, "Device started");
|
||||
|
||||
// Send initial heartbeat
|
||||
send_heartbeat_impl();
|
||||
|
||||
log("Boot: COMPLETE");
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Command handler ---
|
||||
void handle_command(const std::string& body, const std::string& corr_id) {
|
||||
commands_received++;
|
||||
log("Command received: " + body.substr(0, 80) + "...");
|
||||
|
||||
Command cmd = json::deserialize_command(body);
|
||||
cmd.correlation_id = corr_id;
|
||||
|
||||
CommandResponse resp;
|
||||
resp.command_id = cmd.command_id;
|
||||
resp.device_id = config.device_id;
|
||||
resp.correlation_id = corr_id;
|
||||
resp.timestamp = json::now_iso8601();
|
||||
|
||||
if (cmd_handler) {
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
resp = cmd_handler(cmd);
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
resp.execution_time_ms = std::chrono::duration<double, std::milli>(t1 - t0).count();
|
||||
resp.correlation_id = corr_id;
|
||||
commands_executed++;
|
||||
} else {
|
||||
resp.status = CommandStatus::Rejected;
|
||||
resp.error_message = "No command handler registered";
|
||||
}
|
||||
|
||||
// Publish response
|
||||
std::string resp_json = json::serialize(resp);
|
||||
broker->publish(exchange::COMMAND_RESPONSE, config.device_id, resp_json, corr_id);
|
||||
log("Command response sent.");
|
||||
}
|
||||
|
||||
// --- Publishing helpers ---
|
||||
void publish_status(DeviceStatus status, const std::string& msg) {
|
||||
DeviceStatusMessage sm;
|
||||
sm.device_id = config.device_id;
|
||||
sm.status = status;
|
||||
sm.timestamp = json::now_iso8601();
|
||||
sm.firmware_version = config.firmware_version;
|
||||
sm.ansvis_version = config.ansvis_version;
|
||||
sm.message = msg;
|
||||
broker->publish(exchange::DEVICE_STATUS, config.device_id, json::serialize(sm));
|
||||
}
|
||||
|
||||
bool send_heartbeat_impl() {
|
||||
Heartbeat hb;
|
||||
hb.device_id = config.device_id;
|
||||
hb.timestamp = json::now_iso8601();
|
||||
hb.status = DeviceStatus::Online;
|
||||
auto elapsed = std::chrono::steady_clock::now() - start_time;
|
||||
hb.uptime_seconds = (uint64_t)std::chrono::duration_cast<std::chrono::seconds>(elapsed).count();
|
||||
hb.firmware_version = config.firmware_version;
|
||||
hb.ansvis_version = config.ansvis_version;
|
||||
|
||||
bool ok = broker->publish(exchange::DEVICE_TELEMETRY,
|
||||
config.device_id + ".heartbeat",
|
||||
json::serialize(hb));
|
||||
if (ok) heartbeats_sent++;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool send_telemetry_impl() {
|
||||
DeviceTelemetry tel;
|
||||
tel.device_id = config.device_id;
|
||||
tel.timestamp = json::now_iso8601();
|
||||
if (metrics_provider) tel.metrics = metrics_provider();
|
||||
if (camera_provider) tel.cameras = camera_provider();
|
||||
if (inference_provider) tel.inference = inference_provider();
|
||||
|
||||
bool ok = broker->publish(exchange::DEVICE_TELEMETRY,
|
||||
config.device_id + ".metrics",
|
||||
json::serialize(tel));
|
||||
if (ok) telemetry_sent++;
|
||||
return ok;
|
||||
}
|
||||
|
||||
// --- Background threads ---
|
||||
void message_loop() {
|
||||
while (running) {
|
||||
if (broker && broker->is_connected()) {
|
||||
broker->process_messages(100);
|
||||
} else {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void heartbeat_loop() {
|
||||
while (running) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(config.heartbeat_interval_sec));
|
||||
if (running && connected) {
|
||||
send_heartbeat_impl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void metrics_loop() {
|
||||
while (running) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(config.metrics_interval_sec));
|
||||
if (running && connected) {
|
||||
send_telemetry_impl();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
// DeviceAgent public methods
|
||||
// ==========================================================================
|
||||
|
||||
DeviceAgent::DeviceAgent() : m_impl(std::make_unique<Impl>()) {}
|
||||
DeviceAgent::~DeviceAgent() { stop(); }
|
||||
|
||||
void DeviceAgent::configure(IMessageBroker* broker, const DeviceAgentConfig& config) {
|
||||
m_impl->broker = broker;
|
||||
m_impl->config = config;
|
||||
}
|
||||
|
||||
void DeviceAgent::set_command_handler(CommandCallback handler) { m_impl->cmd_handler = std::move(handler); }
|
||||
void DeviceAgent::set_metrics_provider(MetricsProvider provider) { m_impl->metrics_provider = std::move(provider); }
|
||||
void DeviceAgent::set_camera_list_provider(CameraListProvider prov) { m_impl->camera_provider = std::move(prov); }
|
||||
void DeviceAgent::set_inference_provider(InferenceProvider provider) { m_impl->inference_provider = std::move(provider); }
|
||||
|
||||
bool DeviceAgent::start() {
|
||||
if (m_impl->running) return true;
|
||||
m_impl->start_time = std::chrono::steady_clock::now();
|
||||
m_impl->running = true;
|
||||
|
||||
if (!m_impl->boot()) {
|
||||
m_impl->running = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start background threads
|
||||
m_impl->message_thread = std::thread([this] { m_impl->message_loop(); });
|
||||
m_impl->heartbeat_thread = std::thread([this] { m_impl->heartbeat_loop(); });
|
||||
m_impl->metrics_thread = std::thread([this] { m_impl->metrics_loop(); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceAgent::stop() {
|
||||
if (!m_impl->running) return;
|
||||
m_impl->running = false;
|
||||
|
||||
// Publish offline
|
||||
if (m_impl->broker && m_impl->broker->is_connected()) {
|
||||
m_impl->publish_status(DeviceStatus::Offline, "Device stopping");
|
||||
if (!m_impl->cmd_consumer_tag.empty())
|
||||
m_impl->broker->cancel_consumer(m_impl->cmd_consumer_tag);
|
||||
if (!m_impl->broadcast_consumer_tag.empty())
|
||||
m_impl->broker->cancel_consumer(m_impl->broadcast_consumer_tag);
|
||||
}
|
||||
|
||||
// Join threads
|
||||
if (m_impl->message_thread.joinable()) m_impl->message_thread.join();
|
||||
if (m_impl->heartbeat_thread.joinable()) m_impl->heartbeat_thread.join();
|
||||
if (m_impl->metrics_thread.joinable()) m_impl->metrics_thread.join();
|
||||
|
||||
m_impl->connected = false;
|
||||
}
|
||||
|
||||
bool DeviceAgent::is_running() const { return m_impl->running; }
|
||||
bool DeviceAgent::is_connected() const { return m_impl->connected && m_impl->broker && m_impl->broker->is_connected(); }
|
||||
|
||||
bool DeviceAgent::publish_event(const DeviceEvent& evt) {
|
||||
if (!m_impl->connected) return false;
|
||||
std::string routing = m_impl->config.device_id + "." + to_string(evt.type);
|
||||
bool ok = m_impl->broker->publish(exchange::DEVICE_EVENTS, routing, json::serialize(evt));
|
||||
if (ok) m_impl->events_sent++;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool DeviceAgent::publish_telemetry() { return m_impl->send_telemetry_impl(); }
|
||||
bool DeviceAgent::send_heartbeat() { return m_impl->send_heartbeat_impl(); }
|
||||
bool DeviceAgent::send_metrics() { return m_impl->send_telemetry_impl(); }
|
||||
|
||||
void DeviceAgent::on_connection_changed(ConnectionCallback cb) { m_impl->connection_cb = std::move(cb); }
|
||||
void DeviceAgent::on_error(ErrorCallback cb) { m_impl->error_cb = std::move(cb); }
|
||||
void DeviceAgent::on_broadcast(BroadcastCallback cb) { m_impl->broadcast_cb = std::move(cb); }
|
||||
|
||||
DeviceAgentStatus DeviceAgent::get_status() const {
|
||||
DeviceAgentStatus s;
|
||||
s.connected = m_impl->connected;
|
||||
s.running = m_impl->running;
|
||||
if (m_impl->running) {
|
||||
auto elapsed = std::chrono::steady_clock::now() - m_impl->start_time;
|
||||
s.uptime_seconds = (uint64_t)std::chrono::duration_cast<std::chrono::seconds>(elapsed).count();
|
||||
}
|
||||
s.commands_received = m_impl->commands_received;
|
||||
s.commands_executed = m_impl->commands_executed;
|
||||
s.heartbeats_sent = m_impl->heartbeats_sent;
|
||||
s.telemetry_sent = m_impl->telemetry_sent;
|
||||
s.events_sent = m_impl->events_sent;
|
||||
s.reconnect_count = m_impl->reconnect_count;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_impl->error_mutex);
|
||||
s.last_error = m_impl->last_error;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
print(" [8] device_agent.cpp done")
|
||||
287
_gen_src_06.py
Normal file
287
_gen_src_06.py
Normal file
@@ -0,0 +1,287 @@
|
||||
import os
|
||||
R = r"C:\Projects\CMSCore"
|
||||
def w(rel, txt):
|
||||
p = os.path.join(R, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8", newline="\r\n") as f:
|
||||
f.write(txt.lstrip("\n"))
|
||||
print(f" OK: {rel}")
|
||||
|
||||
# ============================================================================
|
||||
# 9. device_agent_c.cpp
|
||||
# ============================================================================
|
||||
w("anscloud-device/src/device_agent_c.cpp", r'''#include <anscloud/device/device_agent_c.h>
|
||||
#include <anscloud/device/device_agent.h>
|
||||
#include <anscloud/common/json_serializer.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
using namespace anscloud;
|
||||
|
||||
static char* alloc_copy(const std::string& s) {
|
||||
char* p = new char[s.size() + 1];
|
||||
memcpy(p, s.c_str(), s.size() + 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
AnsDeviceHandle ansdevice_create(void) {
|
||||
return new DeviceAgent();
|
||||
}
|
||||
|
||||
void ansdevice_destroy(AnsDeviceHandle h) {
|
||||
delete static_cast<DeviceAgent*>(h);
|
||||
}
|
||||
|
||||
bool ansdevice_configure(AnsDeviceHandle h, void* broker_ptr, const char* config_json) {
|
||||
if (!h || !broker_ptr) return false;
|
||||
auto* agent = static_cast<DeviceAgent*>(h);
|
||||
auto* broker = static_cast<IMessageBroker*>(broker_ptr);
|
||||
// TODO: parse config_json into DeviceAgentConfig
|
||||
DeviceAgentConfig cfg;
|
||||
// For now just a minimal config
|
||||
cfg.device_id = "device";
|
||||
cfg.verbose_logging = true;
|
||||
agent->configure(broker, cfg);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ansdevice_set_command_handler(AnsDeviceHandle h, AnsDeviceCmdHandlerFn fn, void* user_data) {
|
||||
if (!h || !fn) return;
|
||||
auto* agent = static_cast<DeviceAgent*>(h);
|
||||
agent->set_command_handler([fn, user_data](const Command& cmd) -> CommandResponse {
|
||||
std::string cmd_json = json::serialize(cmd);
|
||||
const char* resp_str = fn(user_data, cmd_json.c_str());
|
||||
CommandResponse resp;
|
||||
if (resp_str) {
|
||||
resp = json::deserialize_response(resp_str);
|
||||
ansdevice_free_string(resp_str);
|
||||
}
|
||||
return resp;
|
||||
});
|
||||
}
|
||||
|
||||
void ansdevice_on_connection_changed(AnsDeviceHandle h, AnsDeviceConnectionFn fn, void* ud) {
|
||||
if (!h || !fn) return;
|
||||
static_cast<DeviceAgent*>(h)->on_connection_changed(
|
||||
[fn, ud](bool c, const std::string& info) { fn(ud, c, info.c_str()); });
|
||||
}
|
||||
|
||||
void ansdevice_on_error(AnsDeviceHandle h, AnsDeviceErrorFn fn, void* ud) {
|
||||
if (!h || !fn) return;
|
||||
static_cast<DeviceAgent*>(h)->on_error(
|
||||
[fn, ud](int code, const std::string& msg) { fn(ud, code, msg.c_str()); });
|
||||
}
|
||||
|
||||
void ansdevice_on_broadcast(AnsDeviceHandle h, AnsDeviceBroadcastFn fn, void* ud) {
|
||||
if (!h || !fn) return;
|
||||
static_cast<DeviceAgent*>(h)->on_broadcast(
|
||||
[fn, ud](const std::string& msg) { fn(ud, msg.c_str()); });
|
||||
}
|
||||
|
||||
bool ansdevice_start(AnsDeviceHandle h) { return h ? static_cast<DeviceAgent*>(h)->start() : false; }
|
||||
void ansdevice_stop(AnsDeviceHandle h) { if (h) static_cast<DeviceAgent*>(h)->stop(); }
|
||||
bool ansdevice_is_running(AnsDeviceHandle h) { return h ? static_cast<DeviceAgent*>(h)->is_running() : false; }
|
||||
bool ansdevice_is_connected(AnsDeviceHandle h){ return h ? static_cast<DeviceAgent*>(h)->is_connected() : false; }
|
||||
|
||||
bool ansdevice_publish_event(AnsDeviceHandle h, const char* event_json) {
|
||||
if (!h || !event_json) return false;
|
||||
DeviceEvent evt = json::deserialize_event(event_json);
|
||||
return static_cast<DeviceAgent*>(h)->publish_event(evt);
|
||||
}
|
||||
|
||||
bool ansdevice_send_heartbeat(AnsDeviceHandle h) { return h ? static_cast<DeviceAgent*>(h)->send_heartbeat() : false; }
|
||||
bool ansdevice_send_metrics(AnsDeviceHandle h) { return h ? static_cast<DeviceAgent*>(h)->send_metrics() : false; }
|
||||
|
||||
const char* ansdevice_get_status(AnsDeviceHandle h) {
|
||||
if (!h) return alloc_copy("{}");
|
||||
auto s = static_cast<DeviceAgent*>(h)->get_status();
|
||||
// Simple JSON
|
||||
std::string j = "{\"connected\":" + std::string(s.connected ? "true" : "false")
|
||||
+ ",\"running\":" + std::string(s.running ? "true" : "false")
|
||||
+ ",\"uptime_seconds\":" + std::to_string(s.uptime_seconds)
|
||||
+ ",\"commands_received\":" + std::to_string(s.commands_received)
|
||||
+ ",\"commands_executed\":" + std::to_string(s.commands_executed)
|
||||
+ ",\"heartbeats_sent\":" + std::to_string(s.heartbeats_sent) + "}";
|
||||
return alloc_copy(j);
|
||||
}
|
||||
|
||||
void ansdevice_free_string(const char* str) {
|
||||
delete[] str;
|
||||
}
|
||||
|
||||
const char* ansdevice_version(void) {
|
||||
return "1.0.0";
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
''')
|
||||
|
||||
# ============================================================================
|
||||
# 10. gateway_agent.h
|
||||
# ============================================================================
|
||||
w("anscloud-gateway/include/anscloud/gateway/gateway_agent.h", r'''#pragma once
|
||||
// ==========================================================================
|
||||
// ANSCloud SDK - Gateway Agent (CMS side)
|
||||
//
|
||||
// Manages CMS gateway lifecycle:
|
||||
// - Connects to broker via IMessageBroker (your existing RabbitMQ API)
|
||||
// - Consumes telemetry, heartbeats, events, status from all devices
|
||||
// - Sends commands to devices (synchronous RPC via correlation_id)
|
||||
// - Tracks device online/offline state
|
||||
// ==========================================================================
|
||||
|
||||
#include <anscloud/common/types.h>
|
||||
#include <anscloud/common/i_message_broker.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Configuration
|
||||
// --------------------------------------------------------------------------
|
||||
struct GatewayAgentConfig {
|
||||
int device_timeout_seconds = 90; // mark offline if no heartbeat
|
||||
int default_command_timeout_seconds = 30;
|
||||
int max_pending_commands = 1000;
|
||||
bool verbose_logging = false;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Command result (from synchronous RPC)
|
||||
// --------------------------------------------------------------------------
|
||||
struct CommandResult {
|
||||
bool success = false;
|
||||
CommandStatus status = CommandStatus::Timeout;
|
||||
std::string result_json;
|
||||
std::string error_message;
|
||||
double execution_time_ms = 0.0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Device state as tracked by the gateway
|
||||
// --------------------------------------------------------------------------
|
||||
struct DeviceState {
|
||||
std::string device_id;
|
||||
DeviceStatus status = DeviceStatus::Unknown;
|
||||
std::string firmware_version;
|
||||
std::string ansvis_version;
|
||||
std::string ip_address;
|
||||
std::string last_heartbeat; // ISO 8601 timestamp
|
||||
std::string last_telemetry;
|
||||
uint64_t uptime_seconds = 0;
|
||||
SystemMetrics last_metrics;
|
||||
uint32_t camera_count = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Batch command result
|
||||
// --------------------------------------------------------------------------
|
||||
struct BatchResult {
|
||||
std::vector<std::pair<std::string, CommandResult>> results; // device_id -> result
|
||||
int succeeded = 0;
|
||||
int failed = 0;
|
||||
int timed_out = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Gateway statistics
|
||||
// --------------------------------------------------------------------------
|
||||
struct GatewayStats {
|
||||
uint64_t commands_sent = 0;
|
||||
uint64_t responses_received = 0;
|
||||
uint64_t timeouts = 0;
|
||||
uint64_t telemetry_received = 0;
|
||||
uint64_t heartbeats_received= 0;
|
||||
uint64_t events_received = 0;
|
||||
uint32_t devices_online = 0;
|
||||
uint32_t devices_total = 0;
|
||||
uint32_t pending_commands = 0;
|
||||
uint64_t uptime_seconds = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// GatewayAgent
|
||||
// --------------------------------------------------------------------------
|
||||
class GatewayAgent {
|
||||
public:
|
||||
GatewayAgent();
|
||||
~GatewayAgent();
|
||||
|
||||
GatewayAgent(const GatewayAgent&) = delete;
|
||||
GatewayAgent& operator=(const GatewayAgent&) = delete;
|
||||
|
||||
// --- Setup ---
|
||||
void configure(IMessageBroker* broker, const GatewayAgentConfig& config);
|
||||
|
||||
// --- Lifecycle ---
|
||||
bool start();
|
||||
void stop();
|
||||
bool is_running() const;
|
||||
bool is_connected() const;
|
||||
|
||||
// --- Commands ---
|
||||
// Synchronous RPC: sends command, blocks until response or timeout
|
||||
CommandResult send_command(
|
||||
const std::string& device_id,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}",
|
||||
int timeout_seconds = 0 // 0 = use default
|
||||
);
|
||||
|
||||
// Async version
|
||||
std::future<CommandResult> send_command_async(
|
||||
const std::string& device_id,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}",
|
||||
int timeout_seconds = 0
|
||||
);
|
||||
|
||||
// Fire-and-forget (no response expected)
|
||||
bool send_command_fire_and_forget(
|
||||
const std::string& device_id,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}"
|
||||
);
|
||||
|
||||
// Send to multiple devices
|
||||
BatchResult send_batch_command(
|
||||
const std::vector<std::string>& device_ids,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}",
|
||||
int timeout_seconds = 0
|
||||
);
|
||||
|
||||
// Broadcast to all devices
|
||||
bool send_broadcast(const std::string& message_json);
|
||||
|
||||
// --- Device tracking ---
|
||||
std::vector<DeviceState> get_all_devices() const;
|
||||
DeviceState get_device(const std::string& device_id) const;
|
||||
std::vector<DeviceState> get_online_devices() const;
|
||||
bool is_device_online(const std::string& device_id) const;
|
||||
|
||||
// --- Callbacks ---
|
||||
void on_telemetry(TelemetryCallback cb);
|
||||
void on_heartbeat(HeartbeatCallback cb);
|
||||
void on_event(EventCallback cb);
|
||||
void on_device_status_changed(StatusCallback cb);
|
||||
void on_connection_changed(ConnectionCallback cb);
|
||||
void on_error(ErrorCallback cb);
|
||||
|
||||
// --- Stats ---
|
||||
GatewayStats get_stats() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace anscloud
|
||||
''')
|
||||
|
||||
print(" [9-10] device_agent_c.cpp, gateway_agent.h done")
|
||||
323
_gen_vcxproj.py
Normal file
323
_gen_vcxproj.py
Normal file
@@ -0,0 +1,323 @@
|
||||
import os
|
||||
|
||||
R = r"C:\Projects\CMSCore"
|
||||
|
||||
def w(rel, txt):
|
||||
p = os.path.join(R, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8", newline="\r\n") as f:
|
||||
f.write(txt.lstrip("\n"))
|
||||
print(f" OK: {rel}")
|
||||
|
||||
# === VCXPROJ: anscloud-common (StaticLibrary) ===
|
||||
w("anscloud-common/anscloud-common.vcxproj", r'''<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64"><Configuration>Debug</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64"><Configuration>Release</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{11111111-1111-4000-8000-000000000001}</ProjectGuid>
|
||||
<RootNamespace>anscloudcommon</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType><UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType><UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><WholeProgramOptimization>true</WholeProgramOptimization><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\anscloud\common\types.h" />
|
||||
<ClInclude Include="include\anscloud\common\i_message_broker.h" />
|
||||
<ClInclude Include="include\anscloud\common\json_serializer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\types.cpp" />
|
||||
<ClCompile Include="src\json_serializer.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
''')
|
||||
|
||||
# === VCXPROJ: anscloud-device (StaticLibrary) ===
|
||||
w("anscloud-device/anscloud-device.vcxproj", r'''<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64"><Configuration>Debug</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64"><Configuration>Release</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{22222222-2222-4000-8000-000000000002}</ProjectGuid>
|
||||
<RootNamespace>ansclouddevice</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType><UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType><UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><WholeProgramOptimization>true</WholeProgramOptimization><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\anscloud\device\device_agent.h" />
|
||||
<ClInclude Include="include\anscloud\device\device_agent_c.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\device_agent.cpp" />
|
||||
<ClCompile Include="src\device_agent_c.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{11111111-1111-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
''')
|
||||
|
||||
# === VCXPROJ: anscloud-gateway (StaticLibrary) ===
|
||||
w("anscloud-gateway/anscloud-gateway.vcxproj", r'''<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64"><Configuration>Debug</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64"><Configuration>Release</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{33333333-3333-4000-8000-000000000003}</ProjectGuid>
|
||||
<RootNamespace>anscloudgateway</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType><UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType><UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><WholeProgramOptimization>true</WholeProgramOptimization><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\anscloud\gateway\gateway_agent.h" />
|
||||
<ClInclude Include="include\anscloud\gateway\gateway_agent_c.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\gateway_agent.cpp" />
|
||||
<ClCompile Include="src\gateway_agent_c.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{11111111-1111-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
''')
|
||||
|
||||
# === VCXPROJ: test-device (Console Application) ===
|
||||
w("test-device/test-device.vcxproj", r'''<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64"><Configuration>Debug</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64"><Configuration>Release</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{44444444-4444-4000-8000-000000000004}</ProjectGuid>
|
||||
<RootNamespace>testdevice</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType><UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType><UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><WholeProgramOptimization>true</WholeProgramOptimization><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-device\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link><SubSystem>Console</SubSystem></Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-device\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link><SubSystem>Console</SubSystem></Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{11111111-1111-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\anscloud-device\anscloud-device.vcxproj">
|
||||
<Project>{22222222-2222-4000-8000-000000000002}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
''')
|
||||
|
||||
# === VCXPROJ: test-gateway (Console Application) ===
|
||||
w("test-gateway/test-gateway.vcxproj", r'''<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64"><Configuration>Debug</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64"><Configuration>Release</Configuration><Platform>x64</Platform></ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{55555555-5555-4000-8000-000000000005}</ProjectGuid>
|
||||
<RootNamespace>testgateway</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType><UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType><UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset><WholeProgramOptimization>true</WholeProgramOptimization><CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-gateway\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link><SubSystem>Console</SubSystem></Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel><SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode><LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-gateway\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link><SubSystem>Console</SubSystem></Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{11111111-1111-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\anscloud-gateway\anscloud-gateway.vcxproj">
|
||||
<Project>{33333333-3333-4000-8000-000000000003}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
''')
|
||||
|
||||
print("\n=== All vcxproj files created ===")
|
||||
74
anscloud-common/anscloud-common.vcxproj
Normal file
74
anscloud-common/anscloud-common.vcxproj
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{B1A2C3D4-0001-4000-8000-000000000001}</ProjectGuid>
|
||||
<RootNamespace>anscloudcommon</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>anscloud-common</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;ANSCLOUD_COMMON_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;ANSCLOUD_COMMON_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\anscloud\common\types.h" />
|
||||
<ClInclude Include="include\anscloud\common\i_message_broker.h" />
|
||||
<ClInclude Include="include\anscloud\common\json_serializer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\types.cpp" />
|
||||
<ClCompile Include="src\json_serializer.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
125
anscloud-common/include/anscloud/common/i_message_broker.h
Normal file
125
anscloud-common/include/anscloud/common/i_message_broker.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
//=============================================================================
|
||||
// IMessageBroker - Abstract interface for message broker operations
|
||||
//
|
||||
// Your existing RabbitMQ C++ API implements this interface.
|
||||
// The SDK (DeviceAgent / GatewayAgent) depends only on this abstraction,
|
||||
// not on any concrete AMQP library.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ANSCLOUD_COMMON_I_MESSAGE_BROKER_H
|
||||
#define ANSCLOUD_COMMON_I_MESSAGE_BROKER_H
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
// Forward declare
|
||||
struct BrokerConfig;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Message received from broker
|
||||
//-----------------------------------------------------------------------------
|
||||
struct BrokerMessage {
|
||||
std::string exchange;
|
||||
std::string routing_key;
|
||||
std::string body; // JSON payload
|
||||
std::string correlation_id; // For RPC matching
|
||||
std::string reply_to; // Reply queue/routing key
|
||||
std::string message_id;
|
||||
std::string content_type; // "application/json"
|
||||
uint64_t delivery_tag = 0;
|
||||
bool redelivered = false;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Publish options
|
||||
//-----------------------------------------------------------------------------
|
||||
struct PublishOptions {
|
||||
std::string correlation_id;
|
||||
std::string reply_to;
|
||||
std::string message_id;
|
||||
std::string content_type = "application/json";
|
||||
bool persistent = true;
|
||||
int expiration_ms = 0; // 0 = no expiry (TTL)
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Callback types
|
||||
//-----------------------------------------------------------------------------
|
||||
using MessageCallback = std::function<void(const BrokerMessage& msg)>;
|
||||
using ConnectionCallback = std::function<void(bool connected)>;
|
||||
using ErrorCallback = std::function<void(const std::string& error)>;
|
||||
|
||||
//=============================================================================
|
||||
// IMessageBroker - Pure virtual interface
|
||||
//
|
||||
// Your existing RabbitMQ C++ API creates a class that inherits from this:
|
||||
//
|
||||
// class MyRabbitMQBroker : public anscloud::IMessageBroker {
|
||||
// // ... implement all pure virtual methods using your existing API
|
||||
// };
|
||||
//
|
||||
//=============================================================================
|
||||
class IMessageBroker {
|
||||
public:
|
||||
virtual ~IMessageBroker() = default;
|
||||
|
||||
//--- Connection lifecycle ------------------------------------------------
|
||||
virtual bool connect(const std::string& host, int port,
|
||||
const std::string& username, const std::string& password,
|
||||
const std::string& vhost) = 0;
|
||||
virtual void disconnect() = 0;
|
||||
virtual bool is_connected() const = 0;
|
||||
|
||||
//--- Exchange & Queue declarations (idempotent) --------------------------
|
||||
virtual bool declare_exchange(const std::string& name,
|
||||
const std::string& type = "topic",
|
||||
bool durable = true) = 0;
|
||||
|
||||
virtual bool declare_queue(const std::string& name,
|
||||
bool durable = true,
|
||||
bool exclusive = false,
|
||||
bool auto_delete = false) = 0;
|
||||
|
||||
virtual bool bind_queue(const std::string& queue,
|
||||
const std::string& exchange,
|
||||
const std::string& routing_key) = 0;
|
||||
|
||||
//--- Publishing ----------------------------------------------------------
|
||||
virtual bool publish(const std::string& exchange,
|
||||
const std::string& routing_key,
|
||||
const std::string& body,
|
||||
const PublishOptions& options = {}) = 0;
|
||||
|
||||
//--- Consuming -----------------------------------------------------------
|
||||
// Start consuming from a queue. Messages delivered via callback.
|
||||
// Returns a consumer tag (string) that can be used to cancel.
|
||||
virtual std::string start_consuming(const std::string& queue,
|
||||
MessageCallback callback,
|
||||
bool auto_ack = true) = 0;
|
||||
|
||||
// Cancel a consumer by tag
|
||||
virtual void cancel_consumer(const std::string& consumer_tag) = 0;
|
||||
|
||||
// Process pending messages (call from event loop).
|
||||
// timeout_ms: max time to wait for messages. 0 = non-blocking poll.
|
||||
// Returns number of messages processed.
|
||||
virtual int process_messages(int timeout_ms = 100) = 0;
|
||||
|
||||
//--- Callbacks -----------------------------------------------------------
|
||||
virtual void on_connected(ConnectionCallback cb) = 0;
|
||||
virtual void on_error(ErrorCallback cb) = 0;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Factory function type - your application provides this
|
||||
//=============================================================================
|
||||
using BrokerFactory = std::function<std::unique_ptr<IMessageBroker>()>;
|
||||
|
||||
} // namespace anscloud
|
||||
|
||||
#endif // ANSCLOUD_COMMON_I_MESSAGE_BROKER_H
|
||||
47
anscloud-common/include/anscloud/common/json_serializer.h
Normal file
47
anscloud-common/include/anscloud/common/json_serializer.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#ifndef ANSCLOUD_COMMON_JSON_SERIALIZER_H
|
||||
#define ANSCLOUD_COMMON_JSON_SERIALIZER_H
|
||||
|
||||
#include "types.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace anscloud {
|
||||
namespace json {
|
||||
|
||||
// Serialization (struct -> JSON string)
|
||||
std::string serialize(const Heartbeat& hb);
|
||||
std::string serialize(const DeviceTelemetry& tel);
|
||||
std::string serialize(const SystemMetrics& m);
|
||||
std::string serialize(const Command& cmd);
|
||||
std::string serialize(const CommandResponse& resp);
|
||||
std::string serialize(const DeviceEvent& evt);
|
||||
std::string serialize(const DeviceStatusMessage& msg);
|
||||
std::string serialize(const CameraInfo& cam);
|
||||
std::string serialize(const std::vector<CameraInfo>& cams);
|
||||
std::string serialize(const DeviceState& state);
|
||||
std::string serialize(const std::vector<DeviceState>& states);
|
||||
std::string serialize(const CommandResult& result);
|
||||
|
||||
// Deserialization (JSON string -> struct)
|
||||
Heartbeat deserialize_heartbeat(const std::string& json);
|
||||
DeviceTelemetry deserialize_telemetry(const std::string& json);
|
||||
SystemMetrics deserialize_metrics(const std::string& json);
|
||||
Command deserialize_command(const std::string& json);
|
||||
CommandResponse deserialize_response(const std::string& json);
|
||||
DeviceEvent deserialize_event(const std::string& json);
|
||||
DeviceStatusMessage deserialize_status_message(const std::string& json);
|
||||
CameraInfo deserialize_camera(const std::string& json);
|
||||
std::vector<CameraInfo> deserialize_cameras(const std::string& json);
|
||||
DeviceState deserialize_device_state(const std::string& json);
|
||||
std::vector<DeviceState> deserialize_device_states(const std::string& json);
|
||||
CommandResult deserialize_command_result(const std::string& json);
|
||||
|
||||
// Utility
|
||||
std::string now_iso8601();
|
||||
std::string generate_uuid();
|
||||
|
||||
} // namespace json
|
||||
} // namespace anscloud
|
||||
|
||||
#endif // ANSCLOUD_COMMON_JSON_SERIALIZER_H
|
||||
255
anscloud-common/include/anscloud/common/types.h
Normal file
255
anscloud-common/include/anscloud/common/types.h
Normal file
@@ -0,0 +1,255 @@
|
||||
#pragma once
|
||||
#ifndef ANSCLOUD_COMMON_TYPES_H
|
||||
#define ANSCLOUD_COMMON_TYPES_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
//=============================================================================
|
||||
// Protocol Constants - Exchange & Queue names
|
||||
//=============================================================================
|
||||
namespace protocol {
|
||||
// Exchanges
|
||||
constexpr const char* EX_DEVICE_TELEMETRY = "ex.device.telemetry";
|
||||
constexpr const char* EX_DEVICE_STATUS = "ex.device.status";
|
||||
constexpr const char* EX_DEVICE_EVENTS = "ex.device.events";
|
||||
constexpr const char* EX_COMMAND = "ex.command";
|
||||
constexpr const char* EX_COMMAND_RESPONSE = "ex.command.response";
|
||||
constexpr const char* EX_BROADCAST = "ex.broadcast";
|
||||
|
||||
// Queue name patterns (format with device_id)
|
||||
inline std::string queue_cmd(const std::string& device_id) {
|
||||
return "q.cmd." + device_id;
|
||||
}
|
||||
inline std::string queue_broadcast(const std::string& device_id) {
|
||||
return "q.broadcast." + device_id;
|
||||
}
|
||||
|
||||
// Gateway consumer queues
|
||||
constexpr const char* Q_TELEMETRY_INGEST = "q.telemetry.ingest";
|
||||
constexpr const char* Q_EVENTS_PROCESSOR = "q.events.processor";
|
||||
constexpr const char* Q_STATUS_TRACKER = "q.status.tracker";
|
||||
constexpr const char* Q_COMMAND_RESPONSES = "q.command.responses";
|
||||
} // namespace protocol
|
||||
|
||||
//=============================================================================
|
||||
// Broker Configuration
|
||||
//=============================================================================
|
||||
struct BrokerConfig {
|
||||
std::string host = "localhost";
|
||||
int port = 5672;
|
||||
std::string username = "guest";
|
||||
std::string password = "guest";
|
||||
std::string vhost = "/";
|
||||
bool use_tls = false;
|
||||
int heartbeat_sec = 60;
|
||||
int reconnect_delay_ms = 1000;
|
||||
int reconnect_max_delay_ms = 30000;
|
||||
int connection_timeout_ms = 10000;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Device Identity
|
||||
//=============================================================================
|
||||
struct DeviceCredentials {
|
||||
std::string device_id; // e.g. "AIBOX-001"
|
||||
std::string device_secret; // Authentication token
|
||||
std::string tenant_id; // Multi-tenancy isolation
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Device Status
|
||||
//=============================================================================
|
||||
enum class DeviceStatus {
|
||||
Online,
|
||||
Offline,
|
||||
Connecting,
|
||||
Error
|
||||
};
|
||||
|
||||
const char* to_string(DeviceStatus status);
|
||||
DeviceStatus device_status_from_string(const std::string& str);
|
||||
|
||||
struct DeviceStatusMessage {
|
||||
std::string device_id;
|
||||
DeviceStatus status = DeviceStatus::Offline;
|
||||
std::string timestamp; // ISO 8601
|
||||
std::string firmware_version;
|
||||
std::string ansvis_version;
|
||||
std::string ip_address;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Telemetry Types
|
||||
//=============================================================================
|
||||
struct SystemMetrics {
|
||||
double cpu_usage_percent = 0.0;
|
||||
double ram_usage_percent = 0.0;
|
||||
double ram_used_mb = 0.0;
|
||||
double ram_total_mb = 0.0;
|
||||
double gpu_usage_percent = 0.0;
|
||||
double gpu_memory_used_mb = 0.0;
|
||||
double gpu_memory_total_mb = 0.0;
|
||||
double gpu_temp_celsius = 0.0;
|
||||
double disk_usage_percent = 0.0;
|
||||
double disk_used_gb = 0.0;
|
||||
double disk_total_gb = 0.0;
|
||||
int process_count = 0;
|
||||
double uptime_hours = 0.0;
|
||||
};
|
||||
|
||||
struct CameraInfo {
|
||||
std::string camera_id;
|
||||
std::string name;
|
||||
std::string rtsp_url;
|
||||
std::string status; // "active", "error", "disabled"
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
double fps = 0.0;
|
||||
std::string error_message;
|
||||
};
|
||||
|
||||
struct InferenceMetrics {
|
||||
int active_models = 0;
|
||||
double total_fps = 0.0;
|
||||
double avg_latency_ms = 0.0;
|
||||
int detections_per_second = 0;
|
||||
};
|
||||
|
||||
struct Heartbeat {
|
||||
std::string device_id;
|
||||
std::string timestamp;
|
||||
uint64_t uptime_seconds = 0;
|
||||
int active_cameras = 0;
|
||||
int active_models = 0;
|
||||
};
|
||||
|
||||
struct DeviceTelemetry {
|
||||
std::string device_id;
|
||||
std::string timestamp;
|
||||
SystemMetrics system;
|
||||
std::vector<CameraInfo> cameras;
|
||||
InferenceMetrics inference;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Command Types
|
||||
//=============================================================================
|
||||
enum class CommandType {
|
||||
// System
|
||||
GetSystemInfo,
|
||||
GetConfig,
|
||||
SetConfig,
|
||||
RestartService,
|
||||
RebootDevice,
|
||||
UpdateFirmware,
|
||||
RunDiagnostics,
|
||||
// Camera
|
||||
GetCameraList,
|
||||
AddCamera,
|
||||
RemoveCamera,
|
||||
UpdateCamera,
|
||||
GetCameraSnapshot,
|
||||
// AI Model
|
||||
GetModelList,
|
||||
LoadModel,
|
||||
UnloadModel,
|
||||
// Custom
|
||||
Custom
|
||||
};
|
||||
|
||||
const char* to_string(CommandType type);
|
||||
CommandType command_type_from_string(const std::string& str);
|
||||
|
||||
enum class CommandStatus {
|
||||
Pending,
|
||||
Executing,
|
||||
Success,
|
||||
Failed,
|
||||
Timeout,
|
||||
Cancelled
|
||||
};
|
||||
|
||||
const char* to_string(CommandStatus status);
|
||||
CommandStatus command_status_from_string(const std::string& str);
|
||||
|
||||
struct Command {
|
||||
std::string command_id; // UUID
|
||||
std::string device_id; // Target device
|
||||
CommandType type = CommandType::Custom;
|
||||
std::string custom_type; // When type == Custom
|
||||
std::string params_json; // JSON parameters
|
||||
std::string correlation_id; // For RPC matching
|
||||
std::string timestamp;
|
||||
int timeout_seconds = 30;
|
||||
};
|
||||
|
||||
struct CommandResponse {
|
||||
std::string command_id;
|
||||
std::string device_id;
|
||||
CommandStatus status = CommandStatus::Pending;
|
||||
std::string result_json; // JSON result payload
|
||||
std::string error_message;
|
||||
std::string correlation_id;
|
||||
std::string timestamp;
|
||||
int execution_time_ms = 0;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Event Types
|
||||
//=============================================================================
|
||||
enum class EventType {
|
||||
Alert,
|
||||
DetectionLPR,
|
||||
DetectionFace,
|
||||
DetectionObject,
|
||||
CameraStatusChanged,
|
||||
ModelStatusChanged,
|
||||
SystemAlert,
|
||||
Custom
|
||||
};
|
||||
|
||||
const char* to_string(EventType type);
|
||||
EventType event_type_from_string(const std::string& str);
|
||||
|
||||
struct DeviceEvent {
|
||||
std::string event_id; // UUID
|
||||
std::string device_id;
|
||||
EventType type = EventType::Custom;
|
||||
std::string custom_type;
|
||||
std::string data_json; // Event payload
|
||||
std::string camera_id; // Optional: related camera
|
||||
std::string timestamp;
|
||||
std::string severity; // "info", "warning", "critical"
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Gateway-side types
|
||||
//=============================================================================
|
||||
struct CommandResult {
|
||||
bool success = false;
|
||||
CommandStatus status = CommandStatus::Pending;
|
||||
std::string result_json;
|
||||
std::string error_message;
|
||||
int execution_time_ms = 0;
|
||||
};
|
||||
|
||||
struct DeviceState {
|
||||
std::string device_id;
|
||||
DeviceStatus status = DeviceStatus::Offline;
|
||||
std::string last_seen; // ISO 8601
|
||||
std::string ip_address;
|
||||
std::string firmware_version;
|
||||
std::string ansvis_version;
|
||||
SystemMetrics last_metrics;
|
||||
int camera_count = 0;
|
||||
};
|
||||
|
||||
} // namespace anscloud
|
||||
|
||||
#endif // ANSCLOUD_COMMON_TYPES_H
|
||||
86
anscloud-device/anscloud-device.vcxproj
Normal file
86
anscloud-device/anscloud-device.vcxproj
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{B1A2C3D4-0001-4000-8000-000000000002}</ProjectGuid>
|
||||
<RootNamespace>ansclouddevice</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>anscloud-device</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;ANSCLOUD_DEVICE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>anscloud-common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;ANSCLOUD_DEVICE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>anscloud-common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\anscloud\device\device_agent.h" />
|
||||
<ClInclude Include="include\anscloud\device\device_agent_c.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\device_agent.cpp" />
|
||||
<ClCompile Include="src\device_agent_c.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{B1A2C3D4-0001-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
123
anscloud-device/include/anscloud/device/device_agent.h
Normal file
123
anscloud-device/include/anscloud/device/device_agent.h
Normal file
@@ -0,0 +1,123 @@
|
||||
#pragma once
|
||||
#ifndef ANSCLOUD_DEVICE_AGENT_H
|
||||
#define ANSCLOUD_DEVICE_AGENT_H
|
||||
|
||||
#include <anscloud/common/types.h>
|
||||
#include <anscloud/common/i_message_broker.h>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
#ifdef ANSCLOUD_DEVICE_EXPORTS
|
||||
#define ANSCLOUD_DEVICE_API __declspec(dllexport)
|
||||
#else
|
||||
#define ANSCLOUD_DEVICE_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
//=============================================================================
|
||||
// DeviceAgent Configuration
|
||||
//=============================================================================
|
||||
struct DeviceAgentConfig {
|
||||
BrokerConfig broker;
|
||||
DeviceCredentials credentials;
|
||||
|
||||
// Telemetry intervals (seconds)
|
||||
int heartbeat_interval_sec = 30;
|
||||
int metrics_interval_sec = 60;
|
||||
int snapshot_interval_sec = 0; // 0 = disabled
|
||||
|
||||
// Device info
|
||||
std::string firmware_version;
|
||||
std::string ansvis_version;
|
||||
std::string ip_address;
|
||||
std::string local_api_endpoint; // e.g. "http://127.0.0.1:8080"
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Application callback types - your app implements these
|
||||
//=============================================================================
|
||||
using CommandHandler = std::function<CommandResponse(const Command& cmd)>;
|
||||
using MetricsProvider = std::function<SystemMetrics()>;
|
||||
using CameraListProvider = std::function<std::vector<CameraInfo>()>;
|
||||
using InferenceProvider = std::function<InferenceMetrics()>;
|
||||
using SnapshotProvider = std::function<std::string(const std::string& camera_id)>; // returns base64 JPEG
|
||||
|
||||
//=============================================================================
|
||||
// Agent runtime status
|
||||
//=============================================================================
|
||||
struct AgentStatus {
|
||||
bool connected = false;
|
||||
bool running = false;
|
||||
uint64_t uptime_seconds = 0;
|
||||
uint64_t commands_received = 0;
|
||||
uint64_t commands_executed = 0;
|
||||
uint64_t heartbeats_sent = 0;
|
||||
uint64_t telemetry_sent = 0;
|
||||
uint64_t events_published = 0;
|
||||
uint64_t reconnect_count = 0;
|
||||
std::string last_error;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// DeviceAgent - AIBOX cloud agent
|
||||
//
|
||||
// Inject your existing RabbitMQ C++ API via BrokerFactory:
|
||||
//
|
||||
// DeviceAgent agent([](){ return std::make_unique<MyRabbitMQBroker>(); });
|
||||
// agent.configure(config);
|
||||
// agent.set_command_handler(...);
|
||||
// agent.start(); // non-blocking
|
||||
//
|
||||
//=============================================================================
|
||||
class ANSCLOUD_DEVICE_API DeviceAgent {
|
||||
public:
|
||||
// Construct with broker factory (your RabbitMQ API)
|
||||
explicit DeviceAgent(BrokerFactory factory);
|
||||
~DeviceAgent();
|
||||
|
||||
// Non-copyable, movable
|
||||
DeviceAgent(const DeviceAgent&) = delete;
|
||||
DeviceAgent& operator=(const DeviceAgent&) = delete;
|
||||
DeviceAgent(DeviceAgent&&) noexcept;
|
||||
DeviceAgent& operator=(DeviceAgent&&) noexcept;
|
||||
|
||||
//--- Configuration (call before start) -----------------------------------
|
||||
void configure(const DeviceAgentConfig& config);
|
||||
|
||||
void set_command_handler(CommandHandler handler);
|
||||
void set_metrics_provider(MetricsProvider provider);
|
||||
void set_camera_list_provider(CameraListProvider provider);
|
||||
void set_inference_provider(InferenceProvider provider);
|
||||
void set_snapshot_provider(SnapshotProvider provider);
|
||||
|
||||
//--- Lifecycle (non-blocking) --------------------------------------------
|
||||
bool start(); // Connects, declares queues, starts background threads
|
||||
void stop(); // Publishes offline, disconnects, stops threads
|
||||
|
||||
bool is_running() const;
|
||||
bool is_connected() const;
|
||||
|
||||
//--- Manual publishing ---------------------------------------------------
|
||||
void publish_event(const DeviceEvent& event);
|
||||
void publish_telemetry(const DeviceTelemetry& telemetry);
|
||||
void send_heartbeat_now();
|
||||
void send_metrics_now();
|
||||
|
||||
//--- Status & callbacks --------------------------------------------------
|
||||
AgentStatus get_status() const;
|
||||
|
||||
void on_connection_changed(ConnectionCallback cb);
|
||||
void on_error(ErrorCallback cb);
|
||||
void on_broadcast(std::function<void(const std::string& message)> cb);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace anscloud
|
||||
|
||||
#endif // ANSCLOUD_DEVICE_AGENT_H
|
||||
114
anscloud-device/include/anscloud/device/device_agent_c.h
Normal file
114
anscloud-device/include/anscloud/device/device_agent_c.h
Normal file
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
#ifndef ANSCLOUD_DEVICE_AGENT_C_H
|
||||
#define ANSCLOUD_DEVICE_AGENT_C_H
|
||||
|
||||
#ifdef ANSCLOUD_DEVICE_EXPORTS
|
||||
#define ANSCLOUD_DEVICE_CAPI __declspec(dllexport)
|
||||
#else
|
||||
#define ANSCLOUD_DEVICE_CAPI __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// Opaque handle
|
||||
//=============================================================================
|
||||
typedef struct AnsDeviceAgent* AnsDeviceAgentHandle;
|
||||
|
||||
//=============================================================================
|
||||
// C-compatible config structs
|
||||
//=============================================================================
|
||||
typedef struct {
|
||||
const char* host;
|
||||
int port;
|
||||
const char* username;
|
||||
const char* password;
|
||||
const char* vhost;
|
||||
int use_tls;
|
||||
} AnsDeviceBrokerConfig;
|
||||
|
||||
typedef struct {
|
||||
const char* device_id;
|
||||
const char* device_secret;
|
||||
const char* tenant_id;
|
||||
} AnsDeviceCredentials;
|
||||
|
||||
typedef struct {
|
||||
AnsDeviceBrokerConfig broker;
|
||||
AnsDeviceCredentials credentials;
|
||||
int heartbeat_interval_sec;
|
||||
int metrics_interval_sec;
|
||||
const char* firmware_version;
|
||||
const char* ansvis_version;
|
||||
const char* ip_address;
|
||||
} AnsDeviceConfig;
|
||||
|
||||
//=============================================================================
|
||||
// Callback types
|
||||
//=============================================================================
|
||||
// command_json: JSON string of Command. Return: JSON string of CommandResponse.
|
||||
// Caller must free returned string with ansdevice_free_string().
|
||||
typedef const char* (*AnsDeviceCommandHandlerFn)(const char* command_json, void* user_data);
|
||||
|
||||
// metrics_json: caller must free returned JSON string
|
||||
typedef const char* (*AnsDeviceMetricsProviderFn)(void* user_data);
|
||||
|
||||
typedef void (*AnsDeviceConnectionCallbackFn)(int connected, void* user_data);
|
||||
typedef void (*AnsDeviceErrorCallbackFn)(const char* error, void* user_data);
|
||||
typedef void (*AnsDeviceBroadcastCallbackFn)(const char* message, void* user_data);
|
||||
|
||||
//=============================================================================
|
||||
// Lifecycle
|
||||
//=============================================================================
|
||||
// broker_factory_fn: function pointer that creates your IMessageBroker.
|
||||
// For simplicity in C API, pass NULL to use a default (if you register one).
|
||||
ANSCLOUD_DEVICE_CAPI AnsDeviceAgentHandle ansdevice_create(void);
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_destroy(AnsDeviceAgentHandle handle);
|
||||
|
||||
ANSCLOUD_DEVICE_CAPI int ansdevice_configure(AnsDeviceAgentHandle handle, const AnsDeviceConfig* config);
|
||||
ANSCLOUD_DEVICE_CAPI int ansdevice_start(AnsDeviceAgentHandle handle);
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_stop(AnsDeviceAgentHandle handle);
|
||||
ANSCLOUD_DEVICE_CAPI int ansdevice_is_running(AnsDeviceAgentHandle handle);
|
||||
ANSCLOUD_DEVICE_CAPI int ansdevice_is_connected(AnsDeviceAgentHandle handle);
|
||||
|
||||
//=============================================================================
|
||||
// Handlers & providers
|
||||
//=============================================================================
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_set_command_handler(AnsDeviceAgentHandle handle,
|
||||
AnsDeviceCommandHandlerFn fn, void* user_data);
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_set_metrics_provider(AnsDeviceAgentHandle handle,
|
||||
AnsDeviceMetricsProviderFn fn, void* user_data);
|
||||
|
||||
//=============================================================================
|
||||
// Publishing
|
||||
//=============================================================================
|
||||
ANSCLOUD_DEVICE_CAPI int ansdevice_publish_event(AnsDeviceAgentHandle handle, const char* event_json);
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_send_heartbeat(AnsDeviceAgentHandle handle);
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_send_metrics(AnsDeviceAgentHandle handle);
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks
|
||||
//=============================================================================
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_on_connection_changed(AnsDeviceAgentHandle handle,
|
||||
AnsDeviceConnectionCallbackFn fn, void* user_data);
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_on_error(AnsDeviceAgentHandle handle,
|
||||
AnsDeviceErrorCallbackFn fn, void* user_data);
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_on_broadcast(AnsDeviceAgentHandle handle,
|
||||
AnsDeviceBroadcastCallbackFn fn, void* user_data);
|
||||
|
||||
//=============================================================================
|
||||
// Status & memory
|
||||
//=============================================================================
|
||||
// Returns JSON string. Caller must free with ansdevice_free_string().
|
||||
ANSCLOUD_DEVICE_CAPI const char* ansdevice_get_status(AnsDeviceAgentHandle handle);
|
||||
|
||||
ANSCLOUD_DEVICE_CAPI void ansdevice_free_string(const char* str);
|
||||
ANSCLOUD_DEVICE_CAPI const char* ansdevice_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ANSCLOUD_DEVICE_AGENT_C_H
|
||||
86
anscloud-gateway/anscloud-gateway.vcxproj
Normal file
86
anscloud-gateway/anscloud-gateway.vcxproj
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{B1A2C3D4-0001-4000-8000-000000000003}</ProjectGuid>
|
||||
<RootNamespace>anscloudgateway</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>anscloud-gateway</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;ANSCLOUD_GATEWAY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>anscloud-common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;ANSCLOUD_GATEWAY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)anscloud-common\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>anscloud-common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\anscloud\gateway\gateway_agent.h" />
|
||||
<ClInclude Include="include\anscloud\gateway\gateway_agent_c.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\gateway_agent.cpp" />
|
||||
<ClCompile Include="src\gateway_agent_c.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{B1A2C3D4-0001-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
145
anscloud-gateway/include/anscloud/gateway/gateway_agent.h
Normal file
145
anscloud-gateway/include/anscloud/gateway/gateway_agent.h
Normal file
@@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
#ifndef ANSCLOUD_GATEWAY_AGENT_H
|
||||
#define ANSCLOUD_GATEWAY_AGENT_H
|
||||
|
||||
#include <anscloud/common/types.h>
|
||||
#include <anscloud/common/i_message_broker.h>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <future>
|
||||
|
||||
#ifdef ANSCLOUD_GATEWAY_EXPORTS
|
||||
#define ANSCLOUD_GATEWAY_API __declspec(dllexport)
|
||||
#else
|
||||
#define ANSCLOUD_GATEWAY_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
namespace anscloud {
|
||||
|
||||
//=============================================================================
|
||||
// Gateway Configuration
|
||||
//=============================================================================
|
||||
struct GatewayCredentials {
|
||||
std::string username;
|
||||
std::string password;
|
||||
std::string vhost = "/";
|
||||
};
|
||||
|
||||
struct GatewayAgentConfig {
|
||||
BrokerConfig broker;
|
||||
GatewayCredentials credentials;
|
||||
int device_timeout_seconds = 90;
|
||||
int default_command_timeout_seconds = 30;
|
||||
int max_pending_commands = 1000;
|
||||
};
|
||||
|
||||
struct GatewayStats {
|
||||
uint64_t commands_sent = 0;
|
||||
uint64_t commands_responded = 0;
|
||||
uint64_t commands_timed_out = 0;
|
||||
uint64_t telemetry_received = 0;
|
||||
uint64_t events_received = 0;
|
||||
uint64_t heartbeats_received = 0;
|
||||
int devices_online = 0;
|
||||
int devices_total = 0;
|
||||
int pending_commands = 0;
|
||||
uint64_t uptime_seconds = 0;
|
||||
};
|
||||
|
||||
struct BatchResult {
|
||||
std::vector<std::pair<std::string, CommandResult>> results; // device_id -> result
|
||||
int succeeded = 0;
|
||||
int failed = 0;
|
||||
int timed_out = 0;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// GatewayAgent - CMS gateway for consuming device messages & sending commands
|
||||
//
|
||||
// GatewayAgent gw([](){ return std::make_unique<MyRabbitMQBroker>(); });
|
||||
// gw.configure(config);
|
||||
// gw.on_telemetry([](const DeviceTelemetry& t){ /* store */ });
|
||||
// gw.on_event([](const DeviceEvent& e){ /* process */ });
|
||||
// gw.start();
|
||||
//
|
||||
// auto result = gw.send_command("AIBOX-001", CommandType::GetConfig);
|
||||
//
|
||||
//=============================================================================
|
||||
class ANSCLOUD_GATEWAY_API GatewayAgent {
|
||||
public:
|
||||
explicit GatewayAgent(BrokerFactory factory);
|
||||
~GatewayAgent();
|
||||
|
||||
GatewayAgent(const GatewayAgent&) = delete;
|
||||
GatewayAgent& operator=(const GatewayAgent&) = delete;
|
||||
GatewayAgent(GatewayAgent&&) noexcept;
|
||||
GatewayAgent& operator=(GatewayAgent&&) noexcept;
|
||||
|
||||
//--- Configuration -------------------------------------------------------
|
||||
void configure(const GatewayAgentConfig& config);
|
||||
|
||||
//--- Lifecycle -----------------------------------------------------------
|
||||
bool start();
|
||||
void stop();
|
||||
bool is_running() const;
|
||||
bool is_connected() const;
|
||||
|
||||
//--- Commands (synchronous RPC) ------------------------------------------
|
||||
CommandResult send_command(const std::string& device_id,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}",
|
||||
int timeout_seconds = 0); // 0 = use default
|
||||
|
||||
std::future<CommandResult> send_command_async(const std::string& device_id,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}",
|
||||
int timeout_seconds = 0);
|
||||
|
||||
CommandResult send_custom_command(const std::string& device_id,
|
||||
const std::string& custom_type,
|
||||
const std::string& params_json = "{}",
|
||||
int timeout_seconds = 0);
|
||||
|
||||
void send_command_fire_and_forget(const std::string& device_id,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}");
|
||||
|
||||
BatchResult send_batch_command(const std::vector<std::string>& device_ids,
|
||||
CommandType type,
|
||||
const std::string& params_json = "{}",
|
||||
int timeout_seconds = 0);
|
||||
|
||||
void send_broadcast(const std::string& message);
|
||||
|
||||
//--- Device tracking -----------------------------------------------------
|
||||
std::vector<DeviceState> get_all_devices() const;
|
||||
DeviceState get_device(const std::string& device_id) const;
|
||||
std::vector<DeviceState> get_online_devices() const;
|
||||
bool is_device_online(const std::string& device_id) const;
|
||||
|
||||
//--- Callbacks -----------------------------------------------------------
|
||||
using TelemetryCallback = std::function<void(const DeviceTelemetry&)>;
|
||||
using HeartbeatCallback = std::function<void(const Heartbeat&)>;
|
||||
using EventCallback = std::function<void(const DeviceEvent&)>;
|
||||
using DeviceStatusCallback = std::function<void(const std::string& device_id, DeviceStatus status)>;
|
||||
|
||||
void on_telemetry(TelemetryCallback cb);
|
||||
void on_heartbeat(HeartbeatCallback cb);
|
||||
void on_event(EventCallback cb);
|
||||
void on_device_status_changed(DeviceStatusCallback cb);
|
||||
void on_connection_changed(ConnectionCallback cb);
|
||||
void on_error(ErrorCallback cb);
|
||||
|
||||
//--- Stats ---------------------------------------------------------------
|
||||
GatewayStats get_stats() const;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace anscloud
|
||||
|
||||
#endif // ANSCLOUD_GATEWAY_AGENT_H
|
||||
57
anscloud-gateway/include/anscloud/gateway/gateway_agent_c.h
Normal file
57
anscloud-gateway/include/anscloud/gateway/gateway_agent_c.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#ifndef ANSCLOUD_GATEWAY_AGENT_C_H
|
||||
#define ANSCLOUD_GATEWAY_AGENT_C_H
|
||||
|
||||
#ifdef ANSCLOUD_GATEWAY_EXPORTS
|
||||
#define ANSCLOUD_GATEWAY_CAPI __declspec(dllexport)
|
||||
#else
|
||||
#define ANSCLOUD_GATEWAY_CAPI __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct AnsGatewayAgent* AnsGatewayAgentHandle;
|
||||
|
||||
typedef struct {
|
||||
const char* host;
|
||||
int port;
|
||||
const char* username;
|
||||
const char* password;
|
||||
const char* vhost;
|
||||
int use_tls;
|
||||
} AnsGatewayBrokerConfig;
|
||||
|
||||
typedef struct {
|
||||
const char* username;
|
||||
const char* password;
|
||||
const char* vhost;
|
||||
} AnsGatewayCredentials;
|
||||
|
||||
typedef struct {
|
||||
AnsGatewayBrokerConfig broker;
|
||||
AnsGatewayCredentials credentials;
|
||||
int device_timeout_seconds;
|
||||
int default_command_timeout_seconds;
|
||||
int max_pending_commands;
|
||||
} AnsGatewayConfig;
|
||||
|
||||
// Callbacks - all receive JSON strings
|
||||
typedef void (*AnsGatewayTelemetryCallbackFn)(const char* telemetry_json, void* user_data);
|
||||
typedef void (*AnsGatewayHeartbeatCallbackFn)(const char* heartbeat_json, void* user_data);
|
||||
typedef void (*AnsGatewayEventCallbackFn)(const char* event_json, void* user_data);
|
||||
typedef void (*AnsGatewayDeviceStatusCallbackFn)(const char* device_id, const char* status, void* user_data);
|
||||
typedef void (*AnsGatewayConnectionCallbackFn)(int connected, void* user_data);
|
||||
typedef void (*AnsGatewayErrorCallbackFn)(const char* error, void* user_data);
|
||||
|
||||
//=============================================================================
|
||||
// Lifecycle
|
||||
//=============================================================================
|
||||
ANSCLOUD_GATEWAY_CAPI AnsGatewayAgentHandle ansgateway_create(void);
|
||||
ANSCLOUD_GATEWAY_CAPI void ansgateway_destroy(AnsGatewayAgentHandle handle);
|
||||
ANSCLOUD_GATEWAY_CAPI int ansgateway_configure(AnsGatewayAgentHandle handle, const AnsGatewayConfig* config);
|
||||
ANSCLOUD_GATEWAY_CAPI int ansgateway_start(AnsGatewayAgentHandle handle);
|
||||
ANSCLOUD_GATEWAY_CAPI void ansgateway_stop(AnsGatewayAgentHandle handle);
|
||||
ANSCLOUD_GATEWAY_CAPI int ansgateway_is_running(AnsGatewayAgentHandle handle);
|
||||
ANSCLOUD_GATEWAY_CAPI int ansgateway_is_connected(AnsGatewayAgentHandle handle);
|
||||
636
architecture-diagram.html
Normal file
636
architecture-diagram.html
Normal file
@@ -0,0 +1,636 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ANSCloud Integration Architecture</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&family=DM+Sans:wght@400;500;600;700&display=swap');
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
background: #0a0e1a;
|
||||
color: #e0e4ef;
|
||||
min-height: 100vh;
|
||||
padding: 30px 20px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.page-title h1 {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
letter-spacing: -0.5px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.page-title .sub {
|
||||
font-size: 13px;
|
||||
color: #6b7394;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* ── Main Architecture ── */
|
||||
.arch-container {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto 50px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* ── Tier Section ── */
|
||||
.tier-section {
|
||||
margin-bottom: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tier-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.tier-badge {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
letter-spacing: 0.5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.tier-1 .tier-badge { background: #1a3a2a; color: #4ade80; border: 1px solid #2d5a3e; }
|
||||
.tier-2 .tier-badge { background: #1a2a4a; color: #60a5fa; border: 1px solid #2d4a6e; }
|
||||
.tier-3 .tier-badge { background: #2a1a3a; color: #c084fc; border: 1px solid #4a2d6e; }
|
||||
|
||||
.tier-label {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #c0c8e0;
|
||||
}
|
||||
.tier-desc {
|
||||
font-size: 12px;
|
||||
color: #6b7394;
|
||||
margin-left: auto;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* ── Flow Row ── */
|
||||
.flow-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
padding: 16px 20px;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tier-1 .flow-row { background: linear-gradient(135deg, #0d1a14 0%, #0f1820 100%); border: 1px solid #1a3a2a; }
|
||||
.tier-2 .flow-row { background: linear-gradient(135deg, #0d1420 0%, #0f1828 100%); border: 1px solid #1a2a4a; }
|
||||
.tier-3 .flow-row { background: linear-gradient(135deg, #14101e 0%, #18122a 100%); border: 1px solid #2a1a3a; }
|
||||
|
||||
/* ── Boxes ── */
|
||||
.box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
min-width: 120px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.box-icon {
|
||||
font-size: 20px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.box-title {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.box-sub {
|
||||
font-size: 10px;
|
||||
color: #6b7394;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* Box themes */
|
||||
.box-partner {
|
||||
background: #141824;
|
||||
border: 1px solid #2a3050;
|
||||
min-width: 150px;
|
||||
}
|
||||
.box-partner .box-title { color: #94a3c8; }
|
||||
|
||||
.box-api {
|
||||
background: linear-gradient(145deg, #1a3a2a, #153020);
|
||||
border: 1px solid #2d5a3e;
|
||||
}
|
||||
.box-api .box-title { color: #4ade80; }
|
||||
|
||||
.box-protocol {
|
||||
background: linear-gradient(145deg, #1a2a4a, #152040);
|
||||
border: 1px solid #2d4a6e;
|
||||
}
|
||||
.box-protocol .box-title { color: #60a5fa; }
|
||||
|
||||
.box-lib {
|
||||
background: linear-gradient(145deg, #2a1a3a, #201530);
|
||||
border: 1px solid #4a2d6e;
|
||||
}
|
||||
.box-lib .box-title { color: #c084fc; }
|
||||
|
||||
.box-broker {
|
||||
background: linear-gradient(145deg, #2a2010, #201810);
|
||||
border: 1px solid #5a4a2d;
|
||||
}
|
||||
.box-broker .box-title { color: #fbbf24; }
|
||||
|
||||
.box-device {
|
||||
background: linear-gradient(145deg, #1a1418, #201820);
|
||||
border: 1px solid #4a3040;
|
||||
}
|
||||
.box-device .box-title { color: #f472b6; }
|
||||
|
||||
.box-gateway {
|
||||
background: linear-gradient(145deg, #1a2820, #152218);
|
||||
border: 1px solid #2d5a3e;
|
||||
}
|
||||
.box-gateway .box-title { color: #34d399; }
|
||||
|
||||
/* ── Arrows ── */
|
||||
.arrow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.arrow-line {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 14px;
|
||||
color: #3a4060;
|
||||
letter-spacing: -2px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.arrow-label {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.tier-1 .arrow-label { color: #4ade80; }
|
||||
.tier-2 .arrow-label { color: #60a5fa; }
|
||||
.tier-3 .arrow-label { color: #c084fc; }
|
||||
|
||||
/* ── Languages list ── */
|
||||
.lang-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
margin-top: 6px;
|
||||
justify-content: center;
|
||||
}
|
||||
.lang-tag {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 9px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
background: rgba(255,255,255,0.06);
|
||||
color: #8890a8;
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
}
|
||||
|
||||
/* ── Cloud B Detail ── */
|
||||
.cloud-b-section {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto 40px;
|
||||
}
|
||||
.cloud-b-section h2 {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #fbbf24;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.cloud-b-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.cloud-b-card {
|
||||
background: linear-gradient(145deg, #12161f 0%, #0e1218 100%);
|
||||
border: 1px solid #1e2438;
|
||||
border-radius: 10px;
|
||||
padding: 18px;
|
||||
position: relative;
|
||||
}
|
||||
.cloud-b-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 2px;
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
.cloud-b-card:nth-child(1)::before { background: #4ade80; }
|
||||
.cloud-b-card:nth-child(2)::before { background: #fbbf24; }
|
||||
.cloud-b-card:nth-child(3)::before { background: #f472b6; }
|
||||
|
||||
.cloud-b-card h3 {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cloud-b-card:nth-child(1) h3 { color: #4ade80; }
|
||||
.cloud-b-card:nth-child(2) h3 { color: #fbbf24; }
|
||||
.cloud-b-card:nth-child(3) h3 { color: #f472b6; }
|
||||
|
||||
.cb-item {
|
||||
font-size: 12px;
|
||||
color: #8890a8;
|
||||
padding: 4px 0;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.04);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
}
|
||||
.cb-item:last-child { border: none; }
|
||||
.cb-dot {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
margin-top: 5px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.cloud-b-card:nth-child(1) .cb-dot { background: #4ade80; }
|
||||
.cloud-b-card:nth-child(2) .cb-dot { background: #fbbf24; }
|
||||
.cloud-b-card:nth-child(3) .cb-dot { background: #f472b6; }
|
||||
|
||||
/* ── Comparison Table ── */
|
||||
.compare-section {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto 40px;
|
||||
}
|
||||
.compare-section h2 {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #c0c8e0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.compare-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 12px;
|
||||
}
|
||||
.compare-table th {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
padding: 10px 14px;
|
||||
border-bottom: 2px solid #1e2438;
|
||||
color: #8890a8;
|
||||
}
|
||||
.compare-table td {
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid #141824;
|
||||
color: #a0a8c0;
|
||||
}
|
||||
.compare-table tr:hover td {
|
||||
background: rgba(255,255,255,0.02);
|
||||
}
|
||||
.compare-table .tier-name {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
.t1c { color: #4ade80; }
|
||||
.t2c { color: #60a5fa; }
|
||||
.t3c { color: #c084fc; }
|
||||
|
||||
.star { color: #fbbf24; }
|
||||
.check { color: #4ade80; }
|
||||
.cross { color: #f87171; opacity: 0.6; }
|
||||
|
||||
/* ── RPC Flow ── */
|
||||
.rpc-section {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto 40px;
|
||||
}
|
||||
.rpc-section h2 {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #c0c8e0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.rpc-flow {
|
||||
background: linear-gradient(145deg, #0e1218 0%, #12161f 100%);
|
||||
border: 1px solid #1e2438;
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 11px;
|
||||
line-height: 1.8;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.rpc-flow .actor { color: #fbbf24; font-weight: 700; }
|
||||
.rpc-flow .action { color: #4ade80; }
|
||||
.rpc-flow .proto { color: #60a5fa; }
|
||||
.rpc-flow .data { color: #c084fc; }
|
||||
.rpc-flow .dim { color: #3a4060; }
|
||||
.rpc-flow .step { color: #f472b6; font-weight: 700; }
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 900px) {
|
||||
.cloud-b-grid { grid-template-columns: 1fr; }
|
||||
.flow-row { flex-wrap: wrap; justify-content: center; gap: 8px; }
|
||||
.arrow { padding: 4px 6px; }
|
||||
.compare-table { font-size: 11px; }
|
||||
.compare-table th, .compare-table td { padding: 8px 8px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="page-title">
|
||||
<h1>ANSCloud — Partner Integration Architecture</h1>
|
||||
<div class="sub">3-Tier Integration Strategy: REST API → AMQP Protocol → C++ FFI Library</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<!-- TIER 1 -->
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<div class="arch-container">
|
||||
<div class="tier-section tier-1">
|
||||
<div class="tier-header">
|
||||
<span class="tier-badge">TIER 1</span>
|
||||
<span class="tier-label">REST / WebSocket API Gateway</span>
|
||||
<span class="tier-desc">★ Recommended for most partners</span>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div class="box box-partner">
|
||||
<div class="box-icon">🌐</div>
|
||||
<div class="box-title">Partner CMS</div>
|
||||
<div class="box-sub">Any language</div>
|
||||
<div class="lang-tags">
|
||||
<span class="lang-tag">Node.js</span>
|
||||
<span class="lang-tag">Python</span>
|
||||
<span class="lang-tag">Go</span>
|
||||
<span class="lang-tag">Java</span>
|
||||
<span class="lang-tag">C#</span>
|
||||
<span class="lang-tag">PHP</span>
|
||||
<span class="lang-tag">Ruby</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">──────►</div>
|
||||
<div class="arrow-label">HTTPS / WSS</div>
|
||||
</div>
|
||||
<div class="box box-api">
|
||||
<div class="box-icon">🛡️</div>
|
||||
<div class="box-title">API Gateway</div>
|
||||
<div class="box-sub">Cloud B<br>Auth + Rate Limit</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">──────►</div>
|
||||
<div class="arrow-label">AMQP internal</div>
|
||||
</div>
|
||||
<div class="box box-broker">
|
||||
<div class="box-icon">📨</div>
|
||||
<div class="box-title">RabbitMQ</div>
|
||||
<div class="box-sub">Cloud B<br>Exchanges + Queues</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">──────►</div>
|
||||
<div class="arrow-label">AMQP TLS</div>
|
||||
</div>
|
||||
<div class="box box-device">
|
||||
<div class="box-icon">📷</div>
|
||||
<div class="box-title">AIBOX</div>
|
||||
<div class="box-sub">anscloud-device<br>C++ + Your RabbitMQ API</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<!-- TIER 2 -->
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<div class="tier-section tier-2">
|
||||
<div class="tier-header">
|
||||
<span class="tier-badge">TIER 2</span>
|
||||
<span class="tier-label">Native AMQP Protocol (Direct Broker Access)</span>
|
||||
<span class="tier-desc">Advanced integrators, on-prem</span>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div class="box box-partner">
|
||||
<div class="box-icon">⚡</div>
|
||||
<div class="box-title">Partner CMS</div>
|
||||
<div class="box-sub">Native AMQP lib</div>
|
||||
<div class="lang-tags">
|
||||
<span class="lang-tag">amqplib</span>
|
||||
<span class="lang-tag">pika</span>
|
||||
<span class="lang-tag">amqp091-go</span>
|
||||
<span class="lang-tag">Spring AMQP</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">════════════════════════►</div>
|
||||
<div class="arrow-label">AMQP 0-9-1 (direct, same protocol)</div>
|
||||
</div>
|
||||
<div class="box box-broker">
|
||||
<div class="box-icon">📨</div>
|
||||
<div class="box-title">RabbitMQ</div>
|
||||
<div class="box-sub">Cloud B<br>Partner vhost</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">──────►</div>
|
||||
<div class="arrow-label">AMQP TLS</div>
|
||||
</div>
|
||||
<div class="box box-device">
|
||||
<div class="box-icon">📷</div>
|
||||
<div class="box-title">AIBOX</div>
|
||||
<div class="box-sub">anscloud-device<br>C++ + Your RabbitMQ API</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<!-- TIER 3 -->
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<div class="tier-section tier-3">
|
||||
<div class="tier-header">
|
||||
<span class="tier-badge">TIER 3</span>
|
||||
<span class="tier-label">C++ Gateway Library via FFI</span>
|
||||
<span class="tier-desc">Your CMS, embedded, C/C++ partners</span>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div class="box box-partner">
|
||||
<div class="box-icon">🔧</div>
|
||||
<div class="box-title">Partner CMS</div>
|
||||
<div class="box-sub">Links .dll / .so</div>
|
||||
<div class="lang-tags">
|
||||
<span class="lang-tag">cgo</span>
|
||||
<span class="lang-tag">ctypes</span>
|
||||
<span class="lang-tag">P/Invoke</span>
|
||||
<span class="lang-tag">ffi-napi</span>
|
||||
<span class="lang-tag">JNI</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">──────►</div>
|
||||
<div class="arrow-label">C API (FFI)</div>
|
||||
</div>
|
||||
<div class="box box-lib">
|
||||
<div class="box-icon">📦</div>
|
||||
<div class="box-title">anscloud-gateway</div>
|
||||
<div class="box-sub">C++ lib (CMSCore)<br>gateway_agent_c.h</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">──────►</div>
|
||||
<div class="arrow-label">Your RabbitMQ API</div>
|
||||
</div>
|
||||
<div class="box box-broker">
|
||||
<div class="box-icon">📨</div>
|
||||
<div class="box-title">RabbitMQ</div>
|
||||
<div class="box-sub">Cloud B</div>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<div class="arrow-line">──────►</div>
|
||||
<div class="arrow-label">AMQP TLS</div>
|
||||
</div>
|
||||
<div class="box box-device">
|
||||
<div class="box-icon">📷</div>
|
||||
<div class="box-title">AIBOX</div>
|
||||
<div class="box-sub">anscloud-device<br>C++ + Your RabbitMQ API</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<!-- Cloud B Detail -->
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<div class="cloud-b-section">
|
||||
<h2>☁️ Cloud B — Messaging Platform (You Own)</h2>
|
||||
<div class="cloud-b-grid">
|
||||
<div class="cloud-b-card">
|
||||
<h3>API Gateway Layer</h3>
|
||||
<div class="cb-item"><div class="cb-dot"></div>REST endpoints for commands, status, telemetry</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>WebSocket for real-time event streaming</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>Webhook push to partner URLs</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>API key auth + JWT per tenant</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>Rate limiting per partner tier</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>Serves Tier 1 partners</div>
|
||||
</div>
|
||||
<div class="cloud-b-card">
|
||||
<h3>RabbitMQ Broker</h3>
|
||||
<div class="cb-item"><div class="cb-dot"></div>ex.command → direct → device queues</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>ex.device.telemetry → topic → ingest</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>ex.device.events → topic → processor</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>ex.device.status → topic → tracker</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>ex.broadcast → fanout → all devices</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>vhost isolation per tenant</div>
|
||||
</div>
|
||||
<div class="cloud-b-card">
|
||||
<h3>AIBOX Devices</h3>
|
||||
<div class="cb-item"><div class="cb-dot"></div>anscloud-device (C++ static lib)</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>Uses YOUR existing RabbitMQ C++ API</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>IMessageBroker adapter pattern</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>Auto boot → connect → heartbeat</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>Publishes telemetry, events, status</div>
|
||||
<div class="cb-item"><div class="cb-dot"></div>Receives & executes commands</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<!-- RPC Command Flow -->
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<div class="rpc-section">
|
||||
<h2>Command RPC Flow (Tier 1 Example)</h2>
|
||||
<div class="rpc-flow">
|
||||
<span class="step">①</span> <span class="actor">Partner</span> <span class="action">POST</span> <span class="proto">/api/v1/devices/AIBOX-001/commands</span> <span class="data">{"command":"get_config"}</span><br>
|
||||
<span class="dim">│</span><br>
|
||||
<span class="step">②</span> <span class="actor">API GW</span> <span class="action">generates</span> <span class="data">cmd_id + correlation_id</span> → <span class="action">publish to</span> <span class="proto">ex.command</span> <span class="dim">routing_key=AIBOX-001</span><br>
|
||||
<span class="dim">│</span><br>
|
||||
<span class="step">③</span> <span class="actor">RabbitMQ</span> <span class="action">routes</span> → <span class="proto">q.cmd.AIBOX-001</span><br>
|
||||
<span class="dim">│</span><br>
|
||||
<span class="step">④</span> <span class="actor">AIBOX</span> <span class="action">consumes</span> → <span class="action">executes locally</span> → <span class="action">publishes response</span> → <span class="proto">ex.command.response</span><br>
|
||||
<span class="dim">│</span><br>
|
||||
<span class="step">⑤</span> <span class="actor">API GW</span> <span class="action">matches</span> <span class="data">correlation_id</span> → <span class="action">resolves pending request</span><br>
|
||||
<span class="dim">│</span><br>
|
||||
<span class="step">⑥</span> <span class="actor">Partner</span> <span class="action">receives</span> <span class="proto">HTTP 200</span> <span class="data">{"status":"success","result":{"version":"3.2.0","cameras":3}}</span><br>
|
||||
<br>
|
||||
<span class="dim">── Partner sees a simple REST call. RabbitMQ is completely hidden. ──</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<!-- Comparison -->
|
||||
<!-- ════════════════════════════════════════════════════ -->
|
||||
<div class="compare-section">
|
||||
<h2>Tier Comparison</h2>
|
||||
<table class="compare-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Language Support</th>
|
||||
<th>Setup Effort</th>
|
||||
<th>Latency</th>
|
||||
<th>Partner Needs</th>
|
||||
<th>You Control</th>
|
||||
<th>Best For</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tier-name t1c">Tier 1 — REST API</td>
|
||||
<td>Any <span class="star">★</span></td>
|
||||
<td>Minutes <span class="star">★</span></td>
|
||||
<td>~50ms added</td>
|
||||
<td>API key + docs</td>
|
||||
<td>Auth, rate limits, versioning <span class="star">★</span></td>
|
||||
<td>SaaS partners, web/mobile</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tier-name t2c">Tier 2 — AMQP Direct</td>
|
||||
<td>Has AMQP lib</td>
|
||||
<td>Hours</td>
|
||||
<td>Lowest <span class="star">★</span></td>
|
||||
<td>Protocol guide + credentials</td>
|
||||
<td>vhost isolation</td>
|
||||
<td>Large integrators, on-prem</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tier-name t3c">Tier 3 — C++ FFI</td>
|
||||
<td>Has FFI support</td>
|
||||
<td>Days</td>
|
||||
<td>Low</td>
|
||||
<td>DLL/so + C headers</td>
|
||||
<td>Full protocol encapsulated</td>
|
||||
<td>Your CMS, embedded, C++ devs</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
86
test-device/test-device.vcxproj
Normal file
86
test-device/test-device.vcxproj
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{B1A2C3D4-0001-4000-8000-000000000004}</ProjectGuid>
|
||||
<RootNamespace>testdevice</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>test-device</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-device\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>anscloud-common.lib;anscloud-device.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-device\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>anscloud-common.lib;anscloud-device.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{B1A2C3D4-0001-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\anscloud-device\anscloud-device.vcxproj">
|
||||
<Project>{B1A2C3D4-0001-4000-8000-000000000002}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
86
test-gateway/test-gateway.vcxproj
Normal file
86
test-gateway/test-gateway.vcxproj
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<ProjectGuid>{B1A2C3D4-0001-4000-8000-000000000005}</ProjectGuid>
|
||||
<RootNamespace>testgateway</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>test-gateway</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-gateway\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>anscloud-common.lib;anscloud-gateway.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)anscloud-common\include;$(SolutionDir)anscloud-gateway\include;$(SolutionDir)packages\nlohmann-json\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>anscloud-common.lib;anscloud-gateway.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\anscloud-common\anscloud-common.vcxproj">
|
||||
<Project>{B1A2C3D4-0001-4000-8000-000000000001}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\anscloud-gateway\anscloud-gateway.vcxproj">
|
||||
<Project>{B1A2C3D4-0001-4000-8000-000000000003}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
Reference in New Issue
Block a user