package docker import ( "context" "encoding/json" "fmt" "log" "net" "reflect" "strings" instancemanager "git.acooldomain.co/server-manager/backend-kubernetes-go/instance_manager" "git.acooldomain.co/server-manager/backend-kubernetes-go/models" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/volume" "github.com/docker/docker/client" ) type InstanceManager struct { instancemanager.InstanceManager client client.Client } func flattenMap(m map[string]any, previous ...string) map[string]string { var flattenedMap map[string]string for key, value := range m { v := reflect.ValueOf(value) switch v.Kind() { case reflect.Map: inner := flattenMap(v.Interface().(map[string]any), append(previous, key)...) for key, value := range inner { flattenedMap[key] = value } default: flattenedMap[key] = fmt.Sprintf("%v", value) } } return flattenedMap } func convertLabelsToFilter(labels any) (*filters.Args, error) { args := filters.NewArgs() raw, err := json.Marshal(labels) if err != nil { return nil, err } var unflattenedMap map[string]any err = json.Unmarshal(raw, &unflattenedMap) if err != nil { return nil, err } flatMap := flattenMap(unflattenedMap) for key, value := range flatMap { args.Add(key, value) } return &args, nil } func convertContainerPortsToPorts(ports []types.Port) []models.Port { containerPorts := make([]models.Port, len(ports)) logger := log.Default() for i, port := range ports { var portProtocol models.PortProtocol switch port.Type { case "TCP": portProtocol = models.TCP case "UDP": portProtocol = models.UDP default: logger.Println(fmt.Sprintf("Unkown Port Protocol %s assuming TCP", port.Type)) portProtocol = models.TCP } containerPorts[i] = models.Port{ PublicPort: port.PublicPort, ContainerPort: port.PrivatePort, Protocol: portProtocol, } } return containerPorts } func convertContainerImageToImage(image string) models.Image { imageSegments := strings.Split(image, ":") imageRegistry := imageSegments[0] imageTag := imageSegments[1] return models.Image{ Registry: imageRegistry, Tag: imageTag, } } func convertImagePortsToPorts(types.Port) *models.Port { return nil } // General // Read Only func (self *InstanceManager) ListImages(ctx context.Context) (*instancemanager.Image, error) { imageFilters, err := convertLabelsToFilter(ImageLabels{Type: Game}) if err != nil { return nil, err } rawImages, err := self.client.ImageList(ctx, image.ListOptions{ Filters: *imageFilters, }) images := make([]instancemanager.Image, len(rawImages)) for i, rawImage := range rawImages { imageInspect, _, err := self.client.ImageInspectWithRaw(ctx, rawImage.ID) if err != nil { return nil, err } } return nil, nil } func (self *InstanceManager) GetServer(ctx context.Context, serverId string) (*instancemanager.Server, error) { volume, err := self.client.VolumeInspect(ctx, serverId) if err != nil { return nil, err } var labels VolumeLabels rawLabels, err := json.Marshal(volume.Labels) if err != nil { return nil, err } err = json.Unmarshal(rawLabels, &labels) if err != nil { return nil, err } if labels.Type != Game { return nil, fmt.Errorf("Server not found") } filterArgs, err := convertLabelsToFilter(ContainerLabels{ VolumeId: volume.Name, Type: Game, }) serverContainers, err := self.client.ContainerList( ctx, container.ListOptions{ Filters: *filterArgs, }, ) if err != nil { return nil, err } if len(serverContainers) == 0 { return &instancemanager.Server{ Id: volume.Name, Running: false, RunningCommand: "", RunningImage: nil, Ports: nil, }, nil } serverContainer := serverContainers[0] var containerLabels ContainerLabels rawContainerLabels, err := json.Marshal(serverContainer.Labels) if err != nil { return nil, err } if err = json.Unmarshal(rawContainerLabels, &containerLabels); err != nil { return nil, err } running := serverContainer.State == "running" runningCommand := serverContainer.Command image := convertContainerImageToImage(serverContainer.Image) return &instancemanager.Server{ Id: volume.Name, Running: running, RunningCommand: runningCommand, Ports: convertContainerPortsToPorts(serverContainer.Ports), RunningImage: &image, }, nil } func (self *InstanceManager) ListServers(ctx context.Context) ([]instancemanager.Server, error) { volumeFilter, err := convertLabelsToFilter(VolumeLabels{Type: Game}) if err != nil { return nil, err } containerFilters, err := convertLabelsToFilter(ContainerLabels{Type: Game}) if err != nil { return nil, err } volumes, err := self.client.VolumeList(ctx, volume.ListOptions{Filters: *volumeFilter}) if err != nil { return nil, err } serverStatus := make(map[string]*instancemanager.Server) for _, volume := range volumes.Volumes { serverStatus[volume.Name] = &instancemanager.Server{ Id: volume.Name, Running: false, RunningCommand: "", Ports: nil, RunningImage: nil, } } containers, err := self.client.ContainerList(ctx, container.ListOptions{Filters: *containerFilters}) for _, container := range containers { rawLabels, err := json.Marshal(container.Labels) if err != nil { return nil, err } var containerLabels ContainerLabels err = json.Unmarshal(rawLabels, &containerLabels) if err != nil { return nil, err } if container.State != "running" { continue } image := convertContainerImageToImage(container.Image) serverStatus[containerLabels.VolumeId].Ports = convertContainerPortsToPorts(container.Ports) serverStatus[containerLabels.VolumeId].Running = true serverStatus[containerLabels.VolumeId].RunningImage = &image serverStatus[containerLabels.VolumeId].RunningCommand = container.Command } servers := make([]instancemanager.Server, len(serverStatus)) i := 0 for _, value := range serverStatus { servers[i] = *value i++ } return servers, nil } // State Changing func (self *InstanceManager) StartServer(ctx context.Context, serverId string, command string, ports []models.Port) error { return nil } func (self *InstanceManager) StopServer(ctx context.Context, serverId string) error { return nil } func (self *InstanceManager) CreateServer(ctx context.Context, image models.Image) (*instancemanager.Server, error) { return nil, nil } func (self *InstanceManager) DeleteServer(ctx context.Context, serverId string) error { return nil } // Terminal // Read Only func (self *InstanceManager) GetLogs(ctx context.Context, serverId string) (string, error) { return "", nil } // Status Changing func (self *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*net.Conn, error) { return nil, nil } func (self *InstanceManager) RunCommand(ctx context.Context, serverId string, command string) (string, error) { return "", nil } // File Browser // Read Only func (self *InstanceManager) GetFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) { return nil, nil } func (self *InstanceManager) ListFileBrowsers(ctx context.Context) ([]models.FileBrowser, error) { return nil, nil } // Status Changing func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) { return nil, nil } func (self *InstanceManager) StopFileBrowser(ctx context.Context, serverId string) error { return nil }