Extensive rewrite of basyx::vab
This commit
- Significantly improves and simplifies frame handling
- Introduces proper exception handling in vab return frames
- Adjusts VAB behaviour to reflect changes made in the Java SDK
- Fixes bugs in server code
- Fixes bugs in model provider code
Change-Id: Iada7096102c3dc6d42a4832ab488d0b4799dd15c
Signed-off-by: Thomas Psota <thomas.psota@iese.fraunhofer.de>
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/abstraction/net/Buffer.h b/sdks/c++/basys.sdk.cc/include/BaSyx/abstraction/net/Buffer.h
index 4bc09cf..4d1da9b 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/abstraction/net/Buffer.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/abstraction/net/Buffer.h
@@ -8,6 +8,7 @@
#ifndef ABSTRACTION_NET_BUFFER_H_
#define ABSTRACTION_NET_BUFFER_H_
+#include <string>
#include <cstddef>
namespace basyx {
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/server/BaSyxNativeProvider.h b/sdks/c++/basys.sdk.cc/include/BaSyx/server/BaSyxNativeProvider.h
index 15282dd..6f74321 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/server/BaSyxNativeProvider.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/server/BaSyxNativeProvider.h
@@ -12,13 +12,14 @@
#include <BaSyx/util/tools/CoderTools.h>
+#include <BaSyx/vab/backend/connector/native/frame/Frame.h>
#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h>
#include <BaSyx/log/log.h>
-#include <asio.hpp>
+#include <BaSyx/abstraction/net/Buffer.h>
-//#define DEFAULT_BUF_SIZE 1024
+#include <asio.hpp>
/**
@@ -41,7 +42,7 @@
// Buffers
static constexpr std::size_t default_buffer_size = 4096;
std::array<char, default_buffer_size> recv_buffer;
- std::array<char, default_buffer_size> ret;
+ std::array<char, default_buffer_size> send_buffer;
bool closed;
basyx::log log;
@@ -58,7 +59,15 @@
~NativeProvider()
{
// Connection no longer needed, close it
- this->clientSocket.close();
+ try
+ {
+ if (this->clientSocket.is_open())
+ this->clientSocket.close();
+ }
+ catch (std::exception & e)
+ {
+ log.warn("Exception in closing socket");
+ };
}
// Has to be called repeatedly
@@ -67,49 +76,23 @@
log.trace("Updating...");
if (!closed)
{
- auto huh = clientSocket.is_open();
-
asio::error_code ec;
log.trace("Waiting for incoming message");
- std::size_t bytes_read = this->clientSocket.receive(asio::buffer(recv_buffer.data(), recv_buffer.size()),0, ec);
- log.debug("Received {} bytes.", bytes_read);
+ auto input_frame = recvFrame(ec);
- if(ec == asio::error::eof) {
-// if (bytes_read == 0 || !this->clientSocket.is_open()) {
+ if(ec) {
log.info("Connection closed");
closed = true;
}
- else if (bytes_read < 0) {
- log.error("Receive failed!");
- closed = true;
- }
else {
log.trace("Received frame.");
-#ifdef PRINT_FRAME
- log.debug("Received:");
- vab::provider::native::frame::BaSyxNativeFrameHelper::printFrame(recv_buffer.data(), bytes_read);
-#endif
- std::size_t txSize = 0;
+ log.info("Received: {}", input_frame.getFirstValue());
- frameProcessor->processInputFrame(
- recv_buffer.data() + BASYX_FRAMESIZE_SIZE,
- bytes_read - BASYX_FRAMESIZE_SIZE,
- ret.data() + BASYX_FRAMESIZE_SIZE,
- &txSize);
-
- // Encode txSize
- CoderTools::setInt32(ret.data(), 0, txSize);
- txSize += BASYX_FRAMESIZE_SIZE;
+ auto output_frame = frameProcessor->processInputFrame(input_frame);
log.info("Sending reply.");
-#ifdef PRINT_FRAME
- log.debug("Sending:");
- vab::provider::native::frame::BaSyxNativeFrameHelper::printFrame(ret.data(), txSize);
-#endif
- log.debug("Sending {} bytes.", txSize);
- std::size_t bytes_sent = this->clientSocket.send(asio::buffer(ret.data(), txSize));
- log.debug("Sent {} bytes.", bytes_sent);
+ auto bytes_sent = sendFrame(output_frame);
if (bytes_sent < 0) {
log.error("Sending failed: {}", "ERROR");
closed = true;
@@ -122,6 +105,46 @@
{
return closed;
}
+
+ std::size_t sendData(char* data, std::size_t size)
+ {
+ log.debug("Sending {} bytes.", size);
+ std::size_t bytes_sent = this->clientSocket.send(asio::buffer(data, size));
+ log.debug("Sent {} bytes.", bytes_sent);
+ return bytes_sent;
+ };
+
+
+ std::size_t receiveData(char* data, asio::error_code & ec)
+ {
+ std::size_t bytes_read = this->clientSocket.receive(asio::buffer(recv_buffer.data(), recv_buffer.size()), 0, ec);
+ log.debug("Received {} bytes.", bytes_read);
+ return bytes_read;
+ };
+
+ std::size_t sendFrame(const connector::native::Frame & frame)
+ {
+ connector::native::Frame::write_to_buffer(
+ basyx::net::make_buffer(
+ send_buffer.data() + BASYX_FRAMESIZE_SIZE, default_buffer_size - BASYX_FRAMESIZE_SIZE),
+ frame);
+
+ auto size_field = reinterpret_cast<uint32_t*>(&send_buffer[0]);
+ *size_field = frame.size();
+
+ return sendData(send_buffer.data(), frame.size() + BASYX_FRAMESIZE_SIZE);
+ };
+
+ connector::native::Frame recvFrame(asio::error_code & ec)
+ {
+ this->receiveData(recv_buffer.data(), ec);
+ auto size = *reinterpret_cast<uint32_t*>(recv_buffer.data());
+ auto frame = connector::native::Frame::read_from_buffer(
+ basyx::net::make_buffer(this->recv_buffer.data() + BASYX_FRAMESIZE_SIZE, size - BASYX_FRAMESIZE_SIZE)
+ );
+
+ return frame;
+ };
};
};
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/server/BaSyxTCPServer.h b/sdks/c++/basys.sdk.cc/include/BaSyx/server/BaSyxTCPServer.h
deleted file mode 100644
index 6c554ee..0000000
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/server/BaSyxTCPServer.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-* BaSyxTCPServer.h
-*
-* Created on: 14.08.2018
-* Author: schnicke
-*/
-
-#ifndef VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_H
-#define VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_H
-
-#include <atomic>
-#include <iostream>
-#include <vector>
-
-#include <BaSyx/log/log.h>
-
-#include <asio.hpp>
-
-#include <BaSyx/server/BaSyxNativeProvider.h>
-#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h>
-
-namespace basyx {
-namespace vab {
-namespace provider {
-namespace native {
-
- template <typename T>
- class TCPServer {
- private:
- T* backend;
-
- //basyx::net::tcp::Acceptor acceptor;
-
- asio::io_context io_context;
- // asio::ip::tcp::endpoint endpoint;
- asio::ip::tcp::acceptor acceptor;
-
- std::vector<std::thread> threads;
- std::vector<std::unique_ptr<asio::ip::tcp::socket>> sockets;
-
- bool closed;
- std::atomic_bool running;
-
- basyx::log log;
-
- public:
- // ToDo: Ownership of backend?
- TCPServer(T* backend, int port)
- : backend{ backend }
- , running{ true }
- // , endpoint{ asio::ip::tcp::v4(), port }
- , acceptor{ io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port) }
- , log{ "TCPServer" }
- {
- // ToDo: Check health of acceptor
- log.info("Starting server on port {}", port);
- acceptor.listen();
- }
-
- void Close()
- {
- log.trace("Closing...");
-
- if (!isRunning())
- return;
-
- running.store(true);
-
- // Close the acceptor socket
- log.trace("Closing Acceptor...");
- acceptor.close();
-
- // Close all accepted connections
- // This will bring all open connection threads to a finish
- log.trace("Closing open connections...");
- for (auto& socket : sockets)
- socket->close();
-
- // Wait for all threads to finish
- for (auto& thread : threads)
- thread.join();
-
- // ToDo: Check for errors during cleanup
- }
-
- ~TCPServer()
- {
- this->Close();
- }
-
- /**
- * Has to be called periodically
- */
- void update()
- {
- if (isRunning()) {
- log.info("Accepting new connections.");
-
- auto ClientSocket = util::make_unique<asio::ip::tcp::socket>(io_context);
- this->acceptor.accept(*ClientSocket.get());
-
- //auto error = WSAGetLastError();
-
- if (!ClientSocket->is_open()) {
- log.warn("Incoming connection failed");
- return;
- }
-
- log.info("Incoming new connection");
- sockets.emplace_back(std::move(ClientSocket));
-
- std::thread handlerThread{ &TCPServer<T>::processConnection, this, std::ref(*sockets.back()) };
- threads.emplace_back(std::move(handlerThread));
- }
- }
-
- bool isRunning()
- {
- return running;
- }
-
- private:
- /**
- * Handles a BaSyxNativeProvider
- */
- void processConnection(asio::ip::tcp::socket & socket)
- {
- log.trace("Processing new connection");
-
- vab::provider::native::frame::BaSyxNativeFrameProcessor processor{ this->backend };
- vab::provider::native::NativeProvider provider{ socket, &processor };
-
- while (!provider.isClosed()) {
- provider.update();
- }
- }
- };
-};
-};
-};
-};
-
-#endif /* VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_H */
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/server/TCPServer.h b/sdks/c++/basys.sdk.cc/include/BaSyx/server/TCPServer.h
new file mode 100644
index 0000000..98e0f22
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/server/TCPServer.h
@@ -0,0 +1,188 @@
+#ifndef VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_2_H
+#define VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_2_H
+
+#include <atomic>
+#include <iostream>
+#include <vector>
+
+#include <BaSyx/log/log.h>
+
+#include <asio.hpp>
+
+#include <BaSyx/server/BaSyxNativeProvider.h>
+#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h>
+
+namespace basyx {
+namespace server {
+
+ template <typename Backend>
+ class TCPServer {
+ public:
+ using socket_ptr_t = std::unique_ptr<asio::ip::tcp::socket>;
+ private:
+ Backend * backend;
+
+ asio::io_context io_context;
+ asio::ip::tcp::acceptor acceptor;
+
+ std::vector<std::thread> threads;
+ std::vector<socket_ptr_t> sockets;
+
+ bool closed;
+ std::atomic_bool running;
+
+ basyx::log log;
+
+ public:
+ TCPServer(Backend * backend, int port)
+ : backend{ backend }
+ , running{ true }
+ , io_context{ 0 }
+ , acceptor{ io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port) }
+ , log{ "TCPServer" }
+ {
+ // ToDo: Check health of acceptor
+ log.info("Starting server on port {}", port);
+// acceptor.listen();
+ start_accept();
+ }
+
+ void run()
+ {
+ this->io_context.run();
+ };
+
+ void stop()
+ {
+ this->io_context.stop();
+ };
+
+ void start_accept()
+ {
+ asio::error_code ec;
+ auto client_socket = util::make_unique<asio::ip::tcp::socket>(io_context);
+ //this->acceptor.accept(*client_socket.get(), ec);
+
+ //auto error = WSAGetLastError();
+
+ //if (!client_socket->is_open()) {
+ // log.warn("Incoming connection failed");
+ // return;
+ //}
+ sockets.emplace_back(std::move(client_socket));
+
+ acceptor.async_accept(*sockets.back(),
+ std::bind(&TCPServer::handle_accept, this,
+ std::placeholders::_1));
+ };
+
+ void handle_accept(
+ const asio::error_code& error)
+ {
+ if (!error)
+ {
+ log.info("Incoming new connection");
+
+ std::thread handlerThread{ &TCPServer<Backend>::processConnection, this, std::ref(*sockets.back()) };
+ threads.emplace_back(std::move(handlerThread));
+ }
+ else
+ {
+ sockets.pop_back();
+ }
+
+ start_accept();
+ };
+
+ void Close()
+ {
+ log.trace("Closing...");
+
+ if (!isRunning())
+ return;
+
+ running.store(false);
+ this->stop();
+
+ //// Close the acceptor socket
+ //log.trace("Closing Acceptor...");
+ //acceptor.close();
+
+ // Close all accepted connections
+ // This will bring all open connection threads to a finish
+ log.trace("Closing open connections...");
+ for (auto& socket : sockets)
+ {
+ try {
+ if (socket->is_open())
+ socket->close();
+ }
+ catch (std::exception & e)
+ {
+ log.warn("Socket closed unexpectedly.");
+ }
+ };
+
+ // Wait for all threads to finish
+ for (auto& thread : threads)
+ thread.join();
+
+ // ToDo: Check for errors during cleanup
+ }
+
+ ~TCPServer()
+ {
+ this->Close();
+ }
+
+ /**
+ * Has to be called periodically
+ */
+ void update()
+ {
+ if (isRunning()) {
+ log.info("Accepting new connections.");
+
+ auto ClientSocket = util::make_unique<asio::ip::tcp::socket>(io_context);
+ this->acceptor.accept(*ClientSocket.get());
+
+ //auto error = WSAGetLastError();
+
+ if (!ClientSocket->is_open()) {
+ log.warn("Incoming connection failed");
+ return;
+ }
+
+ log.info("Incoming new connection");
+ sockets.emplace_back(std::move(ClientSocket));
+
+ std::thread handlerThread{ &TCPServer<Backend>::processConnection, this, std::ref(*sockets.back()) };
+ threads.emplace_back(std::move(handlerThread));
+ }
+ }
+
+ bool isRunning()
+ {
+ return running.load();
+ }
+
+ private:
+ /**
+ * Handles a BaSyxNativeProvider
+ */
+ void processConnection(asio::ip::tcp::socket & socket)
+ {
+ log.trace("Processing new connection");
+
+ vab::provider::native::frame::BaSyxNativeFrameProcessor processor{ this->backend };
+ vab::provider::native::NativeProvider provider{ socket, &processor };
+
+ while (!provider.isClosed()) {
+ provider.update();
+ }
+ }
+ };
+};
+};
+
+#endif /* VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_2_H */
\ No newline at end of file
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/server/server.h b/sdks/c++/basys.sdk.cc/include/BaSyx/server/server.h
deleted file mode 100644
index df488b3..0000000
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/server/server.h
+++ /dev/null
@@ -1,6 +0,0 @@
-
-#ifndef VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_2_H
-#define VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_2_H
-
-
-#endif /* VAB_VAB_PROVIDER_NATIVE_BASYXTCPSERVER_H */
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/shared/object/obj_error.h b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/object/obj_error.h
new file mode 100644
index 0000000..34114c7
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/object/obj_error.h
@@ -0,0 +1,29 @@
+#ifndef BASYX_ENUM_ERROR_H
+#define BASYX_ENUM_ERROR_H
+
+#include <string>
+
+namespace basyx {
+namespace detail {
+
+enum class error {
+ None,
+ PropertyNotFound,
+ IndexOutOfBounds,
+ NotInvokable,
+ ObjectAlreadyExists,
+ MalformedRequest,
+ ProviderException,
+};
+
+class error_
+{
+public:
+ static error from_string(const std::string & name);
+ static const char * to_string(error value);
+};
+
+}
+}
+
+#endif
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/shared/object/object_header.h b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/object/object_header.h
index fe9de4f..806c110 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/shared/object/object_header.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/object/object_header.h
@@ -15,6 +15,7 @@
#include <nlohmann/json.hpp>
+#include <BaSyx/shared/object/obj_error.h>
#include <BaSyx/shared/object/obj_placeholder.h>
#include <vector>
@@ -30,15 +31,7 @@
class object
{
public:
- enum class error
- {
- None,
- PropertyNotFound,
- IndexOutOfBounds,
- NotInvokable,
- ObjectAlreadyExists,
- MalformedRequest,
- };
+ using error = basyx::detail::error;
public: // Type definitions
template<typename T>
using list_t = std::vector<T>;
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/shared/serialization/json/json.h b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/serialization/json/json.h
index 22170ec..336a14a 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/shared/serialization/json/json.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/serialization/json/json.h
@@ -19,9 +19,9 @@
#include <BaSyx/shared/serialization/json/typeid.h>
namespace basyx {
+ using json_t = nlohmann::json;
namespace serialization {
namespace json {
- using json_t = nlohmann::json;
template <typename T>
inline json_t serialize(const T& t)
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/shared/types.h b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/types.h
index f8179d1..d9a106c 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/shared/types.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/shared/types.h
@@ -44,7 +44,8 @@
Set = 0x2,
Create = 0x3,
Delete = 0x4,
- Invoke = 0x5
+ Invoke = 0x5,
+ Invalid = 0xFF,
};
#define BASYX_FRAMESIZE_SIZE 4
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/IBaSyxConnector.h b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/IBaSyxConnector.h
index 44c6253..53353c1 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/IBaSyxConnector.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/IBaSyxConnector.h
@@ -29,20 +29,14 @@
virtual basyx::object basysGet(std::string const& path) = 0;
/**
- * Invoke a BaSys get operation without de-serialization
- * @return the serialized element as a JSONObject
- */
- virtual basyx::serialization::json::json_t basysGetRaw(std::string const& path) = 0;
-
- /**
* Invoke a Basys Set operation. Sets or overrides existing property, operation or event.
*/
- virtual void basysSet(std::string const& path, const basyx::object & newValue) = 0;
+ virtual basyx::object basysSet(std::string const& path, const basyx::object & newValue) = 0;
/**
* Creates a new Property, Operation, Event, Submodel or AAS
*/
- virtual void basysCreate(std::string const& servicePath, const basyx::object & value) = 0;
+ virtual basyx::object basysCreate(std::string const& servicePath, const basyx::object & value) = 0;
/**
* Invoke a Basys Invoke operation. Invokes an operation on the server.
@@ -53,12 +47,12 @@
* Invoke a Basys operation. Deletes any resource under the given path.
*
*/
- virtual void basysDelete(std::string const& servicePath) = 0;
+ virtual basyx::object basysDelete(std::string const& servicePath) = 0;
/**
* Invoke a Basys oxperation. Deletes an entry from a map or collection by the given key
*/
- virtual void basysDelete(std::string const& servicePath, const basyx::object & obj) = 0;
+ virtual basyx::object basysDelete(std::string const& servicePath, const basyx::object & obj) = 0;
};
}
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/JSONProvider.h b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/JSONProvider.h
index dad0312..b38d701 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/JSONProvider.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/JSONProvider.h
@@ -9,13 +9,15 @@
#ifndef VAB_BACKEND_CONNECTOR_JSONPROVIDER_H
#define VAB_BACKEND_CONNECTOR_JSONPROVIDER_H
-#include <string>
-
#include <BaSyx/shared/object.h>
#include <BaSyx/shared/serialization/json.h>
-// TODO: Repository?
-// TODO: Implement exception when JSONTools support them
+#include <BaSyx/vab/backend/connector/native/frame/EntityWrapper.h>
+
+#include <string>
+
+namespace basyx {
+namespace vab {
template <typename Provider>
class JSONProvider {
@@ -33,44 +35,73 @@
std::string processBaSysGet(std::string const& path)
{
auto res = providerBackend->getModelPropertyValue(path);
- return serializeToJSON(path, res);
+
+ return EntityWrapper::build_from_object(res).dump(4);
}
std::string processBaSysSet(std::string const& path, std::string const& serializedJSONValue)
{
auto deserialized = basyx::serialization::json::deserialize(serializedJSONValue);
- providerBackend->setModelPropertyValue(path, std::move(deserialized));
+ auto error = providerBackend->setModelPropertyValue(path, std::move(deserialized));
- return serializeSuccess();
+ if (error != basyx::object::error::None)
+ {
+ return EntityWrapper::build_from_error(error).dump(4);
+ }
+ else
+ {
+ return serializeSuccess();
+ }
}
std::string processBaSysCreate(std::string const& path, std::string const& serializedJSONValue)
{
auto deserialized = basyx::serialization::json::deserialize(serializedJSONValue);
- providerBackend->createValue(path, std::move(deserialized));
+ auto error = providerBackend->createValue(path, std::move(deserialized));
- return serializeSuccess();
- }
+ if (error != basyx::object::error::None)
+ {
+ return EntityWrapper::build_from_error(error).dump(4);
+ }
+ else
+ {
+ return serializeSuccess();
+ }
+ }
std::string processBaSysDelete(std::string const& path, std::string const& serializedJSONValue)
{
auto deserialized = basyx::serialization::json::deserialize(serializedJSONValue);
- providerBackend->deleteValue(path, std::move(deserialized));
+ auto error = providerBackend->deleteValue(path, std::move(deserialized));
- return serializeSuccess();
- }
+ if (error != basyx::object::error::None)
+ {
+ return EntityWrapper::build_from_error(error).dump(4);
+ }
+ else
+ {
+ return serializeSuccess();
+ }
+ }
std::string processBaSysDelete(std::string const& path)
{
- providerBackend->deleteValue(path);
- return serializeSuccess();
- }
+ auto error = providerBackend->deleteValue(path);
+ if (error != basyx::object::error::None)
+ {
+ return EntityWrapper::build_from_error(error).dump(4);
+ }
+ else
+ {
+ return serializeSuccess();
+ }
+ }
- std::string processBaSysInvoke(std::string const& path, std::string const& serializedJSONValue, char* output, size_t* size)
+ std::string processBaSysInvoke(std::string const& path, std::string const& serializedJSONValue)
{
auto deserialized = basyx::serialization::json::deserialize(serializedJSONValue);
auto res = providerBackend->invokeOperation(path, deserialized);
- return serializeToJSON(path, res);
+ return EntityWrapper::build_from_object(res).dump(4);
}
private:
@@ -81,16 +112,10 @@
nlohmann::json retJson { { "success", true } };
return retJson.dump(4);
- }
+ }
+};
- std::string serializeToJSON(const std::string& path, const basyx::object& value)
- {
- auto json = basyx::serialization::json::serialize(value);
-
- nlohmann::json retJson { { "success", true }, { "entity", json } };
-
- return retJson.dump(4);
- }
+}
};
#endif /* VAB_VAB_BACKEND_CONNECTOR_JSONPROVIDER_H */
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/BaSyxConnector.h b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/BaSyxConnector.h
index 10da741..fc19d2a 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/BaSyxConnector.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/BaSyxConnector.h
@@ -9,7 +9,7 @@
#define VAB_VAB_BACKEND_CONNECTOR_NATIVE_BASYXCONNECTOR_H
#include <BaSyx/vab/backend/connector/IBaSyxConnector.h>
-#include <BaSyx/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.h>
+#include <BaSyx/vab/backend/connector/native/frame/Frame.h>
#include <BaSyx/abstraction/Net.h>
@@ -23,41 +23,30 @@
class NativeConnector : public IBaSyxConnector {
public:
static constexpr std::size_t default_buffer_length = 4096;
-
- public:
+ private:
+ basyx::net::tcp::Socket socket;
+ std::array<char, default_buffer_length> buffer;
+ private:
+ basyx::log log;
+ public:
NativeConnector(std::string const& address, int port);
-
virtual ~NativeConnector();
-
public:
- virtual ::basyx::object basysGet(std::string const& path) override;
-
- virtual nlohmann::json basysGetRaw(std::string const& path) override;
-
- virtual void basysSet(std::string const& path, const ::basyx::object& newValue) override;
-
- virtual void basysCreate(std::string const& servicePath, const ::basyx::object& val)
- override;
-
- virtual ::basyx::object basysInvoke(std::string const& servicePath, const ::basyx::object& param)
- override;
-
- virtual void basysDelete(std::string const& servicePath) override;
-
- virtual void basysDelete(std::string const& servicePath, const ::basyx::object& obj) override;
-
- private:
- basyx::net::tcp::Socket socket;
- frame::BaSyxNativeFrameBuilder builder;
- std::array<char, default_buffer_length> buffer;
-
- void sendData(char* data, size_t size);
-
- size_t receiveData(char* data);
- basyx::object decode(char* buffer);
- basyx::log log;
+ virtual basyx::object basysGet(std::string const& path) override;
+ virtual basyx::object basysSet(std::string const& path, const basyx::object& newValue) override;
+ virtual basyx::object basysCreate(std::string const& servicePath, const basyx::object& val) override;
+ virtual basyx::object basysInvoke(std::string const& servicePath, const basyx::object& param) override;
+ virtual basyx::object basysDelete(std::string const& servicePath) override;
+ virtual basyx::object basysDelete(std::string const& servicePath, const ::basyx::object& obj) override;
+ protected:
+ virtual basyx::object basysProcess(const Frame & frame);
+ protected:
+ void sendFrame(const Frame & frame);
+ Frame recvFrame();
+ private:
+ void sendData(char* data, size_t size);
+ size_t receiveData(char* data);
};
-
}
}
}
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.h b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.h
deleted file mode 100644
index 992a31b..0000000
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * BaSyxNativeFrameBuilder.h
- *
- * Created on: 14.08.2018
- * Author: schnicke
- */
-
-#ifndef VAB_VAB_BACKEND_CONNECTOR_NATIVE_FRAME_BASYXNATIVEFRAMEBUILDER_H
-#define VAB_VAB_BACKEND_CONNECTOR_NATIVE_FRAME_BASYXNATIVEFRAMEBUILDER_H
-
-#include <string>
-
-
-
-#include <BaSyx/shared/types.h>
-#include <BaSyx/shared/object.h>
-
-//#include <BaSyx/vab/provider/BaSyx/frame/BaSyxNativeFrameProcessor.h>
-
-
-namespace basyx {
-namespace vab {
-namespace connector {
-namespace native {
-namespace frame {
-
- /**
- * Provides support methods for building native basyx frames
- */
- class BaSyxNativeFrameBuilder {
- public:
- BaSyxNativeFrameBuilder();
-
- size_t buildGetFrame(std::string const& path, char* buffer);
-
- size_t buildSetFrame(std::string const& path, const basyx::object& newVal, char* buffer);
-
- size_t buildCreateFrame(std::string const& path, const basyx::object& newVal, char* buffer);
-
- size_t buildDeleteFrame(std::string const& path, char* buffer);
-
- size_t buildDeleteFrame(std::string const& path, const basyx::object& deleteVal, char* buffer);
-
- size_t buildInvokeFrame(std::string const& path, const basyx::object& param, char* buffer);
- size_t buildInvokeFrame(std::string const& path, const basyx::object::object_list_t & params, char * buffer);
- private:
- size_t encodeCommand(BaSyxCommand command, char* buffer);
-
- size_t encodeCommandAndPath(BaSyxCommand command, std::string const& path, char* buffer);
-
- std::size_t encodeValue(const ::basyx::object& value, char* buffer);
- };
-
-
-}
-}
-}
-}
-}
-
-
-#endif /* VAB_VAB_BACKEND_CONNECTOR_NATIVE_FRAME_BASYXNATIVEFRAMEBUILDER_H */
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/EntityWrapper.h b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/EntityWrapper.h
new file mode 100644
index 0000000..a8caa25
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/EntityWrapper.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <BaSyx/shared/object.h>
+#include <BaSyx/shared/serialization/json.h>
+
+#include <string>
+
+namespace basyx {
+namespace vab {
+
+class EntityWrapper
+{
+public:
+ static json_t build_from_object(const basyx::object & obj);
+ static json_t build_from_error(basyx::object::error error, const std::string & message = "");
+ //static json_t build_exception(const basyx::object::error & error, const std::string & message);
+ //static json_t to_json(const EntityWrapper & result);
+ static basyx::object from_json(const json_t & json);
+};
+
+}
+}
\ No newline at end of file
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/Frame.h b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/Frame.h
new file mode 100644
index 0000000..4035b1a
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/backend/connector/native/frame/Frame.h
@@ -0,0 +1,64 @@
+#ifndef VAB_VAB_BACKEND_CONNECTOR_NATIVE_FRAME_FRAME_H
+#define VAB_VAB_BACKEND_CONNECTOR_NATIVE_FRAME_FRAME_H
+
+#include <BaSyx/abstraction/net/Buffer.h>
+
+#include <BaSyx/shared/object.h>
+#include <BaSyx/shared/types.h>
+
+
+namespace basyx {
+namespace vab {
+namespace connector {
+namespace native {
+
+class Frame
+{
+private:
+ uint8_t flag;
+ std::string value_1;
+ std::string value_2;
+public:
+ struct Builder {
+ static Frame Get(const std::string & path);
+ static Frame Set(const std::string & path, const basyx::object & value);
+ static Frame Create(const std::string & path, const basyx::object & value);
+ static Frame Delete(const std::string & path);
+ static Frame Delete(const std::string & path, const basyx::object & value);
+ static Frame Invoke(const std::string & path, const basyx::object & value);
+ };
+public:
+ Frame();
+ Frame(uint8_t flag, const std::string & value_1);
+ Frame(uint8_t flag, const std::string & value_1, const std::string & value_2);
+
+ Frame(const Frame & other) = default;
+ Frame(Frame && other) noexcept = default;
+
+ Frame & operator=(const Frame & other) = default;
+ Frame & operator=(Frame && other) noexcept = default;
+
+ ~Frame() = default;
+public:
+ const std::string & getFirstValue() const;
+ void setFirstValue(const std::string & value);
+
+ const std::string & getSecondValue() const;
+ void setSecondValue(const std::string & path);
+
+ uint8_t getFlag() const;
+ void setFlag(uint8_t flag);
+ void setFlag(BaSyxCommand flag);
+
+ std::size_t size() const;
+public:
+ static bool write_to_buffer(const basyx::net::Buffer & buffer, const Frame & frame);
+ static Frame read_from_buffer(const basyx::net::Buffer & buffer);
+};
+
+}
+}
+}
+}
+
+#endif /* VAB_VAB_BACKEND_CONNECTOR_NATIVE_FRAME_FRAME_H */
\ No newline at end of file
diff --git a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h
index 8143bcc..f049e79 100644
--- a/sdks/c++/basys.sdk.cc/include/BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h
+++ b/sdks/c++/basys.sdk.cc/include/BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h
@@ -12,6 +12,7 @@
#include <string>
#include <BaSyx/vab/backend/connector/JSONProvider.h>
+#include <BaSyx/vab/backend/connector/native/frame/Frame.h>
#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameHelper.h>
#include <BaSyx/vab/core/IModelProvider.h>
@@ -23,29 +24,21 @@
namespace native {
namespace frame {
-class BaSyxNativeFrameProcessor {
-
-public:
- BaSyxNativeFrameProcessor(vab::core::IModelProvider* providerBackend);
- ~BaSyxNativeFrameProcessor();
-
-
- /**
- * Processes a rxFrame and performs the encoded command
- *
- * The following structure is assumed:
- * 1 byte command
- * x byte depending on command
- */
- void processInputFrame(char const* rxFrame, std::size_t rxSize, char* txFrame, std::size_t* txSize);
+class BaSyxNativeFrameProcessor
+{
private:
JSONProvider<vab::core::IModelProvider> jsonProvider;
-
- void processGet(char const* rxFrame, char* txFrame, std::size_t* txSize);
- void processSet(char const* rxFrame, char* txFrame, std::size_t* txSize);
- void processCreate(char const* rxFrame, char* txFrame, std::size_t* txSize);
- void processDelete(char const* rxFrame, std::size_t rxSize, char* txFrame, std::size_t* txSize);
- void processInvoke(char const* rxFrame, char* txFrame, std::size_t* txSize);
+private:
+ connector::native::Frame processGet(const connector::native::Frame & frame);
+ connector::native::Frame processSet(const connector::native::Frame & frame);
+ connector::native::Frame processCreate(const connector::native::Frame & frame);
+ connector::native::Frame processDelete(const connector::native::Frame & frame);
+ connector::native::Frame processInvoke(const connector::native::Frame & frame);
+public:
+ BaSyxNativeFrameProcessor(vab::core::IModelProvider* providerBackend);
+ ~BaSyxNativeFrameProcessor() = default;
+public:
+ connector::native::Frame processInputFrame(const connector::native::Frame & frame);
};
diff --git a/sdks/c++/basys.sdk.cc/src/server/CMakeLists.txt b/sdks/c++/basys.sdk.cc/src/server/CMakeLists.txt
index 301dc9c..8d40802 100644
--- a/sdks/c++/basys.sdk.cc/src/server/CMakeLists.txt
+++ b/sdks/c++/basys.sdk.cc/src/server/CMakeLists.txt
@@ -6,6 +6,7 @@
set (BASYX_SERVER_LIB_SUFFIX "Server")
set (BASYX_SERVER_LIBRARY_NAME "${PROJECT_SHORTNAME}${BASYX_SERVER_LIB_SUFFIX}")
+set (BASYX_SHARED_INCLUDE_DIR "${BASYX_INCLUDE_DIR}/BaSyx/server")
add_library(${BASYX_SERVER_LIB_SUFFIX})
@@ -22,7 +23,8 @@
target_sources(${BASYX_SERVER_LIB_SUFFIX}
PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/server/server.cpp
+ ${BASYX_SHARED_INCLUDE_DIR}/TCPServer.h
+ ${BASYX_SHARED_INCLUDE_DIR}/BaSyxNativeProvider.h
)
# TCPSelectServer currently only supported under UNIX
diff --git a/sdks/c++/basys.sdk.cc/src/server/server/TCPSelectServer.cpp b/sdks/c++/basys.sdk.cc/src/server/server/TCPSelectServer.cpp
index bebecc0..7e32b56 100644
--- a/sdks/c++/basys.sdk.cc/src/server/server/TCPSelectServer.cpp
+++ b/sdks/c++/basys.sdk.cc/src/server/server/TCPSelectServer.cpp
@@ -4,8 +4,8 @@
* Author: wendel
*/
-#include "include/BaSyx/server/TCPSelectServer.h"
-#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameHelper.h>
+#include <BaSyx/server/TCPSelectServer.h>
+#include <BaSyx/vab/backend//connector/native/frame/Frame.h>
#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameProcessor.h>
#include <errno.h>
@@ -21,242 +21,226 @@
namespace provider {
namespace native {
-TCPSelectServer::TCPSelectServer(core::IModelProvider *backend, int port, int timeout_ms, int listen_backlog)
+TCPSelectServer::TCPSelectServer(core::IModelProvider* backend, int port, int timeout_ms, int listen_backlog)
: port(port)
- , initialized(false)
- , backend(backend)
- , log("TCPSelectServer")
- , listen_backlog(listen_backlog)
+ , initialized(false)
+ , backend(backend)
+ , log("TCPSelectServer")
+ , listen_backlog(listen_backlog)
{
- frame_processor = std::unique_ptr<frame::BaSyxNativeFrameProcessor>(new frame::BaSyxNativeFrameProcessor(backend));
- timeout.tv_sec = timeout_ms / 1000;
- timeout.tv_usec = (timeout_ms % 1000) * 1000;
+ frame_processor = std::unique_ptr<frame::BaSyxNativeFrameProcessor>(new frame::BaSyxNativeFrameProcessor(backend));
+ timeout.tv_sec = timeout_ms / 1000;
+ timeout.tv_usec = (timeout_ms % 1000) * 1000;
}
TCPSelectServer::~TCPSelectServer()
{
- this->clean_up();
+ this->clean_up();
}
void TCPSelectServer::Init()
{
- int rc, on = 1;
- // create socket to accept incoming connections
- listen_sd = socket(AF_INET, SOCK_STREAM, 0);
- if (listen_sd < 0)
- {
- log.error("socket() failed");
- exit(-1);
- }
+ int rc, on = 1;
+ // create socket to accept incoming connections
+ listen_sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (listen_sd < 0) {
+ log.error("socket() failed");
+ exit(-1);
+ }
- // set socket reusable
- int setsocketopt_state = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
- if (setsocketopt_state < 0)
- {
- log.error("setsockopt() failed");
- close(listen_sd);
- exit(-1);
- }
+ // set socket reusable
+ int setsocketopt_state = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
+ if (setsocketopt_state < 0) {
+ log.error("setsockopt() failed");
+ close(listen_sd);
+ exit(-1);
+ }
- // Set socket to nonblocking state (FIONBIO -> non-blocking io)
- int ioctl_state = ioctl(listen_sd, FIONBIO, (char *) &on);
- if (ioctl_state < 0)
- {
- log.error("ioctl() failed");
- close(listen_sd);
- exit(-1);
- }
+ // Set socket to nonblocking state (FIONBIO -> non-blocking io)
+ int ioctl_state = ioctl(listen_sd, FIONBIO, (char*)&on);
+ if (ioctl_state < 0) {
+ log.error("ioctl() failed");
+ close(listen_sd);
+ exit(-1);
+ }
- // bind socket
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- memset(&addr.sin_addr, INADDR_ANY, sizeof(INADDR_ANY));
- //memcpy(&addr.sin_addr, INADDR_ANY, sizeof(INADDR_ANY));
- addr.sin_port = htons(port);
+ // bind socket
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ memset(&addr.sin_addr, INADDR_ANY, sizeof(INADDR_ANY));
+ //memcpy(&addr.sin_addr, INADDR_ANY, sizeof(INADDR_ANY));
+ addr.sin_port = htons(port);
- int bind_state = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
- if (bind_state < 0)
- {
- log.error("bind() failed");
- close(listen_sd);
- exit(-1);
- }
+ int bind_state = bind(listen_sd, (struct sockaddr*)&addr, sizeof(addr));
+ if (bind_state < 0) {
+ log.error("bind() failed");
+ close(listen_sd);
+ exit(-1);
+ }
- int listen_state = listen(listen_sd, listen_backlog);
- if (listen_state < 0)
- {
- log.error("listen() failed");
- close(listen_sd);
- exit(-1);
- }
+ int listen_state = listen(listen_sd, listen_backlog);
+ if (listen_state < 0) {
+ log.error("listen() failed");
+ close(listen_sd);
+ exit(-1);
+ }
- //init master filedescriptor
- FD_ZERO(&master_set);
- max_socket = listen_sd;
- FD_SET(listen_sd, &master_set);
+ //init master filedescriptor
+ FD_ZERO(&master_set);
+ max_socket = listen_sd;
+ FD_SET(listen_sd, &master_set);
- log.info("Select server initialized. Listen socket-descriptor({})", listen_sd);
- this->initialized = true;
+ log.info("Select server initialized. Listen socket-descriptor({})", listen_sd);
+ this->initialized = true;
}
int TCPSelectServer::Update()
{
- if (not initialized)
- log.warn("Select server not initialized");
+ if (not initialized)
+ log.warn("Select server not initialized");
- int rc;
- fd_set working_set;
+ int rc;
+ fd_set working_set;
- // copy filedescriptor
- memcpy(&working_set, &master_set, sizeof(master_set));
+ // copy filedescriptor
+ memcpy(&working_set, &master_set, sizeof(master_set));
- log.info("Waiting on select()...");
- rc = select(max_socket + 1, &working_set, nullptr, nullptr, &timeout);
+ log.info("Waiting on select()...");
+ rc = select(max_socket + 1, &working_set, nullptr, nullptr, &timeout);
- // check select state
- if (rc < 0)
- {
- log.error("select() failed");
- return -1;
- }
- if (rc == 0)
- {
- log.info("select() timed out. End program.");
- return -2;
- }
-
- desc_ready = rc;
- // check which descriptors are readable
- for (int fd = 0; fd <= max_socket && desc_ready > 0; ++fd)
- {
- // Check readiness of descriptors
- if (FD_ISSET(fd, &working_set))
- {
- // decrease number of readable descriptors, if all found stop looking for them
- desc_ready -= 1;
-
- if (fd == listen_sd)
- this->accept_incoming_connections();
- else //if not listen socket, socket should be readable
- {
- log.info("Descriptor {} is readable", fd);
- close_connection = false;
- this->receive_incoming_data(fd);
-
- // if connection is closed, clean up
- if (close_connection)
- {
- close(fd);
- log.info("Connection {} closed", fd);
- FD_CLR(fd, &master_set);
- if (fd == max_socket)
- {
- while (FD_ISSET(max_socket, &master_set) == false)
- {
- max_socket -= 1;
- }
- }
- }
- }
+ // check select state
+ if (rc < 0) {
+ log.error("select() failed");
+ return -1;
}
- }
- return 0;
+ if (rc == 0) {
+ log.info("select() timed out. End program.");
+ return -2;
+ }
+
+ desc_ready = rc;
+ // check which descriptors are readable
+ for (int fd = 0; fd <= max_socket && desc_ready > 0; ++fd) {
+ // Check readiness of descriptors
+ if (FD_ISSET(fd, &working_set)) {
+ // decrease number of readable descriptors, if all found stop looking for them
+ desc_ready -= 1;
+
+ if (fd == listen_sd)
+ this->accept_incoming_connections();
+ else //if not listen socket, socket should be readable
+ {
+ log.info("Descriptor {} is readable", fd);
+ close_connection = false;
+ this->receive_incoming_data(fd);
+
+ // if connection is closed, clean up
+ if (close_connection) {
+ close(fd);
+ log.info("Connection {} closed", fd);
+ FD_CLR(fd, &master_set);
+ if (fd == max_socket) {
+ while (FD_ISSET(max_socket, &master_set) == false) {
+ max_socket -= 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
}
void TCPSelectServer::Close()
{
- this->clean_up();
+ this->clean_up();
}
bool TCPSelectServer::isRunning()
{
- log.warn("Not implemented!");
- return false;
+ log.warn("Not implemented!");
+ return false;
}
void TCPSelectServer::clean_up()
{
- for (int i = 0; i <= max_socket; ++i)
- {
- if (FD_ISSET(i, &master_set))
- {
- close(i);
+ for (int i = 0; i <= max_socket; ++i) {
+ if (FD_ISSET(i, &master_set)) {
+ close(i);
+ }
}
- }
}
void TCPSelectServer::accept_incoming_connections()
{
- log.info("Listening socket is readable");
- int new_sd;
- do
- {
- // accept incoming connections
- new_sd = accept(listen_sd, nullptr, nullptr);
- if (new_sd < 0)
- {
- // if not EWOULDBLOCK -> all incomminng connections are accepted
- if (errno != EWOULDBLOCK)
- {
- log.error("accept() failed");
- end_server = true;
- }
- break;
- }
+ log.info("Listening socket is readable");
+ int new_sd;
+ do {
+ // accept incoming connections
+ new_sd = accept(listen_sd, nullptr, nullptr);
+ if (new_sd < 0) {
+ // if not EWOULDBLOCK -> all incomminng connections are accepted
+ if (errno != EWOULDBLOCK) {
+ log.error("accept() failed");
+ end_server = true;
+ }
+ break;
+ }
- log.info("New incoming connection - {}", new_sd);
+ log.info("New incoming connection - {}", new_sd);
- // add incoming connections to master read set
- FD_SET(new_sd, &master_set);
- if (new_sd > max_socket)
- {
- max_socket = new_sd;
- }
- } while (new_sd != -1);
+ // add incoming connections to master read set
+ FD_SET(new_sd, &master_set);
+ if (new_sd > max_socket) {
+ max_socket = new_sd;
+ }
+ } while (new_sd != -1);
}
void TCPSelectServer::receive_incoming_data(int fd)
{
- do
- {
- // receive data
- int receive_state = recv(fd, recv_buffer.data(), recv_buffer.size(), 0);
- if (receive_state < 0)
- {
- log.debug("receive state {}", receive_state);
- if (errno != EWOULDBLOCK)
- {
- log.error("recv() failed {}", errno);
- close_connection = true;
- }
- break;
- }
+ do {
+ // receive data
+ int receive_state = recv(fd, recv_buffer.data(), recv_buffer.size(), 0);
+ if (receive_state < 0) {
+ log.debug("receive state {}", receive_state);
+ if (errno != EWOULDBLOCK) {
+ log.error("recv() failed {}", errno);
+ close_connection = true;
+ }
+ break;
+ }
- // if 0, client closed connection
- if (receive_state == 0)
- {
- log.info("Connection closed");
- close_connection = true;
- break;
- }
+ // if 0, client closed connection
+ if (receive_state == 0) {
+ log.info("Connection closed");
+ close_connection = true;
+ break;
+ }
- int len = receive_state;
- log.info("{} bytes received", len);
+ int len = receive_state;
+ log.info("{} bytes received", len);
- std::size_t txSize = 0;
- frame_processor->processInputFrame(recv_buffer.data() + BASYX_FRAMESIZE_SIZE, len - BASYX_FRAMESIZE_SIZE, ret_buffer.data() + BASYX_FRAMESIZE_SIZE, &txSize);
- txSize += BASYX_FRAMESIZE_SIZE;
+ std::size_t txSize = 0;
- // answer client
- int send_state = send(fd, ret_buffer.data(), txSize, 0);
- if (send_state < 0)
- {
- log.error("send() failed");
- close_connection = true;
- break;
- }
- } while (true);
+
+
+
+
+ // ToDo: Use new frame handling
+ // frame_processor->processInputFrame(recv_buffer.data() + BASYX_FRAMESIZE_SIZE, len - BASYX_FRAMESIZE_SIZE, ret_buffer.data() + BASYX_FRAMESIZE_SIZE, &txSize);
+ // txSize += BASYX_FRAMESIZE_SIZE;
+
+ // answer client
+ int send_state = send(fd, ret_buffer.data(), txSize, 0);
+ if (send_state < 0) {
+ log.error("send() failed");
+ close_connection = true;
+ break;
+ }
+
+ } while (true);
}
}
diff --git a/sdks/c++/basys.sdk.cc/src/server/server/server.cpp b/sdks/c++/basys.sdk.cc/src/server/server/server.cpp
deleted file mode 100644
index e69de29..0000000
--- a/sdks/c++/basys.sdk.cc/src/server/server/server.cpp
+++ /dev/null
diff --git a/sdks/c++/basys.sdk.cc/src/shared/CMakeLists.txt b/sdks/c++/basys.sdk.cc/src/shared/CMakeLists.txt
index 4982767..98e2bc5 100644
--- a/sdks/c++/basys.sdk.cc/src/shared/CMakeLists.txt
+++ b/sdks/c++/basys.sdk.cc/src/shared/CMakeLists.txt
@@ -21,6 +21,7 @@
target_sources(${BASYX_SHARED_TARGET_NAME}
PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/shared/object/impl/obj_error.cpp
${CMAKE_CURRENT_SOURCE_DIR}/shared/object/impl/object_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/shared/serialization/json/typeid.cpp
)
@@ -36,6 +37,7 @@
${BASYX_SHARED_INCLUDE_DIR}/object/object_header.h
${BASYX_SHARED_INCLUDE_DIR}/object/object_type.h
${BASYX_SHARED_INCLUDE_DIR}/object/obj_function.h
+ ${BASYX_SHARED_INCLUDE_DIR}/object/obj_error.h
${BASYX_SHARED_INCLUDE_DIR}/object/obj_holder.h
${BASYX_SHARED_INCLUDE_DIR}/object/obj_placeholder.h
${BASYX_SHARED_INCLUDE_DIR}/object/obj_error_holder.h
diff --git a/sdks/c++/basys.sdk.cc/src/shared/shared/object/impl/obj_error.cpp b/sdks/c++/basys.sdk.cc/src/shared/shared/object/impl/obj_error.cpp
new file mode 100644
index 0000000..43b9ff0
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/src/shared/shared/object/impl/obj_error.cpp
@@ -0,0 +1,42 @@
+#include <BaSyx/shared/object/obj_error.h>
+
+#include <array>
+#include <algorithm>
+#include <memory>
+#include <string>
+
+using namespace basyx::detail;
+
+using enum_pair_t = std::pair<const char*, error>;
+
+static const std::array<enum_pair_t, 7> string_to_enum =
+{
+ std::make_pair("None", error::None),
+ std::make_pair("PropertyNotFound", error::PropertyNotFound),
+ std::make_pair("IndexOutOfBounds", error::IndexOutOfBounds),
+ std::make_pair("NotInvokable", error::NotInvokable),
+ std::make_pair("ObjectAlreadyExists", error::ObjectAlreadyExists),
+ std::make_pair("MalformedRequest", error::MalformedRequest),
+ std::make_pair("ProviderException", error::ProviderException),
+};
+
+error error_::from_string(const std::string & name)
+{
+ auto pair = std::find_if(string_to_enum.begin(), string_to_enum.end(),
+ [&name](const enum_pair_t & pair) {
+ return !name.compare(pair.first);
+ });
+
+ return pair->second;
+}
+
+const char * error_::to_string(error value)
+{
+ auto pair = std::find_if(string_to_enum.begin(), string_to_enum.end(),
+ [value](const enum_pair_t & pair) {
+ return value == pair.second;
+ });
+
+ return pair->first;
+}
+
diff --git a/sdks/c++/basys.sdk.cc/src/shared/shared/object/impl/object_impl.cpp b/sdks/c++/basys.sdk.cc/src/shared/shared/object/impl/object_impl.cpp
index 584ca15..257e74d 100644
--- a/sdks/c++/basys.sdk.cc/src/shared/shared/object/impl/object_impl.cpp
+++ b/sdks/c++/basys.sdk.cc/src/shared/shared/object/impl/object_impl.cpp
@@ -208,6 +208,9 @@
basyx::object::error basyx::object::getError() const
{
+ if (this->GetObjectType() != basyx::type::objectType::Error)
+ return basyx::object::error::None;
+
auto & errorHolder = dynamic_cast<basyx::detail::objErrorHolder&>(*this->content);
return errorHolder.error;
}
diff --git a/sdks/c++/basys.sdk.cc/src/vab/CMakeLists.txt b/sdks/c++/basys.sdk.cc/src/vab/CMakeLists.txt
index f3425fa..549a9e0 100644
--- a/sdks/c++/basys.sdk.cc/src/vab/CMakeLists.txt
+++ b/sdks/c++/basys.sdk.cc/src/vab/CMakeLists.txt
@@ -25,7 +25,8 @@
target_sources(${BASYX_VAB_LIB_SUFFIX}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/vab/backend/connector/native/BaSyxConnector.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/vab/backend/connector/native/frame/Frame.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/vab/backend/connector/native/frame/EntityWrapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vab/core/proxy/VABElementProxy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vab/core/util/VABPath.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vab/core/VABConnectionManager.cpp
@@ -40,7 +41,8 @@
${BASYX_VAB_INCLUDE_DIR}/backend/connector/IBaSyxConnector.h
${BASYX_VAB_INCLUDE_DIR}/backend/connector/JSONProvider.h
${BASYX_VAB_INCLUDE_DIR}/backend/connector/native/BaSyxConnector.h
- ${BASYX_VAB_INCLUDE_DIR}/backend/connector/native/frame/BaSyxNativeFrameBuilder.h
+ ${BASYX_VAB_INCLUDE_DIR}/backend/connector/native/frame/Frame.h
+ ${BASYX_VAB_INCLUDE_DIR}/backend/connector/native/frame/EntityWrapper.h
${BASYX_VAB_INCLUDE_DIR}/core/IModelProvider.h
${BASYX_VAB_INCLUDE_DIR}/core/proxy/IVABElementProxy.h
${BASYX_VAB_INCLUDE_DIR}/core/proxy/VABElementProxy.h
diff --git a/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/BaSyxConnector.cpp b/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/BaSyxConnector.cpp
index c5fdd01..8924014 100644
--- a/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/BaSyxConnector.cpp
+++ b/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/BaSyxConnector.cpp
@@ -6,7 +6,8 @@
*/
#include <BaSyx/vab/backend/connector/native/BaSyxConnector.h>
-#include <BaSyx/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.h>
+#include <BaSyx/vab/backend/connector/native/frame/Frame.h>
+#include <BaSyx/vab/backend/connector/native/frame/EntityWrapper.h>
#include <BaSyx/vab/provider/native/frame/BaSyxNativeFrameHelper.h>
#include <BaSyx/shared/serialization/json.h>
@@ -22,8 +23,7 @@
namespace native {
NativeConnector::NativeConnector(std::string const& address, int port)
- : builder{}
- , socket{ basyx::net::tcp::Socket::Connect(address, port) }
+ : socket{ basyx::net::tcp::Socket::Connect(address, port) }
, log{ "NativeConnector" }
{
log.trace("Connected to {}:{}", address, port);
@@ -32,7 +32,6 @@
NativeConnector::~NativeConnector() {
- this->socket.Close();
}
@@ -42,65 +41,69 @@
log.trace("basysGet() called:");
log.trace(" path: {}", path);
- auto entityWrapper = basysGetRaw(path);
- auto value = basyx::serialization::json::deserialize(entityWrapper["entity"]);
+ auto value = basysProcess(Frame::Builder::Get(path));
return value;
}
-nlohmann::json NativeConnector::basysGetRaw(std::string const& path) {
- size_t size = builder.buildGetFrame(path, buffer.data() + BASYX_FRAMESIZE_SIZE);
- sendData(buffer.data(), size);
- size = receiveData(buffer.data());
- if (buffer[4] != 0) { // Error happened
- return ""_json; // TODO: Error handling
- }
- std::string data = StringTools::fromArray(buffer.data() + BASYX_FRAMESIZE_SIZE + 1);
- return nlohmann::json::parse(data);
-}
+basyx::object NativeConnector::basysProcess(const Frame & frame)
+{
+ this->sendFrame(frame);
-void NativeConnector::basysSet(std::string const& path, const basyx::object & newValue)
+ auto response_frame = this->recvFrame();
+ if (response_frame.getFlag() != 0x00) {
+ return basyx::object::make_error(basyx::object::error::MalformedRequest, "invalid frame received");
+ };
+
+ auto entityWrapper = nlohmann::json::parse(response_frame.getFirstValue());
+
+ auto value = basyx::vab::EntityWrapper::from_json(entityWrapper);
+ return value;
+};
+
+basyx::object NativeConnector::basysSet(std::string const& path, const basyx::object & newValue)
{
log.trace("basysSet() called:");
log.trace(" path: {}", path);
- size_t size = builder.buildSetFrame(path, newValue, buffer.data() + BASYX_FRAMESIZE_SIZE);
- sendData(buffer.data(), size);
- size = receiveData(buffer.data());
+ auto return_code = basysProcess(Frame::Builder::Set(path, newValue));
+ return return_code;
}
-void NativeConnector::basysCreate(std::string const& path, const basyx::object & val)
+basyx::object NativeConnector::basysCreate(std::string const& path, const basyx::object & val)
{
- size_t size = builder.buildCreateFrame(path, val, buffer.data() + BASYX_FRAMESIZE_SIZE);
- sendData(buffer.data(), size);
- size = receiveData(buffer.data());
+ log.trace("basysCreate() called:");
+ log.trace(" path: {}", path);
+
+ auto return_code = basysProcess(Frame::Builder::Create(path, val));
+ return return_code;
}
basyx::object NativeConnector::basysInvoke(std::string const& path, const basyx::object & param)
{
- size_t size = builder.buildInvokeFrame(path, param, buffer.data() + BASYX_FRAMESIZE_SIZE);
- sendData(buffer.data(), size);
- size = receiveData(buffer.data());
- return decode(buffer.data() + 5);
+ log.trace("basysInvoke() called:");
+ log.trace(" path: {}", path);
+
+ auto return_code = basysProcess(Frame::Builder::Invoke(path, param));
+ return return_code;
}
-void NativeConnector::basysDelete(std::string const& path)
+basyx::object NativeConnector::basysDelete(std::string const& path)
{
- size_t size = builder.buildDeleteFrame(path, buffer.data() + BASYX_FRAMESIZE_SIZE);
- sendData(buffer.data(), size);
- size = receiveData(buffer.data());
+ log.trace("basysDelete() called:");
+ log.trace(" path: {}", path);
+
+ auto return_code = basysProcess(Frame::Builder::Delete(path));
+ return return_code;
}
-void NativeConnector::basysDelete(std::string const& path, const basyx::object & obj) {
- size_t size = builder.buildDeleteFrame(path, obj, buffer.data() + BASYX_FRAMESIZE_SIZE);
- sendData(buffer.data(), size);
- size = receiveData(buffer.data());
-}
+basyx::object NativeConnector::basysDelete(std::string const& path, const basyx::object & obj)
+{
+ log.trace("basysDelete() called:");
+ log.trace(" path: {}", path);
-// TODO: Error handling
-/**
- * Builds a send frame and sends it to server
- * @param msg a frame constructed with the BaSyxNativeFrameBuilder
- */
+ auto return_code = basysProcess(Frame::Builder::Delete(path, obj));
+ return return_code;
+}
void NativeConnector::sendData(char* msg, size_t size)
{
@@ -110,10 +113,6 @@
CoderTools::setInt32(msg, 0, size);
size += BASYX_FRAMESIZE_SIZE;
-#ifdef PRINT_FRAME
- log.debug("Sending:");
- vab::provider::native::frame::BaSyxNativeFrameHelper::printFrame(msg, size);
-#endif
log.debug("Sending {} bytes.", size);
int sent_bytes = this->socket.Send(basyx::net::make_buffer(msg, size));
@@ -125,7 +124,8 @@
}
// TODO: Error handling
-size_t NativeConnector::receiveData(char* data) {
+size_t NativeConnector::receiveData(char* data)
+{
log.trace("receiveData() called");
log.trace(" data: 0x{0:x}", (std::size_t)data);
@@ -135,10 +135,6 @@
log.debug("Received {} bytes.", recv_bytes);
if (recv_bytes > 0) {
-#ifdef PRINT_FRAME
- log.debug("Received:");
- vab::provider::native::frame::BaSyxNativeFrameHelper::printFrame(data, recv_bytes);
-#endif
return recv_bytes;
}
else {
@@ -147,10 +143,23 @@
}
}
-basyx::object NativeConnector::decode(char* buffer)
+void NativeConnector::sendFrame(const Frame & frame)
{
- std::string data = StringTools::fromArray(buffer);
- return basyx::serialization::json::deserialize(data).Get<basyx::object::object_map_t&>()["entity"];
+ Frame::write_to_buffer(
+ basyx::net::make_buffer(
+ buffer.data() + BASYX_FRAMESIZE_SIZE, default_buffer_length - BASYX_FRAMESIZE_SIZE),
+ frame);
+
+ sendData(buffer.data(), frame.size());
+};
+
+Frame NativeConnector::recvFrame()
+{
+ this->receiveData(buffer.data());
+ auto size = *reinterpret_cast<uint32_t*>(buffer.data());
+ auto frame = Frame::read_from_buffer(basyx::net::make_buffer(this->buffer.data() + BASYX_FRAMESIZE_SIZE, size));
+
+ return frame;
};
}
diff --git a/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.cpp b/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.cpp
deleted file mode 100644
index 34987eb..0000000
--- a/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * BaSyxNativeFrameBuilder.cpp
- *
- * Created on: 14.08.2018
- * Author: schnicke
- */
-
-#include <BaSyx/vab/backend/connector/native/frame/BaSyxNativeFrameBuilder.h>
-
-#include <BaSyx/shared/serialization/json.h>
-
-#include <BaSyx/util/tools/StringTools.h>
-
-namespace basyx {
-namespace vab {
-namespace connector {
-namespace native {
-namespace frame {
-
-
-BaSyxNativeFrameBuilder::BaSyxNativeFrameBuilder() { };
-
-size_t BaSyxNativeFrameBuilder::buildGetFrame(std::string const& path, char * buffer)
-{
- return encodeCommandAndPath(BaSyxCommand::Get, path, buffer);
-}
-
-size_t BaSyxNativeFrameBuilder::buildSetFrame(std::string const& path, const basyx::object & newVal, char * buffer)
-{
- size_t size = encodeCommandAndPath(BaSyxCommand::Set, path, buffer);
- size += encodeValue(newVal, buffer + size);
- return size;
-}
-
-size_t BaSyxNativeFrameBuilder::buildCreateFrame(std::string const& path, const basyx::object & newVal, char * buffer)
-{
- size_t size = encodeCommandAndPath(BaSyxCommand::Create, path, buffer);
- size += encodeValue(newVal, buffer + size);
- return size;
-}
-
-size_t BaSyxNativeFrameBuilder::buildDeleteFrame(std::string const& path, char * buffer)
-{
- return encodeCommandAndPath(BaSyxCommand::Delete, path, buffer);
-}
-
-size_t BaSyxNativeFrameBuilder::buildDeleteFrame(std::string const& path, const basyx::object & deleteVal, char * buffer)
-{
- size_t size = encodeCommandAndPath(BaSyxCommand::Delete, path, buffer);
- size += encodeValue(deleteVal, buffer + size);
- return size;
-}
-
-size_t BaSyxNativeFrameBuilder::buildInvokeFrame(std::string const& path, const basyx::object & param, char * buffer)
-{
- size_t size = encodeCommandAndPath(BaSyxCommand::Invoke, path, buffer);
- size += encodeValue(param, buffer + size);
- return size;
-}
-
-size_t BaSyxNativeFrameBuilder::buildInvokeFrame(std::string const& path, const basyx::object::object_list_t & params, char * buffer)
-{
- size_t size = encodeCommandAndPath(BaSyxCommand::Invoke, path, buffer);
- size += encodeValue(params, buffer + size);
- return size;
-}
-
-size_t BaSyxNativeFrameBuilder::encodeCommand(BaSyxCommand command, char* buffer)
-{
- buffer[0] = static_cast<uint8_t>(command);
- return 1;
-}
-
-std::size_t BaSyxNativeFrameBuilder::encodeValue(const basyx::object & value, char * buffer)
-{
- std::string dumped = basyx::serialization::json::serialize(value).dump(4);
- return StringTools::toArray(dumped, buffer);
-}
-
-size_t BaSyxNativeFrameBuilder::encodeCommandAndPath(BaSyxCommand command, std::string const& path, char* buffer)
-{
- size_t size = encodeCommand(command, buffer);
- size += StringTools::toArray(path, buffer + size);
- return size;
-}
-
-}
-}
-}
-}
-}
diff --git a/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/EntityWrapper.cpp b/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/EntityWrapper.cpp
new file mode 100644
index 0000000..37c2989
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/EntityWrapper.cpp
@@ -0,0 +1,112 @@
+#include <BaSyx/vab/backend/connector/native/frame/EntityWrapper.h>
+
+using basyx::vab::EntityWrapper;
+
+
+namespace {
+ std::string prepareErrorCode(basyx::object::error errorCode)
+ {
+ std::string error;
+ switch (errorCode)
+ {
+ case basyx::object::error::PropertyNotFound:
+ error = "ResourceNotFoundException";
+ break;
+ case basyx::object::error::ObjectAlreadyExists:
+ error = "ResourceAlreadyExistsException";
+ break;
+ case basyx::object::error::MalformedRequest:
+ error = "MalformedRequestException";
+ break;
+ default:
+ error = "ProviderException";
+ break;
+ };
+ return error;
+ };
+
+ std::string prepareErrorMessage(basyx::object::error errorCode, const std::string & message)
+ {
+ return prepareErrorCode(errorCode) + ": " + message;
+ };
+}
+
+basyx::object build_exception(const std::string & type, const std::string & message)
+{
+ basyx::object::error error = basyx::object::error::ProviderException;
+
+ if (type == "ResourceNotFoundException")
+ {
+ error = basyx::object::error::PropertyNotFound;
+ }
+ else if (type == "ResourceAlreadyExistsException")
+ {
+ error = basyx::object::error::ObjectAlreadyExists;
+ }
+ else if (type == "MalformedRequestException")
+ {
+ error = basyx::object::error::MalformedRequest;
+ }
+ else if (type == "ProviderException")
+ {
+ error = basyx::object::error::ProviderException;
+ };
+
+ return basyx::object::make_error(error, message);
+};
+
+basyx::json_t EntityWrapper::build_from_error(basyx::object::error error, const std::string & message)
+{
+ json_t msg;
+ msg["messageType"] = 6;
+ msg["text"] = prepareErrorMessage(error, message);
+ msg["code"] = nullptr;
+
+ basyx::json_t j_obj;
+ j_obj["success"] = false;
+ j_obj["isException"] = true;
+ j_obj["messages"] = json_t::array({ msg });
+ j_obj["entityType"] = prepareErrorCode(error);
+ return j_obj;
+};
+
+basyx::json_t EntityWrapper::build_from_object(const basyx::object & object)
+{
+ basyx::json_t j_obj;
+ if (object.IsError())
+ {
+ return build_from_error(object.getError(), object.getErrorMessage());
+ }
+ else
+ {
+ j_obj["success"] = true;
+// j_obj["isException"] = false;
+ j_obj["entityType"] = "entity";
+ j_obj["entity"] = basyx::serialization::json::serialize(object);
+ }
+ return j_obj;
+};
+
+
+basyx::object EntityWrapper::from_json(const basyx::json_t & json)
+{
+ bool success = json["success"];
+ // everyhing okay, deserialize entity
+ if (success)
+ {
+ if (json.contains("entity"))
+ return basyx::serialization::json::deserialize(json["entity"]);
+ else
+ return basyx::object::make_null();
+ }
+ // something went wrong, check for exception
+ else if (json.contains("isException") && json.contains("messages"))
+ {
+ return build_exception(json["entityType"], json["messages"][0]["text"]);
+ }
+ // error and no exception; create one
+ else
+ {
+ return basyx::object::make_error(basyx::object::error::MalformedRequest);
+ };
+};
\ No newline at end of file
diff --git a/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/Frame.cpp b/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/Frame.cpp
new file mode 100644
index 0000000..9d7a649
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/src/vab/vab/backend/connector/native/frame/Frame.cpp
@@ -0,0 +1,166 @@
+#include <BaSyx/vab/backend/connector/native/frame/Frame.h>
+
+#include <BaSyx/util/tools/StringTools.h>
+
+using namespace basyx::vab::connector::native;
+
+Frame::Frame()
+ : flag(0xFF)
+ , value_1()
+ , value_2()
+{
+};
+
+Frame::Frame(uint8_t flag, const std::string & value_1)
+ : flag(flag)
+ , value_1(value_1)
+ , value_2()
+{
+};
+
+Frame::Frame(uint8_t flag, const std::string & value_1, const std::string & value_2)
+ : flag(flag)
+ , value_1(value_1)
+ , value_2(value_2)
+{
+};
+
+uint8_t Frame::getFlag() const
+{
+ return this->flag;
+};
+
+void Frame::setFlag(uint8_t flag)
+{
+ this->flag = flag;
+};
+
+void Frame::setFlag(BaSyxCommand flag)
+{
+ this->flag = static_cast<decltype(this->flag)>(flag);
+};
+
+const std::string & Frame::getFirstValue() const
+{
+ return this->value_1;
+};
+
+void Frame::setFirstValue(const std::string & value)
+{
+ this->value_1 = value;
+};
+
+const std::string & Frame::getSecondValue() const
+{
+ return this->value_2;
+};
+
+void Frame::setSecondValue(const std::string & value)
+{
+ this->value_2 = value;
+};
+
+bool Frame::write_to_buffer(const basyx::net::Buffer & buffer, const Frame & frame)
+{
+ // bail out if buffer to small
+ if (frame.size() > buffer.size())
+ return false;
+
+ std::size_t pos = 0;
+ char * data = reinterpret_cast<char*>(buffer.data());
+
+ // write command field
+ data[pos] = static_cast<uint8_t>(frame.getFlag());
+ pos += 1;
+
+ // write first value field
+ pos += StringTools::toArray(frame.getFirstValue(), &data[pos]);
+
+ // write second value field
+ if (!frame.getSecondValue().empty())
+ {
+ pos += StringTools::toArray(frame.getSecondValue(), &data[pos]);
+ };
+
+ return true;
+};
+
+Frame Frame::read_from_buffer(const basyx::net::Buffer & buffer)
+{
+ Frame frame;
+
+ std::size_t pos = 0;
+ char * data = reinterpret_cast<char*>(buffer.data());
+
+ uint8_t flag = static_cast<uint8_t>(data[pos]);
+ frame.setFlag(flag);
+ pos += 1;
+
+ frame.setFirstValue(StringTools::fromArray(&data[pos]));
+ pos += frame.getFirstValue().size() + sizeof(uint32_t);
+
+ if (pos < buffer.size())
+ {
+ frame.setSecondValue(StringTools::fromArray(&data[pos]));
+ pos += frame.getSecondValue().size() + sizeof(uint32_t);
+ };
+
+ return frame;
+};
+
+std::size_t Frame::size() const
+{
+ std::size_t size = 1; // size of flag field
+ size += sizeof(uint32_t) + this->getFirstValue().size(); // size of first value + length
+
+ if(!this->getSecondValue().empty())
+ size += sizeof(uint32_t) + this->getSecondValue().size(); // size of second value + length
+
+ return size;
+};
+
+Frame Frame::Builder::Get(const std::string & path)
+{
+ return Frame{ static_cast<uint8_t>(BaSyxCommand::Get), path };
+};
+
+Frame Frame::Builder::Set(const std::string & path, const basyx::object & value)
+{
+ return Frame{
+ static_cast<uint8_t>(BaSyxCommand::Set),
+ path,
+ basyx::serialization::json::serialize(value).dump(4)
+ };
+};
+
+Frame Frame::Builder::Create(const std::string & path, const basyx::object & value)
+{
+ return Frame{
+ static_cast<uint8_t>(BaSyxCommand::Create),
+ path,
+ basyx::serialization::json::serialize(value).dump(4)
+ };
+};
+
+Frame Frame::Builder::Delete(const std::string & path)
+{
+ return Frame{ static_cast<uint8_t>(BaSyxCommand::Delete), path };
+};
+
+Frame Frame::Builder::Delete(const std::string & path, const basyx::object & value)
+{
+ return Frame{
+ static_cast<uint8_t>(BaSyxCommand::Delete),
+ path,
+ basyx::serialization::json::serialize(value).dump(4)
+ };
+};
+
+Frame Frame::Builder::Invoke(const std::string & path, const basyx::object & value)
+{
+ return Frame{
+ static_cast<uint8_t>(BaSyxCommand::Invoke),
+ path,
+ basyx::serialization::json::serialize(value).dump(4)
+ };
+};
\ No newline at end of file
diff --git a/sdks/c++/basys.sdk.cc/src/vab/vab/provider/VABModelProvider.cpp b/sdks/c++/basys.sdk.cc/src/vab/vab/provider/VABModelProvider.cpp
index b63c498..10b2a67 100644
--- a/sdks/c++/basys.sdk.cc/src/vab/vab/provider/VABModelProvider.cpp
+++ b/sdks/c++/basys.sdk.cc/src/vab/vab/provider/VABModelProvider.cpp
@@ -87,11 +87,12 @@
// Only write values, that already exist
auto thisElement = parentElement.getProperty(propertyName);
- if (!parentElement.IsNull() && !thisElement.IsNull()) {
+ if (!parentElement.IsNull()/* && !thisElement.IsNull()*/) {
parentElement.insertKey(propertyName, newValue, true);
+ return basyx::object::error::None;
}
- return basyx::object::error::None;
+ return basyx::object::error::PropertyNotFound;
};
basyx::object::error VABModelProvider::createValue(const std::string& path, const basyx::object newValue)
@@ -163,10 +164,11 @@
if (!childElement.IsNull()) {
//handler.DeleteValue(childElement, deletedValue);
childElement.remove(deletedValue);
+ return basyx::object::error::None;
}
}
- return basyx::object::error::None;
+ return basyx::object::error::PropertyNotFound;
};
basyx::object::error VABModelProvider::deleteValue(const std::string& path)
@@ -200,14 +202,14 @@
log.error("Function not found!");
log.trace("Returning basyx::object::null");
- return basyx::object{ nullptr };
+ return basyx::object::make_error(basyx::object::error::PropertyNotFound, "method not found");
}
if (!element.IsInvokable()) {
log.error("Found object is not invokable!");
log.trace("Returning basyx::object::null");
- return basyx::object{ nullptr };
+ return basyx::object::make_error(basyx::object::error::ProviderException, "method not invokable");
};
log.trace("Function found. Invoking...");
diff --git a/sdks/c++/basys.sdk.cc/src/vab/vab/provider/native/frame/BaSyxNativeFrameProcessor.cpp b/sdks/c++/basys.sdk.cc/src/vab/vab/provider/native/frame/BaSyxNativeFrameProcessor.cpp
index 805dda6..9667497 100644
--- a/sdks/c++/basys.sdk.cc/src/vab/vab/provider/native/frame/BaSyxNativeFrameProcessor.cpp
+++ b/sdks/c++/basys.sdk.cc/src/vab/vab/provider/native/frame/BaSyxNativeFrameProcessor.cpp
@@ -13,159 +13,96 @@
#include <BaSyx/util/tools/StringTools.h>
#include <BaSyx/shared/types.h>
-
+
namespace basyx {
namespace vab {
namespace provider {
namespace native {
namespace frame {
+using connector::native::Frame;
+
+
BaSyxNativeFrameProcessor::BaSyxNativeFrameProcessor(vab::core::IModelProvider* providerBackend)
: jsonProvider{ providerBackend}
{
}
-BaSyxNativeFrameProcessor::~BaSyxNativeFrameProcessor()
+Frame BaSyxNativeFrameProcessor::processInputFrame(const Frame & frame)
{
-}
+ auto command = static_cast<BaSyxCommand>(frame.getFlag());
-void BaSyxNativeFrameProcessor::processInputFrame(char const* rxFrame, std::size_t rxSize, char* txFrame, std::size_t* txSize)
-{
- std::size_t offset;
- auto command = vab::provider::native::frame::BaSyxNativeFrameHelper::getCommand(rxFrame, &offset);
- rxFrame += offset;
- switch (command) {
+ switch (command)
+ {
case BaSyxCommand::Get:
- processGet(rxFrame, txFrame, txSize);
- break;
+ return processGet(frame);
case BaSyxCommand::Set:
- processSet(rxFrame, txFrame, txSize);
- break;
+ return processSet(frame);
case BaSyxCommand::Create:
- processCreate(rxFrame, txFrame, txSize);
- break;
+ return processCreate(frame);
case BaSyxCommand::Delete:
- processDelete(rxFrame, rxSize - offset, txFrame, txSize);
- break;
+ return processDelete(frame);
case BaSyxCommand::Invoke:
- processInvoke(rxFrame, txFrame, txSize);
- break;
-
- }
-}
-
-void BaSyxNativeFrameProcessor::processGet(char const* rxFrame, char* txFrame, std::size_t* txSize)
-{
- // Try to get the requested value
- // TODO: Error Handling?
-
- std::string path = BaSyxNativeFrameHelper::getString(rxFrame, 0);
- // Advance txFrame by 5 because of the following setup of txFrame:
- // 1 byte result field
- // 4 byte string size
- // N byte return value
- std::string getResult = jsonProvider.processBaSysGet(path);
- *txSize += getResult.size();
- memcpy(txFrame + 5, getResult.c_str(), getResult.size());
-
- // Set return string size
- CoderTools::setInt32(txFrame + 1, 0, *txSize);
- *txSize += BASYX_STRINGSIZE_SIZE;
-
- // Set result field to 0 to indicate success
- txFrame[0] = 0;
- *txSize += 1;
-}
-
-void BaSyxNativeFrameProcessor::processSet(char const* rxFrame, char* txFrame, std::size_t* txSize)
-{
- std::string path = BaSyxNativeFrameHelper::getString(rxFrame, 0);
-
- // TODO: Error Handling?
- std::string serializedValue = BaSyxNativeFrameHelper::getString(rxFrame, 1);
- std::string getResult = jsonProvider.processBaSysSet(path, serializedValue);
- memcpy(txFrame + 5, getResult.c_str(), getResult.size());
-
- // Set return string size
- CoderTools::setInt32(txFrame + 1, 0, *txSize);
- *txSize += BASYX_STRINGSIZE_SIZE;
-
- // Set result field to 0 to indicate success
- txFrame[0] = 0;
- *txSize += 1;
-}
-
-void BaSyxNativeFrameProcessor::processCreate(char const* rxFrame, char* txFrame, std::size_t* txSize)
-{
- std::string path = BaSyxNativeFrameHelper::getString(rxFrame, 0);
-
- // TODO: Error Handling?
- std::string serializedValue = BaSyxNativeFrameHelper::getString(rxFrame, 1);
-
- std::string getResult = jsonProvider.processBaSysCreate(path, serializedValue);
- memcpy(txFrame + 5, getResult.c_str(), getResult.size());
-
- // Set return string size
- CoderTools::setInt32(txFrame + 1, 0, *txSize);
- *txSize += BASYX_STRINGSIZE_SIZE;
-
- // Set result field to 0 to indicate success
- txFrame[0] = 0;
- *txSize += 1;
-}
-
-void BaSyxNativeFrameProcessor::processDelete(char const* rxFrame, std::size_t rxSize, char* txFrame, std::size_t* txSize)
-{
- std::string path = BaSyxNativeFrameHelper::getString(rxFrame, 0);
-
- std::string result;
-
- // Check if there is a serialized json after the path to distinguish between map/collection delete and simple delete
- if (path.size() + BASYX_STRINGSIZE_SIZE < rxSize) {
- std::string serializedValue = BaSyxNativeFrameHelper::getString(rxFrame,
- 1);
- result = jsonProvider.processBaSysDelete(path, serializedValue);
- } else {
- result = jsonProvider.processBaSysDelete(path);
+ return processInvoke(frame);
}
- memcpy(txFrame + 5, result.c_str(), result.size());
-
- // Set return string size
- CoderTools::setInt32(txFrame + 1, 0, *txSize);
- *txSize += BASYX_STRINGSIZE_SIZE;
-
- // Set result field to 0 to indicate success
- txFrame[0] = 0;
- *txSize += 1;
+ return Frame{};
}
-void BaSyxNativeFrameProcessor::processInvoke(char const* rxFrame, char* txFrame, std::size_t* txSize)
+Frame BaSyxNativeFrameProcessor::processGet(const Frame & frame)
{
- std::string path = BaSyxNativeFrameHelper::getString(rxFrame, 0);
+ auto path = frame.getFirstValue();
+ auto getResult = jsonProvider.processBaSysGet(path);
- // TODO: Error Handling?
- std::string serializedValue = BaSyxNativeFrameHelper::getString(rxFrame, 1);
-
- // Advance txFrame by 5 because of the following setup of txFrame:
- // 1 byte result field
- // 4 byte string size
- // N byte return value
- auto result = jsonProvider.processBaSysInvoke(path, serializedValue, txFrame + 5,
- txSize);
-
- *txSize = result.size();
- memcpy(txFrame + 5, result.c_str(), result.size());
-
- // Set return value size
- CoderTools::setInt32(txFrame + 1, 0, *txSize);
- *txSize += BASYX_STRINGSIZE_SIZE;
-
- // Set result field to 0 to indicate success
- txFrame[0] = 0;
- *txSize += 1;
+ return Frame{ 0x00, getResult };
}
+Frame BaSyxNativeFrameProcessor::processSet(const Frame & frame)
+{
+ auto path = frame.getFirstValue();
+ auto value = frame.getSecondValue();
+
+ auto result = jsonProvider.processBaSysSet(path, value);
+
+ return Frame{ 0x00, result };
+};
+
+Frame BaSyxNativeFrameProcessor::processCreate(const Frame & frame)
+{
+ auto path = frame.getFirstValue();
+ auto value = frame.getSecondValue();
+
+ auto result = jsonProvider.processBaSysCreate(path, value);
+
+ return Frame{ 0x00, result };
+};
+
+Frame BaSyxNativeFrameProcessor::processDelete(const Frame & frame)
+{
+ auto path = frame.getFirstValue();
+ auto value = frame.getSecondValue();
+
+ // if no value specified, simple delete
+ if (value.empty())
+ {
+ auto result = jsonProvider.processBaSysDelete(path);
+ return Frame{ 0x00, result };
+ };
+
+ auto result = jsonProvider.processBaSysDelete(path, value);
+ return Frame{ 0x00, result };
+};
+
+Frame BaSyxNativeFrameProcessor::processInvoke(const Frame & frame)
+{
+ auto path = frame.getFirstValue();
+ auto value = frame.getSecondValue();
+
+ auto result = jsonProvider.processBaSysInvoke(path, value);
+
+ return Frame{ 0x00, result };
+};
+
}
}
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/CMakeLists.txt b/sdks/c++/basys.sdk.cc/tests/regression/vab/CMakeLists.txt
index a4d7665..52e4d42 100644
--- a/sdks/c++/basys.sdk.cc/tests/regression/vab/CMakeLists.txt
+++ b/sdks/c++/basys.sdk.cc/tests/regression/vab/CMakeLists.txt
@@ -9,10 +9,10 @@
target_sources(tests_vab
PRIVATE
- connector/basyx/frame/test_BaSyxNativeFrameBuilder.cpp
- connector/Test_VABBasyxTCP.cpp
core/proxy/test_vab_elementproxy.cpp
provider/basyx/frame/test_BaSyxNativeFrameProcessor.cpp
+ provider/basyx/frame/test_BaSyxNativeFrame.cpp
+ provider/basyx/test_BaSyxNative.cpp
provider/test_hashmap.cpp
provider/test_hashmap_collection.cpp
provider/test_hashmap_map.cpp
@@ -25,10 +25,6 @@
support/MockupModelProvider.h
)
-if (UNIX)
- target_sources(tests_vab PRIVATE server/test_TCPSelectServer.cpp )
-endif (UNIX)
-
target_include_directories(tests_vab PUBLIC ${PROJECT_SOURCE_DIR})
target_link_libraries(tests_vab basyx::util basyx::vab basyx::shared lib::gtest tests::support tests::main basyx::server)
gtest_discover_tests(tests_vab)
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/connector/Test_VABBasyxTCP.cpp b/sdks/c++/basys.sdk.cc/tests/regression/vab/connector/Test_VABBasyxTCP.cpp
deleted file mode 100644
index 1a52a88..0000000
--- a/sdks/c++/basys.sdk.cc/tests/regression/vab/connector/Test_VABBasyxTCP.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * test_BaSyxNative.cpp
- * Tests the whole loop of BaSyxNativeConnector -> BaSyxNativeProvider
- * Created on: 15.08.2018
- * Author: schnicke
- */
-
-#ifdef tsktsktsk
-
-
-#include <atomic>
-#include <memory>
-
-#include <BaSyx/abstraction/Thread.h>
-
-#include <gtest/gtest.h>
-
-#include <BaSyx/shared/basyx/function.h>
-
-#include <BaSyx/vab/backend/connector/native/BaSyxConnector.h>
-#include <BaSyx/vab/provider/native/BaSyxTCPServer.h>
-
-#include "support/MockupModelProvider.h"
-
-
-using namespace basyx;
-
-std::atomic_flag running = ATOMIC_FLAG_INIT;
-
-void serverLoop(std::unique_ptr<vab::provider::native::TCPServer<MockupModelProvider>> & tcpServer)
-{
- while (running.test_and_set(std::memory_order_acquire))
- {
- tcpServer->update();
- }
-};
-
-/**
- * Creates the test environment needed in the following tests:
- * - Provides BaSyxTCPServer
- * - Provides BaSyxNativeConnector
- */
-class BaSyxNativeTest: public ::testing::Test {
-protected:
- const int port = 6114;
-
- std::unique_ptr<vab::connector::native::NativeConnector> connector;
- std::unique_ptr<vab::provider::native::TCPServer<MockupModelProvider>> tcpServer;
- std::unique_ptr<MockupModelProvider> mockup;
- basyx::thread serverThread{};
-
- virtual void SetUp() {
- running.test_and_set(std::memory_order_acquire);
-
- mockup = util::make_unique<MockupModelProvider>();
- tcpServer = util::make_unique<vab::provider::native::TCPServer<MockupModelProvider>>(mockup.get(), port);
-
- serverThread = basyx::thread{serverLoop, std::ref(tcpServer)};
-
- connector = util::make_unique<vab::connector::native::NativeConnector>("127.0.0.1", port);
- }
-
- virtual void TearDown() {
- running.clear(std::memory_order_release);
-
- tcpServer->Close();
-
- serverThread.join();
- }
-
-};
-
-TEST_F(BaSyxNativeTest, getTest) {
- std::string path = "TestPath";
- basyx::object val = connector->basysGet(path);
-
- // Check if correct call occured
- ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::GET);
- ASSERT_EQ(mockup->path, path);
-
- // Check return value
- ASSERT_TRUE(val.InstanceOf<int>());
- ASSERT_EQ(val.Get<int>(), 2);
-}
-
-TEST_F(BaSyxNativeTest, setTest) {
- std::string path = "TestPath";
- basyx::object val = 10;
- connector->basysSet(path, val);
-
- while (mockup->called != MockupModelProvider::CalledFunction::SET)
- ;
-
- // Check if correct call occured
- ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::SET);
- ASSERT_EQ(mockup->path, path);
-}
-
-TEST_F(BaSyxNativeTest, createTest) {
- std::string path = "TestPath";
- basyx::object val = 10;
- connector->basysCreate(path, val);
-
- // Check if correct call occured
- ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::CREATE);
- ASSERT_EQ(mockup->path, path);
- ASSERT_TRUE(mockup->val.InstanceOf<int>());
- ASSERT_EQ(mockup->val.Get<int>(), 10);
-}
-
-TEST_F(BaSyxNativeTest, deleteSimpleTest) {
- std::string path = "TestPath";
- connector->basysDelete(path);
-
- // Check if correct call occured
- ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::DELETE_SIMPLE);
- ASSERT_EQ(mockup->path, path);
-}
-
-TEST_F(BaSyxNativeTest, deleteComplexTest) {
- std::string path = "TestPath";
- basyx::object val = 10;
- connector->basysDelete(path, val);
-
- // Check if correct call occured
- ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::DELETE_COMPLEX);
- ASSERT_EQ(mockup->path, path);
- ASSERT_TRUE(mockup->val.InstanceOf<int>());
- ASSERT_EQ(mockup->val.Get<int>(), 10);
-}
-
-int invokeTestFunc(int a, int b)
-{
- return a + b;
-}
-
-
-// TODO: invokeTest
-TEST_F(BaSyxNativeTest, invokeTest) {
- std::string path = "TestPath";
- basyx::object val = 10;
- basyx::object retVal = connector->basysInvoke(path, val);
-
- // Check if correct call occured
- ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::INVOKE);
- ASSERT_EQ(mockup->path, path);
- ASSERT_TRUE(mockup->val.InstanceOf<basyx::object::list_t<int>>());
- ASSERT_EQ(mockup->val.Get<basyx::object::list_t<int>&>().size(), 1);
-
- auto & calledArgs = mockup->val.Get<basyx::object::list_t<int>&>();
-
- ASSERT_TRUE(calledArgs.front().InstanceOf<int>());
- ASSERT_EQ(calledArgs.front().Get<int>(), 10);
-
- //// Check return value
- ASSERT_TRUE(retVal.InstanceOf<int>());
- ASSERT_EQ(retVal.Get<int>(), 3);
-}
-
-
-#endif
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/frame/test_BaSyxNativeFrame.cpp b/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/frame/test_BaSyxNativeFrame.cpp
new file mode 100644
index 0000000..df6692d
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/frame/test_BaSyxNativeFrame.cpp
@@ -0,0 +1,60 @@
+#include <gtest/gtest.h>
+
+#include <BaSyx/shared/types.h>
+
+#include <BaSyx/vab/backend/connector/native/frame/Frame.h>
+
+using namespace basyx::vab::connector::native;
+
+TEST(BaSyxNativeFrame, frameTestNoValue)
+{
+ Frame frame;
+ frame.setFlag(static_cast<uint8_t>(BaSyxCommand::Get));
+ frame.setFirstValue("/test/path");
+
+ char buffer[4096];
+ memset(buffer, 0, 4096);
+
+ Frame::write_to_buffer(basyx::net::make_buffer(buffer, 4096), frame);
+ auto frame_b = Frame::read_from_buffer(basyx::net::make_buffer(buffer, 4096));
+
+ ASSERT_EQ(buffer[frame.size()], 0x0);
+
+ ASSERT_EQ(frame_b.getFlag(), frame.getFlag());
+ ASSERT_EQ(frame_b.getFirstValue(), frame.getFirstValue());
+ ASSERT_EQ(frame_b.getSecondValue(), frame.getSecondValue());
+}
+
+TEST(BaSyxNativeFrame, frameTestWithValue)
+{
+ Frame frame;
+ frame.setFlag(BaSyxCommand::Set);
+ frame.setFirstValue("/test/path");
+ frame.setSecondValue("{testValue}");
+
+ char buffer[4096];
+ memset(buffer, 0, 4096);
+
+ Frame::write_to_buffer(basyx::net::make_buffer(buffer, 4096), frame);
+ auto frame_b = Frame::read_from_buffer(basyx::net::make_buffer(buffer, 4096));
+
+ ASSERT_EQ(buffer[frame.size()], 0x0);
+
+ ASSERT_EQ(frame_b.getFlag(), frame.getFlag());
+ ASSERT_EQ(frame_b.getFirstValue(), frame.getFirstValue());
+ ASSERT_EQ(frame_b.getSecondValue(), frame.getSecondValue());
+}
+
+TEST(BaSyxNativeFrame, bufferTooSmall)
+{
+ Frame frame;
+ frame.setFlag(BaSyxCommand::Set);
+ frame.setFirstValue("/test/path");
+ frame.setSecondValue("{testValue}");
+
+ char buffer[4096];
+ memset(buffer, 0, 4096);
+
+ auto result = Frame::write_to_buffer(basyx::net::make_buffer(buffer, 10), frame);
+ ASSERT_FALSE(result);
+}
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/frame/test_BaSyxNativeFrameProcessor.cpp b/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/frame/test_BaSyxNativeFrameProcessor.cpp
index 1d6b60c..b4c123c 100644
--- a/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/frame/test_BaSyxNativeFrameProcessor.cpp
+++ b/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/frame/test_BaSyxNativeFrameProcessor.cpp
@@ -20,25 +20,20 @@
#include "support/MockupModelProvider.h"
using namespace basyx;
+using Frame = basyx::vab::connector::native::Frame;
TEST(BaSyxNativeFrameProcessor, getTest) {
auto mockup = util::make_unique<MockupModelProvider>();
vab::provider::native::frame::BaSyxNativeFrameProcessor provider(mockup.get());
- char frame[] = { static_cast<uint8_t>(BaSyxCommand::Get), 4, 0, 0, 0, 't', 'e', 's', 't' };
-
- std::unique_ptr<char> receive(new char[1000]);
-
- size_t txSize = 0;
-
- provider.processInputFrame(frame, sizeof frame, receive.get(), &txSize);
+ auto inputFrame = Frame::Builder::Get("test");
+ auto answerFrame = provider.processInputFrame(inputFrame);
ASSERT_EQ(mockup->path, "test");
ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::GET);
- ASSERT_EQ(receive.get()[0], (char ) 0);
-
- std::string serialized = StringTools::fromArray(receive.get() + 1);
- basyx::object deserialzed = basyx::serialization::json::deserialize(serialized);
+ ASSERT_EQ(answerFrame.getFlag(), 0);
+
+ basyx::object deserialzed = basyx::serialization::json::deserialize(answerFrame.getFirstValue());
ASSERT_TRUE(deserialzed.InstanceOf<basyx::object::object_map_t>());
auto & entityWrapper = deserialzed.Get<basyx::object::object_map_t&>();
@@ -54,30 +49,12 @@
auto mockup = util::make_unique<MockupModelProvider>();
vab::provider::native::frame::BaSyxNativeFrameProcessor provider(mockup.get());
- std::unique_ptr<char> frame(new char[1000]);
+ const std::string path = "TestPath/aas";
- // Build test frame
- frame.get()[0] = static_cast<uint8_t>(BaSyxCommand::Set);
+ auto inputFrame = Frame::Builder::Set(path, 10);
+ auto answerFrame = provider.processInputFrame(inputFrame);
- std::string path = "TestPath/aas";
- StringTools::toArray(path, frame.get() + 1);
-
- std::string newVal = basyx::serialization::json::serialize(10).dump(4);
-
- // write serialized data after path
- StringTools::toArray(newVal, frame.get() + 1 + 4 + path.length());
-
- std::unique_ptr<char> receive(new char[1000]);
- size_t txSize;
-
- provider.processInputFrame(
- frame.get(),
- 1 + 4 + path.length() + 4 + newVal.length(),
- receive.get(),
- &txSize
- );
-
- ASSERT_EQ(receive.get()[0], (char ) 0);
+ ASSERT_EQ(answerFrame.getFlag(), 0);
ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::SET);
@@ -91,26 +68,12 @@
auto mockup = util::make_unique<MockupModelProvider>();
vab::provider::native::frame::BaSyxNativeFrameProcessor provider(mockup.get());
- std::unique_ptr<char> frame(new char[1000]);
-
- // Build test frame
- frame.get()[0] = static_cast<uint8_t>(BaSyxCommand::Create);
-
std::string path = "TestPath";
- StringTools::toArray(path, frame.get() + 1);
- std::string newVal = basyx::serialization::json::serialize(10).dump(4);
+ auto inputFrame = Frame::Builder::Create(path, 10);
+ auto answerFrame = provider.processInputFrame(inputFrame);
- // write serialized data after path
- StringTools::toArray(newVal, frame.get() + 1 + 4 + path.length());
-
- std::unique_ptr<char> receive(new char[1000]);
- size_t txSize;
- provider.processInputFrame(frame.get(),
- 1 + 4 + path.length() + 4 + newVal.length(), receive.get(),
- &txSize);
-
- ASSERT_EQ(receive.get()[0], (char ) 0);
+ ASSERT_EQ(answerFrame.getFlag(), 0);
ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::CREATE);
@@ -124,26 +87,12 @@
auto mockup = util::make_unique<MockupModelProvider>();
vab::provider::native::frame::BaSyxNativeFrameProcessor provider(mockup.get());
- std::unique_ptr<char> frame(new char[1000]);
-
- // Build test frame
- frame.get()[0] = static_cast<uint8_t>(BaSyxCommand::Delete);
-
std::string path = "TestPath/aas/properties/C1";
- StringTools::toArray(path, frame.get() + 1);
- std::string deleteVal = basyx::serialization::json::serialize(10).dump(4);
+ auto inputFrame = Frame::Builder::Delete(path, 10);
+ auto answerFrame = provider.processInputFrame(inputFrame);
- // write serialized data after path
- StringTools::toArray(deleteVal, frame.get() + 1 + 4 + path.length());
-
- std::unique_ptr<char> receive(new char[1000]);
- size_t txSize;
- provider.processInputFrame(frame.get(),
- 1 + 4 + path.length() + 4 + deleteVal.length(), receive.get(),
- &txSize);
-
- ASSERT_EQ(receive.get()[0], (char ) 0);
+ ASSERT_EQ(answerFrame.getFlag(), 0);
ASSERT_EQ(mockup->called,
MockupModelProvider::CalledFunction::DELETE_COMPLEX);
@@ -158,20 +107,12 @@
auto mockup = util::make_unique<MockupModelProvider>();
vab::provider::native::frame::BaSyxNativeFrameProcessor provider(mockup.get());
- std::unique_ptr<char> frame(new char[1000]);
-
- // Build test frame
- frame.get()[0] = static_cast<uint8_t>(BaSyxCommand::Delete);
-
std::string path = "TestPath/aas/properties/P1";
- StringTools::toArray(path, frame.get() + 1);
- std::unique_ptr<char> receive(new char[1000]);
- size_t txSize;
- provider.processInputFrame(frame.get(), 1 + 4 + path.length(),
- receive.get(), &txSize);
+ auto inputFrame = Frame::Builder::Delete(path);
+ auto answerFrame = provider.processInputFrame(inputFrame);
- ASSERT_EQ(receive.get()[0], (char ) 0);
+ ASSERT_EQ(answerFrame.getFlag(), 0);
ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::DELETE_SIMPLE);
@@ -182,36 +123,20 @@
auto mockup = util::make_unique<MockupModelProvider>();
vab::provider::native::frame::BaSyxNativeFrameProcessor provider{ mockup.get() };
- std::unique_ptr<char> frame(new char[1000]);
-
- // Build test frame
- frame.get()[0] = static_cast<uint8_t>(BaSyxCommand::Invoke);
-
std::string path = "TestPath";
- StringTools::toArray(path, frame.get() + 1);
-
- std::string newVal = basyx::serialization::json::serialize(10).dump();
-
- // write serialized data after path
- StringTools::toArray(newVal, frame.get() + 1 + 4 + path.length());
-
- std::unique_ptr<char> receive(new char[1000]);
- size_t txSize;
- provider.processInputFrame(frame.get(),
- 1 + 4 + path.length() + 4 + newVal.length(), receive.get(),
- &txSize);
+ auto inputFrame = Frame::Builder::Invoke(path, 10);
+ auto answerFrame = provider.processInputFrame(inputFrame);
ASSERT_EQ(mockup->called, MockupModelProvider::CalledFunction::INVOKE);
ASSERT_EQ(mockup->path, path);
ASSERT_TRUE(mockup->val.InstanceOf<int>());
ASSERT_EQ(mockup->val.Get<int>(), 10);
- ASSERT_EQ(receive.get()[0], (char ) 0);
+ ASSERT_EQ(answerFrame.getFlag(), 0);
// Deserialize return value of operation
- std::string serialized = StringTools::fromArray(receive.get() + 1);
- auto val = basyx::serialization::json::deserialize(nlohmann::json::parse(serialized)["entity"]);
+ auto val = basyx::serialization::json::deserialize(nlohmann::json::parse(answerFrame.getFirstValue())["entity"]);
ASSERT_TRUE(val.InstanceOf<int>());
ASSERT_EQ(val.Get<int>(),3);
-}
+}
\ No newline at end of file
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/test_BaSyxNative.cpp b/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/test_BaSyxNative.cpp
new file mode 100644
index 0000000..6d7c82d
--- /dev/null
+++ b/sdks/c++/basys.sdk.cc/tests/regression/vab/provider/basyx/test_BaSyxNative.cpp
@@ -0,0 +1,140 @@
+#include <gtest/gtest.h>
+
+#include <BaSyx/vab/provider/hashmap/VABHashmapProvider.h>
+#include <BaSyx/vab/provider/hashmap/VABHashmapProvider.h>
+#include <BaSyx/vab/backend/connector/native/BaSyxConnector.h>
+#include <BaSyx/server/TCPServer.h>
+
+#include <vab/stub/elements/SimpleVABElement.h>
+
+#include "snippet/MapRead.h"
+#include "snippet/MapCreateDelete.h"
+#include "snippet/MapInvoke.h"
+#include "snippet/TestCollectionProperty.h"
+
+#include <BaSyx/shared/serialization/json.h>
+
+#include <atomic>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+#include <thread>
+
+using namespace basyx;
+
+class TestBaSyxNative : public ::testing::Test {
+ using TcpServer_t = server::TCPServer<vab::provider::VABModelProvider>;
+public:
+ static constexpr int port = 7002;
+ std::thread server_thread;
+
+ std::unique_ptr<vab::provider::VABModelProvider> provider;
+ std::unique_ptr<TcpServer_t> tcpServer;
+
+ std::atomic<bool> done;
+
+ TestBaSyxNative()
+ {
+ };
+
+ virtual void SetUp()
+ {
+ done.store(false);
+
+ provider = util::make_unique<vab::provider::VABModelProvider>(tests::support::make_simple_vab_element());
+ tcpServer = util::make_unique<TcpServer_t>(provider.get(), port);
+
+ server_thread = std::thread{ [this]() {
+ tcpServer->run();
+ }
+ };
+
+ // Wait until server started up
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+ }
+
+ virtual void TearDown()
+ {
+ tcpServer->Close();
+ server_thread.join();
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+ }
+};
+
+class ConnectedModelProvider : public vab::core::IModelProvider
+{
+public:
+ using Connector = vab::connector::IBaSyxConnector;
+ Connector * connector;
+public:
+ ConnectedModelProvider(Connector * connector) : connector(connector)
+ {};
+
+ // Inherited via IModelProvider
+ virtual basyx::object getModelPropertyValue(const std::string & path) override
+ {
+ return connector->basysGet(path);
+ }
+
+ virtual basyx::object::error setModelPropertyValue(const std::string & path, const basyx::object newValue) override
+ {
+ auto obj = connector->basysSet(path, newValue);
+ return obj.getError();
+ }
+
+ virtual basyx::object::error createValue(const std::string & path, const basyx::object addedValue) override
+ {
+ auto obj = connector->basysCreate(path, addedValue);
+ return obj.getError();
+ }
+
+ virtual basyx::object::error deleteValue(const std::string & path, basyx::object deletedValue) override
+ {
+ auto obj = connector->basysDelete(path, deletedValue);
+ return obj.getError();
+ }
+
+ virtual basyx::object::error deleteValue(const std::string & path) override
+ {
+ auto obj = connector->basysDelete(path);
+ return obj.getError();
+ }
+ virtual basyx::object invokeOperation(const std::string & path, basyx::object parameter) override
+ {
+ return connector->basysInvoke(path, parameter);
+ }
+};
+
+TEST_F(TestBaSyxNative, MapRead)
+{
+ auto connector = util::make_unique<vab::connector::native::NativeConnector>("127.0.0.1", port);
+ auto provider = ConnectedModelProvider(connector.get());
+
+ tests::regression::vab::snippet::MapRead::test(&provider);
+}
+
+TEST_F(TestBaSyxNative, MapCreateDelete)
+{
+ auto connector = util::make_unique<vab::connector::native::NativeConnector>("127.0.0.1", port);
+ auto provider = ConnectedModelProvider(connector.get());
+
+ tests::regression::vab::snippet::MapCreateDelete::test(&provider);
+}
+
+TEST_F(TestBaSyxNative, MapInvoke)
+{
+ auto connector = util::make_unique<vab::connector::native::NativeConnector>("127.0.0.1", port);
+ auto provider = ConnectedModelProvider(connector.get());
+
+ tests::regression::vab::snippet::MapInvoke::test(&provider);
+}
+
+TEST_F(TestBaSyxNative, TestCollectionProperty)
+{
+ auto connector = util::make_unique<vab::connector::native::NativeConnector>("127.0.0.1", port);
+ auto provider = ConnectedModelProvider(connector.get());
+
+ tests::regression::vab::snippet::TestCollectionProperty::test(&provider);
+}
+
+int constexpr TestBaSyxNative::port;
\ No newline at end of file
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapRead.h b/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapRead.h
index 71e8961..b7237fd 100644
--- a/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapRead.h
+++ b/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapRead.h
@@ -23,8 +23,8 @@
static void test(basyx::vab::core::IModelProvider * modelProvider) {
// Test path access
- auto slashB = modelProvider->getModelPropertyValue("primitives/integer/");
auto slashA = modelProvider->getModelPropertyValue("/primitives/integer");
+ auto slashB = modelProvider->getModelPropertyValue("primitives/integer/");
auto slashC = modelProvider->getModelPropertyValue("/primitives/integer/");
auto slashD = modelProvider->getModelPropertyValue("/primitives/integer/");
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapUpdate.h b/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapUpdate.h
index f636a29..94b4302 100644
--- a/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapUpdate.h
+++ b/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/MapUpdate.h
@@ -15,10 +15,15 @@
namespace snippet {
-class MapRead {
+class MapUpdate{
public:
+ static void test(basyx::vab::core::IModelProvider * modelProvider)
+ {
+ testUpdate(modelProvider);
+ testWholeMap(modelProvider);
+ }
- static void test(basyx::vab::core::IModelProvider * modelProvider)
+ static void testUpdate(basyx::vab::core::IModelProvider * modelProvider)
{
// Set primitives
modelProvider->setModelPropertyValue("primitives/integer", 12);
@@ -56,7 +61,7 @@
ASSERT_EQ(nullUpdate.Get<bool>(), true);
}
- static void test(basyx::vab::core::IModelProvider * modelProvider)
+ static void testWholeMap(basyx::vab::core::IModelProvider * modelProvider)
{
// Push whole map via ""-Path
// - create object
diff --git a/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/TestCollectionProperty.h b/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/TestCollectionProperty.h
index 936e65e..382e338 100644
--- a/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/TestCollectionProperty.h
+++ b/sdks/c++/basys.sdk.cc/tests/regression/vab/snippet/TestCollectionProperty.h
@@ -44,8 +44,6 @@
modelProvider->deleteValue("/structure/list", 12);
auto collection2 = modelProvider->getModelPropertyValue("/structure/list/");
- //ASSERT_TRUE(collection.InstanceOf<basyx::object::list_t<int>>());
- //ASSERT_EQ(collection.Get<basyx::object::list_t<int>&>().size(), 0);
ASSERT_TRUE(collection2.empty());
}
@@ -64,8 +62,7 @@
// by object
modelProvider->deleteValue("/structure/list/", 56);
toTest = modelProvider->getModelPropertyValue("/structure/list/");
- ASSERT_TRUE(toTest.InstanceOf<basyx::object::list_t<int>>());
- //ASSERT_EQ(toTest.Get<basyx::object::list_t<int>&>().size(), 0);
+ ASSERT_EQ(toTest.GetObjectType(), basyx::type::objectType::List);
ASSERT_TRUE(toTest.empty());
// Create a list element