package main // NativePlanet GroundSeg: Go Edition (goseg) // 🄯 2023 ~nallux-dozryl & ~sitful-hatred // This is a Golang rewrite of GroundSeg that serves the v2 json // object via websocket. // The v2 rewrite decouples the frontend and backend, which makes it // straightforward to implement alternative backends. // // Under development: reimplementing all pyseg functionality. // Advantages: // - Really, really fast // - Event-driven // - First-class support for concurrent operations // - Very good golang Docker libraries import ( "encoding/json" "fmt" "goseg/config" "goseg/docker" "goseg/rectify" "goseg/startram" "goseg/structs" "goseg/ws" "io/ioutil" "log/slog" "net/http" "os" "path/filepath" "strings" // "time" "github.com/gorilla/mux" ) var ( logger = slog.New(slog.NewJSONHandler(os.Stdout, nil)) DevMode = false ) func loadService(loadFunc func() error, errMsg string) { go func() { if err := loadFunc(); err != nil { logger.Error(fmt.Sprintf("%s %v", errMsg, err)) } }() } func main() { // global SysConfig var is managed through config package conf := config.Conf() internetAvailable := config.NetCheck("1.1.1.1:53") availMsg := fmt.Sprintf("Internet available: %t", internetAvailable) logger.Info(availMsg) // async operation to retrieve version info if updates are on versionUpdateChannel := make(chan bool) remoteVersion := false if conf.UpdateMode == "auto" { remoteVersion = true // get version info from remote server go func() { _, versionUpdate := config.CheckVersion() if versionUpdate { logger.Info("Version info retrieved") } versionUpdateChannel <- versionUpdate }() // otherwise use cached if possible, or save hardcoded defaults and use that } else { confPath := filepath.Join(config.BasePath, "settings", "version_info.json") _, err := os.Open(confPath) if err != nil { // create a default if it doesn't exist err = config.CreateDefaultVersion() if err != nil { // panic if we can't create it errmsg := fmt.Sprintf("Unable to write version info! %v", err) logger.Error(errmsg) panic(errmsg) } } file, err := ioutil.ReadFile(confPath) if err != nil { errmsg := fmt.Sprintf("Unable to load version info: %v", err) panic(errmsg) } var versionStruct structs.Version if err := json.Unmarshal(file, &versionStruct); err != nil { errmsg := fmt.Sprintf("Error decoding version JSON: %v", err) panic(errmsg) } // Store in var releaseChannel := conf.UpdateBranch targetChan := versionStruct.Groundseg[releaseChannel] config.VersionInfo = targetChan } // infinite version check loop go config.CheckVersionLoop() // listen to docker daemon go docker.DockerListener() // digest docker events from eventbus go rectify.DockerSubscriptionHandler() // just making sure we can parse (debug) if len(conf.Piers) > 0 { pierList := strings.Join(conf.Piers, ", ") logger.Info(fmt.Sprintf("Loaded piers: %s", pierList)) } // block until returns if remoteVersion == true { <-versionUpdateChannel } if conf.WgRegistered == true { startram.Retrieve() } // Load Netdata loadService(docker.LoadNetdata, "Unable to load Netdata!") // Load Wireguard loadService(docker.LoadWireguard, "Unable to load Wireguard!") // Load Urbits loadService(docker.LoadUrbits, "Unable to load Urbit ships!") // Load MC loadService(docker.LoadMC, "Unable to load MinIO Client!") // Load MinIOs loadService(docker.LoadMinIOs, "Unable to load MinIO containers!") // Websocket r := mux.NewRouter() r.HandleFunc("/ws", ws.WsHandler) http.ListenAndServe(":3000", r) }