Skip to content

Commit

Permalink
Adding cmd to the networkhub
Browse files Browse the repository at this point in the history
  • Loading branch information
otherview committed Jun 7, 2024
1 parent 8fd68db commit 6495fe5
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 16 deletions.
18 changes: 17 additions & 1 deletion .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,23 @@ networkHub is a versatile framework designed to streamline the process of launch
networkHub enables teams to quickly deploy custom networks, facilitating development and testing in a controlled environment. This framework is especially beneficial for protocol and dapp teams looking to experiment with network configurations and behaviors without the overhead of setting up infrastructure from scratch.

## Quick start
- **Launch Pre-configured Network (ThreeMasterNodeNetwork)**:
- **Launch Pre-configured Network via command line**:
```bash
# Setup the preset network
> go run cmd/main.go cmd preset threeMasterNodesNetwork /Users/pedro/go/src/github.com/vechain/thor/bin/thor
...
2024/06/07 17:31:43 INFO preset network config was successful... networkId=localthreeMaster

# Start preset network
> go run cmd/main.go cmd start localthreeMaster
2024/06/07 17:31:57 INFO Registered preset network networkId=threeMasterNodesNetwork
2024/06/07 17:31:57 INFO Registered preset network networkId=sixNodesNetwork
2024/06/07 17:31:57 INFO Starting network... ID=localthreeMaster
...
```


