mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
go: add first version of Golang node-type support
This commit is contained in:
parent
619c620e1a
commit
db67c468bc
16 changed files with 840 additions and 296 deletions
|
@ -106,6 +106,7 @@ endif()
|
|||
# Check programs
|
||||
find_program(PROTOBUFC_COMPILER NAMES protoc-c)
|
||||
find_program(PROTOBUF_COMPILER NAMES protoc)
|
||||
find_program(GO NAMES go)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig:/usr/local/share/pkgconfig:/usr/lib64/pkgconfig")
|
||||
|
||||
|
@ -163,19 +164,14 @@ else()
|
|||
endif()
|
||||
|
||||
# Build options
|
||||
cmake_dependent_option(WITH_HOOKS "Build with support for processing hook plugins" ON "" OFF)
|
||||
cmake_dependent_option(WITH_WEB "Build with internal webserver" ON "LIBWEBSOCKETS_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_API "Build with remote control API" ON "" OFF)
|
||||
cmake_dependent_option(WITH_CONFIG "Build with support for libconfig configuration syntax" ON "LIBCONFIG_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_OPENMP "Build with support for OpenMP for parallel hooks" ON "OPENMP_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_SRC "Build executables" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_FPGA "Build with support for VILLASfpga" ON "XIL_FOUND; FOUND_SUBMODULE_FPGA" OFF)
|
||||
cmake_dependent_option(WITH_TOOLS "Build auxilary tools" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_TESTS "Run tests" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_PLUGINS "Build plugins" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_CLIENTS "Build client applications" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_CONFIG "Build with support for libconfig configuration syntax" ON "LIBCONFIG_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_DOC "Build documentation" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_FPGA "Build with support for VILLASfpga" ON "XIL_FOUND; FOUND_SUBMODULE_FPGA" OFF)
|
||||
cmake_dependent_option(WITH_GO "Build with Go" ON "GO" OFF)
|
||||
cmake_dependent_option(WITH_GRAPHVIZ "Build with Graphviz" ON "CGRAPH_FOUND; GVC_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_HOOKS "Build with support for processing hook plugins" ON "" OFF)
|
||||
cmake_dependent_option(WITH_LUA "Build with Lua" ON "LUA_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_AMQP "Build with amqp node-type" ON "RABBITMQ_C_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_CAN "Build with can node-type" ON "" OFF)
|
||||
|
@ -185,6 +181,7 @@ cmake_dependent_option(WITH_NODE_EXAMPLE "Build with example node-type"
|
|||
cmake_dependent_option(WITH_NODE_EXEC "Build with exec node-type" ON "" OFF)
|
||||
cmake_dependent_option(WITH_NODE_FILE "Build with file node-type" ON "" OFF)
|
||||
cmake_dependent_option(WITH_NODE_FPGA "Build with fpga node-type" ON "WITH_FPGA" OFF)
|
||||
cmake_dependent_option(WITH_NODE_GO "Build with Go-based nodes-types" ON "WITH_GO" OFF)
|
||||
cmake_dependent_option(WITH_NODE_IEC61850 "Build with iec61850 node-types" ON "LIBIEC61850_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_INFINIBAND "Build with infiniband node-type" ON "IBVerbs_FOUND; RDMACM_FOUND" OFF) # Infiniband node-type is currenly broken
|
||||
cmake_dependent_option(WITH_NODE_INFLUXDB "Build with influxdb node-type" ON "" OFF)
|
||||
|
@ -205,6 +202,12 @@ cmake_dependent_option(WITH_NODE_TEST_RTT "Build with test_rtt node-type"
|
|||
cmake_dependent_option(WITH_NODE_ULDAQ "Build with uldaq node-type" ON "LIBULDAQ_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_WEBSOCKET "Build with websocket node-type" ON "WITH_WEB; LIBWEBSOCKETS_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_NODE_ZEROMQ "Build with zeromq node-type" ON "LIBZMQ_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_OPENMP "Build with support for OpenMP for parallel hooks" ON "OPENMP_FOUND" OFF)
|
||||
cmake_dependent_option(WITH_PLUGINS "Build plugins" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_SRC "Build executables" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_TESTS "Run tests" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_TOOLS "Build auxilary tools" ON "TOPLEVEL_PROJECT" OFF)
|
||||
cmake_dependent_option(WITH_WEB "Build with internal webserver" ON "LIBWEBSOCKETS_FOUND" OFF)
|
||||
|
||||
# Add more build configurations
|
||||
include(cmake/config/Debug.cmake)
|
||||
|
@ -255,24 +258,26 @@ configure_file(
|
|||
)
|
||||
|
||||
# Show feature summary
|
||||
add_feature_info(HOOKS WITH_HOOKS "Build with support for processing hook plugins")
|
||||
add_feature_info(WEB WITH_WEB "Build with internal webserver")
|
||||
add_feature_info(API WITH_API "Build with remote control API")
|
||||
add_feature_info(CONFIG WITH_CONFIG "Build with support for libconfig configuration syntax")
|
||||
add_feature_info(SRC WITH_SRC "Build executables")
|
||||
add_feature_info(FPGA WITH_FPGA "Build with FPGA support")
|
||||
add_feature_info(TOOLS WITH_TOOLS "Build auxilary tools")
|
||||
add_feature_info(TESTS WITH_TESTS "Run tests")
|
||||
add_feature_info(PLUGINS WITH_PLUGINS "Build plugins")
|
||||
add_feature_info(CLIENTS WITH_CLIENTS "Build client applications")
|
||||
add_feature_info(CONFIG WITH_CONFIG "Build with support for libconfig configuration syntax")
|
||||
add_feature_info(DOC WITH_DOC "Build documentation")
|
||||
add_feature_info(FPGA WITH_FPGA "Build with FPGA support")
|
||||
add_feature_info(GO WITH_GO "Build with Go code")
|
||||
add_feature_info(GRAPHVIZ WITH_GRAPHVIZ "Build with Graphviz support")
|
||||
add_feature_info(HOOKS WITH_HOOKS "Build with support for processing hook plugins")
|
||||
add_feature_info(LUA WITH_LUA "Build with Lua support")
|
||||
add_feature_info(OPENMP WITH_OPENMP "Build with OpenMP support")
|
||||
add_feature_info(DOC WITH_DOC "Build documentation")
|
||||
add_feature_info(PLUGINS WITH_PLUGINS "Build plugins")
|
||||
add_feature_info(SRC WITH_SRC "Build executables")
|
||||
add_feature_info(TESTS WITH_TESTS "Run tests")
|
||||
add_feature_info(TOOLS WITH_TOOLS "Build auxilary tools")
|
||||
add_feature_info(WEB WITH_WEB "Build with internal webserver")
|
||||
|
||||
add_feature_info(NODE_AMQP WITH_NODE_AMQP "Build with amqp node-type")
|
||||
add_feature_info(NODE_COMEDI WITH_NODE_COMEDI "Build with comedi node-type")
|
||||
add_feature_info(NODE_FILE WITH_NODE_FILE "Build with file node-type")
|
||||
add_feature_info(NODE_GO WITH_NODE_GO "Build with Go-based nodes-types")
|
||||
add_feature_info(NODE_IEC61850 WITH_NODE_IEC61850 "Build with iec61850 node-types")
|
||||
add_feature_info(NODE_INFINIBAND WITH_NODE_INFINIBAND "Build with infiniband node-type")
|
||||
add_feature_info(NODE_INFLUXDB WITH_NODE_INFLUXDB "Build with influxdb node-type")
|
||||
|
@ -282,6 +287,7 @@ add_feature_info(NODE_MQTT WITH_NODE_MQTT "Build with
|
|||
add_feature_info(NODE_NANOMSG WITH_NODE_NANOMSG "Build with nanomsg node-type")
|
||||
add_feature_info(NODE_NGSI WITH_NODE_NGSI "Build with ngsi node-type")
|
||||
add_feature_info(NODE_OPAL WITH_NODE_OPAL "Build with opal node-type")
|
||||
add_feature_info(NODE_REDIS WITH_NODE_REDIS "Build with redis node-type")
|
||||
add_feature_info(NODE_RTP WITH_NODE_RTP "Build with rtp node-type")
|
||||
add_feature_info(NODE_SHMEM WITH_NODE_SHMEM "Build with shmem node-type")
|
||||
add_feature_info(NODE_SIGNAL_GENERATOR WITH_NODE_SIGNAL "Build with signal node-type")
|
||||
|
@ -292,7 +298,6 @@ add_feature_info(NODE_TEST_RTT WITH_NODE_TEST_RTT "Build with
|
|||
add_feature_info(NODE_ULDAQ WITH_NODE_ULDAQ "Build with uldaq node-type")
|
||||
add_feature_info(NODE_WEBSOCKET WITH_NODE_WEBSOCKET "Build with websocket node-type")
|
||||
add_feature_info(NODE_ZEROMQ WITH_NODE_ZEROMQ "Build with zeromq node-type")
|
||||
add_feature_info(NODE_REDIS WITH_NODE_REDIS "Build with redis node-type")
|
||||
|
||||
if(TOPLEVEL_PROJECT)
|
||||
feature_summary(WHAT ALL VAR FEATURES)
|
||||
|
|
133
include/villas/nodes/go.hpp
Normal file
133
include/villas/nodes/go.hpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
/** Node-type implemeted in Go language
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASnode
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <villas/node.hpp>
|
||||
|
||||
namespace villas {
|
||||
namespace node {
|
||||
|
||||
/* Forward declarations */
|
||||
struct Sample;
|
||||
class Format;
|
||||
|
||||
class GoNode : public Node {
|
||||
|
||||
protected:
|
||||
void *node;
|
||||
|
||||
std::string _details;
|
||||
|
||||
Format *formatter;
|
||||
|
||||
virtual
|
||||
int _read(struct Sample * smps[], unsigned cnt);
|
||||
|
||||
virtual
|
||||
int _write(struct Sample * smps[], unsigned cnt);
|
||||
|
||||
public:
|
||||
GoNode(void *n);
|
||||
|
||||
virtual
|
||||
~GoNode();
|
||||
|
||||
virtual
|
||||
int parse(json_t *json, const uuid_t sn_uuid);
|
||||
|
||||
virtual
|
||||
std::vector<int> getPollFDs();
|
||||
|
||||
virtual
|
||||
std::vector<int> getNetemFDs();
|
||||
|
||||
virtual
|
||||
const std::string & getDetails();
|
||||
|
||||
virtual
|
||||
int prepare();
|
||||
|
||||
virtual
|
||||
int check();
|
||||
|
||||
virtual
|
||||
int start();
|
||||
|
||||
virtual
|
||||
int stop();
|
||||
|
||||
virtual
|
||||
int pause();
|
||||
|
||||
virtual
|
||||
int resume();
|
||||
|
||||
virtual
|
||||
int restart()
|
||||
{
|
||||
assert(state == State::STARTED);
|
||||
|
||||
logger->info("Restarting node");
|
||||
|
||||
return GoNodeRestart(node);
|
||||
}
|
||||
|
||||
virtual
|
||||
int reverse()
|
||||
{
|
||||
return GoNodeReverse(node);
|
||||
}
|
||||
};
|
||||
|
||||
class GoNodeFactory : public NodeFactory {
|
||||
|
||||
protected:
|
||||
std::string type;
|
||||
|
||||
public:
|
||||
GoNodeFactory(char *t) :
|
||||
NodeFactory(),
|
||||
type(t)
|
||||
{ }
|
||||
|
||||
virtual
|
||||
Node * make();
|
||||
|
||||
virtual
|
||||
std::string getName() const;
|
||||
|
||||
virtual
|
||||
std::string getDescription() const;
|
||||
};
|
||||
|
||||
class GoPluginRegistry : public plugin::SubRegistry {
|
||||
|
||||
public:
|
||||
GoPluginRegistry();
|
||||
|
||||
plugin::List<> lookup();
|
||||
};
|
||||
|
||||
} /* namespace node */
|
||||
} /* namespace villas */
|
|
@ -60,6 +60,12 @@ if(WITH_NODE_EXEC)
|
|||
list(APPEND NODE_SRC exec.cpp)
|
||||
endif()
|
||||
|
||||
if(WITH_NODE_GO)
|
||||
add_subdirectory(go)
|
||||
list(APPEND LIBRARIES nodes-go)
|
||||
list(APPEND NODE_SRC go.cpp)
|
||||
endif()
|
||||
|
||||
# Enable Universal Library for Linux DAQ devices (libuldaq)
|
||||
if(WITH_NODE_ULDAQ)
|
||||
list(APPEND NODE_SRC uldaq.cpp)
|
||||
|
|
283
lib/nodes/go.cpp
283
lib/nodes/go.cpp
|
@ -0,0 +1,283 @@
|
|||
/** Node-type implemeted in Go language
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASnode
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <libnodes-go.h>
|
||||
}
|
||||
|
||||
#include <villas/nodes/go.hpp>
|
||||
#include <villas/format.hpp>
|
||||
|
||||
using namespace villas::node;
|
||||
|
||||
GoNode::GoNode(void *n) :
|
||||
Node(),
|
||||
node(n)
|
||||
{ }
|
||||
|
||||
GoNode::~GoNode()
|
||||
{
|
||||
GoNodeClose(node);
|
||||
}
|
||||
|
||||
int GoNode::parse(json_t *json, const uuid_t sn_uuid)
|
||||
{
|
||||
int ret = Node::parse(json, sn_uuid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
json_t *json_format = nullptr;
|
||||
json_error_t err;
|
||||
|
||||
ret = json_unpack_ex(json, &err, 0, "{ s?: o }",
|
||||
"format", &json_format
|
||||
);
|
||||
if (ret)
|
||||
throw ConfigError(json, err, "node-config-node-format", "Failed to parse node configuration");
|
||||
|
||||
formatter = json_format
|
||||
? FormatFactory::make(json_format)
|
||||
: FormatFactory::make("json");
|
||||
if (!formatter)
|
||||
throw ConfigError(json_format, "node-config-node-format", "Invalid format configuration");
|
||||
|
||||
auto *cfg = json_dumps(json, JSON_COMPACT);
|
||||
ret = GoNodeParse(node, cfg);
|
||||
free(cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GoNode::check()
|
||||
{
|
||||
int ret = Node::check();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return GoNodeCheck(node);
|
||||
}
|
||||
|
||||
int GoNode::prepare()
|
||||
{
|
||||
int ret = GoNodePrepare(node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return Node::prepare();
|
||||
}
|
||||
|
||||
int GoNode::start()
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(state == State::PREPARED ||
|
||||
state == State::PAUSED);
|
||||
|
||||
/* Initialize IO */
|
||||
formatter->start(getInputSignals(false));
|
||||
|
||||
ret = GoNodeStart(node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = Node::start();
|
||||
if (!ret)
|
||||
state = State::STARTED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GoNode::stop() {
|
||||
int ret;
|
||||
|
||||
assert(state == State::STARTED ||
|
||||
state == State::PAUSED ||
|
||||
state == State::STOPPING);
|
||||
|
||||
ret = GoNodeStop(node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = Node::stop();
|
||||
if (!ret)
|
||||
state = State::STOPPED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GoNode::pause()
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = Node::pause();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = GoNodePause(node);
|
||||
if (!ret)
|
||||
state = State::PAUSED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GoNode::resume()
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = Node::resume();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = GoNodeResume(node);
|
||||
if (!ret)
|
||||
state = State::STARTED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::string & GoNode::getDetails()
|
||||
{
|
||||
if (_details.empty()) {
|
||||
auto *d = GoNodeDetails(node);
|
||||
_details = std::string(d);
|
||||
free(d);
|
||||
}
|
||||
|
||||
return _details;
|
||||
}
|
||||
|
||||
std::vector<int> GoNode::getPollFDs()
|
||||
{
|
||||
auto ret = GoNodeGetPollFDs(node);
|
||||
if (ret.r1)
|
||||
return {};
|
||||
|
||||
auto begin = (int *) ret.r0.data;
|
||||
auto end = begin + ret.r0.len;
|
||||
|
||||
return std::vector<int>(begin, end);
|
||||
}
|
||||
|
||||
std::vector<int> GoNode::getNetemFDs()
|
||||
{
|
||||
auto ret = GoNodeGetNetemFDs(node);
|
||||
if (ret.r1)
|
||||
return {};
|
||||
|
||||
auto begin = (int *) ret.r0.data;
|
||||
auto end = begin + ret.r0.len;
|
||||
|
||||
return std::vector<int>(begin, end);
|
||||
}
|
||||
|
||||
int GoNode::_read(struct Sample * smps[], unsigned cnt)
|
||||
{
|
||||
int ret;
|
||||
size_t rbytes;
|
||||
|
||||
auto d = GoNodeRead(node);
|
||||
if (d.r1)
|
||||
return d.r1;
|
||||
|
||||
ret = formatter->sscan((const char*) d.r0.data, d.r0.len, &rbytes, smps, cnt);
|
||||
if (ret < 0 || (size_t) d.r0.len != rbytes)
|
||||
logger->warn("Received invalid packet: ret={}, bytes={}, rbytes={}", ret, d.r0.len, rbytes);
|
||||
|
||||
logger->info("Received {} bytes: {}", d.r0.len, (char *) d.r0.data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GoNode::_write(struct Sample * smps[], unsigned cnt)
|
||||
{
|
||||
int ret;
|
||||
char buf[4096];
|
||||
size_t wbytes;
|
||||
|
||||
ret = formatter->sprint(buf, 4096, &wbytes, smps, cnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
GoSlice slice = {
|
||||
data: buf,
|
||||
len: GoInt(wbytes),
|
||||
cap: 4096
|
||||
};
|
||||
|
||||
ret = GoNodeWrite(node, slice);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
Node * GoNodeFactory::make()
|
||||
{
|
||||
auto *nt = NewGoNode((char *) type.c_str());
|
||||
if (!nt)
|
||||
return nullptr;
|
||||
|
||||
auto *n = new GoNode(nt);
|
||||
|
||||
init(n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string GoNodeFactory::getName() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
std::string GoNodeFactory::getDescription() const
|
||||
{
|
||||
return "Go-based node-type";
|
||||
}
|
||||
|
||||
GoPluginRegistry::GoPluginRegistry() {
|
||||
if (plugin::registry == nullptr)
|
||||
plugin::registry = new plugin::Registry();
|
||||
|
||||
plugin::registry->addSubRegistry(this);
|
||||
}
|
||||
|
||||
villas::plugin::List<> GoPluginRegistry::lookup()
|
||||
{
|
||||
plugin::List<> plugins;
|
||||
|
||||
auto nt = GoNodeTypes();
|
||||
auto ntl = std::vector<char*>(nt.r1, nt.r1+nt.r0);
|
||||
|
||||
for (auto nt : ntl) {
|
||||
plugins.push_back(new GoNodeFactory(nt));
|
||||
free(nt);
|
||||
}
|
||||
|
||||
free(nt.r1);
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
static GoPluginRegistry pr;
|
|
@ -0,0 +1,18 @@
|
|||
set(LIB libnodes-go.a)
|
||||
file(GLOB_RECURSE SRCS *.go)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${LIB}
|
||||
DEPENDS ${SRCS}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND env CGO_ENABLED=1 GOPATH=${GOPATH} go build -buildmode=c-archive -o "${CMAKE_CURRENT_BINARY_DIR}/${LIB}" ${CMAKE_GO_FLAGS} .
|
||||
COMMENT "Building Go library ${LIB}")
|
||||
|
||||
add_custom_target(libvillas-go DEPENDS ${LIB} ${HEADER})
|
||||
|
||||
add_library(nodes-go STATIC IMPORTED GLOBAL)
|
||||
add_dependencies(nodes-go libvillas-go)
|
||||
set_target_properties(nodes-go
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${LIB}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
|
@ -1,264 +0,0 @@
|
|||
package node
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
gopointer "github.com/mattn/go-pointer"
|
||||
)
|
||||
|
||||
func registerNode(name string, ctor CreateNode) {
|
||||
|
||||
}
|
||||
|
||||
type Signal struct {
|
||||
}
|
||||
|
||||
type Sample struct {
|
||||
Timestamp struct {
|
||||
Origin time.Time
|
||||
Received time.Time
|
||||
}
|
||||
|
||||
Data []interface{}
|
||||
}
|
||||
|
||||
type Node interface {
|
||||
Close() error
|
||||
|
||||
Prepare() error
|
||||
|
||||
Parse(cfg []byte) error
|
||||
|
||||
Check() error
|
||||
|
||||
Start() error
|
||||
Stop() error
|
||||
|
||||
Pause() error
|
||||
Resume() error
|
||||
Restart() error
|
||||
|
||||
Read(smps []Sample) (int, error)
|
||||
Write(smps []Sample) (int, error)
|
||||
|
||||
Reverse() error
|
||||
|
||||
GetPollFDs() ([]int, error)
|
||||
GetNetemFDs() ([]int, error)
|
||||
|
||||
// GetMemoryType()
|
||||
|
||||
Details() string
|
||||
}
|
||||
|
||||
type CreateNode func() Node
|
||||
|
||||
// Wrapper
|
||||
|
||||
func intSliceToCArray(s []int) unsafe.Pointer {
|
||||
b := (*[1 << 16]byte)(unsafe.Pointer(&s[0]))[0 : len(s)*8 : len(s)*8]
|
||||
return C.CBytes(unsafe.Pointer(&b[0]))
|
||||
}
|
||||
|
||||
func errorToInt(err error) int {
|
||||
if err == nil {
|
||||
return -1
|
||||
} else {
|
||||
return -22
|
||||
}
|
||||
}
|
||||
|
||||
//export NodeClose
|
||||
func NodeClose(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Close())
|
||||
}
|
||||
|
||||
//export NodePrepare
|
||||
func NodePrepare(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Prepare())
|
||||
}
|
||||
|
||||
//export NodeParse
|
||||
func NodeParse(p unsafe.Pointer, c unsafe.Pointer) int {
|
||||
cfg := gopointer.Restore(c).([]byte)
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Parse(cfg))
|
||||
}
|
||||
|
||||
//export NodeCheck
|
||||
func NodeCheck(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Check())
|
||||
}
|
||||
|
||||
//export NodeStart
|
||||
func NodeStart(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Start())
|
||||
}
|
||||
|
||||
//export NodeStop
|
||||
func NodeStop(p unsafe.Pointer) error {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Stop())
|
||||
}
|
||||
|
||||
//export NodePause
|
||||
func NodePause(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Pause())
|
||||
}
|
||||
|
||||
//export NodeResume
|
||||
func NodeResume(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Resume())
|
||||
}
|
||||
|
||||
//export NodeRestart
|
||||
func NodeRestart(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Restart())
|
||||
}
|
||||
|
||||
//export NodeRead
|
||||
func NodeRead(p unsafe.Pointer, smps []Sample) (int, error) {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return n.Read(smps)
|
||||
}
|
||||
|
||||
//export NodeWrite
|
||||
func NodeWrite(p unsafe.Pointer, smps []Sample) (int, int) {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
r, err := n.Write(smps)
|
||||
return r, errorToInt(err)
|
||||
}
|
||||
|
||||
//export NodeReverse
|
||||
func NodeReverse(p unsafe.Pointer) int {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
return errorToInt(n.Reverse())
|
||||
}
|
||||
|
||||
//export NodeGetPollFDs
|
||||
func NodeGetPollFDs(p unsafe.Pointer) (unsafe.Pointer, int) {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
f, err := n.GetPollFDs()
|
||||
if err == nil {
|
||||
return intSliceToCArray(f), 0
|
||||
} else {
|
||||
return nil, errorToInt(err)
|
||||
}
|
||||
}
|
||||
|
||||
//export NodeGetNetemFDs
|
||||
func NodeGetNetemFDs(p unsafe.Pointer) (unsafe.Pointer, int) {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
f, err := n.GetNetemFDs()
|
||||
if err == nil {
|
||||
return intSliceToCArray(f), 0
|
||||
} else {
|
||||
return nil, errorToInt(err)
|
||||
}
|
||||
}
|
||||
|
||||
//export NodeDetails
|
||||
func NodeDetails(p unsafe.Pointer) *C.char {
|
||||
n := gopointer.Restore(p).(Node)
|
||||
d := n.Details()
|
||||
return C.CString(d)
|
||||
}
|
||||
|
||||
// Example
|
||||
|
||||
type ExampleNode struct {
|
||||
Node
|
||||
}
|
||||
|
||||
func NewExampleNode() Node {
|
||||
return &ExampleNode{}
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Close() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Prepare() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Parse(cfg []byte) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Check() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Start() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Stop() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Pause() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Resume() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Restart() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Read(smps []Sample) (int, error) {
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Write(smps []Sample) (int, error) {
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Reverse() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) GetPollFDs() ([]int, error) {
|
||||
|
||||
return []int{}, nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) GetNetemFDs() ([]int, error) {
|
||||
return []int{}, nil
|
||||
}
|
||||
|
||||
func (n *ExampleNode) Details() string {
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// init
|
||||
|
||||
func init() {
|
||||
registerNode("example-go", NewExampleNode)
|
||||
}
|
5
lib/nodes/go/go.mod
Normal file
5
lib/nodes/go/go.mod
Normal file
|
@ -0,0 +1,5 @@
|
|||
module git.rwth-aachen.de/acs/public/villas/node
|
||||
|
||||
go 1.16
|
||||
|
||||
require github.com/mattn/go-pointer v0.0.1
|
2
lib/nodes/go/go.sum
Normal file
2
lib/nodes/go/go.sum
Normal file
|
@ -0,0 +1,2 @@
|
|||
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
|
||||
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
13
lib/nodes/go/helper.go
Normal file
13
lib/nodes/go/helper.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
)
|
||||
|
||||
func errorToInt(e error) C.int {
|
||||
if e == nil {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
160
lib/nodes/go/main.go
Normal file
160
lib/nodes/go/main.go
Normal file
|
@ -0,0 +1,160 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
node "git.rwth-aachen.de/acs/public/villas/node/pkg"
|
||||
gopointer "github.com/mattn/go-pointer"
|
||||
|
||||
_ "git.rwth-aachen.de/acs/public/villas/node/pkg/nodes/loopback"
|
||||
_ "git.rwth-aachen.de/acs/public/villas/node/pkg/nodes/webrtc"
|
||||
)
|
||||
|
||||
func main() {}
|
||||
|
||||
//export GoNodeTypes
|
||||
func GoNodeTypes() (int, **C.char) {
|
||||
var nodeTypes = node.NodeTypes()
|
||||
var n = len(nodeTypes)
|
||||
|
||||
types := (**C.char)(C.malloc(C.size_t(n) * C.size_t(unsafe.Sizeof(uintptr(0)))))
|
||||
slice := (*[1 << 31]*C.char)(unsafe.Pointer(types))[:n:n]
|
||||
|
||||
i := 0
|
||||
for typ, _ := range nodeTypes {
|
||||
slice[i] = C.CString(typ)
|
||||
i++
|
||||
}
|
||||
|
||||
return n, types
|
||||
}
|
||||
|
||||
//export NewGoNode
|
||||
func NewGoNode(t *C.char) unsafe.Pointer {
|
||||
var nodeTypes = node.NodeTypes()
|
||||
|
||||
typ := C.GoString(t)
|
||||
ctor, ok := nodeTypes[typ]
|
||||
if !ok {
|
||||
return unsafe.Pointer(nil)
|
||||
}
|
||||
|
||||
node := ctor()
|
||||
|
||||
ptr := gopointer.Save(node)
|
||||
return ptr
|
||||
}
|
||||
|
||||
//export GoNodeClose
|
||||
func GoNodeClose(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Close())
|
||||
}
|
||||
|
||||
//export GoNodePrepare
|
||||
func GoNodePrepare(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Prepare())
|
||||
}
|
||||
|
||||
//export GoNodeParse
|
||||
func GoNodeParse(p unsafe.Pointer, c *C.char) C.int {
|
||||
scfg := C.GoString(c)
|
||||
bcfg := []byte(scfg)
|
||||
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Parse(bcfg))
|
||||
}
|
||||
|
||||
//export GoNodeCheck
|
||||
func GoNodeCheck(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Check())
|
||||
}
|
||||
|
||||
//export GoNodeStart
|
||||
func GoNodeStart(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Start())
|
||||
}
|
||||
|
||||
//export GoNodeStop
|
||||
func GoNodeStop(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Stop())
|
||||
}
|
||||
|
||||
//export GoNodePause
|
||||
func GoNodePause(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Pause())
|
||||
}
|
||||
|
||||
//export GoNodeResume
|
||||
func GoNodeResume(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Resume())
|
||||
}
|
||||
|
||||
//export GoNodeRestart
|
||||
func GoNodeRestart(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Restart())
|
||||
}
|
||||
|
||||
//export GoNodeRead
|
||||
func GoNodeRead(p unsafe.Pointer) ([]byte, C.int) {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
|
||||
d, err := n.Read()
|
||||
if err != nil {
|
||||
return nil, errorToInt(err)
|
||||
}
|
||||
|
||||
return d, 0
|
||||
}
|
||||
|
||||
//export GoNodeWrite
|
||||
func GoNodeWrite(p unsafe.Pointer, data []byte) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Write(data))
|
||||
}
|
||||
|
||||
//export GoNodeReverse
|
||||
func GoNodeReverse(p unsafe.Pointer) C.int {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
return errorToInt(n.Reverse())
|
||||
}
|
||||
|
||||
//export GoNodeGetPollFDs
|
||||
func GoNodeGetPollFDs(p unsafe.Pointer) ([]int, C.int) {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
f, err := n.GetPollFDs()
|
||||
if err != nil {
|
||||
return nil, errorToInt(err)
|
||||
}
|
||||
|
||||
return f, 0
|
||||
}
|
||||
|
||||
//export GoNodeGetNetemFDs
|
||||
func GoNodeGetNetemFDs(p unsafe.Pointer) ([]int, C.int) {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
f, err := n.GetNetemFDs()
|
||||
if err != nil {
|
||||
return nil, errorToInt(err)
|
||||
}
|
||||
|
||||
return f, 0
|
||||
}
|
||||
|
||||
//export GoNodeDetails
|
||||
func GoNodeDetails(p unsafe.Pointer) *C.char {
|
||||
n := gopointer.Restore(p).(node.Node)
|
||||
d := n.Details()
|
||||
return C.CString(d)
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package node
|
||||
|
||||
/*
|
||||
#include <villas/node_type.h>
|
||||
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func registerNode(name string, ctor CreateNode) {
|
||||
|
||||
}
|
42
lib/nodes/go/pkg/node.go
Normal file
42
lib/nodes/go/pkg/node.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package node
|
||||
|
||||
type NodeCtor func() Node
|
||||
|
||||
type Node interface {
|
||||
Close() error
|
||||
|
||||
Prepare() error
|
||||
|
||||
Parse(cfg []byte) error
|
||||
|
||||
Check() error
|
||||
|
||||
Start() error
|
||||
Stop() error
|
||||
|
||||
Pause() error
|
||||
Resume() error
|
||||
Restart() error
|
||||
|
||||
Read() ([]byte, error)
|
||||
Write(data []byte) error
|
||||
|
||||
Reverse() error
|
||||
|
||||
GetPollFDs() ([]int, error)
|
||||
GetNetemFDs() ([]int, error)
|
||||
|
||||
// GetMemoryType()
|
||||
|
||||
Details() string
|
||||
}
|
||||
|
||||
type NodeConfig struct {
|
||||
Type string `json:"type"`
|
||||
|
||||
In struct {
|
||||
} `json:"in"`
|
||||
|
||||
Out struct {
|
||||
} `json:"out"`
|
||||
}
|
74
lib/nodes/go/pkg/nodes/loopback/loopback.go
Normal file
74
lib/nodes/go/pkg/nodes/loopback/loopback.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
node "git.rwth-aachen.de/acs/public/villas/node/pkg"
|
||||
)
|
||||
|
||||
type LoopbackNode struct {
|
||||
node.Node
|
||||
|
||||
channel chan []byte
|
||||
|
||||
Config LoopbackConfig
|
||||
}
|
||||
|
||||
type LoopbackConfig struct {
|
||||
node.NodeConfig
|
||||
|
||||
Value int `json:"value"`
|
||||
}
|
||||
|
||||
func NewLoopbackNode() node.Node {
|
||||
return &LoopbackNode{
|
||||
channel: make(chan []byte, 1024),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Parse(c []byte) error {
|
||||
return json.Unmarshal(c, &n.Config)
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Check() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Prepare() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Read() ([]byte, error) {
|
||||
return <-n.channel, nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Write(data []byte) error {
|
||||
n.channel <- data
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) PollFDs() []int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) NetemFDs() []int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *LoopbackNode) Details() string {
|
||||
return fmt.Sprintf("value=%d", n.Config.Value)
|
||||
}
|
||||
|
||||
func init() {
|
||||
node.RegisterNode("go.loopback", NewLoopbackNode)
|
||||
}
|
67
lib/nodes/go/pkg/nodes/webrtc/webrtc.go
Normal file
67
lib/nodes/go/pkg/nodes/webrtc/webrtc.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package nodes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
|
||||
node "git.rwth-aachen.de/acs/public/villas/node/pkg"
|
||||
)
|
||||
|
||||
type WebRTCNode struct {
|
||||
node.Node
|
||||
|
||||
Config WebRTCConfig
|
||||
}
|
||||
|
||||
type WebRTCConfig struct {
|
||||
RendezvouzToken string `json:"token,omitempty"`
|
||||
RendezvouzAddress url.URL `json:"address,omitempty"`
|
||||
}
|
||||
|
||||
func NewWebRTCNode() node.Node {
|
||||
return &WebRTCNode{}
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Parse(c []byte) error {
|
||||
return json.Unmarshal(c, &n.Config)
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Check() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Prepare() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Read() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Write(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) PollFDs() []int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) NetemFDs() []int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *WebRTCNode) Details() string {
|
||||
return "this-is-my-webrtc-node"
|
||||
}
|
||||
|
||||
func init() {
|
||||
node.RegisterNode("webrtc", NewWebRTCNode)
|
||||
}
|
13
lib/nodes/go/pkg/registry.go
Normal file
13
lib/nodes/go/pkg/registry.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package node
|
||||
|
||||
var (
|
||||
goNodeTypes = map[string]NodeCtor{}
|
||||
)
|
||||
|
||||
func RegisterNode(name string, ctor NodeCtor) {
|
||||
goNodeTypes[name] = ctor
|
||||
}
|
||||
|
||||
func NodeTypes() map[string]NodeCtor {
|
||||
return goNodeTypes
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package node
|
Loading…
Add table
Reference in a new issue