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