File keyvalueFeature.h
File List > features > keyvalueFeature.h
Go to the documentation of this file
#pragma once
#include <jac/machine/machine.h>
#include <jac/machine/functionFactory.h>
#include <jac/machine/class.h>
#include <jac/device/keyvalue.h>
#include <noal_func.h>
#include <memory>
namespace jac {
struct KeyValueNamespaceProtoBuilder : public jac::ProtoBuilder::Opaque<jac::KeyValueNamespace>, public jac::ProtoBuilder::Properties {
static jac::Value get(jac::ContextRef ctx, jac::ValueWeak thisVal, std::string key) {
using namespace jac;
using DT = KeyValueNamespace::DataType;
auto& self = *KeyValueNamespaceProtoBuilder::getOpaque(ctx, thisVal);
switch(self.getType(key)) {
case DT::INT64:
return Value::from(ctx, self.getInt(key));
case DT::FLOAT32:
return Value::from(ctx, self.getFloat(key));
case DT::STRING:
return Value::from(ctx, self.getString(key));
default:
return Value::null(ctx);
}
}
static void addProperties(JSContext* ctx, jac::Object proto) {
jac::FunctionFactory ff(ctx);
proto.defineProperty("get", ff.newFunctionThis(std::function(&get)), jac::PropFlags::Enumerable);
proto.defineProperty("getString", ff.newFunctionThis([](jac::ContextRef ctx_, jac::ValueWeak thisVal, std::string key) {
auto res = get(ctx_, thisVal, key);
if(JS_IsString(res.getVal())) {
return res;
}
return jac::Value::null(ctx_);
}), jac::PropFlags::Enumerable);
proto.defineProperty("getNumber", ff.newFunctionThis([](jac::ContextRef ctx_, jac::ValueWeak thisVal, std::string key) {
auto res = get(ctx_, thisVal, key);
if(JS_IsNumber(res.getVal())) {
return res;
}
return jac::Value::null(ctx_);
}), jac::PropFlags::Enumerable);
proto.defineProperty("set", ff.newFunctionThis([](jac::ContextRef ctx_, jac::ValueWeak thisVal, std::string key, jac::Value value) {
using namespace jac;
if(key.length() > 15) {
throw Exception::create(Exception::Type::TypeError, "key is too long (max 15 chars)");
}
auto& self = *KeyValueNamespaceProtoBuilder::getOpaque(ctx_, thisVal);
auto tag = JS_VALUE_GET_TAG(value.getVal());
if(tag == JS_TAG_INT) {
self.setInt(key, value.to<int64_t>());
} else if(JS_TAG_IS_FLOAT64(tag)) {
self.setFloat(key, value.to<double>());
} else if(tag == JS_TAG_STRING) {
self.setString(key, value.to<std::string>());
} else {
throw Exception::create(Exception::Type::TypeError, "value has wrong type");
}
}), jac::PropFlags::Enumerable);
proto.defineProperty("erase", ff.newFunctionThis([](jac::ContextRef ctx_, jac::ValueWeak thisVal, std::string key) {
auto& self = *KeyValueNamespaceProtoBuilder::getOpaque(ctx_, thisVal);
self.erase(key);
}), jac::PropFlags::Enumerable);
proto.defineProperty("exists", ff.newFunctionThis([](jac::ContextRef ctx_, jac::ValueWeak thisVal, std::string key) {
auto& self = *KeyValueNamespaceProtoBuilder::getOpaque(ctx_, thisVal);
return self.exists(key);
}), jac::PropFlags::Enumerable);
proto.defineProperty("commit", ff.newFunctionThis([](jac::ContextRef ctx_, jac::ValueWeak thisVal) {
using namespace jac;
auto& self = *KeyValueNamespaceProtoBuilder::getOpaque(ctx_, thisVal);
if(!self.commit()) {
throw Exception::create(Exception::Type::InternalError, "NVS saving failed");
}
}), jac::PropFlags::Enumerable);
}
};
template<class Next>
class KeyValueFeature : public Next {
public:
using KvClass = jac::Class<KeyValueNamespaceProtoBuilder>;
jac::KeyValueOpener kvOpener;
KeyValueFeature() {
KvClass::init("KeyValueNamespace");
}
void initialize() {
using namespace jac;
Next::initialize();
FunctionFactory ff(this->context());
Module& mod = this->newModule("keyvalue");
mod.addExport("open", ff.newFunction(noal::function([this](std::string nsname) {
if(!kvOpener) {
throw Exception::create(Exception::Type::InternalError, "KeyValueFeature not set up");
}
if(nsname.length() > 15) {
throw Exception::create(Exception::Type::TypeError, "namespace is too long (max 15 chars)");
}
if(nsname == "wifi_net") {
throw Exception::create(Exception::Type::InternalError, "this namespace is protected");
}
auto nsHandle = kvOpener(nsname);
if(!nsHandle) {
throw Exception::create(Exception::Type::InternalError, "failed to open namespace");
}
return KvClass::createInstance(this->context(), nsHandle.release());
})));
}
};
} // namespace jac