Refactor project structure
This commit is contained in:
300
integrations/ANSPulsar/ANSPulsar.cpp
Normal file
300
integrations/ANSPulsar/ANSPulsar.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
#include "ANSPulsar.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace ANSCENTER {
|
||||
|
||||
void Callback(pulsar::Result code, const pulsar::MessageId& msgId) {
|
||||
std::cout << "Received code:" << code << " -- MsgID: " << msgId << std::endl;
|
||||
}
|
||||
ANSPULSAR::ANSPULSAR() {
|
||||
// Initialize the Pulsar client with default values
|
||||
_hostname = "localhost";
|
||||
_port = 5672;
|
||||
_jwtToken = "";
|
||||
_useTls = false;
|
||||
_caCertPath = "";
|
||||
_enableBatching = false;
|
||||
_batchingMaxMessages = 100;
|
||||
_batchingDelayMs = 1000;
|
||||
_allowInsecureConnection = false;
|
||||
_verifyHostname = true;
|
||||
_procuderInit = false;
|
||||
_consumerInit = false;
|
||||
_compressionType = pulsar::CompressionLZ4;
|
||||
}
|
||||
ANSPULSAR::~ANSPULSAR() {
|
||||
Close();
|
||||
}
|
||||
bool ANSPULSAR::Initialize(const std::string& hostname, int port, const std::string& jwtToken, bool useTls, const std::string& caCertPath,
|
||||
bool enableBatching, int batchingMaxMessages, int batchingDelayMs,
|
||||
bool allowInsecureConnection, bool verifyHostname) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
_hostname = hostname;
|
||||
_port = port;
|
||||
_jwtToken = jwtToken;
|
||||
_useTls = useTls;
|
||||
_caCertPath = caCertPath;
|
||||
_enableBatching = enableBatching;
|
||||
_batchingMaxMessages = batchingMaxMessages;
|
||||
_batchingDelayMs = batchingDelayMs;
|
||||
_allowInsecureConnection = allowInsecureConnection;
|
||||
_verifyHostname = verifyHostname;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ANSPULSAR::Connect(const std::string& topicName) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
_pubTopicName = topicName;
|
||||
|
||||
std::string hostname = _hostname;
|
||||
size_t pos = hostname.find("://");
|
||||
if (pos != std::string::npos) {
|
||||
hostname = hostname.substr(pos + 3);
|
||||
}
|
||||
|
||||
_fullServiceUrl = (_useTls ? "pulsar+ssl://" : "pulsar://") + hostname + ":" + std::to_string(_port);
|
||||
|
||||
if (_useTls) {
|
||||
_clientConfig.setUseTls(true);
|
||||
_clientConfig.setTlsTrustCertsFilePath(_caCertPath);
|
||||
_clientConfig.setTlsAllowInsecureConnection(_allowInsecureConnection);
|
||||
_clientConfig.setValidateHostName(_verifyHostname);
|
||||
}
|
||||
|
||||
if (!_jwtToken.empty()) {
|
||||
_clientConfig.setAuth(pulsar::AuthToken::createWithToken(_jwtToken));
|
||||
}
|
||||
|
||||
_producerConfig.setSendTimeout(5000);
|
||||
_producerConfig.setCompressionType(_compressionType);
|
||||
_producerConfig.setBatchingEnabled(_enableBatching);
|
||||
if (_enableBatching) {
|
||||
_producerConfig.setBatchingMaxMessages(_batchingMaxMessages);
|
||||
_producerConfig.setBatchingMaxPublishDelayMs(_batchingDelayMs);
|
||||
}
|
||||
|
||||
_client = std::make_unique<pulsar::Client>(_fullServiceUrl, _clientConfig);
|
||||
auto result = _client->createProducer(_pubTopicName, _producerConfig, _producer);
|
||||
if (result != pulsar::ResultOk) {
|
||||
_logger.LogError("ANSPULSAR::Connect", "Failed to create producer: " + std::to_string(result), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
_procuderInit = true;
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
_logger.LogFatal("ANSPULSAR::Connect", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
_logger.LogFatal("ANSPULSAR::Connect", "Unknown exception occurred", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ANSPULSAR::Disconnect() {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
if (_procuderInit) {
|
||||
_producer.close();
|
||||
_procuderInit = false;
|
||||
}
|
||||
if (_consumerInit) {
|
||||
_consumer.close();
|
||||
_consumerInit=false;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
_logger.LogError("ANSPULSAR::Disconnect", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
_logger.LogError("ANSPULSAR::Disconnect", "Unknown exception occurred", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ANSPULSAR::Close() {
|
||||
try {
|
||||
if (_client) {
|
||||
_client->close();
|
||||
_client.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
_logger.LogError("ANSPULSAR::Close", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
_logger.LogError("ANSPULSAR::Close", "Unknown exception occurred", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ANSPULSAR::Publish(const std::string& message, const std::string& properties) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
if (message.empty()) {
|
||||
_logger.LogError("ANSPULSAR::Publish", "Cannot send empty message", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
pulsar::MessageBuilder builder;
|
||||
builder.setContent(message);
|
||||
builder.setProperty("content-type", "application/json");
|
||||
|
||||
if (!properties.empty()) {
|
||||
std::istringstream iss(properties);
|
||||
std::string pair;
|
||||
while (std::getline(iss, pair, ';')) {
|
||||
size_t pos = pair.find(':');
|
||||
if (pos != std::string::npos) {
|
||||
std::string key = pair.substr(0, pos);
|
||||
std::string value = pair.substr(pos + 1);
|
||||
key.erase(0, key.find_first_not_of(" \t\r\n"));
|
||||
key.erase(key.find_last_not_of(" \t\r\n") + 1);
|
||||
value.erase(0, value.find_first_not_of(" \t\r\n"));
|
||||
value.erase(value.find_last_not_of(" \t\r\n") + 1);
|
||||
builder.setProperty(key, value);
|
||||
}
|
||||
else {
|
||||
_logger.LogError("ANSPULSAR::Publish", "Invalid property: " + pair, __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto msg = builder.build();
|
||||
auto result = _producer.send(msg);
|
||||
if (result != pulsar::ResultOk) {
|
||||
_logger.LogError("ANSPULSAR::Publish", "Send failed: " + std::to_string(result), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
_logger.LogFatal("ANSPULSAR::Publish", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
_logger.LogFatal("ANSPULSAR::Publish", "Unknown exception occurred", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ANSPULSAR::PublishAsync(const std::string& message, const std::string& properties) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
if (message.empty()) {
|
||||
_logger.LogError("ANSPULSAR::PublishAsync", "Cannot send empty message", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
pulsar::MessageBuilder builder;
|
||||
builder.setContent(message);
|
||||
builder.setProperty("content-type", "application/json");
|
||||
|
||||
if (!properties.empty()) {
|
||||
std::istringstream iss(properties);
|
||||
std::string pair;
|
||||
while (std::getline(iss, pair, ';')) {
|
||||
size_t pos = pair.find(':');
|
||||
if (pos != std::string::npos) {
|
||||
std::string key = pair.substr(0, pos);
|
||||
std::string value = pair.substr(pos + 1);
|
||||
key.erase(0, key.find_first_not_of(" \t\r\n"));
|
||||
key.erase(key.find_last_not_of(" \t\r\n") + 1);
|
||||
value.erase(0, value.find_first_not_of(" \t\r\n"));
|
||||
value.erase(value.find_last_not_of(" \t\r\n") + 1);
|
||||
builder.setProperty(key, value);
|
||||
}
|
||||
else {
|
||||
_logger.LogError("ANSPULSAR::PublishAsync", "Invalid property: " + pair, __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto msg = builder.build();
|
||||
_producer.sendAsync(msg, Callback);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
_logger.LogFatal("ANSPULSAR::PublishAsync", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
_logger.LogFatal("ANSPULSAR::PublishAsync", "Unknown exception occurred", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ANSPULSAR::Subscribe(const std::string& topicName, const std::string& subscriptionName) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
if (!_client) {
|
||||
_logger.LogError("ANSPULSAR::Subscribe", "Client not initialized", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
_consumerConfig.setConsumerType(pulsar::ConsumerExclusive);
|
||||
_consumerConfig.setReceiverQueueSize(1000);
|
||||
_subTopicName = topicName;
|
||||
_subscriptionName = subscriptionName;
|
||||
auto result = _client->subscribe(_subTopicName, _subscriptionName, _consumerConfig, _consumer);
|
||||
if (result != pulsar::ResultOk) {
|
||||
_logger.LogError("ANSPULSAR::Subscribe", "Subscribe failed: " + std::to_string(result), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
_consumerInit = true;
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
_logger.LogFatal("ANSPULSAR::Subscribe", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
_logger.LogFatal("ANSPULSAR::Subscribe", "Unknown exception occurred", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ANSPULSAR::Receive(std::string& messageOut, bool doAcknowledge, int timeoutMs) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
try {
|
||||
if (!_client) {
|
||||
_logger.LogError("ANSPULSAR::Receive", "Client not initialized", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
pulsar::Message msg;
|
||||
pulsar::Result result = _consumer.receive(msg, timeoutMs);
|
||||
|
||||
if (result != pulsar::ResultOk) {
|
||||
if (result != pulsar::ResultTimeout) {
|
||||
_logger.LogError("ANSPULSAR::Receive", "Receive failed: " + std::to_string(result), __FILE__, __LINE__);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
messageOut = msg.getDataAsString();
|
||||
|
||||
if (doAcknowledge) {
|
||||
result = _consumer.acknowledge(msg);
|
||||
if (result != pulsar::ResultOk) {
|
||||
_logger.LogError("ANSPULSAR::Receive", "Acknowledge failed: " + std::to_string(result), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
_logger.LogFatal("ANSPULSAR::Receive", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
_logger.LogFatal("ANSPULSAR::Receive", "Unknown exception occurred", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ANSCENTER
|
||||
|
||||
81
integrations/ANSPulsar/ANSPulsar.h
Normal file
81
integrations/ANSPulsar/ANSPulsar.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifndef ANSPALSAR_H
|
||||
#define ANSPALSAR_H
|
||||
#define ANSPALSAR_API __declspec(dllexport)
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include "ANSLicense.h"
|
||||
#include "LabVIEWHeader/extcode.h"
|
||||
#include <pulsar/Client.h>
|
||||
|
||||
using pulsar::Client;
|
||||
namespace ANSCENTER {
|
||||
class ANSPALSAR_API ANSPULSAR {
|
||||
private:
|
||||
std::string _hostname;
|
||||
int _port = 5672;
|
||||
std::string _jwtToken;
|
||||
bool _useTls = false;
|
||||
std::string _caCertPath;
|
||||
bool _enableBatching = false;
|
||||
int _batchingMaxMessages = 100;
|
||||
int _batchingDelayMs = 1000;
|
||||
bool _allowInsecureConnection = false;
|
||||
bool _verifyHostname = true;
|
||||
bool _procuderInit = false;
|
||||
bool _consumerInit = false;
|
||||
std::string _pubTopicName;
|
||||
std::string _subTopicName;
|
||||
std::string _subscriptionName = "ans_sub";
|
||||
std::string _fullServiceUrl;
|
||||
|
||||
pulsar::CompressionType _compressionType = pulsar::CompressionLZ4;
|
||||
std::unique_ptr<pulsar::Client> _client = nullptr;
|
||||
pulsar::Producer _producer;
|
||||
pulsar::Consumer _consumer;
|
||||
pulsar::ClientConfiguration _clientConfig;
|
||||
pulsar::ProducerConfiguration _producerConfig;
|
||||
pulsar::ConsumerConfiguration _consumerConfig;
|
||||
SPDLogger& _logger = SPDLogger::GetInstance("ANSPulsar", true);
|
||||
std::recursive_mutex _mutex;
|
||||
|
||||
public:
|
||||
ANSPULSAR();
|
||||
~ANSPULSAR();
|
||||
[[nodiscard]] bool Initialize(const std::string& hostname, int port, const std::string& jwtToken, bool useSSL, const std::string& caCertPath,
|
||||
bool enableBatching, int batchingMaxMessages, int batchingDelayMs, bool allowInsecureConnection,
|
||||
bool verifyHostname);
|
||||
[[nodiscard]] bool Connect(const std::string& topicName);
|
||||
[[nodiscard]] bool Disconnect();
|
||||
[[nodiscard]] bool Publish(const std::string& message, const std::string& properties);
|
||||
[[nodiscard]] bool PublishAsync(const std::string& message, const std::string& properties);
|
||||
[[nodiscard]] bool Subscribe(const std::string& topicName, const std::string& subscriptionName);
|
||||
[[nodiscard]] bool Receive(std::string& messageOut, bool doAcknowledge, int timeoutMs = 1000);
|
||||
[[nodiscard]] bool Close();
|
||||
};
|
||||
}
|
||||
|
||||
// C API exports
|
||||
extern "C" {
|
||||
ANSPALSAR_API int CreateANSPulsarHandle(ANSCENTER::ANSPULSAR** Handle, const char* hostname,int port, const char* jwtToken, int useTls, const char* caCertPath, int enableBatching, int batchingMaxMessages, int batchingDelayMs, int allowInsecureConnection,int verifyHostName);
|
||||
ANSPALSAR_API int ReleasePulsarHandle(ANSCENTER::ANSPULSAR** Handle);
|
||||
ANSPALSAR_API int ConnectANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName);
|
||||
ANSPALSAR_API int DisconnectANSPulsar(ANSCENTER::ANSPULSAR** Handle);
|
||||
ANSPALSAR_API int PublishANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties);
|
||||
ANSPALSAR_API int PublishAsyncANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties);
|
||||
ANSPALSAR_API int SubscribeANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName, const char* subscriptionName);
|
||||
ANSPALSAR_API int ReceiveMessageANSPulsar(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, LStrHandle strMessage);
|
||||
ANSPALSAR_API int ReceiveMessageANSPulsar_CPP(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, std::string& message);
|
||||
|
||||
// V2 API — handle passed by value (uint64_t) to avoid LabVIEW buffer reuse bug
|
||||
ANSPALSAR_API int ConnectANSPulsar_V2(uint64_t handleVal, const char* topicName);
|
||||
ANSPALSAR_API int DisconnectANSPulsar_V2(uint64_t handleVal);
|
||||
ANSPALSAR_API int PublishANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties);
|
||||
ANSPALSAR_API int PublishAsyncANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties);
|
||||
ANSPALSAR_API int SubscribeANSPulsar_V2(uint64_t handleVal, const char* topicName, const char* subscriptionName);
|
||||
ANSPALSAR_API int ReceiveMessageANSPulsar_V2(uint64_t handleVal, int timeoutMs, int doAcknowledge, LStrHandle strMessage);
|
||||
}
|
||||
#endif
|
||||
30
integrations/ANSPulsar/CMakeLists.txt
Normal file
30
integrations/ANSPulsar/CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
# ANSPulsar — Apache Pulsar messaging DLL
|
||||
add_library(ANSPulsar SHARED
|
||||
ANSPulsar.cpp
|
||||
ANSPulsar.h
|
||||
dllmain.cpp
|
||||
pch.cpp
|
||||
pch.h
|
||||
framework.h
|
||||
)
|
||||
|
||||
target_include_directories(ANSPulsar PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${SHARED_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(ANSPulsar PRIVATE
|
||||
${ANSLIBS_DIR}/Pulsar/include
|
||||
)
|
||||
|
||||
target_link_directories(ANSPulsar PRIVATE ${ANSLIBS_DIR}/Pulsar/lib)
|
||||
|
||||
target_link_libraries(ANSPulsar
|
||||
PRIVATE ANSLicensingSystem
|
||||
PRIVATE anslicensing
|
||||
PRIVATE labview
|
||||
PRIVATE pulsar.lib
|
||||
)
|
||||
|
||||
target_compile_definitions(ANSPulsar PRIVATE UNICODE _UNICODE ANSPULSAR_EXPORTS _USRDLL)
|
||||
target_precompile_headers(ANSPulsar PRIVATE pch.h)
|
||||
419
integrations/ANSPulsar/dllmain.cpp
Normal file
419
integrations/ANSPulsar/dllmain.cpp
Normal file
@@ -0,0 +1,419 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
#include "ANSPulsar.h"
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
// Handle registry with refcount — prevents use-after-free when
|
||||
// ReleasePulsarHandle is called while an operation is still running.
|
||||
static std::unordered_map<ANSCENTER::ANSPULSAR*, int>& PulsarHandleRegistry() {
|
||||
static std::unordered_map<ANSCENTER::ANSPULSAR*, int> s;
|
||||
return s;
|
||||
}
|
||||
static std::mutex& PulsarHandleRegistryMutex() {
|
||||
static std::mutex m;
|
||||
return m;
|
||||
}
|
||||
static std::condition_variable& PulsarHandleRegistryCV() {
|
||||
static std::condition_variable cv;
|
||||
return cv;
|
||||
}
|
||||
|
||||
static void RegisterPulsarHandle(ANSCENTER::ANSPULSAR* h) {
|
||||
std::lock_guard<std::mutex> lk(PulsarHandleRegistryMutex());
|
||||
PulsarHandleRegistry()[h] = 1;
|
||||
}
|
||||
|
||||
static ANSCENTER::ANSPULSAR* AcquirePulsarHandle(ANSCENTER::ANSPULSAR* h) {
|
||||
std::lock_guard<std::mutex> lk(PulsarHandleRegistryMutex());
|
||||
auto it = PulsarHandleRegistry().find(h);
|
||||
if (it == PulsarHandleRegistry().end()) return nullptr;
|
||||
it->second++;
|
||||
return h;
|
||||
}
|
||||
|
||||
static bool ReleasePulsarHandleRef(ANSCENTER::ANSPULSAR* h) {
|
||||
std::lock_guard<std::mutex> lk(PulsarHandleRegistryMutex());
|
||||
auto it = PulsarHandleRegistry().find(h);
|
||||
if (it == PulsarHandleRegistry().end()) return false;
|
||||
it->second--;
|
||||
if (it->second <= 0) {
|
||||
PulsarHandleRegistry().erase(it);
|
||||
PulsarHandleRegistryCV().notify_all();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool UnregisterPulsarHandle(ANSCENTER::ANSPULSAR* h) {
|
||||
std::unique_lock<std::mutex> lk(PulsarHandleRegistryMutex());
|
||||
auto it = PulsarHandleRegistry().find(h);
|
||||
if (it == PulsarHandleRegistry().end()) return false;
|
||||
it->second--;
|
||||
bool ok = PulsarHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||
auto it2 = PulsarHandleRegistry().find(h);
|
||||
return it2 == PulsarHandleRegistry().end() || it2->second <= 0;
|
||||
});
|
||||
if (!ok) {
|
||||
OutputDebugStringA("WARNING: UnregisterPulsarHandle timed out waiting for in-flight operations\n");
|
||||
}
|
||||
PulsarHandleRegistry().erase(h);
|
||||
return true;
|
||||
}
|
||||
|
||||
// RAII guard — ensures ReleasePulsarHandleRef is always called
|
||||
class PulsarHandleGuard {
|
||||
ANSCENTER::ANSPULSAR* engine;
|
||||
public:
|
||||
explicit PulsarHandleGuard(ANSCENTER::ANSPULSAR* e) : engine(e) {}
|
||||
~PulsarHandleGuard() { if (engine) ReleasePulsarHandleRef(engine); }
|
||||
ANSCENTER::ANSPULSAR* get() const { return engine; }
|
||||
explicit operator bool() const { return engine != nullptr; }
|
||||
PulsarHandleGuard(const PulsarHandleGuard&) = delete;
|
||||
PulsarHandleGuard& operator=(const PulsarHandleGuard&) = delete;
|
||||
};
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int CreateANSPulsarHandle(ANSCENTER::ANSPULSAR** Handle, const char* hostname,
|
||||
int port, const char* jwtToken, int useTls, const char* caCertPath,
|
||||
int enableBatching, int batchingMaxMessages, int batchingDelayMs,
|
||||
int allowInsecureConnection, int verifyHostName)
|
||||
{
|
||||
if (Handle == nullptr) {
|
||||
return 0; // Invalid handle
|
||||
}
|
||||
try {
|
||||
// Release existing handle if called twice (prevents leak from LabVIEW)
|
||||
if (*Handle) {
|
||||
if (UnregisterPulsarHandle(*Handle)) {
|
||||
delete *Handle;
|
||||
}
|
||||
*Handle = nullptr;
|
||||
}
|
||||
|
||||
*Handle = new ANSCENTER::ANSPULSAR();
|
||||
if (*Handle == nullptr) {
|
||||
return 0; // Memory allocation failed
|
||||
}
|
||||
std::string host = hostname ? hostname : "";
|
||||
std::string token = jwtToken ? jwtToken : "";
|
||||
std::string certPath = caCertPath ? caCertPath : "";
|
||||
|
||||
bool _useTls = (useTls == 1);
|
||||
bool _enableBatching = (enableBatching == 1);
|
||||
bool _allowInsecureConnection = (allowInsecureConnection == 1);
|
||||
bool _verifyHostname = (verifyHostName == 1);
|
||||
|
||||
if (!(*Handle)->Initialize(host, port, token, _useTls, certPath,
|
||||
_enableBatching, batchingMaxMessages, batchingDelayMs,
|
||||
_allowInsecureConnection, _verifyHostname)) {
|
||||
delete *Handle;
|
||||
*Handle = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
RegisterPulsarHandle(*Handle);
|
||||
return 1;
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
|
||||
return 0;
|
||||
}
|
||||
catch (...) {
|
||||
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static int ReleasePulsarHandle_Impl(ANSCENTER::ANSPULSAR** Handle) {
|
||||
try {
|
||||
if (!Handle || !*Handle) return 1;
|
||||
if (!UnregisterPulsarHandle(*Handle)) {
|
||||
*Handle = nullptr;
|
||||
return 1;
|
||||
}
|
||||
delete *Handle;
|
||||
*Handle = nullptr;
|
||||
return 1;
|
||||
}
|
||||
catch (...) {
|
||||
if (Handle) *Handle = nullptr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int ReleasePulsarHandle(ANSCENTER::ANSPULSAR** Handle) {
|
||||
__try {
|
||||
return ReleasePulsarHandle_Impl(Handle);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
if (Handle) *Handle = nullptr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" ANSPALSAR_API int ConnectANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName) {
|
||||
if (Handle == nullptr || *Handle == nullptr) {
|
||||
return -1; // Invalid handle
|
||||
}
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
|
||||
if (!guard) return -1;
|
||||
if (topicName == nullptr) {
|
||||
return -1; // Invalid parameters
|
||||
}
|
||||
std::string topic = topicName;
|
||||
if (guard.get()->Connect(topic)) {
|
||||
return 1; // Success
|
||||
}
|
||||
else {
|
||||
return 0; // Connection failed
|
||||
}
|
||||
}
|
||||
extern "C" ANSPALSAR_API int DisconnectANSPulsar(ANSCENTER::ANSPULSAR** Handle) {
|
||||
if (Handle == nullptr || *Handle == nullptr) {
|
||||
return -1; // Invalid handle
|
||||
}
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
|
||||
if (!guard) return -1;
|
||||
if (guard.get()->Disconnect()) {
|
||||
return 1; // Success
|
||||
}
|
||||
else {
|
||||
return 0; // Disconnection failed
|
||||
}
|
||||
}
|
||||
extern "C" ANSPALSAR_API int PublishANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties) {
|
||||
if (Handle == nullptr || *Handle == nullptr) {
|
||||
return -1; // Invalid handle
|
||||
}
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
|
||||
if (!guard) return -1;
|
||||
if (message == nullptr) {
|
||||
return -1; // Invalid parameters
|
||||
}
|
||||
std::string msg = message ? message : "";
|
||||
std::string props = properties ? properties : "";
|
||||
|
||||
if (guard.get()->Publish(msg, props)) {
|
||||
return 1; // Success
|
||||
}
|
||||
else {
|
||||
return 0; // Publish failed
|
||||
}
|
||||
}
|
||||
extern "C" ANSPALSAR_API int PublishAsyncANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties) {
|
||||
if (Handle == nullptr || *Handle == nullptr) {
|
||||
return -1; // Invalid handle
|
||||
}
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
|
||||
if (!guard) return -1;
|
||||
if (message == nullptr) {
|
||||
return -1; // Invalid parameters
|
||||
}
|
||||
std::string msg = message ? message : "";
|
||||
std::string props = properties ? properties : "";
|
||||
|
||||
if (guard.get()->PublishAsync(msg, props)) {
|
||||
return 1; // Success
|
||||
}
|
||||
else {
|
||||
return 0; // Publish failed
|
||||
}
|
||||
}
|
||||
extern "C" ANSPALSAR_API int SubscribeANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName, const char* subscriptionName) {
|
||||
if (Handle == nullptr || *Handle == nullptr) {
|
||||
return -1; // Invalid handle
|
||||
}
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
|
||||
if (!guard) return -1;
|
||||
if (topicName == nullptr || subscriptionName == nullptr) {
|
||||
return -1; // Invalid parameters
|
||||
}
|
||||
std::string topic = topicName ? topicName : "";
|
||||
std::string subName = subscriptionName ? subscriptionName : "";
|
||||
|
||||
if (guard.get()->Subscribe(topic, subName)) {
|
||||
return 1; // Success
|
||||
}
|
||||
else {
|
||||
return 0; // Subscribe failed
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int ReceiveMessageANSPulsar_CPP(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, std::string& message) {
|
||||
if (Handle == nullptr || *Handle == nullptr) {
|
||||
return -1; // Invalid handle
|
||||
}
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
|
||||
if (!guard) return -1;
|
||||
if (timeoutMs < 0) {
|
||||
return -1; // Invalid parameters
|
||||
}
|
||||
bool _doAcknowledge = (doAcknowledge == 1);
|
||||
if (guard.get()->Receive(message, _doAcknowledge, timeoutMs)) {
|
||||
return 1; // Success
|
||||
}
|
||||
else {
|
||||
return 0; // Receive failed
|
||||
}
|
||||
|
||||
}
|
||||
extern "C" ANSPALSAR_API int ReceiveMessageANSPulsar(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, LStrHandle strMessage) {
|
||||
if (Handle == nullptr || *Handle == nullptr) {
|
||||
return -1; // Invalid handle
|
||||
}
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
|
||||
if (!guard) return -1;
|
||||
if (timeoutMs < 0 || strMessage == nullptr) {
|
||||
return -1; // Invalid parameters
|
||||
}
|
||||
std::string message;
|
||||
bool _doAcknowledge = (doAcknowledge == 1);
|
||||
if (guard.get()->Receive(message, _doAcknowledge, timeoutMs)) {
|
||||
if (message.empty()) return 0;
|
||||
int size = static_cast<int>(message.length());
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(strMessage, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*strMessage)->cnt = size;
|
||||
memcpy((*strMessage)->str, message.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else {
|
||||
return 0; // Receive failed
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// V2 API — handle passed by value (uint64_t) to avoid LabVIEW buffer reuse bug
|
||||
// ============================================================================
|
||||
|
||||
extern "C" ANSPALSAR_API int ConnectANSPulsar_V2(uint64_t handleVal, const char* topicName) {
|
||||
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
|
||||
if (!_v2h) return -1;
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
|
||||
if (!guard) return -1;
|
||||
if (topicName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
std::string topic = topicName;
|
||||
if (guard.get()->Connect(topic)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int DisconnectANSPulsar_V2(uint64_t handleVal) {
|
||||
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
|
||||
if (!_v2h) return -1;
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
|
||||
if (!guard) return -1;
|
||||
if (guard.get()->Disconnect()) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int PublishANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties) {
|
||||
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
|
||||
if (!_v2h) return -1;
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
|
||||
if (!guard) return -1;
|
||||
if (message == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
std::string msg = message ? message : "";
|
||||
std::string props = properties ? properties : "";
|
||||
if (guard.get()->Publish(msg, props)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int PublishAsyncANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties) {
|
||||
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
|
||||
if (!_v2h) return -1;
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
|
||||
if (!guard) return -1;
|
||||
if (message == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
std::string msg = message ? message : "";
|
||||
std::string props = properties ? properties : "";
|
||||
if (guard.get()->PublishAsync(msg, props)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int SubscribeANSPulsar_V2(uint64_t handleVal, const char* topicName, const char* subscriptionName) {
|
||||
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
|
||||
if (!_v2h) return -1;
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
|
||||
if (!guard) return -1;
|
||||
if (topicName == nullptr || subscriptionName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
std::string topic = topicName ? topicName : "";
|
||||
std::string subName = subscriptionName ? subscriptionName : "";
|
||||
if (guard.get()->Subscribe(topic, subName)) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ANSPALSAR_API int ReceiveMessageANSPulsar_V2(uint64_t handleVal, int timeoutMs, int doAcknowledge, LStrHandle strMessage) {
|
||||
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
|
||||
if (!_v2h) return -1;
|
||||
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
|
||||
if (!guard) return -1;
|
||||
if (timeoutMs < 0 || strMessage == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
std::string message;
|
||||
bool _doAcknowledge = (doAcknowledge == 1);
|
||||
if (guard.get()->Receive(message, _doAcknowledge, timeoutMs)) {
|
||||
if (message.empty()) return 0;
|
||||
int size = static_cast<int>(message.length());
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(strMessage, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*strMessage)->cnt = size;
|
||||
memcpy((*strMessage)->str, message.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
7
integrations/ANSPulsar/framework.h
Normal file
7
integrations/ANSPulsar/framework.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#define NOMINMAX // Prevent windows.h from defining min/max macros
|
||||
// which break std::min / std::max (C2589)
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
5
integrations/ANSPulsar/pch.cpp
Normal file
5
integrations/ANSPulsar/pch.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
||||
13
integrations/ANSPulsar/pch.h
Normal file
13
integrations/ANSPulsar/pch.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// pch.h: This is a precompiled header file.
|
||||
// Files listed below are compiled only once, improving build performance for future builds.
|
||||
// This also affects IntelliSense performance, including code completion and many code browsing features.
|
||||
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
|
||||
// Do not add files here that you will be updating frequently as this negates the performance advantage.
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
|
||||
#endif //PCH_H
|
||||
Reference in New Issue
Block a user