Files
allwpilib/src/ntcore_cpp.cpp
Peter Johnson 424bf51a7b Implement local notification.
The default behavior is to only notify remote changes, but for some
applications (e.g. GUI's) it's advantageous to know about local
changes as well.

This is (slightly) optimized in that local changes only result in
additional resources being consumed if (any) local listeners have been
created.
2015-09-23 00:56:08 -07:00

261 lines
7.3 KiB
C++

/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "ntcore.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include "Dispatcher.h"
#include "Log.h"
#include "Notifier.h"
#include "RpcServer.h"
#include "Storage.h"
#include "WireDecoder.h"
#include "WireEncoder.h"
namespace nt {
/*
* Table Functions
*/
std::shared_ptr<Value> GetEntryValue(StringRef name) {
return Storage::GetInstance().GetEntryValue(name);
}
bool SetEntryValue(StringRef name, std::shared_ptr<Value> value) {
return Storage::GetInstance().SetEntryValue(name, value);
}
void SetEntryTypeValue(StringRef name, std::shared_ptr<Value> value) {
Storage::GetInstance().SetEntryTypeValue(name, value);
}
void SetEntryFlags(StringRef name, unsigned int flags) {
Storage::GetInstance().SetEntryFlags(name, flags);
}
unsigned int GetEntryFlags(StringRef name) {
return Storage::GetInstance().GetEntryFlags(name);
}
void DeleteEntry(StringRef name) {
Storage::GetInstance().DeleteEntry(name);
}
void DeleteAllEntries() {
Storage::GetInstance().DeleteAllEntries();
}
std::vector<EntryInfo> GetEntryInfo(StringRef prefix, unsigned int types) {
return Storage::GetInstance().GetEntryInfo(prefix, types);
}
void Flush() {
Dispatcher::GetInstance().Flush();
}
/*
* Callback Creation Functions
*/
unsigned int AddEntryListener(StringRef prefix, EntryListenerCallback callback,
bool immediate_notify, bool local_notify) {
Notifier& notifier = Notifier::GetInstance();
unsigned int uid = notifier.AddEntryListener(prefix, callback, local_notify);
notifier.Start();
if (immediate_notify) Storage::GetInstance().NotifyEntries(prefix, callback);
return uid;
}
void RemoveEntryListener(unsigned int entry_listener_uid) {
Notifier::GetInstance().RemoveEntryListener(entry_listener_uid);
}
unsigned int AddConnectionListener(ConnectionListenerCallback callback,
bool immediate_notify) {
Notifier& notifier = Notifier::GetInstance();
unsigned int uid = notifier.AddConnectionListener(callback);
Notifier::GetInstance().Start();
if (immediate_notify) Dispatcher::GetInstance().NotifyConnections(callback);
return uid;
}
void RemoveConnectionListener(unsigned int conn_listener_uid) {
Notifier::GetInstance().RemoveConnectionListener(conn_listener_uid);
}
bool NotifierDestroyed() { return Notifier::destroyed(); }
/*
* Remote Procedure Call Functions
*/
void CreateRpc(StringRef name, StringRef def, RpcCallback callback) {
Storage::GetInstance().CreateRpc(name, def, callback);
}
void CreatePolledRpc(StringRef name, StringRef def) {
Storage::GetInstance().CreatePolledRpc(name, def);
}
bool PollRpc(bool blocking, RpcCallInfo* call_info) {
return RpcServer::GetInstance().PollRpc(blocking, call_info);
}
void PostRpcResponse(unsigned int rpc_id, unsigned int call_uid,
StringRef result) {
RpcServer::GetInstance().PostRpcResponse(rpc_id, call_uid, result);
}
unsigned int CallRpc(StringRef name, StringRef params) {
return Storage::GetInstance().CallRpc(name, params);
}
bool GetRpcResult(bool blocking, unsigned int call_uid, std::string* result) {
return Storage::GetInstance().GetRpcResult(blocking, call_uid, result);
}
std::string PackRpcDefinition(const RpcDefinition& def) {
WireEncoder enc(0x0300);
enc.Write8(def.version);
enc.WriteString(def.name);
// parameters
unsigned int params_size = def.params.size();
if (params_size > 0xff) params_size = 0xff;
enc.Write8(params_size);
for (std::size_t i = 0; i < params_size; ++i) {
enc.WriteType(def.params[i].def_value->type());
enc.WriteString(def.params[i].name);
enc.WriteValue(*def.params[i].def_value);
}
// results
unsigned int results_size = def.results.size();
if (results_size > 0xff) results_size = 0xff;
enc.Write8(results_size);
for (std::size_t i = 0; i < results_size; ++i) {
enc.WriteType(def.results[i].type);
enc.WriteString(def.results[i].name);
}
return enc.ToStringRef();
}
bool UnpackRpcDefinition(StringRef packed, RpcDefinition* def) {
raw_mem_istream is(packed.data(), packed.size());
WireDecoder dec(is, 0x0300);
if (!dec.Read8(&def->version)) return false;
if (!dec.ReadString(&def->name)) return false;
// parameters
unsigned int params_size;
if (!dec.Read8(&params_size)) return false;
def->params.resize(0);
def->params.reserve(params_size);
for (std::size_t i = 0; i < params_size; ++i) {
RpcParamDef pdef;
NT_Type type;
if (!dec.ReadType(&type)) return false;
if (!dec.ReadString(&pdef.name)) return false;
pdef.def_value = dec.ReadValue(type);
if (!pdef.def_value) return false;
def->params.emplace_back(std::move(pdef));
}
// results
unsigned int results_size;
if (!dec.Read8(&results_size)) return false;
def->results.resize(0);
def->results.reserve(results_size);
for (std::size_t i = 0; i < results_size; ++i) {
RpcResultDef rdef;
if (!dec.ReadType(&rdef.type)) return false;
if (!dec.ReadString(&rdef.name)) return false;
def->results.emplace_back(std::move(rdef));
}
return true;
}
std::string PackRpcValues(ArrayRef<std::shared_ptr<Value>> values) {
WireEncoder enc(0x0300);
for (auto& value : values) enc.WriteValue(*value);
return enc.ToStringRef();
}
std::vector<std::shared_ptr<Value>> UnpackRpcValues(StringRef packed,
ArrayRef<NT_Type> types) {
raw_mem_istream is(packed.data(), packed.size());
WireDecoder dec(is, 0x0300);
std::vector<std::shared_ptr<Value>> vec;
for (auto type : types) {
auto item = dec.ReadValue(type);
if (!item) return std::vector<std::shared_ptr<Value>>();
vec.emplace_back(std::move(item));
}
return vec;
}
/*
* Client/Server Functions
*/
void SetNetworkIdentity(StringRef name) {
Dispatcher::GetInstance().SetIdentity(name);
}
void StartServer(StringRef persist_filename, const char *listen_address,
unsigned int port) {
Dispatcher::GetInstance().StartServer(persist_filename, listen_address, port);
}
void StopServer() {
Dispatcher::GetInstance().Stop();
}
void StartClient(const char *server_name, unsigned int port) {
Dispatcher::GetInstance().StartClient(server_name, port);
}
void StopClient() {
Dispatcher::GetInstance().Stop();
}
void SetUpdateRate(double interval) {
Dispatcher::GetInstance().SetUpdateRate(interval);
}
std::vector<ConnectionInfo> GetConnections() {
return Dispatcher::GetInstance().GetConnections();
}
/*
* Persistent Functions
*/
const char* SavePersistent(StringRef filename) {
return Storage::GetInstance().SavePersistent(filename, false);
}
const char* LoadPersistent(
StringRef filename,
std::function<void(size_t line, const char* msg)> warn) {
return Storage::GetInstance().LoadPersistent(filename, warn);
}
void SetLogger(LogFunc func, unsigned int min_level) {
Logger& logger = Logger::GetInstance();
logger.SetLogger(func);
logger.set_min_level(min_level);
}
} // namespace nt