1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

remove Golang node-types

Signed-off-by: Steffen Vogel <post@steffenvogel.de>
This commit is contained in:
Steffen Vogel 2022-10-21 09:34:18 +00:00 committed by Philipp Jungkamp
parent 472048a0d0
commit b2955e3e3c
30 changed files with 0 additions and 2635 deletions

View file

@ -90,17 +90,10 @@ endif()
# Check programs
find_program(PROTOBUFC_COMPILER NAMES protoc-c)
find_program(PROTOBUF_COMPILER NAMES protoc)
find_program(GO NAMES go PATHS /usr/local/go/bin)
# Build without any GPL-code
option(WITHOUT_GPL "Build VILLASnode without any GPL code" OFF)
# Optionally download Go toolchain
option(DOWNLOAD_GO "Download Go toolchain" ON)
if(NOT GO AND DOWNLOAD_GO)
include("${CMAKE_CURRENT_LIST_DIR}/cmake/Go.cmake")
endif()
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig:/usr/local/share/pkgconfig:/usr/lib64/pkgconfig")
pkg_check_modules(JANSSON IMPORTED_TARGET REQUIRED jansson>=2.13)
@ -162,7 +155,6 @@ cmake_dependent_option(WITH_CLIENTS "Build client applications"
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 "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)
@ -181,7 +173,6 @@ 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 nodes-types" ON "WITH_GO" OFF)
cmake_dependent_option(WITH_NODE_IEC61850 "Build with iec61850 node-types" ON "LIBIEC61850_FOUND;NOT WITHOUT_GPL" OFF)
cmake_dependent_option(WITH_NODE_IEC60870 "Build with iec60870 node-types" ON "LIB60870_FOUND;NOT WITHOUT_GPL" OFF)
cmake_dependent_option(WITH_NODE_INFINIBAND "Build with infiniband node-type" ON "IBVerbs_FOUND; RDMACM_FOUND" OFF) # Infiniband node-type is currenly broken
@ -218,10 +209,6 @@ if(WITH_FPGA)
add_subdirectory(fpga)
endif()
if(WITH_GO)
add_subdirectory(go)
endif()
add_subdirectory(common)
add_subdirectory(etc)
add_subdirectory(lib)
@ -263,7 +250,6 @@ add_feature_info(CLIENTS WITH_CLIENTS "Build clien
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")
@ -282,7 +268,6 @@ add_feature_info(NODE_EXAMPLE WITH_NODE_EXAMPLE "Build with
add_feature_info(NODE_EXEC WITH_NODE_EXEC "Build with exec node-type")
add_feature_info(NODE_FILE WITH_NODE_FILE "Build with file node-type")
add_feature_info(NODE_FPGA WITH_NODE_FPGA "Build with fpga node-type")
add_feature_info(NODE_GO WITH_NODE_GO "Build with Go node-types")
add_feature_info(NODE_IEC61850 WITH_NODE_IEC61850 "Build with iec61850 node-types")
add_feature_info(NODE_IEC60870 WITH_NODE_IEC60870 "Build with iec60870 node-types")
add_feature_info(NODE_INFINIBAND WITH_NODE_INFINIBAND "Build with infiniband node-type")

View file

@ -1 +0,0 @@
add_subdirectory(lib)

View file

@ -1,108 +0,0 @@
/** Example of using libvillas node-types in Go code
*
* This example demonstrate how you can use VILLASnode's
* node-types from a Go application.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package main
import (
"log"
"os"
"time"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/config"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/node"
"github.com/google/uuid"
)
func main() {
cfg := &config.LoopbackNode{
Node: config.Node{
Name: "lo1",
Type: "loopback",
},
In: config.NodeLoopbackIn{
Hooks: []interface{}{
&config.PrintHook{
Hook: config.Hook{
Type: "print",
},
},
},
Signals: []config.Signal{
{
Name: "sig1",
},
{
Name: "sig2",
},
{
Name: "sig3",
},
},
},
}
n, err := node.NewNode(cfg, uuid.New())
if err != nil {
log.Fatalf("Failed to create node: %s", err)
}
defer n.Close()
if err := n.Check(); err != nil {
log.Fatalf("Failed to check node: %s", err)
}
if err := n.Prepare(); err != nil {
log.Fatalf("Failed to prepare node: %s", err)
}
if err := n.Start(); err != nil {
log.Fatalf("Failed to start node: %s", err)
}
defer n.Stop()
log.Printf("%s\n", n.NameFull())
now := time.Now()
smps_send := []node.Sample{
{
Sequence: 1234,
Timestamps: pkg.Timestamps{
Origin: pkg.Timestamp{now.Unix(), now.UnixNano()},
},
Data: []float64{1.1, 2.2, 3.3},
},
{
Sequence: 1235,
Timestamps: pkg.Timestamps{
Origin: pkg.Timestamp{now.Unix(), now.UnixNano()},
}, Data: []float64{4.4, 5.5, 6.6},
},
}
log.Printf("Sent: %+#v\n", smps_send)
cnt_written := n.Write(smps_send)
smps_received := n.Read(cnt_written)
log.Printf("Received: %+#v\n", smps_received)
if len(smps_send) != len(smps_received) {
log.Printf("Different length")
os.Exit(-1)
}
if smps_send[0].Data[0] != smps_received[0].Data[0] {
log.Printf("Different data")
os.Exit(-1)
}
}

View file

@ -1,32 +0,0 @@
module git.rwth-aachen.de/acs/public/villas/node/go
go 1.17
require (
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0
github.com/pion/webrtc/v3 v3.1.24
)
require (
github.com/pion/datachannel v1.5.2 // indirect
github.com/pion/dtls/v2 v2.1.3 // indirect
github.com/pion/ice/v2 v2.2.1 // indirect
github.com/pion/interceptor v0.1.7 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.5 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.9 // indirect
github.com/pion/rtp v1.7.4 // indirect
github.com/pion/sctp v1.8.2 // indirect
github.com/pion/sdp/v3 v3.0.4 // indirect
github.com/pion/srtp/v2 v2.0.5 // indirect
github.com/pion/stun v0.3.5 // indirect
github.com/pion/transport v0.13.0 // indirect
github.com/pion/turn/v2 v2.0.8 // indirect
github.com/pion/udp v0.1.1 // indirect
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

154
go/go.sum
View file

@ -1,154 +0,0 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
github.com/pion/dtls/v2 v2.1.2/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
github.com/pion/dtls/v2 v2.1.3 h1:3UF7udADqous+M2R5Uo2q/YaP4EzUoWKdfX2oscCUio=
github.com/pion/dtls/v2 v2.1.3/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
github.com/pion/ice/v2 v2.2.1 h1:R3MeuJZpU1ty3diPqpD5OxaxcZ15eprAc+EtUiSoFxg=
github.com/pion/ice/v2 v2.2.1/go.mod h1:Op8jlPtjeiycsXh93Cs4jK82C9j/kh7vef6ztIOvtIQ=
github.com/pion/interceptor v0.1.7 h1:HThW0tIIKT9RRoDWGURe8rlZVOx0fJHxBHpA0ej0+bo=
github.com/pion/interceptor v0.1.7/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA=
github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA=
github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ=
github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY=
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw=
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.1.24 h1:s9PuwisrgHe1FTqfwK4p3T7rXtAHaUNhycbdMjADT28=
github.com/pion/webrtc/v3 v3.1.24/go.mod h1:mO/yv7fBN3Lp7YNlnYcTj1jtpvNvssJG+7eh6itZ4xM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -1,34 +0,0 @@
set(LIB libvillas-go.a)
set(HEADER libvillas-go.h)
file(GLOB_RECURSE SRCS *.go)
file(GLOB_RECURSE NODE_SRCS ../pkg/nodes/*)
list(FILTER SRCS EXCLUDE REGEX /_obj/)
list(FILTER NODE_SRCS EXCLUDE REGEX /_obj/)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${HEADER}
DEPENDS ${SRCS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND env "GOPATH=${GOPATH}" "CGO_ENABLED=1" "GOARM=${GOARM}" "GOARCH=${GOARCH}" ${GO} tool cgo -exportheader "${CMAKE_CURRENT_BINARY_DIR}/${HEADER}" -- -I "${CMAKE_CURRENT_SOURCE_DIR}/../../include" ${SRCS}
COMMENT "Generating CGo header ${HEADER}"
COMMAND_EXPAND_LISTS
)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${LIB}
DEPENDS ${SRCS} ${NODE_SRCS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND env "PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig" "GOPATH=${GOPATH}" "CGO_ENABLED=1" "GOARM=${GOARM}" "GOARCH=${GOARCH}" "CGO_CFLAGS=-I${CMAKE_CURRENT_SOURCE_DIR}/../../include" ${GO} build -buildmode=c-archive -o "${CMAKE_CURRENT_BINARY_DIR}/${LIB}" ${CMAKE_GO_FLAGS} .
COMMENT "Building CGo library ${LIB}"
COMMAND_EXPAND_LISTS)
add_custom_target(villas-go-lib DEPENDS ${LIB})
add_custom_target(villas-go-header DEPENDS ${HEADER})
add_library(villas-go STATIC IMPORTED GLOBAL)
add_dependencies(villas-go villas-go-lib)
set_target_properties(villas-go
PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${LIB}"
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}
)

View file

@ -1,7 +0,0 @@
# Writing custom node-type in Go
This directory contains the required glue code for implementing custom node-types in the Go programming language.
Contents of this directory will be compiled into a static library and linked into 'libvillas.so'.
Have a look at the 'go.example' node-type implemented in '<villas-node-git>/go/pkg/nodes/example' for an example on how to implement your own node-type in Go.

View file

@ -1,21 +0,0 @@
/** Bridge code for call C-function pointers from Go code
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
#include <stdlib.h>
#include <villas/nodes/go.h>
void bridge_go_register_node_factory(_go_register_node_factory_cb cb, _go_plugin_list pl, char *name, char *desc, int flags)
{
cb(pl, name, desc, flags);
}
void bridge_go_logger_log(_go_logger_log_cb cb, _go_logger l, int level, char *msg)
{
cb(l, level, msg);
free(msg);
}

View file

@ -1,190 +0,0 @@
/** CGo interface for writing node-types in Go
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package main
// #include <stdint.h>
// #include <villas/nodes/go.h>
// void bridge_go_register_node_factory(_go_register_node_factory_cb cb, _go_plugin_list pl, char *name, char *desc, int flags);
import "C"
import (
"runtime/cgo"
"unsafe"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes"
_ "git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes/example"
_ "git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes/loopback"
_ "git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes/webrtc"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/errors"
)
func main() {}
type NodeType struct {
nodes.NodeType
}
//export RegisterGoNodeTypes
func RegisterGoNodeTypes(cb C._go_register_node_factory_cb, pl C._go_plugin_list) {
ntm := nodes.NodeTypes()
for n, t := range ntm {
C.bridge_go_register_node_factory(cb, pl, C.CString(n), C.CString(t.Description), C.int(t.Flags))
}
}
//export NewGoNode
func NewGoNode(t *C.char) C.uintptr_t {
nodeTypes := nodes.NodeTypes()
typ, ok := nodeTypes[C.GoString(t)]
if !ok {
return 0
}
node := typ.Constructor()
return C.uintptr_t(cgo.NewHandle(node))
}
//export GoNodeSetLogger
func GoNodeSetLogger(p C.uintptr_t, cb C._go_logger_log_cb, l C._go_logger) {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
n.SetLogger(NewVillasLogger(cb, l))
}
//export GoNodeClose
func GoNodeClose(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Close()))
}
//export GoNodePrepare
func GoNodePrepare(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Prepare()))
}
//export GoNodeParse
func GoNodeParse(p C.uintptr_t, c *C.char) C.int {
scfg := C.GoString(c)
bcfg := []byte(scfg)
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Parse(bcfg)))
}
//export GoNodeCheck
func GoNodeCheck(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Check()))
}
//export GoNodeStart
func GoNodeStart(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Start()))
}
//export GoNodeStop
func GoNodeStop(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Stop()))
}
//export GoNodePause
func GoNodePause(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Pause()))
}
//export GoNodeResume
func GoNodeResume(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Resume()))
}
//export GoNodeRestart
func GoNodeRestart(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Restart()))
}
//export GoNodeRead
func GoNodeRead(p C.uintptr_t, buf *C.char, sz C.int) (C.int, C.int) {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
src, err := n.Read()
if err != nil {
return -1, C.int(errors.ErrorToInt(err))
}
// Create slice which is backed by buf
dst := (*[1 << 30]byte)(unsafe.Pointer(buf))[:sz]
lsz := copy(dst, src)
return C.int(lsz), 0
}
//export GoNodeWrite
func GoNodeWrite(p C.uintptr_t, data []byte) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Write(data)))
}
//export GoNodeReverse
func GoNodeReverse(p C.uintptr_t) C.int {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
return C.int(errors.ErrorToInt(n.Reverse()))
}
//export GoNodeGetPollFDs
func GoNodeGetPollFDs(p C.uintptr_t) ([]int, C.int) {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
f, err := n.PollFDs()
if err != nil {
return nil, C.int(errors.ErrorToInt(err))
}
return f, 0
}
//export GoNodeGetNetemFDs
func GoNodeGetNetemFDs(p C.uintptr_t) ([]int, C.int) {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
f, err := n.NetemFDs()
if err != nil {
return nil, C.int(errors.ErrorToInt(err))
}
return f, 0
}
//export GoNodeDetails
func GoNodeDetails(p C.uintptr_t) *C.char {
h := cgo.Handle(p)
n := h.Value().(nodes.Node)
d := n.Details()
return C.CString(d)
}

View file

@ -1,113 +0,0 @@
/** CGo interface for VILLASnode logger
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package main
// #include <stdlib.h>
// #include <villas/nodes/go.h>
// void bridge_go_logger_log(_go_logger_log_cb cb, _go_logger l, int level, char *msg);
import "C"
import (
"fmt"
"os"
)
type LogLevel int
const (
// https://github.com/gabime/spdlog/blob/a51b4856377a71f81b6d74b9af459305c4c644f8/include/spdlog/common.h#L76
LogLevelTrace LogLevel = iota
LogLevelDebug LogLevel = iota
LogLevelInfo LogLevel = iota
LogLevelWarn LogLevel = iota
LogLevelError LogLevel = iota
LogLevelCritical LogLevel = iota
LogLevelOff LogLevel = iota
)
type VillasLogger struct {
inst C._go_logger
cb C._go_logger_log_cb
}
func NewVillasLogger(cb C._go_logger_log_cb, l C._go_logger) *VillasLogger {
return &VillasLogger{
cb: cb,
inst: l,
}
}
func (l *VillasLogger) log(lvl LogLevel, msg string) {
C.bridge_go_logger_log(l.cb, l.inst, C.int(lvl), C.CString(msg))
}
func (l *VillasLogger) Trace(msg string) {
l.log(LogLevelTrace, msg)
}
func (l *VillasLogger) Debug(msg string) {
l.log(LogLevelDebug, msg)
}
func (l *VillasLogger) Info(msg string) {
l.log(LogLevelInfo, msg)
}
func (l *VillasLogger) Warn(msg string) {
l.log(LogLevelWarn, msg)
}
func (l *VillasLogger) Error(msg string) {
l.log(LogLevelError, msg)
}
func (l *VillasLogger) Critical(msg string) {
l.log(LogLevelCritical, msg)
}
func (l *VillasLogger) Tracef(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
l.log(LogLevelTrace, msg)
}
func (l *VillasLogger) Debugf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
l.log(LogLevelDebug, msg)
}
func (l *VillasLogger) Infof(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
l.log(LogLevelInfo, msg)
}
func (l *VillasLogger) Warnf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
l.log(LogLevelWarn, msg)
}
func (l *VillasLogger) Errorf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
l.log(LogLevelError, msg)
}
func (l *VillasLogger) Criticalf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
l.log(LogLevelCritical, msg)
}
func (l *VillasLogger) Panic(msg string) {
l.Critical(msg)
fmt.Println("Paniced")
os.Exit(-1)
}
func (l *VillasLogger) Panicf(format string, args ...interface{}) {
l.Criticalf(format, args...)
fmt.Println("Paniced")
os.Exit(-1)
}

View file

@ -1,17 +0,0 @@
/** Go types for hook configuration.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package config
type Hook struct {
Type string `json:"type"`
Priority int `json:"priority,omitempty"`
}
type PrintHook struct {
Hook
}

View file

@ -1,28 +0,0 @@
/** Go types for node configuration.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package config
type Node struct {
Name string `json:"name"`
Type string `json:"type"`
}
type NodeDir struct{}
type NodeLoopbackIn struct {
NodeDir
Signals []Signal `json:"signals"`
Hooks []interface{} `json:"hooks"`
}
type LoopbackNode struct {
Node
In NodeLoopbackIn `json:"in"`
}

View file

@ -1,22 +0,0 @@
/** Go types for signal configuration.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package config
const (
SignalTypeFloat = "float"
SignalTypeInteger = "integer"
SignalTypeBoolean = "boolean"
SignalTypeComplex = "complex"
)
type Signal struct {
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Unit string `json:"unit,omitempty"`
Init float64 `json:"init,omitempty"`
}

View file

@ -1,31 +0,0 @@
/** Common error types
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package errors
import (
"C"
)
import "fmt"
var ErrEndOfFile = fmt.Errorf("end-of-file")
func ErrorToInt(e error) int {
if e == nil {
return 0
} else {
return -1
}
}
func IntToError(ret int) error {
if ret == 0 {
return nil
} else {
return fmt.Errorf("ret=%d", ret)
}
}

View file

@ -1,212 +0,0 @@
/** Wrapper for using libvillas in Go applications.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package node
// #cgo LDFLAGS: -lvillas
// #include <villas/node.h>
import "C"
import (
"encoding/json"
"fmt"
"log"
"unsafe"
"github.com/google/uuid"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/errors"
)
const (
MAX_SIGNALS = 64
NUM_HUGEPAGES = 100
)
type Node struct {
inst *C.vnode
}
func IsValidNodeNname(name string) bool {
return bool(C.node_is_valid_name(C.CString(name)))
}
func NewNode(cfg interface{}, sn_uuid uuid.UUID) (*Node, error) {
if js, err := json.Marshal(cfg); err != nil {
return nil, fmt.Errorf("failed to serialize config: %w", err)
} else {
log.Printf("Config = %s\n", js)
n := C.node_new(C.CString(string(js)), C.CString(sn_uuid.String()))
return &Node{n}, nil
}
}
func (n *Node) Prepare() error {
return errors.IntToError(int(C.node_prepare(n.inst)))
}
func (n *Node) Check() error {
return errors.IntToError(int(C.node_check(n.inst)))
}
func (n *Node) Start() error {
return errors.IntToError(int(C.node_start(n.inst)))
}
func (n *Node) Stop() error {
return errors.IntToError(int(C.node_stop(n.inst)))
}
func (n *Node) Pause() error {
return errors.IntToError(int(C.node_pause(n.inst)))
}
func (n *Node) Resume() error {
return errors.IntToError(int(C.node_resume(n.inst)))
}
func (n *Node) Restart() error {
return errors.IntToError(int(C.node_restart(n.inst)))
}
func (n *Node) Close() error {
return errors.IntToError(int(C.node_destroy(n.inst)))
}
func (n *Node) Reverse() error {
return errors.IntToError(int(C.node_reverse(n.inst)))
}
func (n *Node) Read(cnt int) []Sample {
csmps := make([]*C.vsample, cnt)
for i := 0; i < cnt; i++ {
csmps[i] = C.sample_alloc(MAX_SIGNALS)
}
read := int(C.node_read(n.inst, (**C.vsample)(unsafe.Pointer(&csmps[0])), C.uint(cnt)))
smps := make([]Sample, read)
for i := 0; i < read; i++ {
smps[i].FromC(csmps[i])
C.sample_decref(csmps[i])
}
return smps
}
func (n *Node) Write(smps []Sample) int {
cnt := len(smps)
csmps := make([]*C.vsample, cnt)
for i := 0; i < cnt; i++ {
csmps[i] = smps[i].ToC()
}
return int(C.node_write(n.inst, (**C.vsample)(unsafe.Pointer(&csmps[0])), C.uint(cnt)))
}
func (n *Node) PollFDs() []int {
var cfds [16]C.int
cnt := int(C.node_poll_fds(n.inst, (*C.int)(unsafe.Pointer(&cfds))))
fds := make([]int, cnt)
for i := 0; i < cnt; i++ {
fds[i] = int(cfds[i])
}
return fds
}
func (n *Node) NetemFDs() []int {
var cfds [16]C.int
cnt := int(C.node_netem_fds(n.inst, (*C.int)(unsafe.Pointer(&cfds))))
fds := make([]int, cnt)
for i := 0; i < cnt; i++ {
fds[i] = int(cfds[i])
}
return fds
}
func (n *Node) IsEnabled() bool {
return bool(C.node_is_enabled(n.inst))
}
func (n *Node) Name() string {
return C.GoString(C.node_name(n.inst))
}
func (n *Node) NameShort() string {
return C.GoString(C.node_name_short(n.inst))
}
func (n *Node) NameFull() string {
return C.GoString(C.node_name_full(n.inst))
}
func (n *Node) Details() string {
return C.GoString(C.node_details(n.inst))
}
func (n *Node) InputSignalsMaxCount() uint {
return uint(C.node_input_signals_max_cnt(n.inst))
}
func (n *Node) OutputSignalsMaxCount() uint {
return uint(C.node_output_signals_max_cnt(n.inst))
}
func (n *Node) ToJSON() string {
json_str := C.node_to_json_str(n.inst)
return C.GoString(json_str)
}
func init() {
C.memory_init(NUM_HUGEPAGES)
}
type Sample pkg.Sample
func (s *Sample) ToC() *C.vsample {
return C.sample_pack(
C.uint(s.Sequence),
&C.struct_timespec{
tv_sec: C.long(s.Timestamps.Origin[0]),
tv_nsec: C.long(s.Timestamps.Origin[1]),
},
&C.struct_timespec{
tv_sec: C.long(s.Timestamps.Received[0]),
tv_nsec: C.long(s.Timestamps.Received[1]),
},
C.uint(len(s.Data)),
(*C.double)(unsafe.Pointer(&s.Data[0])),
)
}
func (s *Sample) FromC(c *C.vsample) {
var tsOrigin C.struct_timespec
var tsReceived C.struct_timespec
len := C.sample_length(c)
s.Data = make([]float64, uint(len))
C.sample_unpack(c,
(*C.uint)(unsafe.Pointer(&s.Sequence)),
&tsOrigin,
&tsReceived,
(*C.int)(unsafe.Pointer(&s.Flags)),
&len,
(*C.double)(unsafe.Pointer(&s.Data[0])),
)
s.Timestamps.Origin = pkg.Timestamp{int64(tsOrigin.tv_sec), int64(tsOrigin.tv_nsec)}
s.Timestamps.Received = pkg.Timestamp{int64(tsReceived.tv_sec), int64(tsReceived.tv_nsec)}
}

View file

@ -1,95 +0,0 @@
/** Unit tests for using libvillas in Go code.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package node_test
import (
"testing"
"time"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/config"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/node"
"github.com/google/uuid"
)
func TestNode(t *testing.T) {
cfg := &config.LoopbackNode{
Node: config.Node{
Name: "lo1",
Type: "loopback",
},
In: config.NodeLoopbackIn{
Hooks: []interface{}{
&config.PrintHook{
Hook: config.Hook{
Type: "print",
},
},
},
Signals: []config.Signal{
{
Name: "sig1",
},
{
Name: "sig2",
},
{
Name: "sig3",
},
},
},
}
n, err := node.NewNode(cfg, uuid.New())
if err != nil {
t.Fatalf("Failed to create node: %s", err)
}
defer n.Close()
if err := n.Check(); err != nil {
t.Fatalf("Failed to check node: %s", err)
}
if err := n.Prepare(); err != nil {
t.Fatalf("Failed to prepare node: %s", err)
}
if err := n.Start(); err != nil {
t.Fatalf("Failed to start node: %s", err)
}
defer n.Stop()
t.Logf("%s", n.NameFull())
smps_send := []node.Sample{
{
Sequence: 1234,
TimestampOrigin: time.Now(),
Data: []float64{1.1, 2.2, 3.3},
},
{
Sequence: 1235,
TimestampOrigin: time.Now(),
Data: []float64{4.4, 5.5, 6.6},
},
}
t.Logf("Sent: %+#v", smps_send)
cnt_written := n.Write(smps_send)
if cnt_written != len(smps_send) {
t.Fatalf("Failed to send all samples")
}
smps_received := n.Read(cnt_written)
if len(smps_received) != cnt_written {
t.Fatalf("Failed to receive samples back")
}
t.Logf("Received: %+#v", smps_received)
}

View file

@ -1,63 +0,0 @@
/** Common code for implementing node-types in Go code.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package nodes
type BaseNode struct {
Node
Logger Logger
Stopped chan struct{}
}
func NewBaseNode() BaseNode {
return BaseNode{}
}
func (n *BaseNode) Start() error {
n.Stopped = make(chan struct{})
return nil
}
func (n *BaseNode) Stop() error {
close(n.Stopped)
return nil
}
func (n *BaseNode) Parse(c []byte) error {
return nil
}
func (n *BaseNode) Check() error {
return nil
}
func (n *BaseNode) Restart() error {
return nil
}
func (n *BaseNode) Pause() error {
return nil
}
func (n *BaseNode) Resume() error {
return nil
}
func (n *BaseNode) Reverse() error {
return nil
}
func (n *BaseNode) Close() error {
return nil
}
func (n *BaseNode) SetLogger(l Logger) {
n.Logger = l
}

View file

@ -1,102 +0,0 @@
/** Little example node-type written in Go code.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package nodes
import (
"encoding/json"
"fmt"
"time"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/errors"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes"
)
type Node struct {
nodes.BaseNode
ticker time.Ticker
lastSequence uint64
Config Config
}
type Config struct {
nodes.NodeConfig
Value int `json:"value"`
}
func NewNode() nodes.Node {
return &Node{
BaseNode: nodes.NewBaseNode(),
ticker: *time.NewTicker(1 * time.Second),
lastSequence: 0,
}
}
func (n *Node) Parse(c []byte) error {
return json.Unmarshal(c, &n.Config)
}
func (n *Node) Check() error {
return nil
}
func (n *Node) Prepare() error {
return nil
}
func (n *Node) Start() error {
n.Logger.Infof("hello from node")
n.Logger.Warnf("hello from node")
n.Logger.Errorf("hello from node")
n.Logger.Tracef("hello from node")
n.Logger.Criticalf("hello from node")
return n.BaseNode.Start()
}
func (n *Node) Read() ([]byte, error) {
select {
case <-n.Stopped:
return nil, errors.ErrEndOfFile
case <-n.ticker.C:
n.lastSequence++
smp := pkg.GenerateRandomSample()
smp.Sequence = n.lastSequence
smps := []pkg.Sample{smp}
return json.Marshal(smps)
}
}
func (n *Node) Write(data []byte) error {
n.Logger.Infof("Data: %s", string(data))
return nil
}
func (n *Node) PollFDs() ([]int, error) {
return []int{}, nil
}
func (n *Node) NetemFDs() ([]int, error) {
return []int{}, nil
}
func (n *Node) Details() string {
return fmt.Sprintf("value=%d", n.Config.Value)
}
func init() {
// Do not forget to import the package in go/lib/main.go!
nodes.RegisterNodeType("go.example", "A example node implemented in Go", NewNode, nodes.NodeSupportsRead|nodes.NodeSupportsWrite|nodes.NodeHidden)
}

View file

@ -1,25 +0,0 @@
/** Logger interface.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package nodes
type Logger interface {
Trace(msg string)
Debug(msg string)
Info(msg string)
Warn(msg string)
Error(msg string)
Critical(msg string)
Tracef(format string, args ...interface{})
Debugf(format string, args ...interface{})
Infof(format string, args ...interface{})
Warnf(format string, args ...interface{})
Errorf(format string, args ...interface{})
Criticalf(format string, args ...interface{})
Panic(msg string)
Panicf(format string, args ...interface{})
}

View file

@ -1,85 +0,0 @@
/** Simple loopback node-type written in Go code.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package nodes
import (
"encoding/json"
"fmt"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/errors"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes"
)
type Node struct {
nodes.BaseNode
channel chan []byte
Config LoopbackConfig
}
type LoopbackConfig struct {
nodes.NodeConfig
Value int `json:"value"`
}
func NewNode() nodes.Node {
return &Node{
BaseNode: nodes.NewBaseNode(),
channel: make(chan []byte, 1024),
}
}
func (n *Node) Parse(c []byte) error {
return json.Unmarshal(c, &n.Config)
}
func (n *Node) Check() error {
return nil
}
func (n *Node) Prepare() error {
return nil
}
func (n *Node) Start() error {
return n.BaseNode.Start()
}
func (n *Node) Read() ([]byte, error) {
select {
case <-n.Stopped:
return nil, errors.ErrEndOfFile
case buf := <-n.channel:
return buf, nil
}
}
func (n *Node) Write(data []byte) error {
n.channel <- data
return nil
}
func (n *Node) PollFDs() ([]int, error) {
return []int{}, nil
}
func (n *Node) NetemFDs() ([]int, error) {
return []int{}, nil
}
func (n *Node) Details() string {
return fmt.Sprintf("value=%d", n.Config.Value)
}
func init() {
nodes.RegisterNodeType("go.loopback", "A loopback node implmented in Go", NewNode, nodes.NodeSupportsRead|nodes.NodeSupportsWrite|nodes.NodeHidden)
}

View file

@ -1,57 +0,0 @@
/** Node interface.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package nodes
const (
NodeSupportsPoll = (1 << iota)
NodeSupportsRead = (1 << iota)
NodeSupportsWrite = (1 << iota)
NodeRequiresWeb = (1 << iota)
NodeProvidesSignals = (1 << iota)
NodeInternal = (1 << iota)
NodeHidden = (1 << iota)
)
type NodeConstructor 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
PollFDs() ([]int, error)
NetemFDs() ([]int, error)
Details() string
SetLogger(l Logger)
}
type NodeConfig struct {
Type string `json:"type"`
In struct{} `json:"in"`
Out struct{} `json:"out"`
}

View file

@ -1,28 +0,0 @@
/** Node-type registry.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package nodes
var goNodeTypes = map[string]NodeType{}
type NodeType struct {
Constructor NodeConstructor
Flags int
Description string
}
func RegisterNodeType(name string, desc string, ctor NodeConstructor, flags int) {
goNodeTypes[name] = NodeType{
Constructor: ctor,
Flags: flags,
Description: desc,
}
}
func NodeTypes() map[string]NodeType {
return goNodeTypes
}

View file

@ -1,38 +0,0 @@
/** Exponential backoffs for reconnect timing.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package webrtc
import "time"
var DefaultExponentialBackoff = ExponentialBackoff{
Factor: 1.5,
Maximum: 1 * time.Minute,
Initial: 1 * time.Second,
Duration: 1 * time.Second,
}
type ExponentialBackoff struct {
Factor float32
Maximum time.Duration
Initial time.Duration
Duration time.Duration
}
func (e *ExponentialBackoff) Next() time.Duration {
e.Duration = time.Duration(1.5 * float32(e.Duration)).Round(time.Second)
if e.Duration > e.Maximum {
e.Duration = e.Maximum
}
return e.Duration
}
func (e *ExponentialBackoff) Reset() {
e.Duration = e.Initial
}

View file

@ -1,173 +0,0 @@
/** Websocket signaling channel for WebRTC.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package webrtc
import (
"fmt"
"net/url"
"time"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes"
"github.com/gorilla/websocket"
)
type SignalingClient struct {
*websocket.Conn
logger nodes.Logger
URL *url.URL
done chan struct{}
isClosing bool
backoff ExponentialBackoff
messageCallbacks []func(msg *SignalingMessage)
connectCallbacks []func()
disconnectCallbacks []func()
}
func NewSignalingClient(u *url.URL, logger nodes.Logger) (*SignalingClient, error) {
c := &SignalingClient{
messageCallbacks: []func(msg *SignalingMessage){},
connectCallbacks: []func(){},
disconnectCallbacks: []func(){},
isClosing: false,
backoff: DefaultExponentialBackoff,
URL: u,
logger: logger,
}
return c, nil
}
func (c *SignalingClient) OnConnect(cb func()) {
c.connectCallbacks = append(c.connectCallbacks, cb)
}
func (c *SignalingClient) OnDisconnect(cb func()) {
c.disconnectCallbacks = append(c.connectCallbacks, cb)
}
func (c *SignalingClient) OnMessage(cb func(msg *SignalingMessage)) {
c.messageCallbacks = append(c.messageCallbacks, cb)
}
func (c *SignalingClient) SendSignalingMessage(msg *SignalingMessage) error {
c.logger.Infof("Sending signaling message: %s", msg)
return c.Conn.WriteJSON(msg)
}
func (c *SignalingClient) Close() error {
// Return immediatly if there is no open connection
if c.Conn == nil {
return nil
}
c.isClosing = true
// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.Conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(5*time.Second))
if err != nil {
return fmt.Errorf("failed to send close message: %s", err)
}
select {
case <-c.done:
c.logger.Infof("Connection closed")
case <-time.After(3 * time.Second):
c.logger.Warn("Timed-out waiting for connection close")
}
return nil
}
func (c *SignalingClient) Connect() error {
var err error
dialer := websocket.Dialer{
HandshakeTimeout: 1 * time.Second,
}
c.Conn, _, err = dialer.Dial(c.URL.String(), nil)
if err != nil {
return fmt.Errorf("failed to dial %s: %w", c.URL, err)
}
for _, cb := range c.connectCallbacks {
cb()
}
go c.read()
// Reset reconnect timer
c.backoff.Reset()
c.done = make(chan struct{})
return nil
}
func (c *SignalingClient) ConnectWithBackoff() error {
t := time.NewTimer(c.backoff.Duration)
for range t.C {
if err := c.Connect(); err != nil {
t.Reset(c.backoff.Next())
c.logger.Errorf("Failed to connect: %s. Reconnecting in %s", err, c.backoff.Duration)
} else {
break
}
}
return nil
}
func (c *SignalingClient) read() {
for {
msg := &SignalingMessage{}
if err := c.Conn.ReadJSON(msg); err != nil {
if websocket.IsCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) {
} else {
c.logger.Errorf("Failed to read: %s", err)
}
break
}
c.logger.Infof("Received signaling message: %s", msg)
for _, cb := range c.messageCallbacks {
cb(msg)
}
}
c.closed()
}
func (c *SignalingClient) closed() {
if err := c.Conn.Close(); err != nil {
c.logger.Errorf("Failed to close connection: %s", err)
}
c.Conn = nil
for _, cb := range c.disconnectCallbacks {
cb()
}
close(c.done)
if c.isClosing {
c.logger.Infof("Connection closed")
} else {
c.logger.Warnf("Connection lost. Reconnecting in %s", c.backoff.Duration)
go c.ConnectWithBackoff()
}
}

View file

@ -1,220 +0,0 @@
/** WebRTC node-type.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package webrtc
import (
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
verrors "git.rwth-aachen.de/acs/public/villas/node/go/pkg/errors"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes"
"github.com/pion/webrtc/v3"
)
var DefaultConfig = Config{
Server: &url.URL{
Scheme: "wss",
Host: "villas.k8s.eonerc.rwth-aachen.de",
Path: "/ws/signaling",
},
Wait: true,
MaxRetransmits: 0,
Ordered: false,
WebRTC: webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
{
URLs: []string{
"stun:stun.0l.de",
},
CredentialType: webrtc.ICECredentialTypePassword,
Username: "villas",
Credential: "villas",
},
{
URLs: []string{
"turn:turn.0l.de?transport=udp",
"turn:turn.0l.de?transport=tcp",
},
CredentialType: webrtc.ICECredentialTypePassword,
Username: "villas",
Credential: "villas",
},
},
},
}
type Node struct {
nodes.BaseNode
*PeerConnection
Config Config
}
type Config struct {
Server *url.URL
Session string
Wait bool
MaxRetransmits uint16
Ordered bool
WebRTC webrtc.Configuration
}
func NewNode() nodes.Node {
return &Node{
Config: DefaultConfig,
}
}
func (n *Node) Parse(c []byte) error {
var err error
var cfg struct {
Session *string `json:"session"`
Server *string `json:"server,omitempty"`
Wait *bool `json:"wait,omitemty"`
MaxRetransmits *uint16 `json:"max_retransmits,omitempty"`
Ordered *bool `json:"ordered,omitempty"`
Ice *struct {
Servers []struct {
URLs []string `json:"urls,omitempty"`
Username *string `json:"username,omitempty"`
Password *string `json:"password,omitempty"`
} `json:"servers,omitempty"`
} `json:"ice,omitempty"`
}
if err := json.Unmarshal(c, &cfg); err != nil {
return fmt.Errorf("failed to unmarshal config: %w", err)
}
if cfg.Wait != nil {
n.Config.Wait = *cfg.Wait
}
if cfg.Ordered != nil {
n.Config.Ordered = *cfg.Ordered
}
if cfg.MaxRetransmits != nil {
n.Config.MaxRetransmits = *cfg.MaxRetransmits
}
if cfg.Session == nil || *cfg.Session == "" {
return errors.New("missing or invalid session name")
} else {
n.Config.Session = *cfg.Session
}
if cfg.Server != nil {
n.Config.Server, err = url.Parse(*cfg.Server)
if err != nil {
return fmt.Errorf("failed to parse server address: %w", err)
}
}
if cfg.Ice != nil {
for _, server := range cfg.Ice.Servers {
iceServer := webrtc.ICEServer{
URLs: server.URLs,
}
if server.Username != nil && server.Password != nil {
iceServer.Username = *server.Username
iceServer.CredentialType = webrtc.ICECredentialTypePassword
iceServer.Credential = *server.Password
}
n.Config.WebRTC.ICEServers = append(n.Config.WebRTC.ICEServers, iceServer)
}
}
return nil
}
func (n *Node) Prepare() error {
var err error
n.PeerConnection, err = NewPeerConnection(&n.Config, n.Logger)
if err != nil {
return fmt.Errorf("failed to create peer connection: %w", err)
}
return nil
}
func (n *Node) Start() error {
n.DataChannelLock.Lock()
defer n.DataChannelLock.Unlock()
if n.Config.Wait {
n.Logger.Info("Waiting until datachannel is connected...")
for n.DataChannel == nil {
n.DataChannelConnected.Wait()
}
}
return n.BaseNode.Start()
}
func (n *Node) Read() ([]byte, error) {
select {
case <-n.Stopped:
return nil, verrors.ErrEndOfFile
case b := <-n.PeerConnection.ReceivedMessages:
return b, nil
}
}
func (n *Node) Write(data []byte) error {
n.DataChannelLock.Lock()
defer n.DataChannelLock.Unlock()
if n.DataChannel == nil {
n.logger.Infof("No datachannel open. Skipping sample...")
return nil
}
return n.DataChannel.Send(data)
}
func (n *Node) PollFDs() ([]int, error) {
return []int{}, nil
}
func (n *Node) NetemFDs() ([]int, error) {
return []int{}, nil
}
func (n *Node) Details() string {
details := map[string]string{
"server": n.Config.Server.String(),
"session": n.Config.Session,
}
kv := []string{}
for k, v := range details {
kv = append(kv, fmt.Sprintf("%s=%s", k, v))
}
return strings.Join(kv, ", ")
}
func (n *Node) Close() error {
return nil
}
func init() {
nodes.RegisterNodeType("webrtc", "Web Real-time Communication", NewNode, nodes.NodeSupportsRead|nodes.NodeSupportsWrite)
}

View file

@ -1,44 +0,0 @@
/** Types for WebRTC node-type.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package webrtc
import (
"encoding/json"
"time"
"github.com/pion/webrtc/v3"
)
type Connection struct {
ID int `json:"id"`
Remote string `json:"remote"`
UserAgent string `json:"user_agent"`
Created time.Time `json:"created"`
}
type ControlMessage struct {
ConnectionID int `json:"connection_id"`
Connections []Connection `json:"connections"`
}
type Role struct {
Polite bool `json:"polite"`
First bool `json:"first"`
}
type SignalingMessage struct {
Description *webrtc.SessionDescription `json:"description,omitempty"`
Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"`
Control *ControlMessage `json:"control,omitempty"`
}
func (msg SignalingMessage) String() string {
b, _ := json.Marshal(msg)
return string(b)
}

View file

@ -1,341 +0,0 @@
/** WebRTC peer connection handling.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package webrtc
import (
"fmt"
"path"
"sync"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/nodes"
"github.com/pion/webrtc/v3"
)
type PeerConnection struct {
*webrtc.PeerConnection
*SignalingClient
config *Config
logger nodes.Logger
makingOffer bool
ignoreOffer bool
first bool
polite bool
rollback bool
DataChannel *webrtc.DataChannel
DataChannelLock sync.Mutex
DataChannelConnected *sync.Cond
ReceivedMessages chan []byte
}
func NewPeerConnection(config *Config, logger nodes.Logger) (*PeerConnection, error) {
u := *config.Server
u.Path = path.Join(u.Path, config.Session)
sc, err := NewSignalingClient(&u, logger)
if err != nil {
return nil, fmt.Errorf("failed to create signaling client: %w", err)
}
ppc := &PeerConnection{
SignalingClient: sc,
config: config,
logger: logger,
DataChannel: nil,
ReceivedMessages: make(chan []byte, 1024),
}
ppc.DataChannelConnected = sync.NewCond(&ppc.DataChannelLock)
ppc.SignalingClient.OnMessage(ppc.OnSignalingMessageHandler)
ppc.SignalingClient.OnConnect(ppc.OnSignalingConnectedHandler)
if err := ppc.SignalingClient.ConnectWithBackoff(); err != nil {
return nil, fmt.Errorf("failed to connect signaling client: %w", err)
}
return ppc, nil
}
func (pc *PeerConnection) createPeerConnection() (*webrtc.PeerConnection, error) {
pc.logger.Info("Created new peer connection")
// Create a new RTCPeerConnection
ppc, err := webrtc.NewPeerConnection(pc.config.WebRTC)
if err != nil {
return nil, fmt.Errorf("failed to create peer connection: %w", err)
}
// Set the handler for ICE connection state
// This will notify you when the peer has connected/disconnected
ppc.OnConnectionStateChange(pc.OnConnectionStateChangeHandler)
ppc.OnSignalingStateChange(pc.OnSignalingStateChangeHandler)
ppc.OnICECandidate(pc.OnICECandidateHandler)
ppc.OnNegotiationNeeded(pc.OnNegotiationNeededHandler)
ppc.OnDataChannel(pc.OnDataChannelHandler)
return ppc, nil
}
func (pc *PeerConnection) createDataChannel() (*webrtc.DataChannel, error) {
dc, err := pc.CreateDataChannel("villas", &webrtc.DataChannelInit{
Ordered: &pc.config.Ordered,
MaxRetransmits: &pc.config.MaxRetransmits,
})
if err != nil {
return nil, fmt.Errorf("failed to create datachannel: %w", err)
}
close := make(chan struct{})
dc.OnClose(func() { pc.OnDataChannelCloseHandler(dc, close) })
dc.OnOpen(func() { pc.OnDataChannelOpenHandler(dc, close) })
dc.OnMessage(func(msg webrtc.DataChannelMessage) { pc.OnDataChannelMessageHandler(dc, &msg, close) })
return dc, nil
}
func (pc *PeerConnection) rollbackPeerConnection() (*webrtc.PeerConnection, error) {
pc.rollback = true
defer func() { pc.rollback = false }()
// Close previous peer connection in before creating a new one
// We need to do this as pion/webrtc currently does not support rollbacks
if err := pc.PeerConnection.Close(); err != nil {
return nil, fmt.Errorf("failed to close peer connection: %w", err)
}
if ppc, err := pc.createPeerConnection(); err != nil {
return nil, err
} else {
return ppc, nil
}
}
func (pc *PeerConnection) OnConnectionCreated() error {
if !pc.first {
if _, err := pc.createDataChannel(); err != nil {
return err
}
}
return nil
}
func (pc *PeerConnection) OnDataChannelOpenHandler(dc *webrtc.DataChannel, close chan struct{}) {
pc.logger.Infof("DataChannel opened: %s", dc.Label())
pc.DataChannelLock.Lock()
defer pc.DataChannelLock.Unlock()
pc.DataChannel = dc
pc.DataChannelConnected.Broadcast()
}
func (pc *PeerConnection) OnDataChannelCloseHandler(dc *webrtc.DataChannel, cl chan struct{}) {
pc.logger.Infof("DataChannel closed: %s", dc.Label())
pc.DataChannel = nil
close(cl)
// We close the connection here to avoid waiting for the disconnected event
if err := pc.PeerConnection.Close(); err != nil {
pc.logger.Errorf("Failed to close peer connection: %s", err)
}
}
func (pc *PeerConnection) OnDataChannelMessageHandler(dc *webrtc.DataChannel, msg *webrtc.DataChannelMessage, close chan struct{}) {
pc.logger.Debugf("Received: %s", string(msg.Data))
pc.ReceivedMessages <- msg.Data
}
func (pc *PeerConnection) OnDataChannelHandler(dc *webrtc.DataChannel) {
pc.logger.Infof("New DataChannel opened: %s", dc.Label())
close := make(chan struct{})
dc.OnOpen(func() { pc.OnDataChannelOpenHandler(dc, close) })
dc.OnClose(func() { pc.OnDataChannelCloseHandler(dc, close) })
dc.OnMessage(func(msg webrtc.DataChannelMessage) { pc.OnDataChannelMessageHandler(dc, &msg, close) })
}
func (pc *PeerConnection) OnICECandidateHandler(c *webrtc.ICECandidate) {
if c == nil {
pc.logger.Info("Candidate gathering concluded")
return
}
pc.logger.Infof("Found new candidate: %s", c)
ci := c.ToJSON()
if err := pc.SendSignalingMessage(&SignalingMessage{
Candidate: &ci,
}); err != nil {
pc.logger.Errorf("Failed to send candidate: %s", err)
}
}
func (pc *PeerConnection) OnNegotiationNeededHandler() {
pc.logger.Info("Negotation needed!")
pc.makingOffer = true
offer, err := pc.CreateOffer(nil)
if err != nil {
pc.logger.Panicf("Failed to create offer: %s", err)
}
if err := pc.SetLocalDescription(offer); err != nil {
pc.logger.Panicf("Failed to set local description: %s", err)
}
if err := pc.SendSignalingMessage(&SignalingMessage{
Description: &offer,
}); err != nil {
pc.logger.Panicf("Failed to send offer: %s", err)
}
pc.makingOffer = false
}
func (pc *PeerConnection) OnSignalingStateChangeHandler(ss webrtc.SignalingState) {
pc.logger.Infof("Signaling State has changed: %s", ss.String())
}
func (pc *PeerConnection) OnConnectionStateChangeHandler(pcs webrtc.PeerConnectionState) {
pc.logger.Infof("Connection State has changed: %s", pcs.String())
switch pcs {
case webrtc.PeerConnectionStateFailed:
fallthrough
case webrtc.PeerConnectionStateDisconnected:
pc.logger.Info("Closing peer connection")
if err := pc.PeerConnection.Close(); err != nil {
pc.logger.Panicf("Failed to close peer connection: %s", err)
}
case webrtc.PeerConnectionStateClosed:
if pc.rollback {
return
}
pc.logger.Info("Closed peer connection")
var err error
pc.PeerConnection, err = pc.createPeerConnection()
if err != nil {
pc.logger.Panicf("Failed to set re-create peer connection: %s", err)
}
if err := pc.OnConnectionCreated(); err != nil {
pc.logger.Panicf("Failed to create connection: %w", err)
}
}
}
func (pc *PeerConnection) OnSignalingConnectedHandler() {
var err error
pc.logger.Info("Signaling connected")
// Create initial peer connection
if pc.PeerConnection == nil {
if pc.PeerConnection, err = pc.createPeerConnection(); err != nil {
pc.logger.Panicf("Failed to create peer connection: %s", err)
}
if err := pc.OnConnectionCreated(); err != nil {
pc.logger.Panicf("Failed to create connection: %s", err)
}
}
}
func (pc *PeerConnection) OnSignalingMessageHandler(msg *SignalingMessage) {
var err error
if msg.Control != nil {
if len(msg.Control.Connections) > 2 {
pc.logger.Panicf("There are already two peers connected to this session.")
}
// The peer with the smallest connection ID connected first
pc.first = true
for _, c := range msg.Control.Connections {
if c.ID < msg.Control.ConnectionID {
pc.first = false
}
}
pc.polite = pc.first
pc.logger.Infof("New role: polite=%v, first=%v", pc.polite, pc.first)
} else if msg.Description != nil {
readyForOffer := !pc.makingOffer && pc.SignalingState() == webrtc.SignalingStateStable
offerCollision := msg.Description.Type == webrtc.SDPTypeOffer && !readyForOffer
pc.ignoreOffer = !pc.polite && offerCollision
if pc.ignoreOffer {
return
}
if msg.Description.Type == webrtc.SDPTypeOffer && pc.PeerConnection.SignalingState() != webrtc.SignalingStateStable {
if pc.PeerConnection, err = pc.rollbackPeerConnection(); err != nil {
pc.logger.Panicf("Failed to rollback peer connection: %s", err)
}
if err := pc.OnConnectionCreated(); err != nil {
pc.logger.Panicf("Failed to create connection: %s", err)
}
}
if err := pc.PeerConnection.SetRemoteDescription(*msg.Description); err != nil {
pc.logger.Panicf("Failed to set remote description: %s", err)
}
if msg.Description.Type == webrtc.SDPTypeOffer {
answer, err := pc.PeerConnection.CreateAnswer(nil)
if err != nil {
pc.logger.Panicf("Failed to create answer: %s", err)
}
if err := pc.SetLocalDescription(answer); err != nil {
pc.logger.Panicf("Failed to rollback signaling state: %s", err)
}
pc.SendSignalingMessage(&SignalingMessage{
Description: pc.LocalDescription(),
})
}
} else if msg.Candidate != nil {
if err := pc.AddICECandidate(*msg.Candidate); err != nil && !pc.ignoreOffer {
pc.logger.Panicf("Failed to add new ICE candidate: %s", err)
}
}
}
func (pc *PeerConnection) Close() error {
if err := pc.SignalingClient.Close(); err != nil {
return fmt.Errorf("failed to close signaling client: %w", err)
}
if err := pc.PeerConnection.Close(); err != nil {
return fmt.Errorf("failed to close peer connection: %w", err)
}
return nil
}

View file

@ -1,79 +0,0 @@
/** Sample datastructure.
*
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
package pkg
import (
"encoding/json"
"math/rand"
"time"
)
type Timestamp [2]int64
func TimestampFromTime(t time.Time) Timestamp {
return Timestamp{t.Unix(), int64(t.Nanosecond())}
}
type Timestamps struct {
Origin Timestamp `json:"origin"`
Received Timestamp `json:"received"`
}
type Sample struct {
Flags int `json:"-"`
Timestamps Timestamps `json:"ts"`
Sequence uint64 `json:"sequence"`
Data []float64 `json:"data"`
}
func GenerateRandomSample() Sample {
now := time.Now()
return Sample{
Timestamps: Timestamps{
Origin: TimestampFromTime(now),
},
Sequence: 1,
Data: []float64{
1 * rand.Float64(),
10 * rand.Float64(),
100 * rand.Float64(),
},
}
}
func (s Sample) Bytes() []byte {
b, _ := json.Marshal(s)
return b
}
func (s Sample) Equal(t Sample) bool {
if s.Flags != t.Flags {
return false
}
if s.Sequence != t.Sequence {
return false
}
if s.Timestamps != t.Timestamps {
return false
}
if len(s.Data) != len(t.Data) {
return false
}
for i, va := range s.Data {
if vb := t.Data[i]; va != vb {
return false
}
}
return true
}

View file

@ -13,12 +13,6 @@ if(WITH_WEB)
list(APPEND NODE_SRC api.cpp)
endif()
# Enable Golang support
if(WITH_NODE_GO)
list(APPEND NODE_SRC go.cpp)
list(APPEND LIBRARIES villas-go)
endif()
if(LIBNL3_ROUTE_FOUND)
list(APPEND LIBRARIES PkgConfig::LIBNL3_ROUTE)
endif()
@ -195,9 +189,3 @@ endif()
add_library(nodes STATIC ${NODE_SRC})
target_include_directories(nodes PUBLIC ${INCLUDE_DIRS})
target_link_libraries(nodes PUBLIC ${LIBRARIES})
if(WITH_NODE_GO)
add_dependencies(nodes villas-go-header)
target_include_directories(nodes PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/../../go/lib)
target_link_libraries(nodes PUBLIC villas-go)
endif()

View file

@ -1,288 +0,0 @@
/** Node-type implemeted in Go language
*
* @file
* @author Steffen Vogel <post@steffenvogel.de>
* @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
* @license Apache 2.0
*********************************************************************************/
#include <villas/nodes/go.hpp>
#include <villas/plugin.hpp>
#include <villas/format.hpp>
extern "C" {
#include <libvillas-go.h>
#include <villas/nodes/go.h>
}
using namespace villas;
using namespace villas::node;
void _go_register_node_factory(_go_plugin_list pl, char *name, char *desc, int flags)
{
auto *plugins = (villas::plugin::List<> *) pl;
plugins->push_back(new villas::node::GoNodeFactory(name, desc, flags));
}
_go_logger * _go_logger_get(char *name)
{
return (_go_logger *) villas::logging.get(name).get();
}
void _go_logger_log(_go_logger l, int level, char *msg)
{
auto *log = (spdlog::logger *) l;
log->log((spdlog::level::level_enum) level, "{}", msg);
}
GoNode::GoNode(uintptr_t n) :
Node(),
node(n),
formatter(nullptr)
{ }
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;
GoNodeSetLogger(node, _go_logger_log, logger.get());
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 = Node::stop();
if (ret)
return ret;
ret = GoNodeStop(node);
if (ret)
return ret;
return 0;
}
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;
char data[DEFAULT_FORMAT_BUFFER_LENGTH];
size_t rbytes;
auto d = GoNodeRead(node, data, sizeof(data));
if (d.r1)
return d.r1;
ret = formatter->sscan(data, d.r0, &rbytes, smps, cnt);
if (ret < 0 || (size_t) d.r0 != rbytes) {
logger->warn("Received invalid packet: ret={}, bytes={}, rbytes={}", ret, d.r0, rbytes);
return ret;
}
return ret;
}
int GoNode::_write(struct Sample * smps[], unsigned cnt)
{
int ret;
char buf[DEFAULT_FORMAT_BUFFER_LENGTH];
size_t wbytes;
ret = formatter->sprint(buf, DEFAULT_FORMAT_BUFFER_LENGTH, &wbytes, smps, cnt);
if (ret < 0)
return ret;
GoSlice slice = {
data: buf,
len: GoInt(wbytes),
cap: DEFAULT_FORMAT_BUFFER_LENGTH
};
ret = GoNodeWrite(node, slice);
if (ret)
return ret;
return cnt;
}
int GoNode::restart()
{
assert(state == State::STARTED);
logger->info("Restarting node");
return GoNodeRestart(node);
}
int GoNode::reverse()
{
return GoNodeReverse(node);
}
Node * GoNodeFactory::make()
{
auto nt = NewGoNode((char *) name.c_str());
if (!nt)
return nullptr;
auto *n = new GoNode(nt);
init(n);
GoNodeSetLogger(n->node, _go_logger_log, n->logger.get());
return n;
}
GoPluginRegistry::GoPluginRegistry() {
if (plugin::registry == nullptr)
plugin::registry = new plugin::Registry();
plugin::registry->addSubRegistry(this);
}
villas::plugin::List<> GoPluginRegistry::lookup()
{
plugin::List<> plugins;
RegisterGoNodeTypes(_go_register_node_factory, &plugins);
return plugins;
}
static GoPluginRegistry pr;