1 #ifndef EVA4_FFI_SDK_HPP
2 #define EVA4_FFI_SDK_HPP
4 #define EVA4_CCP_SDK_VERSION "0.0.1"
10 #include "eva4-common.h"
18 const uint16_t ABI_VERSION = 1;
29 const auto sleepStep = chrono::milliseconds(100);
42 void msgpack_unpack(msgpack::object o) {
43 if (o.type != msgpack::type::MAP) {
44 throw msgpack::type_error();
46 msgpack::object_kv* p = o.via.map.ptr;
47 msgpack::object_kv*
const pend = o.via.map.ptr + o.via.map.size;
49 for (; p != pend; ++p) {
50 if (p->key.as<std::string>() ==
"startup") {
51 startup = chrono::milliseconds((int32_t)(p->val.as<
double>() * 1000));
52 }
else if (p->key.as<std::string>() ==
"shutdown") {
53 shutdown = chrono::milliseconds((int32_t)(p->val.as<
double>() * 1000));
54 }
else if (p->key.as<std::string>() ==
"default") {
55 _default = chrono::milliseconds((int32_t)(p->val.as<
double>() * 1000));
67 uint16_t eapi_version;
71 MSGPACK_DEFINE_MAP(build, version, eapi_version, path,
active);
92 MSGPACK_DEFINE_MAP(version, system_name,
id, data_path,
93 timeout, core, config, user, fail_mode, fips, call_tracing);
110 return this->core.path;
129 this->operator[](-32001) =
"Not found";
130 this->operator[](-32002) =
"Access denied";
131 this->operator[](-32003) =
"System error";
132 this->operator[](-32004) =
"Other";
133 this->operator[](-32005) =
"Not ready";
134 this->operator[](-32006) =
"Unsupported";
135 this->operator[](-32007) =
"Core error";
136 this->operator[](-32008) =
"Timeout";
137 this->operator[](-32009) =
"Invalid data";
138 this->operator[](-32010) =
"Function failed";
139 this->operator[](-32011) =
"Aborted";
140 this->operator[](-32012) =
"Resource already existS";
141 this->operator[](-32013) =
"Busy";
142 this->operator[](-32014) =
"Method not implemented";
143 this->operator[](-32015) =
"Token restricted";
144 this->operator[](-32016) =
"I/O";
145 this->operator[](-32017) =
"Registry";
146 this->operator[](-32018) =
"evaHI auth required";
147 this->operator[](-32022) =
"Access denied more data required";
148 this->operator[](-32700) =
"Parse error";
149 this->operator[](-32600) =
"Invalid request";
150 this->operator[](-32601) =
"Method not found";
151 this->operator[](-32602) =
"Invalid params";
152 this->operator[](-32603) =
"Internal RPC";
153 this->operator[](-32113) =
"Bus client not registered";
154 this->operator[](-32114) =
"Bus data";
155 this->operator[](-32115) =
"Bus io";
156 this->operator[](-32116) =
"Bus other";
157 this->operator[](-32117) =
"Bus not supported";
158 this->operator[](-32118) =
"Bus busy";
159 this->operator[](-32119) =
"Bus not delivered";
160 this->operator[](-32120) =
"Bus timeout";
161 this->operator[](-32121) =
"Bus access";
174 this->operator[](
"unit") = Unit;
175 this->operator[](
"sensor") = Sensor;
176 this->operator[](
"lvar") = LVar;
177 this->operator[](
"lmacro") = LMacro;
178 this->operator[](
"+") = Any;
186 this->operator[](Unit) =
"unit";
187 this->operator[](Sensor) =
"sensor";
188 this->operator[](LVar) =
"lvar";
189 this->operator[](LMacro) =
"lmacro";
190 this->operator[](Any) =
"+";
219 ss << i->second <<
' ';
221 ss <<
'(' << this->code <<
')';
222 this->msg = ss.str();
225 return (
char *)this->msg.c_str();
231 cerr << this->msg << endl << flush;
238 void log(
string context) {
239 cerr << context <<
": " << this->msg << endl << flush;
252 MSGPACK_DEFINE_MAP(status);
260 template <
typename T>
265 MSGPACK_DEFINE_MAP(status, value);
274 MSGPACK_DEFINE_MAP(i);
277 atomic<int32_t (*)(int16_t op_code,
struct EvaFFIBuffer* payload)> svc_op_fn(
nullptr);
279 stringstream packStrings(vector<string>& strings) {
281 for (
const auto& s : strings) {
294 return svc_op_fn ? svc_op_fn(op_code,
nullptr) : EVA_ERR_CODE_NOT_READY;
303 int32_t
svcOpSS(int16_t op_code, stringstream& ss) {
304 size_t size = ss.tellp();
305 char* buf = (
char *)malloc(size);
306 struct EvaFFIBuffer payload = EvaFFIBuffer { size, buf, size };
307 memcpy(payload.data, ss.str().c_str(), size);
308 int32_t res = svc_op_fn(op_code, &payload);
319 return svcOp(EVA_FFI_SVC_OP_IS_ACTIVE) == 1;
342 stringstream ss = packStrings(topics);
343 c2e(
svcOpSS(EVA_FFI_SVC_OP_SUBSCRIBE_TOPIC, ss));
356 c2e(
svcOpSS(EVA_FFI_SVC_OP_SUBSCRIBE_TOPIC, ss));
367 stringstream ss = packStrings(topics);
368 c2e(
svcOpSS(EVA_FFI_SVC_OP_UNSUBSCRIBE_TOPIC, ss));
381 c2e(
svcOpSS(EVA_FFI_SVC_OP_UNSUBSCRIBE_TOPIC, ss));
394 template <
typename T>
void publish(
string topic, T data) {
398 msgpack::pack(ss, data);
399 c2e(
svcOpSS(EVA_FFI_SVC_OP_PUBLISH_TOPIC, ss));
408 this->kind = vars::ItemKind::Any;
410 this->path = string();
411 this->rawTopic = string();
421 this->parse(s,
false);
431 OID(
string s,
bool fromPath) {
432 this->parse(s, fromPath);
440 return this->i.substr(this->pos + 1);
478 bool operator==(
const OID& other)
const {
479 return this->i==other.
i;
482 void parse(
string s,
bool fromPath) {
483 char sep = fromPath?
'/':
':';
484 size_t pos = s.find(sep);
485 if (pos == string::npos) {
486 string opk = fromPath?
"oid path":
"oid";
487 throw invalid_argument(
"invalid " + opk +
": " + s);
489 string sKind = s.substr(0, pos);
492 throw invalid_argument(
"invalid oid kind: " + s);
494 string full_id = s.substr(pos + 1);
495 this->kind = i->second;
496 this->i = fromPath?sKind+
":"+full_id:s;
497 this->path = fromPath?s:sKind+
"/"+full_id;
498 this->rawTopic = EVA_RAW_STATE_TOPIC + this->path;
503 ostream& operator<<(ostream &strm,
const OID &o) {
507 thread_local stringstream result_buf;
510 return result_buf.tellp();
516 namespace controller {
520 typedef uint8_t uuidBuf[16];
526 MSGPACK_DEFINE_MAP(uuid, status)
535 MSGPACK_DEFINE_MAP(uuid, status, out, exitcode)
544 MSGPACK_DEFINE_MAP(uuid, status, err, exitcode)
555 MSGPACK_DEFINE_MAP(value)
570 MSGPACK_DEFINE_MAP(uuid,i,timeout,priority,params)
576 MSGPACK_DEFINE_MAP(i)
592 copy(begin(a.uuid), end(a.uuid), begin(this->uuid));
594 this->timeout = chrono::microseconds(a.timeout);
595 this->priority = a.priority;
596 this->params = a.params;
597 this->topic = string(EVA_ACTION_STATUS_TOPIC) + this->oid.path;
605 this->markAction(EVA_ACTION_STATUS_PENDING);
613 this->markAction(EVA_ACTION_STATUS_RUNNING);
624 copy(begin(this->uuid), end(this->uuid), begin(a.uuid));
625 publish<BusActionStatusCompleted>(this->topic, a);
637 copy(begin(this->uuid), end(this->uuid), begin(a.uuid));
638 publish<BusActionStatusError>(this->topic, a);
646 this->markAction(EVA_ACTION_STATUS_CANCELED);
654 this->markAction(EVA_ACTION_STATUS_TERMINATED);
668 void markAction(uint8_t status) {
670 copy(begin(this->uuid), end(this->uuid), begin(a.uuid));
671 publish<BusActionStatusShort>(this->topic, a);
680 MSGPACK_DEFINE_MAP(required);
685 map<string, SvcMethodParam> params;
687 MSGPACK_DEFINE_MAP(description, params);
700 this->description=
"";
708 this->description= description;
716 this->params.insert(pair<string, SvcMethodParam>(name,
SvcMethodParam { required:
true }));
725 this->params.insert(pair<string, SvcMethodParam>(name,
SvcMethodParam { required:
false }));
730 map<string, SvcMethodParam> params;
743 this->author = author;
744 this->version = version;
745 this->description = description;
754 methods.insert(pair<string, SvcMethod>(method.name,
SvcMethod {method.description, method.params}));
760 map<string, SvcMethod> methods;
762 MSGPACK_DEFINE_MAP(author, version, description, methods);
777 msgpack::object_handle oh = msgpack::unpack(buf->data, buf->len);
778 msgpack::object
const& obj = oh.get();
798 return string(this->r->primary_sender);
804 return string(this->r->topic);
810 return this->r->payload_size > 0;
818 msgpack::object_handle oh = msgpack::unpack(this->r->payload, this->r->payload_size);
840 return string(this->r->primary_sender);
846 return string(this->r->method, this->r->method_size);
852 return this->r->payload_size > 0;
860 msgpack::object_handle oh = msgpack::unpack(this->r->payload, this->r->payload_size);
871 if (this->hasPayload()) {
872 msgpack::object_handle oh=this->unpack();
873 msgpack::object
const& obj = oh.get();
877 throw Exception(EVA_ERR_CODE_INVALID_PARAMS);
890 if (this->hasPayload()) {
891 msgpack::object_handle oh=this->unpack();
892 msgpack::object
const& obj = oh.get();
896 throw Exception(EVA_ERR_CODE_INVALID_PARAMS);
910 size_t size = (size_t)res;
911 char* data = (
char *)malloc(size);
912 this->buf = EvaFFIBuffer { size, data, size };
915 this->getCallResult();
918 this->code = (int16_t)res;
926 return this->size > 0;
934 msgpack::object_handle oh = msgpack::unpack(this->buf.data, this->buf.len);
944 void getCallResult() {
945 int16_t code = svc_op_fn(EVA_FFI_SVC_OP_GET_RPC_RESULT, &this->buf);
946 if (code != EVA_OK) {
948 this->code = EVA_ERR_CODE_CORE_ERROR;
973 msgpack::pack(ss, params);
974 int32_t res =
svcOpSS(EVA_FFI_SVC_OP_RPC_CALL, ss);
995 int32_t res =
svcOpSS(EVA_FFI_SVC_OP_RPC_CALL, ss);
1010 template<
typename T> int32_t
result(T payload) {
1011 msgpack::pack(result_buf, payload);
1012 return result_buf.tellp();
1021 c2e(
svcOp(EVA_FFI_SVC_OP_TERMINATE));
1064 void poc(exception& e,
string context) {
1075 MSGPACK_DEFINE_MAP(
active);
1085 msgpack::object_handle oh = r.
unpack();
1086 msgpack::object
const& obj = oh.get();
1098 this_thread::sleep_for(vars::sleepStep);
1110 const auto waitUntil = chrono::steady_clock::now() + timeout;
1112 this_thread::sleep_for(vars::sleepStep);
1113 if (chrono::steady_clock::now() >= waitUntil) {
1132 svcOpSS(EVA_FFI_SVC_OP_LOG_TRACE, ss);
1143 svcOpSS(EVA_FFI_SVC_OP_LOG_DEBUG, ss);
1154 svcOpSS(EVA_FFI_SVC_OP_LOG_INFO, ss);
1165 svcOpSS(EVA_FFI_SVC_OP_LOG_WARN, ss);
1176 svcOpSS(EVA_FFI_SVC_OP_LOG_ERROR, ss);
1184 void o(
string message) {
1185 cout << message << endl << flush;
1193 void e(
string message) {
1194 cerr << message << endl << flush;
1203 void e(exception& e,
string context) {
1204 cerr << context <<
": " <<
e.what() << endl << flush;
1212 void e(exception& e) {
1213 cerr <<
e.what() << endl << flush;
1218 namespace internal {
1222 int16_t eva_svc_get_result(
struct EvaFFIBuffer *ebuf) {
1223 size_t size = eva::result_buf.tellp();
1224 if (size > ebuf->max)
return EVA_ERR_CODE_ABORTED;
1226 memcpy(ebuf->data, result_buf.str().c_str(), size);
1227 result_buf.str(
string());
1231 int16_t eva_svc_set_op_fn(uint16_t abi_version, int32_t (*f)(int16_t,
struct EvaFFIBuffer*)) {
1232 if (abi_version != ABI_VERSION) {
1233 return EVA_ERR_CODE_UNSUPPORTED;