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:
parent
472048a0d0
commit
b2955e3e3c
30 changed files with 0 additions and 2635 deletions
|
@ -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")
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
add_subdirectory(lib)
|
|
@ -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)
|
||||
}
|
||||
}
|
32
go/go.mod
32
go/go.mod
|
@ -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
154
go/go.sum
|
@ -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=
|
|
@ -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}
|
||||
)
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
190
go/lib/lib.go
190
go/lib/lib.go
|
@ -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)
|
||||
}
|
113
go/lib/logger.go
113
go/lib/logger.go
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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"`
|
||||
}
|
|
@ -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"`
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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{})
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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"`
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
|
|
288
lib/nodes/go.cpp
288
lib/nodes/go.cpp
|
@ -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;
|
Loading…
Add table
Reference in a new issue