Initial idea
This commit is contained in:
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")
|
||||
Reference in New Issue
Block a user