Procházet zdrojové kódy

bootstrap startram region

reid před 2 roky
rodič
revize
4db1273ca7
6 změnil soubory, kde provedl 147 přidání a 44 odebrání
  1. 82 23
      broadcast/broadcast.go
  2. 2 2
      config/config.go
  3. 5 5
      docker/docker.go
  4. 1 1
      main.go
  5. 44 0
      startram/startram.go
  6. 13 13
      structs/structs.go

+ 82 - 23
broadcast/broadcast.go

@@ -2,15 +2,16 @@ package broadcast
 
 import (
 	"encoding/json"
+	"fmt"
 	"goseg/config"
 	"goseg/docker"
+	"goseg/startram"
 	"goseg/structs"
 	"log/slog"
 	"os"
 	"reflect"
 	"strings"
 	"sync"
-	"fmt"
 
 	"github.com/gorilla/websocket"
 )
@@ -27,7 +28,7 @@ func init() {
 	config := config.Conf()
 	broadcast, err := bootstrapBroadcastState(config)
 	if err != nil {
-		errmsg := fmt.Sprintf("Unable to initialize broadcast: %v",err)
+		errmsg := fmt.Sprintf("Unable to initialize broadcast: %v", err)
 		panic(errmsg)
 	}
 	broadcastState = broadcast
@@ -54,18 +55,24 @@ func UnregisterClient(conn *websocket.Conn) {
 
 // take in config file and addt'l info to initialize broadcast
 func bootstrapBroadcastState(config structs.SysConfig) (structs.AuthBroadcast, error) {
+	logger.Info("Bootstrapping state")
 	var res structs.AuthBroadcast
+	currentState := GetState()
+	// get a list of piers from config
 	piers := config.Piers
+	// this returns a map of ship:running status
+	logger.Info("Resolving pier status")
 	pierStatus, err := docker.GetShipStatus(piers)
 	if err != nil {
-		errmsg := fmt.Sprintf("Unable to bootstrap urbit states: %v",err)
+		errmsg := fmt.Sprintf("Unable to bootstrap urbit states: %v", err)
 		logger.Error(errmsg)
 		return res, err
 	}
 	updates := make(map[string]structs.Urbit)
+	// convert the running status into bools
 	for pier, status := range pierStatus {
 		urbit := structs.Urbit{}
-		if existingUrbit, exists := broadcastState.Urbits[pier]; exists {
+		if existingUrbit, exists := currentState.Urbits[pier]; exists {
 			// If the ship already exists in broadcastState, use its current state
 			urbit = existingUrbit
 		}
@@ -82,26 +89,53 @@ func bootstrapBroadcastState(config structs.SysConfig) (structs.AuthBroadcast, e
 		logger.Error(errmsg)
 		return res, err
 	}
+	currentState = GetState()
+	// get startram regions
+	logger.Info("Retrieving StarTram region info")
+	regions, err := startram.GetRegions()
+	if err != nil {
+		logger.Warn("Couldn't get StarTram regions")
+	} else {
+		updates := map[string]interface{}{
+			"Profile": map[string]interface{}{
+				"Startram": map[string]interface{}{
+					"Info": map[string]interface{}{
+						"Regions": regions,
+					},
+				},
+			},
+		}		
+		err := UpdateBroadcastState(updates)
+		if err != nil {
+			errmsg := fmt.Sprintf("Error updating broadcast state:", err)
+			logger.Error(errmsg)
+		}
+	}
+	// return the boostrapped result
 	res = GetState()
 	return res, nil
 }
 
 // update broadcastState with a map of items
 func UpdateBroadcastState(values map[string]interface{}) error {
-    mu.Lock()
-    defer mu.Unlock()
-    v := reflect.ValueOf(&broadcastState).Elem()
-    for key, value := range values {
-        field := v.FieldByName(key)
-        if !field.IsValid() || !field.CanSet() {
-            return fmt.Errorf("field %s does not exist or is not settable", key)
-        }
-        if err := recursiveUpdate(field, reflect.ValueOf(value)); err != nil {
-            return err
-        }
-    }
-    BroadcastToClients()
-    return nil
+	mu.Lock()
+	defer mu.Unlock()
+	v := reflect.ValueOf(&broadcastState).Elem()
+	for key, value := range values {
+		field := v.FieldByName(key)
+		if !field.IsValid() || !field.CanSet() {
+			return fmt.Errorf("field %s does not exist or is not settable", key)
+		}
+		val := reflect.ValueOf(value)
+		if val.Kind() == reflect.Interface {
+			val = val.Elem() // Extract the underlying value from the interface
+		}
+		if err := recursiveUpdate(field, val); err != nil {
+			return err
+		}
+	}	
+	BroadcastToClients()
+	return nil
 }
 
 // this allows us to insert stuff into nested vals and not overwrite the existing contents
@@ -109,6 +143,30 @@ func recursiveUpdate(dst, src reflect.Value) error {
     if !dst.CanSet() {
         return fmt.Errorf("field is not settable")
     }
+    // If dst is a struct and src is a map, handle them field by field
+	if dst.Kind() == reflect.Struct && src.Kind() == reflect.Map {
+		for _, key := range src.MapKeys() {
+			dstField := dst.FieldByName(key.String())
+			if !dstField.IsValid() {
+				return fmt.Errorf("field %s does not exist in the struct", key.String())
+			}
+			// Initialize the map if it's nil and we're trying to set a map
+			if dstField.Kind() == reflect.Map && dstField.IsNil() && src.MapIndex(key).Kind() == reflect.Map {
+				dstField.Set(reflect.MakeMap(dstField.Type()))
+			}
+			if !dstField.CanSet() {
+				return fmt.Errorf("field %s is not settable in the struct", key.String())
+			}
+			srcVal := src.MapIndex(key)
+			if srcVal.Kind() == reflect.Interface {
+				srcVal = srcVal.Elem()
+			}
+			if err := recursiveUpdate(dstField, srcVal); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
     // If both dst and src are maps, handle them recursively
     if dst.Kind() == reflect.Map && src.Kind() == reflect.Map {
         for _, key := range src.MapKeys() {
@@ -118,18 +176,19 @@ func recursiveUpdate(dst, src reflect.Value) error {
             if !dstVal.IsValid() {
                 dstVal = reflect.New(dst.Type().Elem()).Elem()
             }
-            // Recursive call to handle potential nested maps
+            // Recursive call to handle potential nested maps or structs
             if err := recursiveUpdate(dstVal, srcVal); err != nil {
                 return err
             }
-			if dst.IsNil() {
-				dst.Set(reflect.MakeMap(dst.Type()))
-			}
+            // Initialize the map if it's nil
+            if dst.IsNil() {
+                dst.Set(reflect.MakeMap(dst.Type()))
+            }
             dst.SetMapIndex(key, dstVal)
         }
         return nil
     }
-    // For non-map fields or direct updates
+    // For non-map or non-struct fields, or for direct updates
     if dst.Type() != src.Type() {
         return fmt.Errorf("type mismatch: expected %s, got %s", dst.Type(), src.Type())
     }

+ 2 - 2
config/config.go

@@ -17,7 +17,7 @@ import (
 var (
 	globalConfig       structs.SysConfig
 	logger             = slog.New(slog.NewJSONHandler(os.Stdout, nil))
-	basePath		   string
+	basePath           string
 	Version            = "v2.0.0"
 	Ready              = false
 	VersionServerReady = false
@@ -40,7 +40,7 @@ func init() {
 	// try loading existing config
 	basePath, err := os.Getwd()
 	if err != nil {
-		errmsg := fmt.Sprintf("Couldn't get cwd: %v",err)
+		errmsg := fmt.Sprintf("Couldn't get cwd: %v", err)
 		logger.Error(errmsg)
 	}
 	confPath := filepath.Join(basePath, "settings", "system.json")

+ 5 - 5
docker/docker.go

@@ -6,16 +6,16 @@ import (
 	"log/slog"
 	"os"
 
-	"github.com/docker/docker/client"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/client"
 )
 
 var (
-	logger         = slog.New(slog.NewJSONHandler(os.Stdout, nil))
+	logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
 )
 
 func GetShipStatus(patps []string) (map[string]string, error) {
-    statuses := make(map[string]string)
+	statuses := make(map[string]string)
 	cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
 	if err != nil {
 		errmsg := fmt.Sprintf("Error getting Docker info: %v", err)
@@ -24,7 +24,7 @@ func GetShipStatus(patps []string) (map[string]string, error) {
 	} else {
 		containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
 		if err != nil {
-			errmsg := fmt.Sprintf("Error getting containers: %v",err)
+			errmsg := fmt.Sprintf("Error getting containers: %v", err)
 			logger.Error(errmsg)
 			return statuses, err
 		} else {
@@ -50,4 +50,4 @@ func GetShipStatus(patps []string) (map[string]string, error) {
 		}
 		return statuses, nil
 	}
-}
+}

+ 1 - 1
main.go

@@ -12,7 +12,7 @@ import (
 )
 
 var (
-	logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
+	logger  = slog.New(slog.NewJSONHandler(os.Stdout, nil))
 	devMode = false
 )
 

+ 44 - 0
startram/startram.go

@@ -0,0 +1,44 @@
+package startram
+
+import (
+	"fmt"
+	"encoding/json"
+	"os"
+	"log/slog"
+	"io/ioutil"
+	"net/http"
+	"goseg/config"
+	"goseg/structs"
+)
+
+var (
+	logger  = slog.New(slog.NewJSONHandler(os.Stdout, nil))
+)
+
+func GetRegions() (map[string]structs.StartramRegion, error) {
+	var regions map[string]structs.StartramRegion
+	config := config.Conf()
+	regionUrl := "https://" + config.EndpointUrl + "/v1/regions"
+	resp, err := http.Get(regionUrl)
+	if err != nil {
+		errmsg := fmt.Sprintf("Unable to connect to API server: %v", err)
+		logger.Warn(errmsg)
+		return regions, err
+	}
+	body, err := ioutil.ReadAll(resp.Body)
+	resp.Body.Close()
+	if err != nil {
+		errmsg := fmt.Sprintf("Error reading regions info: %v", err)
+		logger.Warn(errmsg)
+		return regions, err
+	}
+	// unmarshal values into struct
+	err = json.Unmarshal(body, &regions)
+	if err != nil {
+		errmsg := fmt.Sprintf("Error unmarshalling regions json: %v", err)
+		fmt.Println(string(body))
+		logger.Warn(errmsg)
+		return regions, err
+	}
+	return regions, nil
+}

+ 13 - 13
structs/structs.go

@@ -135,13 +135,13 @@ type Profile struct {
 
 type Startram struct {
 	Info struct {
-		Registered bool              `json:"registered"`
-		Running    bool              `json:"running"`
-		Region     any               `json:"region"`
-		Expiry     any               `json:"expiry"`
-		Renew      bool              `json:"renew"`
-		Endpoint   string            `json:"endpoint"`
-		Regions    map[string]Region `json:"regions"`
+		Registered bool                      `json:"registered"`
+		Running    bool                      `json:"running"`
+		Region     any                       `json:"region"`
+		Expiry     any                       `json:"expiry"`
+		Renew      bool                      `json:"renew"`
+		Endpoint   string                    `json:"endpoint"`
+		Regions    map[string]StartramRegion `json:"regions"`
 	} `json:"info"`
 	Transition struct {
 		Register any `json:"register"`
@@ -209,14 +209,14 @@ type UnauthBroadcast struct {
 }
 
 type SetupBroadcast struct {
-	Type      string            `json:"type"`
-	AuthLevel string            `json:"auth_level"`
-	Stage     string            `json:"stage"`
-	Page      string            `json:"page"`
-	Regions   map[string]Region `json:"regions"`
+	Type      string                    `json:"type"`
+	AuthLevel string                    `json:"auth_level"`
+	Stage     string                    `json:"stage"`
+	Page      string                    `json:"page"`
+	Regions   map[string]StartramRegion `json:"regions"`
 }
 
-type Region struct {
+type StartramRegion struct {
 	Country string `json:"country"`
 	Desc    string `json:"desc"`
 }