Skip to content

Commit

Permalink
feat: listeners support
Browse files Browse the repository at this point in the history
  • Loading branch information
agaffney committed Apr 10, 2024
1 parent dab11f0 commit 1ac25af
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 10 deletions.
4 changes: 2 additions & 2 deletions cmd/node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func main() {
fmt.Printf("%s %s\n", programName, version.GetVersionString())
os.Exit(0)
}
// Configure default logger
// Configure logger
logLevel := slog.LevelInfo
if globalFlags.debug {
logLevel = slog.LevelDebug
Expand All @@ -53,7 +53,7 @@ func main() {
)
slog.SetDefault(logger)
// Run node
if err := node.Run(); err != nil {
if err := node.Run(logger); err != nil {
slog.Error(err.Error())
os.Exit(1)
}
Expand Down
109 changes: 109 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2024 Blink Labs Software
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package node

import (
"fmt"
"io"
"log/slog"

ouroboros "github.com/blinklabs-io/gouroboros"
)

type Config struct {
logger *slog.Logger
listeners []ListenerConfig
network string
networkMagic uint32
peerSharing bool
// TODO
}

// configPopulateNetworkMagic uses the named network (if specified) to determine the network magic value (if not specified)
func (n *Node) configPopulateNetworkMagic() error {
if n.config.networkMagic == 0 && n.config.network != "" {
tmpCfg := n.config
tmpNetwork := ouroboros.NetworkByName(n.config.network)
if tmpNetwork == ouroboros.NetworkInvalid {
return fmt.Errorf("unknown network name: %s", n.config.network)
}
tmpCfg.networkMagic = tmpNetwork.NetworkMagic
n.config = tmpCfg
}
return nil
}

func (n *Node) configValidate() error {
if n.config.networkMagic == 0 {
return fmt.Errorf("invalid network magic value: %d", n.config.networkMagic)
}
if len(n.config.listeners) == 0 {
return fmt.Errorf("no listeners defined")
}
return nil
}

// ConfigOptionFunc is a type that represents functions that modify the Connection config
type ConfigOptionFunc func(*Config)

// NewConfig creates a new node config with the specified options
func NewConfig(opts ...ConfigOptionFunc) Config {
c := Config{
// Default logger will throw away logs
// We do this so we don't have to add guards around every log operation
logger: slog.New(slog.NewJSONHandler(io.Discard, nil)),
// TODO: add defaults
}
// Apply options
for _, opt := range opts {
opt(&c)
}
return c
}

// WithLogger specifies the logger to use. This defaults to discarding log output
func WithLogger(logger *slog.Logger) ConfigOptionFunc {
return func(c *Config) {
c.logger = logger
}
}

// WithListeners specifies the listener config(s) to use
func WithListeners(listeners ...ListenerConfig) ConfigOptionFunc {
return func(c *Config) {
c.listeners = append(c.listeners, listeners...)
}
}

// WithNetwork specifies the named network to operate on. This will automatically set the appropriate network magic value
func WithNetwork(network string) ConfigOptionFunc {
return func(c *Config) {
c.network = network
}
}

// WithNetworkMagic specifies the network magic value to use. This will override any named network specified
func WithNetworkMagic(networkMagic uint32) ConfigOptionFunc {
return func(c *Config) {
c.networkMagic = networkMagic
}
}

// WithPeerSharing specifies whether to enable peer sharing. This is disabled by default
func WithPeerSharing(peerSharing bool) ConfigOptionFunc {
return func(c *Config) {
c.peerSharing = peerSharing
}
}
12 changes: 11 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ module github.com/blinklabs-io/node

go 1.21.5

require github.com/spf13/cobra v1.8.0
require (
github.com/blinklabs-io/gouroboros v0.78.0
github.com/spf13/cobra v1.8.0
)

require (
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/utxorpc/go-codegen v0.4.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
24 changes: 24 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
github.com/blinklabs-io/gouroboros v0.78.0 h1:m/qI5WhN4ZpF96p+dQteiqWP0w+jn1vpL2BG/9JCjgo=
github.com/blinklabs-io/gouroboros v0.78.0/go.mod h1:xlSqLRuMknQWY73AJCx2HRWo49BfyGnreYT1t3/riVo=
github.com/blinklabs-io/ouroboros-mock v0.3.0 h1:6VRWyhAv0k7nQEgzFpuqhS/n8OM+OAaLN/sCT5K2Hbc=
github.com/blinklabs-io/ouroboros-mock v0.3.0/go.mod h1:0dzTNEk/Kvqa7qYHDy7/Nn3OTt+EOosMknB37FRzI1k=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA=
github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/utxorpc/go-codegen v0.4.4 h1:NnRFkqKJ9ZkZ3pffpD3bb6K0IU6IaDXbkVD/DzDmuKs=
github.com/utxorpc/go-codegen v0.4.4/go.mod h1:NWAVa5/vHWgSrp/wJzXnMpbaBeST0PmWCU5vX63hZdw=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
25 changes: 21 additions & 4 deletions internal/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,31 @@ package node

import (
"log/slog"
"net"

"github.com/blinklabs-io/node"
)

func Run() error {
// TODO
slog.Info("running node")
n, err := node.New()
func Run(logger *slog.Logger) error {
logger.Info("running node")
// TODO: make this configurable
l, err := net.Listen("tcp", ":3000")
if err != nil {
return err
}
logger.Info("listening for connections on :3000")
n, err := node.New(
node.NewConfig(
node.WithLogger(logger),
// TODO: make this configurable
node.WithNetwork("preview"),
node.WithListeners(
node.ListenerConfig{
Listener: l,
},
),
),
)
if err != nil {
return err
}
Expand Down
60 changes: 60 additions & 0 deletions listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2024 Blink Labs Software
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package node

import (
"fmt"
"net"

ouroboros "github.com/blinklabs-io/gouroboros"
)

type ListenerConfig struct {
UseNtC bool
Listener net.Listener
// TODO
}

func (n *Node) startListener(l ListenerConfig) {
defaultConnOpts := []ouroboros.ConnectionOptionFunc{
ouroboros.WithNetworkMagic(n.config.networkMagic),
ouroboros.WithNodeToNode(!l.UseNtC),
ouroboros.WithServer(true),
ouroboros.WithPeerSharing(n.config.peerSharing),
// TODO: add protocol configs to configure callback functions
}
for {
// Accept connection
conn, err := l.Listener.Accept()
if err != nil {
n.config.logger.Error(fmt.Sprintf("accept failed: %s", err))
continue
}
n.config.logger.Info(fmt.Sprintf("accepted connection from %s", conn.RemoteAddr()))
// Setup Ouroboros connection
connOpts := append(
defaultConnOpts,
ouroboros.WithConnection(conn),
)
oConn, err := ouroboros.NewConnection(connOpts...)
if err != nil {
n.config.logger.Error(fmt.Sprintf("failed to setup connection: %s", err))
continue
}
// Add to connection manager
// TODO: add tags for connection for later tracking
n.connManager.AddConnection(oConn)
}
}
50 changes: 47 additions & 3 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,60 @@

package node

import (
"fmt"

ouroboros "github.com/blinklabs-io/gouroboros"
)

type Node struct {
config Config
connManager *ouroboros.ConnectionManager
// TODO
}

func New() (*Node, error) {
// TODO
return &Node{}, nil
func New(cfg Config) (*Node, error) {
n := &Node{
config: cfg,
}
if err := n.configPopulateNetworkMagic(); err != nil {
return nil, fmt.Errorf("invalid configuration: %s", err)
}
if err := n.configValidate(); err != nil {
return nil, fmt.Errorf("invalid configuration: %s", err)
}
return n, nil
}

func (n *Node) Run() error {
// Configure connection manager
n.connManager = ouroboros.NewConnectionManager(
ouroboros.ConnectionManagerConfig{
ConnClosedFunc: n.connectionManagerConnClosed,
},
)
// Start listeners
for _, l := range n.config.listeners {
go n.startListener(l)
}
// TODO

// Wait forever
select {}
return nil
}

func (n *Node) connectionManagerConnClosed(connId ouroboros.ConnectionId, err error) {
if err != nil {
n.config.logger.Error(fmt.Sprintf("unexpected connection failure: %s: %s", connId.String(), err))
} else {
n.config.logger.Info(fmt.Sprintf("connection closed: %s", connId.String()))
}
conn := n.connManager.GetConnectionById(connId)
if conn == nil {
return
}
// Remove connection
n.connManager.RemoveConnection(connId)
// TODO: additional cleanup
}

0 comments on commit 1ac25af

Please sign in to comment.