1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-23 00:00:01 +01:00
VILLASnode/go/pkg/nodes/webrtc/node.go
Steffen Vogel 7eec1bb753 update Steffens mail address
Signed-off-by: Steffen Vogel <post@steffenvogel.de>
2022-12-16 23:44:07 +01:00

220 lines
4.6 KiB
Go

/** 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)
}