Initial idea

This commit is contained in:
2026-03-28 12:05:34 +11:00
commit 6c6bb79cab
21 changed files with 3860 additions and 0 deletions

View 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>

View 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

View 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);