1
0
Fork 0
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:
Steffen Vogel 2022-02-25 09:58:33 -05:00
parent 619c620e1a
commit db67c468bc
16 changed files with 840 additions and 296 deletions

View file

@ -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
View 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 */

View file

@ -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)

View file

@ -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;

View file

@ -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}
)

View file

@ -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
View 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
View 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
View 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
View 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)
}

View file

@ -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
View 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"`
}

View 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)
}

View 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)
}

View 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
}

View file

@ -1 +0,0 @@
package node