HEX
Server: Apache/2.4.54 (Win64) OpenSSL/1.1.1p PHP/7.4.30
System: Windows NT website-api 10.0 build 20348 (Windows Server 2016) AMD64
User: SYSTEM (0)
PHP: 7.4.30
Disabled: NONE
Upload Files
File: C:/github_repos/casibase_customer_0022/pkgdocker/docker_container.go
// Copyright 2025 The Casibase Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pkgdocker

import (
	"context"
	"fmt"
	"strconv"
	"time"

	"github.com/casibase/casibase/i18n"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
)

type Container struct {
	Owner       string `xorm:"varchar(100) notnull pk" json:"owner"`
	Name        string `xorm:"varchar(100) notnull pk" json:"name"`
	DisplayName string `xorm:"varchar(100)" json:"displayName"`
	Provider    string `xorm:"varchar(100)" json:"provider"`
	CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
	Image       string `xorm:"varchar(100)" json:"image"`
	ImageId     string `xorm:"varchar(100)" json:"imageId"`
	Command     string `xorm:"varchar(100)" json:"command"`
	SizeRw      int64  `xorm:"varchar(100)"  json:"sizeRw,omitempty"`
	SizeRootFs  int64  `xorm:"varchar(100)"  json:"sizeRootFs,omitempty"`
	Labels      map[string]string
	State       string `xorm:"varchar(100)" json:"state"`
	Status      string `xorm:"varchar(100)" json:"status"`
	Ports       string `xorm:"varchar(100)" json:"ports"`

	HostConfig struct {
		NetworkMode string            `json:",omitempty"`
		Annotations map[string]string `json:",omitempty"`
	}
}

type ContainerClient struct {
	Client *client.Client
}

// Docker remote access service needs to be enabled and configured in advance.
func NewContainerClient(username string, hostname string, region string) (ContainerClient, error) {
	remoteAddr := "tcp://" + hostname + ":2375"
	containerClient, err := client.NewClientWithOpts(client.WithHost(remoteAddr), client.WithAPIVersionNegotiation())
	if err != nil {
		return ContainerClient{}, err
	}

	return ContainerClient{Client: containerClient}, nil
}

func getContainerFromSummary(summary container.Summary) *Container {
	var ports string
	for _, port := range summary.Ports {
		ports += port.IP + ":" + strconv.Itoa(int(port.PublicPort)) + ":" + strconv.Itoa(int(port.PrivatePort)) + " "
	}
	myContainer := &Container{
		Name:        summary.ID,
		DisplayName: summary.Names[0],
		CreatedTime: time.Unix(summary.Created, 0).Format(time.RFC3339),
		Image:       summary.Image,
		ImageId:     summary.ImageID,
		Command:     summary.Command,
		SizeRw:      summary.SizeRw,
		SizeRootFs:  summary.SizeRootFs,
		Labels:      summary.Labels,
		State:       summary.State,
		Status:      summary.Status,
		Ports:       ports,
		HostConfig:  summary.HostConfig,
	}
	return myContainer
}

func (client ContainerClient) GetContainers() ([]*Container, error) {
	containers := []*Container{}
	sum, err := client.Client.ContainerList(context.Background(), container.ListOptions{All: true})
	if err != nil {
		return nil, err
	}
	for _, summary := range sum {
		containers = append(containers, getContainerFromSummary(summary))
	}
	return containers, nil
}

func (client ContainerClient) GetContainer(name string, lang string) (*Container, error) {
	sum, err := client.Client.ContainerList(context.Background(), container.ListOptions{All: true})
	if err != nil {
		return nil, err
	}
	for _, summary := range sum {
		if summary.ID == name {
			return getContainerFromSummary(summary), nil
		}
	}
	return nil, fmt.Errorf(i18n.Translate(lang, "pkgdocker:Container %s not found"), name)
}

func (client ContainerClient) UpdateContainerState(name string, state string, lang string) (bool, string, error) {
	myContainer, err := client.GetContainer(name, lang)
	if err != nil {
		return false, "", err
	}
	id := myContainer.Name
	switch state {
	case "Running":
		err = client.Client.ContainerStart(context.Background(), id, container.StartOptions{})
	case "Stopped":
		err = client.Client.ContainerStop(context.Background(), id, container.StopOptions{})
	default:
		return false, fmt.Sprintf("Unsupported state: %s", state), nil
	}

	if err != nil {
		return false, "", err
	}

	return true, fmt.Sprintf("Container: [%s]'s state has been successfully updated to: [%s]", id, state), nil
}