added browser support

This commit is contained in:
ACoolName 2025-04-02 22:19:42 +03:00
parent 9616aa3d5c
commit 8b74b73704

View File

@ -30,13 +30,13 @@ type InstanceManager struct {
siteDomain string
}
func (self *InstanceManager) containerList(ctx context.Context, labels ContainerLabels, all bool) ([]container.Summary, error) {
func (im *InstanceManager) containerList(ctx context.Context, labels ContainerLabels, all bool) ([]container.Summary, error) {
filters, err := convertLabelsToFilter(labels)
if err != nil {
return nil, err
}
containers, err := self.client.ContainerList(ctx, container.ListOptions{Filters: *filters, All: all})
containers, err := im.client.ContainerList(ctx, container.ListOptions{Filters: *filters, All: all})
if err != nil {
return nil, err
}
@ -44,8 +44,8 @@ func (self *InstanceManager) containerList(ctx context.Context, labels Container
return containers, nil
}
func (self *InstanceManager) getVolume(ctx context.Context, serverId string) (*volume.Volume, error) {
volume, err := self.client.VolumeInspect(ctx, serverId)
func (im *InstanceManager) getVolume(ctx context.Context, serverId string) (*volume.Volume, error) {
volume, err := im.client.VolumeInspect(ctx, serverId)
if err != nil {
return nil, err
}
@ -56,7 +56,7 @@ func (self *InstanceManager) getVolume(ctx context.Context, serverId string) (*v
}
if labels.Type != Game {
return nil, fmt.Errorf("Server not found")
return nil, fmt.Errorf("server not found")
}
return &volume, err
@ -64,8 +64,8 @@ func (self *InstanceManager) getVolume(ctx context.Context, serverId string) (*v
// General
// Read Only
func (self *InstanceManager) GetImage(ctx context.Context, imageId string) (*instancemanager.Image, error) {
imageInspect, err := self.client.ImageInspect(ctx, imageId)
func (im *InstanceManager) GetImage(ctx context.Context, imageId string) (*instancemanager.Image, error) {
imageInspect, err := im.client.ImageInspect(ctx, imageId)
if err != nil {
return nil, err
}
@ -82,23 +82,22 @@ func (self *InstanceManager) GetImage(ctx context.Context, imageId string) (*ins
image := convertImageInspectToInstanceImage(imageInspect)
return &image, nil
}
func (self *InstanceManager) ListImages(ctx context.Context) ([]instancemanager.Image, error) {
func (im *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{
rawImages, err := im.client.ImageList(ctx, image.ListOptions{
Filters: *imageFilters,
})
images := make([]instancemanager.Image, len(rawImages))
for i, rawImage := range rawImages {
imageInspect, err := self.client.ImageInspect(ctx, rawImage.ID)
imageInspect, err := im.client.ImageInspect(ctx, rawImage.ID)
if err != nil {
return nil, err
}
@ -109,12 +108,12 @@ func (self *InstanceManager) ListImages(ctx context.Context) ([]instancemanager.
return images, nil
}
func (self *InstanceManager) GetServer(ctx context.Context, serverId string) (*instancemanager.Server, error) {
volume, err := self.getVolume(ctx, serverId)
func (im *InstanceManager) GetServer(ctx context.Context, serverId string) (*instancemanager.Server, error) {
volume, err := im.getVolume(ctx, serverId)
if err != nil {
return nil, err
}
serverContainers, err := self.containerList(
serverContainers, err := im.containerList(
ctx,
ContainerLabels{
VolumeId: serverId,
@ -132,7 +131,7 @@ func (self *InstanceManager) GetServer(ctx context.Context, serverId string) (*i
RunningCommand: "",
RunningImage: nil,
Ports: nil,
Domain: self.siteDomain,
Domain: im.siteDomain,
}, nil
}
@ -149,17 +148,17 @@ func (self *InstanceManager) GetServer(ctx context.Context, serverId string) (*i
RunningCommand: runningCommand,
Ports: convertContainerPortsToPorts(serverContainer.Ports),
RunningImage: &image,
Domain: self.siteDomain,
Domain: im.siteDomain,
}, nil
}
func (self *InstanceManager) ListServers(ctx context.Context) ([]instancemanager.Server, error) {
func (im *InstanceManager) ListServers(ctx context.Context) ([]instancemanager.Server, error) {
volumeFilter, err := convertLabelsToFilter(VolumeLabels{Type: Game})
if err != nil {
return nil, err
}
volumes, err := self.client.VolumeList(ctx, volume.ListOptions{Filters: *volumeFilter})
volumes, err := im.client.VolumeList(ctx, volume.ListOptions{Filters: *volumeFilter})
if err != nil {
return nil, err
}
@ -173,11 +172,11 @@ func (self *InstanceManager) ListServers(ctx context.Context) ([]instancemanager
RunningCommand: "",
Ports: nil,
RunningImage: nil,
Domain: self.siteDomain,
Domain: im.siteDomain,
}
}
containers, err := self.containerList(ctx, ContainerLabels{Type: Game}, false)
containers, err := im.containerList(ctx, ContainerLabels{Type: Game}, false)
for _, container := range containers {
rawLabels, err := json.Marshal(container.Labels)
@ -215,13 +214,13 @@ func (self *InstanceManager) ListServers(ctx context.Context) ([]instancemanager
}
// State Changing
func (self *InstanceManager) StartServer(ctx context.Context,
func (im *InstanceManager) StartServer(ctx context.Context,
serverId string,
imageId string,
command string,
ports []models.Port,
) error {
server, err := self.GetServer(ctx, serverId)
server, err := im.GetServer(ctx, serverId)
if err != nil {
return err
}
@ -238,7 +237,7 @@ func (self *InstanceManager) StartServer(ctx context.Context,
volumes := make(map[string]struct{})
var portMapping nat.PortMap = make(nat.PortMap)
image, err := self.GetImage(ctx, imageId)
image, err := im.GetImage(ctx, imageId)
if err != nil {
return err
}
@ -281,7 +280,7 @@ func (self *InstanceManager) StartServer(ctx context.Context,
return err
}
createdContainer, err := self.client.ContainerCreate(
createdContainer, err := im.client.ContainerCreate(
context.TODO(),
&container.Config{
AttachStdin: true,
@ -306,23 +305,23 @@ func (self *InstanceManager) StartServer(ctx context.Context,
&v1.Platform{},
"",
)
if err != nil {
return err
}
err = self.client.ContainerStart(ctx, createdContainer.ID, container.StartOptions{})
err = im.client.ContainerStart(ctx, createdContainer.ID, container.StartOptions{})
if err != nil {
return err
}
return nil
}
func (self *InstanceManager) StopServer(ctx context.Context, serverId string) error {
runningContainers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
func (im *InstanceManager) StopServer(ctx context.Context, serverId string) error {
runningContainers, err := im.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
for _, rawContainer := range runningContainers {
err = self.client.ContainerStop(ctx, rawContainer.ID, container.StopOptions{})
err = im.client.ContainerStop(ctx, rawContainer.ID, container.StopOptions{})
if err != nil {
return err
}
@ -331,22 +330,21 @@ func (self *InstanceManager) StopServer(ctx context.Context, serverId string) er
return nil
}
func (self *InstanceManager) createVolume(ctx context.Context, volumeLabels VolumeLabels) (volume.Volume, error) {
func (im *InstanceManager) createVolume(ctx context.Context, volumeLabels VolumeLabels) (volume.Volume, error) {
labels, err := convertLabelsToMap(volumeLabels)
if err != nil {
return volume.Volume{}, err
}
volume, err := self.client.VolumeCreate(ctx, volume.CreateOptions{
volume, err := im.client.VolumeCreate(ctx, volume.CreateOptions{
Labels: *labels,
})
return volume, err
}
func (self *InstanceManager) CreateServer(ctx context.Context) (*instancemanager.Server, error) {
volume, err := self.createVolume(ctx, VolumeLabels{Type: Game})
func (im *InstanceManager) CreateServer(ctx context.Context) (*instancemanager.Server, error) {
volume, err := im.createVolume(ctx, VolumeLabels{Type: Game})
if err != nil {
return nil, err
}
@ -356,29 +354,29 @@ func (self *InstanceManager) CreateServer(ctx context.Context) (*instancemanager
Running: false,
RunningImage: nil,
RunningCommand: "",
Domain: self.siteDomain,
Domain: im.siteDomain,
}, nil
}
func (self *InstanceManager) DeleteServer(ctx context.Context, serverId string) error {
server, err := self.GetServer(ctx, serverId)
func (im *InstanceManager) DeleteServer(ctx context.Context, serverId string) error {
server, err := im.GetServer(ctx, serverId)
if err != nil {
return err
}
if server.Running {
err = self.StopServer(ctx, server.Id)
err = im.StopServer(ctx, server.Id)
if err != nil {
return err
}
}
err = self.StopFileBrowser(ctx, server.Id)
err = im.StopFileBrowser(ctx, server.Id)
if err != nil {
return err
}
err = self.client.VolumeRemove(ctx, server.Id, true)
err = im.client.VolumeRemove(ctx, server.Id, true)
if err != nil {
return err
}
@ -388,8 +386,8 @@ func (self *InstanceManager) DeleteServer(ctx context.Context, serverId string)
// Terminal
// Status Changing
func (self *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*net.Conn, error) {
server, err := self.GetServer(ctx, serverId)
func (im *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*net.Conn, error) {
server, err := im.GetServer(ctx, serverId)
if err != nil {
return nil, err
}
@ -398,7 +396,7 @@ func (self *InstanceManager) InteractiveTerminal(ctx context.Context, serverId s
return nil, fmt.Errorf("Server %s not running", server.Id)
}
rawContainers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
rawContainers, err := im.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
if err != nil {
return nil, err
}
@ -409,16 +407,16 @@ func (self *InstanceManager) InteractiveTerminal(ctx context.Context, serverId s
rawContainer := rawContainers[0]
attach, err := self.client.ContainerAttach(ctx,
attach, err := im.client.ContainerAttach(ctx,
rawContainer.ID,
container.AttachOptions{Stream: true,
container.AttachOptions{
Stream: true,
Stdin: true,
Stdout: true,
Stderr: true,
Logs: true,
},
)
if err != nil {
return nil, err
}
@ -426,8 +424,8 @@ func (self *InstanceManager) InteractiveTerminal(ctx context.Context, serverId s
return &attach.Conn, nil
}
func (self *InstanceManager) ResizeTerminal(ctx context.Context, serverId string, width uint, height uint) error {
containers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
func (im *InstanceManager) ResizeTerminal(ctx context.Context, serverId string, width uint, height uint) error {
containers, err := im.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
if err != nil {
return err
}
@ -436,7 +434,7 @@ func (self *InstanceManager) ResizeTerminal(ctx context.Context, serverId string
return fmt.Errorf("Server %s not running", serverId)
}
err = self.client.ContainerResize(context.TODO(), containers[0].ID, container.ResizeOptions{Height: height, Width: width})
err = im.client.ContainerResize(context.TODO(), containers[0].ID, container.ResizeOptions{Height: height, Width: width})
return err
}
@ -444,8 +442,8 @@ func (self *InstanceManager) ResizeTerminal(ctx context.Context, serverId string
// File Browser
// Read Only
func (self *InstanceManager) GetFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
containers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: FileBrowser}, false)
func (im *InstanceManager) GetFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
containers, err := im.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: FileBrowser}, false)
if err != nil {
return nil, err
}
@ -462,14 +460,14 @@ func (self *InstanceManager) GetFileBrowser(ctx context.Context, serverId string
}
return &models.FileBrowser{
Url: fmt.Sprintf("%s/browsers/%s/", self.siteDomain, containerLabels.VolumeId),
Url: fmt.Sprintf("%s/browsers/%s/", im.siteDomain, containerLabels.VolumeId),
ServerId: containerLabels.VolumeId,
Id: rawContainer.ID,
}, nil
}
func (self *InstanceManager) ListFileBrowsers(ctx context.Context) ([]models.FileBrowser, error) {
containers, err := self.containerList(ctx, ContainerLabels{Type: FileBrowser}, false)
func (im *InstanceManager) ListFileBrowsers(ctx context.Context) ([]models.FileBrowser, error) {
containers, err := im.containerList(ctx, ContainerLabels{Type: FileBrowser}, false)
if err != nil {
return nil, err
}
@ -483,7 +481,7 @@ func (self *InstanceManager) ListFileBrowsers(ctx context.Context) ([]models.Fil
}
fileBrowsers[i] = models.FileBrowser{
Url: fmt.Sprintf("%s/browsers/%s/", self.siteDomain, containerLabels.VolumeId),
Url: fmt.Sprintf("%s/browsers/%s/", im.siteDomain, containerLabels.VolumeId),
ServerId: containerLabels.VolumeId,
Id: rawContainer.ID,
}
@ -494,9 +492,8 @@ func (self *InstanceManager) ListFileBrowsers(ctx context.Context) ([]models.Fil
}
// Status Changing
func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
server, err := self.GetServer(ctx, serverId)
func (im *InstanceManager) StartFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
server, err := im.GetServer(ctx, serverId)
if err != nil {
return nil, err
}
@ -507,31 +504,35 @@ func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId stri
VolumeId: server.Id,
}
containers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: FileBrowser}, false)
containers, err := im.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: FileBrowser}, false)
if err != nil {
return nil, err
}
if len(containers) > 0 {
return &models.FileBrowser{
Url: fmt.Sprintf("%s/browsers/%s/", self.siteDomain, server.Id),
Url: fmt.Sprintf("%s/browsers/%s/", im.siteDomain, server.Id),
ServerId: server.Id,
Id: containers[0].ID,
}, nil
}
volume, err := self.createVolume(ctx, volumeLabels)
containerConfig, err := convertLabelsToMap(ContainerLabels{VolumeId: serverId, Type: FileBrowser})
volume, err := im.createVolume(ctx, volumeLabels)
if err != nil {
return nil, err
}
PrepareDatabaseContainer, err := self.client.ContainerCreate(
containerConfig, err := convertLabelsToMap(ContainerLabels{VolumeId: serverId, Type: FileBrowser})
if err != nil {
return nil, err
}
PrepareDatabaseContainer, err := im.client.ContainerCreate(
ctx,
&container.Config{
Entrypoint: []string{"/bin/sh"},
Cmd: []string{"-c", "/filebrowser config init -d /tmp/database/database.db && /filebrowser config set -d /tmp/database/database.db --auth.method=proxy --auth.header=X-Auth-Username"},
Image: fmt.Sprintf("%s:%s", self.config.FileBrowser.Image.Registry, self.config.FileBrowser.Image.Tag),
Image: fmt.Sprintf("%s:%s", im.config.FileBrowser.Image.Registry, im.config.FileBrowser.Image.Tag),
Labels: *containerConfig,
},
&container.HostConfig{
@ -542,28 +543,26 @@ func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId stri
&v1.Platform{},
"",
)
if err != nil {
return nil, err
}
err = self.client.ContainerStart(ctx, PrepareDatabaseContainer.ID, container.StartOptions{})
err = im.client.ContainerStart(ctx, PrepareDatabaseContainer.ID, container.StartOptions{})
if err != nil {
log.Printf("Failed to wait %s", err)
}
responseChan, _ := self.client.ContainerWait(ctx, PrepareDatabaseContainer.ID, container.WaitConditionNotRunning)
responseChan, _ := im.client.ContainerWait(ctx, PrepareDatabaseContainer.ID, container.WaitConditionNotRunning)
response := <-responseChan
log.Printf("%#v\n", response)
browserLabels := make(map[string]string)
browserLabels["traefik.enable"] = "true"
browserLabels[fmt.Sprintf("traefik.http.routers.%s.rule", labelId)] = fmt.Sprintf("Host(`%s`) && PathPrefix(`/browsers/%s/`)", self.siteDomain, labelId)
browserLabels[fmt.Sprintf("traefik.http.routers.%s.entrypoints", labelId)] = self.config.FileBrowser.ReverseProxy.Entrypoint
browserLabels[fmt.Sprintf("traefik.http.routers.%s.middlewares", labelId)] = strings.Join(self.config.FileBrowser.ReverseProxy.Middlewares, ",")
if self.config.FileBrowser.ReverseProxy.Tls {
browserLabels[fmt.Sprintf("traefik.http.routers.%s.tls.certresolver", labelId)] = self.config.FileBrowser.ReverseProxy.TlsResolver
browserLabels[fmt.Sprintf("traefik.http.routers.%s.rule", labelId)] = fmt.Sprintf("Host(`%s`) && PathPrefix(`/browsers/%s/`)", im.siteDomain, labelId)
browserLabels[fmt.Sprintf("traefik.http.routers.%s.entrypoints", labelId)] = im.config.FileBrowser.ReverseProxy.Entrypoint
browserLabels[fmt.Sprintf("traefik.http.routers.%s.middlewares", labelId)] = strings.Join(im.config.FileBrowser.ReverseProxy.Middlewares, ",")
if im.config.FileBrowser.ReverseProxy.Tls {
browserLabels[fmt.Sprintf("traefik.http.routers.%s.tls.certresolver", labelId)] = im.config.FileBrowser.ReverseProxy.TlsResolver
}
if err != nil {
@ -572,7 +571,7 @@ func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId stri
maps.Copy(browserLabels, *containerConfig)
command := self.config.FileBrowser.Command
command := im.config.FileBrowser.Command
command += fmt.Sprintf("-d /tmp/database/database.db -r /tmp/data -b /browsers/%s/", labelId)
@ -581,11 +580,11 @@ func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId stri
return nil, err
}
ContainerResponse, err := self.client.ContainerCreate(
ContainerResponse, err := im.client.ContainerCreate(
ctx,
&container.Config{
Cmd: splitCommand,
Image: fmt.Sprintf("%s:%s", self.config.FileBrowser.Image.Registry, self.config.FileBrowser.Image.Tag),
Image: fmt.Sprintf("%s:%s", im.config.FileBrowser.Image.Registry, im.config.FileBrowser.Image.Tag),
Labels: browserLabels,
Tty: true,
},
@ -596,7 +595,7 @@ func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId stri
},
&network.NetworkingConfig{
EndpointsConfig: map[string]*network.EndpointSettings{"browsers": {
NetworkID: self.config.FileBrowser.Network,
NetworkID: im.config.FileBrowser.Network,
}},
},
&v1.Platform{},
@ -606,34 +605,34 @@ func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId stri
return nil, err
}
err = self.client.ContainerStart(ctx, ContainerResponse.ID, container.StartOptions{})
err = im.client.ContainerStart(ctx, ContainerResponse.ID, container.StartOptions{})
if err != nil {
return nil, err
}
return &models.FileBrowser{
Url: fmt.Sprintf("%s/browsers/%s/", self.siteDomain, server.Id),
Url: fmt.Sprintf("%s/browsers/%s/", im.siteDomain, server.Id),
ServerId: server.Id,
Id: volume.Name,
}, nil
}
func (self *InstanceManager) StopFileBrowser(ctx context.Context, serverId string) error {
containers, err := self.containerList(ctx, ContainerLabels{Type: FileBrowser}, false)
func (im *InstanceManager) StopFileBrowser(ctx context.Context, serverId string) error {
containers, err := im.containerList(ctx, ContainerLabels{Type: FileBrowser}, false)
if err != nil {
return err
}
for _, rawContainer := range containers {
stopChan, _ := self.client.ContainerWait(ctx, rawContainer.ID, container.WaitConditionRemoved)
err := self.client.ContainerStop(ctx, rawContainer.ID, container.StopOptions{})
stopChan, _ := im.client.ContainerWait(ctx, rawContainer.ID, container.WaitConditionRemoved)
err := im.client.ContainerStop(ctx, rawContainer.ID, container.StopOptions{})
if err != nil {
return err
}
<-stopChan
for _, mount := range rawContainer.Mounts {
if mount.Destination == "/tmp/database" {
err := self.client.VolumeRemove(ctx, mount.Name, true)
err := im.client.VolumeRemove(ctx, mount.Name, true)
if err != nil {
return err
}