- **Launch Pre-configured Network via API server**:
```bash
# Start the networkhub api
go run ./cmd/main.go api
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ package.json
coverage.out

.idea
network.json
networks_db.json
132 changes: 132 additions & 0 deletions cmd/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package cmd

import (
"fmt"
"io/ioutil"
"log/slog"
"os"
"os/signal"
"path/filepath"
"syscall"

"github.com/vechain/networkhub/environments/local"
"github.com/vechain/networkhub/hub"
"github.com/vechain/networkhub/preset"

"github.com/spf13/cobra"

cmdentrypoint "github.com/vechain/networkhub/entrypoint/cmd"
)

func setup() *cmdentrypoint.Cmd {
envManager := hub.NewNetworkHub()
envManager.RegisterEnvironment("local", local.NewLocalEnv)

presets := preset.NewPresetNetworks()
presets.Register("threeMasterNodesNetwork", preset.LocalThreeMasterNodesNetwork)
presets.Register("sixNodesNetwork", preset.LocalSixNodesNetwork)

execDir, err := os.Getwd() // TODO might want to make this configurable in the future ?
if err != nil {
panic(fmt.Errorf("unable to use current directory: %w", err))
}

cmdEntrypoint := cmdentrypoint.New(envManager, presets, filepath.Join(execDir, "networks_db.json"))
if err = cmdEntrypoint.LoadExistingNetworks(); err != nil {
panic(fmt.Errorf("unable to load existing networks: %w", err))
}

return cmdEntrypoint
}

var cmdCmd = &cobra.Command{
Use: "cmd",
Short: "Directly uses NetworkHub",
}

var startCmd = &cobra.Command{
Use: "start [network-id]",
Short: "Start a specific network",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
cmdManager := setup()
networkID := args[0]
slog.Info("Starting network...", "ID", networkID)

// Channel to listen for interrupt signals
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

go func() {
err := cmdManager.Start(networkID)
if err != nil {
slog.Error("unable to start network", "err", err)
return
}
slog.Info("network started successfully...")
}()

// Wait for interrupt signal
<-sigChan
slog.Info("Interrupt signal received. Stopping the network...")

err := cmdManager.Stop(networkID)
if err != nil {
slog.Error("unable to stop network", "err", err)
} else {
slog.Info("network stopped successfully.")
}
},
}

var configureCmd = &cobra.Command{
Use: "config [network-json-config]",
Short: "Configures a specific network",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
cmdManager := setup()

// Read from the specified file
data, err := ioutil.ReadFile(args[0])
if err != nil {
fmt.Printf("Error reading config file: %v\n", err)
os.Exit(1)
}

slog.Info("Configuring network...")

networkID, err := cmdManager.Config(string(data))
if err != nil {
slog.Error("unable to config network", "err", err)
return
}
slog.Info("network config was successful...", "networkId", networkID)
},
}

var presetCmd = &cobra.Command{
Use: "preset [preset-name] [preset-thor-path]",
Short: "Configures a preset network",
Args: cobra.MinimumNArgs(2),
Run: func(cmd *cobra.Command, args []string) {
cmdManager := setup()

presetNetwork := args[0]
presetArtifactPath := args[1]

slog.Info("Configuring network...")

networkID, err := cmdManager.Preset(presetNetwork, presetArtifactPath)
if err != nil {
slog.Error("unable to config preset network", "err", err)
return
}
slog.Info("preset network config was successful...", "networkId", networkID)
},
}

func init() {

cmdCmd.AddCommand(startCmd, configureCmd, presetCmd)
rootCmd.AddCommand(cmdCmd)
}
12 changes: 6 additions & 6 deletions entrypoint/api/http_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import (
)

type Server struct {
entrypoint *hub.NetworkHub
networkHub *hub.NetworkHub
presets *preset.Networks
}

func New(envMgr *hub.NetworkHub, presets *preset.Networks) *Server {
return &Server{
entrypoint: envMgr,
networkHub: envMgr,
presets: presets,
}
}
Expand Down Expand Up @@ -63,7 +63,7 @@ func (s *Server) presetHandler(w http.ResponseWriter, r *http.Request) {
return
}

networkID, err := s.entrypoint.LoadNetworkConfig(networkCfg)
networkID, err := s.networkHub.LoadNetworkConfig(networkCfg)
if err != nil {
http.Error(w, fmt.Sprintf("Unable to load network config - %s", err.Error()), http.StatusInternalServerError)
return
Expand All @@ -85,7 +85,7 @@ func (s *Server) configHandler(w http.ResponseWriter, r *http.Request) {
return
}

networkID, err := s.entrypoint.LoadNetworkConfig(&networkCfg)
networkID, err := s.networkHub.LoadNetworkConfig(&networkCfg)
if err != nil {
http.Error(w, fmt.Sprintf("Unable to load network config - %s", err.Error()), http.StatusInternalServerError)
return
Expand All @@ -109,7 +109,7 @@ func (s *Server) startHandler(w http.ResponseWriter, r *http.Request) {
return
}

err := s.entrypoint.StartNetwork(networkID)
err := s.networkHub.StartNetwork(networkID)
if err != nil {
http.Error(w, fmt.Sprintf("Unable to start network - %s", err.Error()), http.StatusInternalServerError)
return
Expand All @@ -133,7 +133,7 @@ func (s *Server) stopHandler(w http.ResponseWriter, r *http.Request) {
return
}

err := s.entrypoint.StopNetwork(networkID)
err := s.networkHub.StopNetwork(networkID)
if err != nil {
http.Error(w, fmt.Sprintf("Unable to stop network - %s", err.Error()), http.StatusInternalServerError)
return
Expand Down
87 changes: 87 additions & 0 deletions entrypoint/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cmd

import (
"encoding/json"
"fmt"
"github.com/vechain/networkhub/hub"
"github.com/vechain/networkhub/network"
"github.com/vechain/networkhub/preset"
)

type Cmd struct {
networkHub *hub.NetworkHub
presets *preset.Networks
storage *Storage
}

func (c *Cmd) Stop(id string) error {
return c.networkHub.StopNetwork(id)
}

func (c *Cmd) Start(id string) error {
return c.networkHub.StartNetwork(id)
}

func (c *Cmd) Config(config string) (string, error) {
var netCfg network.Network

if err := json.Unmarshal([]byte(config), &netCfg); err != nil {
return "", err
}
return c.config(&netCfg)
}

func (c *Cmd) LoadExistingNetworks() error {
nets, err := c.storage.LoadExistingNetworks()
if err != nil {
return fmt.Errorf("unable to load existing networks: %w", err)
}

for networkID, net := range nets {
loadedID, err := c.networkHub.LoadNetworkConfig(net)
if err != nil {
return err
}

if networkID != loadedID {
return fmt.Errorf("unexpected networkID loaded: storedID:%s configuredID:%s", networkID, loadedID)
}
}

return nil
}

func (c *Cmd) Preset(presetNetwork string, presetConfig string) (string, error) {
netCfg, err := c.presets.Load(presetNetwork, &preset.APIConfigPayload{ArtifactPath: presetConfig})
if err != nil {
return "", fmt.Errorf("unable to load network preset: %w", err)
}
return c.config(netCfg)
}

func New(networkHub *hub.NetworkHub, presets *preset.Networks, storagePath string) *Cmd {
return &Cmd{
networkHub: networkHub,
presets: presets,
storage: NewStorage(storagePath),
}
}

func (c *Cmd) config(netCfg *network.Network) (string, error) {
networkID, err := c.networkHub.LoadNetworkConfig(netCfg)
if err != nil {
return "", fmt.Errorf("unable to load config: %w", err)
}

networkInst, err := c.networkHub.GetNetwork(networkID)
if err != nil {
return "", fmt.Errorf("unable to retrieve network: %w", err)
}

err = c.storage.Store(networkID, networkInst)
if err != nil {
return "", fmt.Errorf("unable to store network: %w", err)
}

return networkID, nil
}
69 changes: 69 additions & 0 deletions entrypoint/cmd/storage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmd

import (
"encoding/json"
"fmt"
"github.com/vechain/networkhub/network"
"io/ioutil"
"log/slog"
"os"
)

type StorageJson struct {
Network map[string]*network.Network `json:"network"`
}

type Storage struct {
path string
}

func (s *Storage) Store(networkID string, net *network.Network) error {
storageJson, err := s.LoadExistingNetworks()
if err != nil {
return fmt.Errorf("unable to load existing networks: %w", err)
}

// Add/Update the network entry
storageJson[networkID] = net

// Marshal the updated data
data, err := json.MarshalIndent(storageJson, "", " ")
if err != nil {
return err
}

// Write the updated data back to file
err = ioutil.WriteFile(s.path, data, 0644)
if err != nil {
return err
}

slog.Info("Network saved to file", "filepath", s.path)
return nil
}

func (s *Storage) LoadExistingNetworks() (map[string]*network.Network, error) {
// Initialize an empty StorageJson
storageJson := make(map[string]*network.Network)

// Check if file exists
if _, err := os.Stat(s.path); err == nil {
// File exists, load the current data
fileData, err := ioutil.ReadFile(s.path)
if err != nil {
return nil, err
}

err = json.Unmarshal(fileData, &storageJson)
if err != nil {
return nil, err
}
}
return storageJson, nil
}

func NewStorage(path string) *Storage {
return &Storage{
path: path,
}
}
3 changes: 2 additions & 1 deletion environments/local/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,13 @@ var networkJSON = fmt.Sprintf(`{
}`, genesis, genesis, genesis)

func TestLocal(t *testing.T) {
t.Skip()
//t.Skip()
networkCfg, err := network.NewNetwork(
network.WithJSON(networkJSON),
)
require.NoError(t, err)

fmt.Println(networkJSON)
localEnv := NewLocalEnv()
_, err = localEnv.LoadConfig(networkCfg)
require.NoError(t, err)
Expand Down
Loading

0 comments on commit 6495fe5

Please sign in to comment.