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_0058/pkgmachine/tencentcloud.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 pkgmachine

import (
	"fmt"
	"strings"

	"github.com/beego/beego/logs"
	"github.com/casibase/casibase/i18n"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
)

type MachineTencentClient struct {
	Client *cvm.Client
}

func newMachineTencentClient(accessKeyId string, accessKeySecret string, region string) (MachineTencentClient, error) {
	credential := common.NewCredential(accessKeyId, accessKeySecret)

	cpf := profile.NewClientProfile()
	cpf.HttpProfile.ReqMethod = "POST"
	cpf.HttpProfile.ReqTimeout = 60
	cpf.HttpProfile.Endpoint = "cvm.tencentcloudapi.com"
	cpf.SignMethod = "TC3-HMAC-SHA256"
	cpf.Debug = false

	client, err := cvm.NewClient(credential, region, cpf)
	if err != nil {
		return MachineTencentClient{}, err
	}

	return MachineTencentClient{Client: client}, nil
}

func getMachineFromTencentInstance(instance *cvm.Instance) *Machine {
	machine := &Machine{
		Name:        getString(instance.InstanceName),
		Id:          getString(instance.InstanceId),
		CreatedTime: getString(instance.CreatedTime),
		ExpireTime:  getString(instance.ExpiredTime),
		DisplayName: getString(instance.InstanceName),
		UpdatedTime: "",
		Zone:        getString(instance.Placement.Zone),

		Category: "",
		Type:     getString(instance.InstanceChargeType),
		Size:     getString(instance.InstanceType),
		State:    cases.Title(language.English).String(strings.ToLower(getString(instance.InstanceState))),

		Image: getString(instance.ImageId),
		Os:    getString(instance.OsName),

		CpuSize: fmt.Sprintf("%d", getInt64(instance.CPU)),
		MemSize: fmt.Sprintf("%d", getInt64(instance.Memory)),
	}

	for _, tag := range instance.Tags {
		machine.Tag += fmt.Sprintf("%s=%s,", getString(tag.Key), getString(tag.Value))
	}

	if len(instance.PublicIpAddresses) > 0 && instance.PublicIpAddresses[0] != nil {
		machine.PublicIp = *instance.PublicIpAddresses[0]
	}

	if len(instance.PrivateIpAddresses) > 0 && instance.PrivateIpAddresses[0] != nil {
		machine.PrivateIp = *instance.PrivateIpAddresses[0]
	}

	return machine
}

func (client MachineTencentClient) GetMachines(lang string) ([]*Machine, error) {
	request := cvm.NewDescribeInstancesRequest()

	response, err := client.Client.DescribeInstances(request)
	if err != nil {
		if _, ok := err.(*errors.TencentCloudSDKError); ok {
			return nil, fmt.Errorf(i18n.Translate(lang, "pkgmachine:Tencent Cloud API error: %s"), err)
		}
		return nil, err
	}

	logs.Info("DescribeInstances response: %s\n", response.ToJsonString())

	machines := []*Machine{}
	for _, reservation := range response.Response.InstanceSet {
		m := getMachineFromTencentInstance(reservation)
		machines = append(machines, m)
	}

	return machines, nil
}

func (client MachineTencentClient) GetMachine(name string, lang string) (*Machine, error) {
	request := cvm.NewDescribeInstancesRequest()

	request.Filters = []*cvm.Filter{
		{
			Name:   common.StringPtr("instance-name"),
			Values: []*string{&name},
		},
	}

	response, err := client.Client.DescribeInstances(request)
	if err != nil {
		if _, ok := err.(*errors.TencentCloudSDKError); ok {
			return nil, fmt.Errorf(i18n.Translate(lang, "pkgmachine:Tencent Cloud API error: %s"), err)
		}
		return nil, err
	}

	if len(response.Response.InstanceSet) == 0 {
		return nil, nil
	}

	instance := response.Response.InstanceSet[0]
	machine := getMachineFromTencentInstance(instance)
	return machine, nil
}

func (client MachineTencentClient) UpdateMachineState(name string, state string, lang string) (bool, string, error) {
	machine, err := client.GetMachine(name, lang)
	if err != nil {
		return false, "", err
	}

	if machine == nil {
		return false, fmt.Sprintf("Instance: [%s] is not found", name), nil
	}

	instanceId := machine.Id

	switch state {
	case "Running":
		startReq := cvm.NewStartInstancesRequest()
		startReq.InstanceIds = []*string{&instanceId}

		_, err = client.Client.StartInstances(startReq)
		if err != nil {
			logs.Error("Error starting instance: %v\n", err)
			return false, "", err
		}

	case "Stopped":
		stopReq := cvm.NewStopInstancesRequest()
		stopReq.InstanceIds = []*string{&instanceId}

		_, err = client.Client.StopInstances(stopReq)
		if err != nil {
			logs.Error("Error stopping instance: %v\n", err)
			return false, "", err
		}
	default:
		return false, fmt.Sprintf("Unsupported state: %s", state), nil
	}

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

func getString(ptr *string) string {
	if ptr == nil {
		return ""
	}
	return *ptr
}

func getInt64(ptr *int64) int64 {
	if ptr == nil {
		return 0
	}
	return *ptr
}