move app domain to its own module (0.4.x) (#689)
This commit is contained in:
parent
fc371bf068
commit
536eac788d
51 changed files with 319 additions and 5592 deletions
|
@ -1,89 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CasaOSURLFilename = "casaos.url"
|
||||
APICasaOSNotify = "/v1/notify"
|
||||
)
|
||||
|
||||
type NotifyService interface {
|
||||
SendNotify(path string, message map[string]interface{}) error
|
||||
SendSystemStatusNotify(message map[string]interface{}) error
|
||||
}
|
||||
type notifyService struct {
|
||||
address string
|
||||
}
|
||||
|
||||
func (n *notifyService) SendNotify(path string, message map[string]interface{}) error {
|
||||
|
||||
url := strings.TrimSuffix(n.address, "/") + APICasaOSNotify + "/" + path
|
||||
body, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := http.Post(url, "application/json", bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New("failed to send notify (status code: " + fmt.Sprint(response.StatusCode) + ")")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// disk: "sys_disk":{"size":56866869248,"avail":5855485952,"health":true,"used":48099700736}
|
||||
// usb: "sys_usb":[{"name": "sdc","size": 7747397632,"model": "DataTraveler_2.0","avail": 7714418688,"children": null}]
|
||||
func (n *notifyService) SendSystemStatusNotify(message map[string]interface{}) error {
|
||||
|
||||
url := strings.TrimSuffix(n.address, "/") + APICasaOSNotify + "/system_status"
|
||||
fmt.Println(url)
|
||||
body, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := http.Post(url, "application/json", bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New("failed to send notify (status code: " + fmt.Sprint(response.StatusCode) + ")")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
func NewNotifyService(runtimePath string) (NotifyService, error) {
|
||||
casaosAddressFile := filepath.Join(runtimePath, CasaOSURLFilename)
|
||||
|
||||
buf, err := os.ReadFile(casaosAddressFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
address := string(buf)
|
||||
|
||||
response, err := http.Get(address + "/ping")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.StatusCode != 200 {
|
||||
return nil, errors.New("failed to ping casaos service")
|
||||
}
|
||||
|
||||
return ¬ifyService{
|
||||
address: address,
|
||||
}, nil
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package common
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSendNotify(t *testing.T) {
|
||||
notify, err := NewNotifyService("/var/run/casaos")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = notify.SendNotify("test", map[string]interface{}{
|
||||
"test": "test",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendSystemStatusNotify(t *testing.T) {
|
||||
notify, err := NewNotifyService("/var/run/casaos")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = notify.SendSystemStatusNotify(map[string]interface{}{
|
||||
"sys_usb": `[{"name": "sdc","size": 7747397632,"model": "DataTraveler_2.0","avail": 7714418688,"children": null}]`,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
APICasaOSShare = "/v1/samba/shares"
|
||||
)
|
||||
|
||||
type ShareService interface {
|
||||
DeleteShare(id string) error
|
||||
}
|
||||
type shareService struct {
|
||||
address string
|
||||
}
|
||||
|
||||
func (n *shareService) DeleteShare(id string) error {
|
||||
url := strings.TrimSuffix(n.address, "/") + APICasaOSShare + "/" + id
|
||||
fmt.Println(url)
|
||||
message := "{}"
|
||||
body, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
// Create request
|
||||
req, err := http.NewRequest("DELETE", url, bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fetch Request
|
||||
response, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return errors.New("failed to send share (status code: " + fmt.Sprint(response.StatusCode) + ")")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func NewShareService(runtimePath string) (ShareService, error) {
|
||||
casaosAddressFile := filepath.Join(runtimePath, CasaOSURLFilename)
|
||||
|
||||
buf, err := os.ReadFile(casaosAddressFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
address := string(buf)
|
||||
|
||||
response, err := http.Get(address + "/ping")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.StatusCode != 200 {
|
||||
return nil, errors.New("failed to ping casaos service")
|
||||
}
|
||||
|
||||
return &shareService{
|
||||
address: address,
|
||||
}, nil
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package common
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDeleteShare(t *testing.T) {
|
||||
share, err := NewShareService("/var/run/casaos")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = share.DeleteShare("1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
18
go.mod
18
go.mod
|
@ -4,18 +4,13 @@ go 1.16
|
|||
|
||||
require (
|
||||
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
|
||||
github.com/IceWhaleTech/CasaOS-Common v0.3.7-5
|
||||
github.com/IceWhaleTech/CasaOS-Common v0.4.0-alpha1
|
||||
github.com/IceWhaleTech/CasaOS-Gateway v0.3.6
|
||||
github.com/Microsoft/go-winio v0.5.0 // indirect
|
||||
github.com/ambelovsky/go-structs v1.1.0 // indirect
|
||||
github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109
|
||||
github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 // indirect
|
||||
github.com/containerd/containerd v1.5.7 // indirect
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/gin-contrib/gzip v0.0.6
|
||||
|
@ -25,21 +20,14 @@ require (
|
|||
github.com/gomodule/redigo v1.8.5
|
||||
github.com/google/go-github/v36 v36.0.0
|
||||
github.com/googollee/go-socket.io v1.6.2
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/hirochachacha/go-smb2 v1.1.0
|
||||
github.com/jinzhu/copier v0.3.2
|
||||
github.com/lucas-clemente/quic-go v0.25.0
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shirou/gopsutil/v3 v3.22.7
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
|
@ -48,9 +36,7 @@ require (
|
|||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
||||
golang.org/x/mod v0.5.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
golang.org/x/tools v0.1.7 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gorm.io/driver/sqlite v1.2.6
|
||||
gorm.io/gorm v1.22.5
|
||||
)
|
||||
|
|
24
main.go
24
main.go
|
@ -9,12 +9,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/model"
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||
"github.com/IceWhaleTech/CasaOS/model/notify"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/cache"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/route"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
|
@ -43,7 +43,7 @@ func init() {
|
|||
}
|
||||
config.InitSetup(*configFlag)
|
||||
|
||||
loger.LogInit()
|
||||
logger.LogInit(config.AppInfo.LogPath, config.AppInfo.LogSaveName, config.AppInfo.LogFileExt)
|
||||
if len(*dbFlag) == 0 {
|
||||
*dbFlag = config.AppInfo.DBPath + "/db"
|
||||
}
|
||||
|
@ -55,14 +55,9 @@ func init() {
|
|||
|
||||
service.Cache = cache.Init()
|
||||
|
||||
service.GetToken()
|
||||
service.GetCPUThermalZone()
|
||||
|
||||
service.NewVersionApp = make(map[string]string)
|
||||
route.InitFunction()
|
||||
|
||||
// go service.LoopFriend()
|
||||
// go service.MyService.App().CheckNewImage()
|
||||
}
|
||||
|
||||
// @title casaOS API
|
||||
|
@ -111,7 +106,7 @@ func main() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
routers := []string{"sys", "apps", "container", "app-categories", "port", "file", "folder", "batch", "image", "samba", "notify"}
|
||||
routers := []string{"sys", "port", "file", "folder", "batch", "image", "samba", "notify"}
|
||||
for _, v := range routers {
|
||||
err = service.MyService.Gateway().CreateRoute(&model.Route{
|
||||
Path: "/v1/" + v,
|
||||
|
@ -138,20 +133,19 @@ func main() {
|
|||
}()
|
||||
|
||||
urlFilePath := filepath.Join(config.CommonInfo.RuntimePath, "casaos.url")
|
||||
err = file.CreateFileAndWriteContent(urlFilePath, "http://"+listener.Addr().String())
|
||||
if err != nil {
|
||||
loger.Error("Management service is listening...",
|
||||
if err := file.CreateFileAndWriteContent(urlFilePath, "http://"+listener.Addr().String()); err != nil {
|
||||
logger.Error("error when creating address file", zap.Error(err),
|
||||
zap.Any("address", listener.Addr().String()),
|
||||
zap.Any("filepath", urlFilePath),
|
||||
)
|
||||
}
|
||||
|
||||
if supported, err := daemon.SdNotify(false, daemon.SdNotifyReady); err != nil {
|
||||
loger.Error("Failed to notify systemd that casaos main service is ready", zap.Any("error", err))
|
||||
logger.Error("Failed to notify systemd that casaos main service is ready", zap.Any("error", err))
|
||||
} else if supported {
|
||||
loger.Info("Notified systemd that casaos main service is ready")
|
||||
logger.Info("Notified systemd that casaos main service is ready")
|
||||
} else {
|
||||
loger.Info("This process is not running as a systemd service.")
|
||||
logger.Info("This process is not running as a systemd service.")
|
||||
}
|
||||
|
||||
s := &http.Server{
|
||||
|
@ -159,6 +153,8 @@ func main() {
|
|||
ReadHeaderTimeout: 5 * time.Second, // fix G112: Potential slowloris attack (see https://github.com/securego/gosec)
|
||||
}
|
||||
|
||||
logger.Info("CasaOS main service is listening...", zap.Any("address", listener.Addr().String()))
|
||||
|
||||
err = s.Serve(listener) // not using http.serve() to fix G114: Use of net/http serve function that has no support for setting timeouts (see https://github.com/securego/gosec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
128
model/app.go
128
model/app.go
|
@ -1,128 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ServerAppListCollection struct {
|
||||
List []ServerAppList `json:"list"`
|
||||
Recommend []ServerAppList `json:"recommend"`
|
||||
Community []ServerAppList `json:"community"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// @tiger - 对于用于出参的数据结构,静态信息(例如 title)和
|
||||
// 动态信息(例如 state、query_count)应该划分到不同的数据结构中
|
||||
//
|
||||
// 这样的好处是
|
||||
// 1 - 多次获取动态信息时可以减少出参复杂度,因为静态信息只获取一次就好
|
||||
// 2 - 在未来的迭代中,可以降低维护成本(所有字段都展开放在一个层级维护成本略高)
|
||||
//
|
||||
// 另外,一些针对性字段,例如 Docker 相关的,可以用 map 来保存。
|
||||
// 这样在未来增加多态 App,例如 Snap,不需要维护多个结构,或者一个结构保存不必要的字段
|
||||
type ServerAppList struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Tagline string `json:"tagline"`
|
||||
Tags Strings `gorm:"type:json" json:"tags"`
|
||||
Icon string `json:"icon"`
|
||||
ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"`
|
||||
Category string `json:"category"`
|
||||
CategoryId int `json:"category_id"`
|
||||
CategoryFont string `json:"category_font"`
|
||||
PortMap string `json:"port_map"`
|
||||
ImageVersion string `json:"image_version"`
|
||||
Tip string `json:"tip"`
|
||||
Envs EnvArray `json:"envs"`
|
||||
Ports PortArray `json:"ports"`
|
||||
Volumes PathArray `json:"volumes"`
|
||||
Devices PathArray `json:"devices"`
|
||||
NetworkModel string `json:"network_model"`
|
||||
Image string `json:"image"`
|
||||
Index string `json:"index"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
State int `json:"state"`
|
||||
Author string `json:"author"`
|
||||
MinMemory int `json:"min_memory"`
|
||||
MinDisk int `json:"min_disk"`
|
||||
MaxMemory uint64 `json:"max_memory"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Healthy string `json:"healthy"`
|
||||
Plugins Strings `json:"plugins"`
|
||||
Origin string `json:"origin"`
|
||||
Type int `json:"type"`
|
||||
QueryCount int `json:"query_count"`
|
||||
Developer string `json:"developer"`
|
||||
HostName string `json:"host_name"`
|
||||
Privileged bool `json:"privileged"`
|
||||
CapAdd Strings `json:"cap_add"`
|
||||
Cmd Strings `json:"cmd"`
|
||||
}
|
||||
|
||||
type Ports struct {
|
||||
ContainerPort uint `json:"container_port"`
|
||||
CommendPort int `json:"commend_port"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑
|
||||
}
|
||||
|
||||
type Volume struct {
|
||||
ContainerPath string `json:"container_path"`
|
||||
Path string `json:"path"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑
|
||||
}
|
||||
|
||||
type Envs struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑
|
||||
}
|
||||
|
||||
type Devices struct {
|
||||
ContainerPath string `json:"container_path"`
|
||||
Path string `json:"path"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"` // 1:必选 2:可选 3:默认值不必显示 4:系统处理 5:container内容也可编辑
|
||||
}
|
||||
|
||||
type configures struct {
|
||||
TcpPorts []Ports `json:"tcp_ports"`
|
||||
UdpPorts []Ports `json:"udp_ports"`
|
||||
Envs []Envs `json:"envs"`
|
||||
Volumes []Volume `json:"volumes"`
|
||||
Devices []Devices `json:"devices"`
|
||||
}
|
||||
|
||||
/****************使gorm支持[]string结构*******************/
|
||||
type Strings []string
|
||||
|
||||
func (c Strings) Value() (driver.Value, error) {
|
||||
b, err := json.Marshal(c)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func (c *Strings) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), c)
|
||||
}
|
||||
|
||||
/****************使gorm支持[]string结构*******************/
|
||||
|
||||
/****************使gorm支持[]string结构*******************/
|
||||
type MapStrings []map[string]string
|
||||
|
||||
func (c MapStrings) Value() (driver.Value, error) {
|
||||
b, err := json.Marshal(c)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func (c *MapStrings) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), c)
|
||||
}
|
||||
|
||||
/****************使gorm支持[]string结构*******************/
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* @Author: link a624669980@163.com
|
||||
* @Date: 2022-05-16 17:37:08
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-07-13 10:46:38
|
||||
* @FilePath: /CasaOS/model/category.go
|
||||
* @Description:
|
||||
*/
|
||||
package model
|
||||
|
||||
type ServerCategoryList struct {
|
||||
Version string `json:"version"`
|
||||
Item []CategoryList `json:"item"`
|
||||
}
|
||||
type CategoryList struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
//CreatedAt time.Time `json:"created_at"`
|
||||
//
|
||||
//UpdatedAt time.Time `json:"updated_at"`
|
||||
Font string `json:"font"` // @tiger - 如果这个和前端有关,应该不属于后端的出参范围,而是前端去界定
|
||||
Name string `json:"name"`
|
||||
Count uint `json:"count"` // @tiger - count 属于动态信息,应该单独放在一个出参结构中(原因见另外一个关于 静态/动态 出参的注释)
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2021-12-08 18:10:25
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-07-13 10:49:16
|
||||
* @FilePath: /CasaOS/model/docker.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
type DockerStatsModel struct {
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
Data interface{} `json:"data"`
|
||||
Previous interface{} `json:"previous"`
|
||||
}
|
||||
|
||||
// reference - https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file
|
||||
type DockerDaemonConfigurationModel struct {
|
||||
// e.g. `/var/lib/docker`
|
||||
Root string `json:"data-root,omitempty"`
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type TcpPorts struct {
|
||||
Desc string `json:"desc"`
|
||||
ContainerPort int `json:"container_port"`
|
||||
}
|
||||
type UdpPorts struct {
|
||||
Desc string `json:"desc"`
|
||||
ContainerPort int `json:"container_port"`
|
||||
}
|
||||
|
||||
/*******************使用gorm支持json************************************/
|
||||
|
||||
type PortMap struct {
|
||||
ContainerPort string `json:"container"`
|
||||
CommendPort string `json:"host"`
|
||||
Protocol string `json:"protocol"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"`
|
||||
}
|
||||
|
||||
type PortArray []PortMap
|
||||
|
||||
// Value 实现方法
|
||||
func (p PortArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(p)
|
||||
}
|
||||
|
||||
// Scan 实现方法
|
||||
func (p *PortArray) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), p)
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*******************使用gorm支持json************************************/
|
||||
|
||||
type Env struct {
|
||||
Name string `json:"container"`
|
||||
Value string `json:"host"`
|
||||
Desc string `json:"desc"`
|
||||
Type int `json:"type"`
|
||||
}
|
||||
|
||||
type JSON json.RawMessage
|
||||
|
||||
type EnvArray []Env
|
||||
|
||||
// Value 实现方法
|
||||
func (p EnvArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(p)
|
||||
//return .MarshalJSON()
|
||||
}
|
||||
|
||||
// Scan 实现方法
|
||||
func (p *EnvArray) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), p)
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*******************使用gorm支持json************************************/
|
||||
|
||||
type PathMap struct {
|
||||
ContainerPath string `json:"container"`
|
||||
Path string `json:"host"`
|
||||
Type int `json:"type"`
|
||||
Desc string `json:"desc"`
|
||||
}
|
||||
|
||||
type PathArray []PathMap
|
||||
|
||||
// Value 实现方法
|
||||
func (p PathArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(p)
|
||||
}
|
||||
|
||||
// Scan 实现方法
|
||||
func (p *PathArray) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), p)
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
//type PostData struct {
|
||||
// Envs EnvArrey `json:"envs,omitempty"`
|
||||
// Udp PortArrey `json:"udp_ports"`
|
||||
// Tcp PortArrey `json:"tcp_ports"`
|
||||
// Volumes PathArrey `json:"volumes"`
|
||||
// Devices PathArrey `json:"devices"`
|
||||
// Port string `json:"port,omitempty"`
|
||||
// PortMap string `json:"port_map"`
|
||||
// CpuShares int64 `json:"cpu_shares,omitempty"`
|
||||
// Memory int64 `json:"memory,omitempty"`
|
||||
// Restart string `json:"restart,omitempty"`
|
||||
// EnableUPNP bool `json:"enable_upnp"`
|
||||
// Label string `json:"label"`
|
||||
// Position bool `json:"position"`
|
||||
//}
|
||||
|
||||
type CustomizationPostData struct {
|
||||
ContainerName string `json:"container_name"`
|
||||
CustomId string `json:"custom_id"`
|
||||
Origin string `json:"origin"`
|
||||
NetworkModel string `json:"network_model"`
|
||||
Index string `json:"index"`
|
||||
Icon string `json:"icon"`
|
||||
Image string `json:"image"`
|
||||
Envs EnvArray `json:"envs"`
|
||||
Ports PortArray `json:"ports"`
|
||||
Volumes PathArray `json:"volumes"`
|
||||
Devices PathArray `json:"devices"`
|
||||
//Port string `json:"port,omitempty"`
|
||||
PortMap string `json:"port_map"`
|
||||
CpuShares int64 `json:"cpu_shares"`
|
||||
Memory int64 `json:"memory"`
|
||||
Restart string `json:"restart"`
|
||||
EnableUPNP bool `json:"enable_upnp"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
Position bool `json:"position"`
|
||||
HostName string `json:"host_name"`
|
||||
Privileged bool `json:"privileged"`
|
||||
CapAdd []string `json:"cap_add"`
|
||||
Cmd []string `json:"cmd"`
|
||||
Protocol string `json:"protocol"`
|
||||
Host string `json:"host"`
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-27 15:01:58
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-05-31 14:51:21
|
||||
* @FilePath: /CasaOS/model/notify/application.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package notify
|
||||
|
||||
type Application struct {
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
Type string `json:"type"`
|
||||
Icon string `json:"icon"`
|
||||
Message string `json:"message"`
|
||||
Finished bool `json:"finished"`
|
||||
Success bool `json:"success"`
|
||||
}
|
|
@ -14,7 +14,7 @@ import "time"
|
|||
|
||||
// 系统配置
|
||||
type SysInfoModel struct {
|
||||
Name string //系统名称
|
||||
Name string // 系统名称
|
||||
}
|
||||
|
||||
// 服务配置
|
||||
|
@ -66,10 +66,6 @@ type SystemConfig struct {
|
|||
ConfigPath string `json:"config_path"`
|
||||
}
|
||||
|
||||
type CasaOSGlobalVariables struct {
|
||||
AppChange bool
|
||||
}
|
||||
|
||||
type FileSetting struct {
|
||||
ShareDir []string `json:"share_dir" delim:"|"`
|
||||
DownloadDir string `json:"download_dir"`
|
||||
|
|
|
@ -31,23 +31,20 @@ var AppInfo = &model.APPModel{}
|
|||
|
||||
var CommonInfo = &model.CommonModel{}
|
||||
|
||||
//var RedisInfo = &model.RedisModel{}
|
||||
// var RedisInfo = &model.RedisModel{}
|
||||
|
||||
// server相关
|
||||
var ServerInfo = &model.ServerModel{}
|
||||
|
||||
var SystemConfigInfo = &model.SystemConfig{}
|
||||
|
||||
var CasaOSGlobalVariables = &model.CasaOSGlobalVariables{}
|
||||
|
||||
var FileSettingInfo = &model.FileSetting{}
|
||||
|
||||
var Cfg *ini.File
|
||||
|
||||
// 初始化设置,获取系统的部分信息。
|
||||
func InitSetup(config string) {
|
||||
|
||||
var configDir = USERCONFIGURL
|
||||
configDir := USERCONFIGURL
|
||||
if len(config) > 0 {
|
||||
configDir = config
|
||||
}
|
||||
|
@ -55,7 +52,7 @@ func InitSetup(config string) {
|
|||
configDir = "./conf/conf.conf"
|
||||
}
|
||||
var err error
|
||||
//读取文件
|
||||
// 读取文件
|
||||
Cfg, err = ini.Load(configDir)
|
||||
if err != nil {
|
||||
Cfg, err = ini.Load("/etc/casaos.conf")
|
||||
|
@ -68,7 +65,7 @@ func InitSetup(config string) {
|
|||
}
|
||||
}
|
||||
mapTo("app", AppInfo)
|
||||
//mapTo("redis", RedisInfo)
|
||||
// mapTo("redis", RedisInfo)
|
||||
mapTo("server", ServerInfo)
|
||||
mapTo("system", SystemConfigInfo)
|
||||
mapTo("file", FileSettingInfo)
|
||||
|
@ -91,7 +88,6 @@ func InitSetup(config string) {
|
|||
}
|
||||
Cfg.SaveTo(configDir)
|
||||
// AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd()
|
||||
|
||||
}
|
||||
|
||||
// 映射
|
||||
|
@ -111,6 +107,7 @@ func getCurrentAbPathByCaller() string {
|
|||
}
|
||||
return abPath
|
||||
}
|
||||
|
||||
func getCurrentDirectory() string {
|
||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
if err != nil {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
package docker
|
||||
|
||||
const NETWORKNAME = "oasis"
|
|
@ -1,402 +0,0 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func NewSshClient(user, password string, port string) (*ssh.Client, error) {
|
||||
// connet to ssh
|
||||
// addr = fmt.Sprintf("%s:%d", host, port)
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
Timeout: time.Second * 5,
|
||||
User: user,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
// HostKeyCallback: ,
|
||||
// HostKeyCallback: hostKeyCallBackFunc(h.Host),
|
||||
}
|
||||
// if h.Type == "password" {
|
||||
config.Auth = []ssh.AuthMethod{ssh.Password(password)}
|
||||
//} else {
|
||||
// config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)}
|
||||
//}
|
||||
addr := fmt.Sprintf("%s:%s", "127.0.0.1", port)
|
||||
c, err := ssh.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// setup ssh shell session
|
||||
// set Session and StdinPipe here,
|
||||
// and the Session.Stdout and Session.Sdterr are also set.
|
||||
func NewSshConn(cols, rows int, sshClient *ssh.Client) (*SshConn, error) {
|
||||
sshSession, err := sshClient.NewSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stdinP, err := sshSession.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
comboWriter := new(wsBufferWriter)
|
||||
|
||||
sshSession.Stdout = comboWriter
|
||||
sshSession.Stderr = comboWriter
|
||||
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 1, // disable echo
|
||||
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
|
||||
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
|
||||
}
|
||||
// Request pseudo terminal
|
||||
if err := sshSession.RequestPty("xterm", rows, cols, modes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Start remote shell
|
||||
if err := sshSession.Shell(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SshConn{StdinPipe: stdinP, ComboOutput: comboWriter, Session: sshSession}, nil
|
||||
}
|
||||
|
||||
type SshConn struct {
|
||||
// calling Write() to write data into ssh server
|
||||
StdinPipe io.WriteCloser
|
||||
// Write() be called to receive data from ssh server
|
||||
ComboOutput *wsBufferWriter
|
||||
Session *ssh.Session
|
||||
}
|
||||
type wsBufferWriter struct {
|
||||
buffer bytes.Buffer
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (w *wsBufferWriter) Write(p []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.buffer.Write(p)
|
||||
}
|
||||
|
||||
func (s *SshConn) Close() {
|
||||
if s.Session != nil {
|
||||
s.Session.Close()
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
wsMsgCmd = "cmd"
|
||||
wsMsgResize = "resize"
|
||||
)
|
||||
|
||||
// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
|
||||
func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
|
||||
// tells other go routine quit
|
||||
username := ""
|
||||
for {
|
||||
|
||||
// read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
msgObj := wsMsg{}
|
||||
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
|
||||
msgObj.Type = "cmd"
|
||||
msgObj.Cmd = string(wsData)
|
||||
}
|
||||
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
|
||||
//}
|
||||
switch msgObj.Type {
|
||||
case wsMsgCmd:
|
||||
// handle xterm.js stdin
|
||||
// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
|
||||
decodeBytes := []byte(msgObj.Cmd)
|
||||
if msgObj.Cmd == "\u007f" {
|
||||
if len(username) == 0 {
|
||||
continue
|
||||
}
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("\b\x1b[K"))
|
||||
username = username[:len(username)-1]
|
||||
continue
|
||||
}
|
||||
if msgObj.Cmd == "\r" {
|
||||
return username
|
||||
}
|
||||
username += msgObj.Cmd
|
||||
|
||||
if err := wsConn.WriteMessage(websocket.TextMessage, decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
|
||||
}
|
||||
// write input cmd to log buffer
|
||||
if _, err := logBuff.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("write received cmd into log buffer failed")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
|
||||
// tells other go routine quit
|
||||
password := ""
|
||||
for {
|
||||
|
||||
// read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("reading webSocket message failed")
|
||||
return ""
|
||||
}
|
||||
|
||||
msgObj := wsMsg{}
|
||||
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
|
||||
msgObj.Type = "cmd"
|
||||
msgObj.Cmd = string(wsData)
|
||||
}
|
||||
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
|
||||
//}
|
||||
switch msgObj.Type {
|
||||
case wsMsgCmd:
|
||||
// handle xterm.js stdin
|
||||
// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
|
||||
if msgObj.Cmd == "\r" {
|
||||
return password
|
||||
}
|
||||
|
||||
if msgObj.Cmd == "\u007f" {
|
||||
if len(password) == 0 {
|
||||
continue
|
||||
}
|
||||
password = password[:len(password)-1]
|
||||
continue
|
||||
}
|
||||
password += msgObj.Cmd
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
|
||||
func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
|
||||
// tells other go routine quit
|
||||
defer setQuit(exitCh)
|
||||
for {
|
||||
select {
|
||||
case <-exitCh:
|
||||
return
|
||||
default:
|
||||
// read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("reading webSocket message failed")
|
||||
return
|
||||
}
|
||||
//unmashal bytes into struct
|
||||
//msgObj := wsMsg{
|
||||
// Type: "cmd",
|
||||
// Cmd: "",
|
||||
// Rows: 50,
|
||||
// Cols: 180,
|
||||
//}
|
||||
msgObj := wsMsg{}
|
||||
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
|
||||
msgObj.Type = "cmd"
|
||||
msgObj.Cmd = string(wsData)
|
||||
}
|
||||
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
|
||||
//}
|
||||
switch msgObj.Type {
|
||||
|
||||
case wsMsgResize:
|
||||
// handle xterm.js size change
|
||||
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
||||
if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
|
||||
logrus.WithError(err).Error("ssh pty change windows size failed")
|
||||
}
|
||||
}
|
||||
case wsMsgCmd:
|
||||
// handle xterm.js stdin
|
||||
// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
|
||||
decodeBytes := []byte(msgObj.Cmd)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("websock cmd string base64 decoding failed")
|
||||
}
|
||||
if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
|
||||
}
|
||||
// write input cmd to log buffer
|
||||
if _, err := logBuff.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("write received cmd into log buffer failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ssConn *SshConn) SendComboOutput(wsConn *websocket.Conn, exitCh chan bool) {
|
||||
// tells other go routine quit
|
||||
// defer setQuit(exitCh)
|
||||
|
||||
// every 120ms write combine output bytes into websocket response
|
||||
tick := time.NewTicker(time.Millisecond * time.Duration(120))
|
||||
// for range time.Tick(120 * time.Millisecond){}
|
||||
defer tick.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
// write combine output bytes into websocket response
|
||||
if err := flushComboOutput(ssConn.ComboOutput, wsConn); err != nil {
|
||||
logrus.WithError(err).Error("ssh sending combo output to webSocket failed")
|
||||
return
|
||||
}
|
||||
case <-exitCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error {
|
||||
if w.buffer.Len() != 0 {
|
||||
err := wsConn.WriteMessage(websocket.TextMessage, w.buffer.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.buffer.Reset()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
|
||||
func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
|
||||
// tells other go routine quit
|
||||
defer setQuit(exitCh)
|
||||
for {
|
||||
select {
|
||||
case <-exitCh:
|
||||
return
|
||||
default:
|
||||
// read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("reading webSocket message failed")
|
||||
return
|
||||
}
|
||||
//unmashal bytes into struct
|
||||
//msgObj := wsMsg{
|
||||
// Type: "cmd",
|
||||
// Cmd: "",
|
||||
// Rows: 50,
|
||||
// Cols: 180,
|
||||
//}
|
||||
msgObj := wsMsg{}
|
||||
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
|
||||
msgObj.Type = "cmd"
|
||||
msgObj.Cmd = string(wsData)
|
||||
}
|
||||
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
|
||||
//}
|
||||
switch msgObj.Type {
|
||||
|
||||
case wsMsgResize:
|
||||
// handle xterm.js size change
|
||||
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
||||
if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
|
||||
logrus.WithError(err).Error("ssh pty change windows size failed")
|
||||
}
|
||||
}
|
||||
case wsMsgCmd:
|
||||
// handle xterm.js stdin
|
||||
// decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
|
||||
decodeBytes := []byte(msgObj.Cmd)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("websock cmd string base64 decoding failed")
|
||||
}
|
||||
if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
|
||||
}
|
||||
// write input cmd to log buffer
|
||||
if _, err := logBuff.Write(decodeBytes); err != nil {
|
||||
logrus.WithError(err).Error("write received cmd into log buffer failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ssConn *SshConn) SessionWait(quitChan chan bool) {
|
||||
if err := ssConn.Session.Wait(); err != nil {
|
||||
logrus.WithError(err).Error("ssh session wait failed")
|
||||
setQuit(quitChan)
|
||||
}
|
||||
}
|
||||
|
||||
func setQuit(ch chan bool) {
|
||||
ch <- true
|
||||
}
|
||||
|
||||
type wsMsg struct {
|
||||
Type string `json:"type"`
|
||||
Cmd string `json:"cmd"`
|
||||
Cols int `json:"cols"`
|
||||
Rows int `json:"rows"`
|
||||
}
|
||||
|
||||
// 将终端的输出转发到前端
|
||||
func WsWriterCopy(reader io.Reader, writer *websocket.Conn) {
|
||||
buf := make([]byte, 8192)
|
||||
reg1 := regexp.MustCompile(`stty rows \d+ && stty cols \d+ `)
|
||||
for {
|
||||
nr, err := reader.Read(buf)
|
||||
if nr > 0 {
|
||||
result1 := reg1.FindIndex(buf[0:nr])
|
||||
if len(result1) > 0 {
|
||||
fmt.Println(result1)
|
||||
} else {
|
||||
err := writer.WriteMessage(websocket.BinaryMessage, buf[0:nr])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将前端的输入转发到终端
|
||||
func WsReaderCopy(reader *websocket.Conn, writer io.Writer) {
|
||||
for {
|
||||
messageType, p, err := reader.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if messageType == websocket.TextMessage {
|
||||
msgObj := wsMsg{}
|
||||
if err = json2.Unmarshal(p, &msgObj); err != nil {
|
||||
writer.Write(p)
|
||||
} else if msgObj.Type == wsMsgResize {
|
||||
// writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package docker
|
||||
|
||||
import "strings"
|
||||
|
||||
func GetDir(id, envName string) string {
|
||||
|
||||
if strings.Contains(envName, "$AppID") && len(id) > 0 {
|
||||
return strings.ReplaceAll(envName, "$AppID", id)
|
||||
}
|
||||
return envName
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDir(t *testing.T) {
|
||||
fmt.Println(GetDir("", "config"))
|
||||
}
|
|
@ -13,8 +13,8 @@ package sqlite
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/driver/sqlite"
|
||||
|
@ -28,8 +28,8 @@ func GetDb(dbPath string) *gorm.DB {
|
|||
return gdb
|
||||
}
|
||||
// Refer https://github.com/go-sql-driver/mysql#dsn-data-source-name
|
||||
//dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName)
|
||||
//db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
|
||||
// dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName)
|
||||
// db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
|
||||
file.IsNotExistMkDir(dbPath)
|
||||
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
|
||||
c, _ := db.DB()
|
||||
|
@ -37,19 +37,18 @@ func GetDb(dbPath string) *gorm.DB {
|
|||
c.SetMaxOpenConns(100)
|
||||
c.SetConnMaxIdleTime(time.Second * 1000)
|
||||
if err != nil {
|
||||
loger.Error("sqlite connect error", zap.Any("db connect error", err))
|
||||
logger.Error("sqlite connect error", zap.Any("db connect error", err))
|
||||
panic("sqlite connect error")
|
||||
return nil
|
||||
}
|
||||
gdb = db
|
||||
|
||||
err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{})
|
||||
err = db.AutoMigrate(&model2.AppNotify{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{})
|
||||
db.Exec("DROP TABLE IF EXISTS o_application")
|
||||
db.Exec("DROP TABLE IF EXISTS o_friend")
|
||||
db.Exec("DROP TABLE IF EXISTS o_person_download")
|
||||
db.Exec("DROP TABLE IF EXISTS o_person_down_record")
|
||||
if err != nil {
|
||||
loger.Error("check or create db error", zap.Any("error", err))
|
||||
logger.Error("check or create db error", zap.Any("error", err))
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package env_helper
|
||||
|
||||
import "strings"
|
||||
|
||||
func ReplaceDefaultENV(key, tz string) string {
|
||||
temp := ""
|
||||
switch key {
|
||||
case "$DefaultPassword":
|
||||
temp = "casaos"
|
||||
case "$DefaultUserName":
|
||||
temp = "admin"
|
||||
|
||||
case "$PUID":
|
||||
temp = "1000"
|
||||
case "$PGID":
|
||||
temp = "1000"
|
||||
case "$TZ":
|
||||
temp = tz
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
//replace env default setting
|
||||
func ReplaceStringDefaultENV(str string) string {
|
||||
return strings.ReplaceAll(strings.ReplaceAll(str, "$DefaultPassword", ReplaceDefaultENV("$DefaultPassword", "")), "$DefaultUserName", ReplaceDefaultENV("$DefaultUserName", ""))
|
||||
}
|
|
@ -12,9 +12,9 @@ import (
|
|||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
//发送GET请求
|
||||
//url:请求地址
|
||||
//response:请求返回的内容
|
||||
// 发送GET请求
|
||||
// url:请求地址
|
||||
// response:请求返回的内容
|
||||
func Get(url string, head map[string]string) (response string) {
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
|
@ -28,10 +28,10 @@ func Get(url string, head map[string]string) (response string) {
|
|||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
//需要错误日志的处理
|
||||
//loger.Error(error)
|
||||
// 需要错误日志的处理
|
||||
// logger.Error(error)
|
||||
return ""
|
||||
//panic(error)
|
||||
// panic(error)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var buffer [512]byte
|
||||
|
@ -42,7 +42,7 @@ func Get(url string, head map[string]string) (response string) {
|
|||
if err != nil && err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
//loger.Error(err)
|
||||
// logger.Error(err)
|
||||
return ""
|
||||
// panic(err)
|
||||
}
|
||||
|
@ -51,22 +51,21 @@ func Get(url string, head map[string]string) (response string) {
|
|||
return
|
||||
}
|
||||
|
||||
//发送GET请求
|
||||
//url:请求地址
|
||||
//response:请求返回的内容
|
||||
// 发送GET请求
|
||||
// url:请求地址
|
||||
// response:请求返回的内容
|
||||
func PersonGet(url string) (response string) {
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
//需要错误日志的处理
|
||||
//loger.Error(error)
|
||||
// 需要错误日志的处理
|
||||
// logger.Error(error)
|
||||
return ""
|
||||
//panic(error)
|
||||
// panic(error)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var buffer [512]byte
|
||||
|
@ -77,7 +76,7 @@ func PersonGet(url string) (response string) {
|
|||
if err != nil && err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
//loger.Error(err)
|
||||
// logger.Error(err)
|
||||
return ""
|
||||
// panic(err)
|
||||
}
|
||||
|
@ -86,11 +85,10 @@ func PersonGet(url string) (response string) {
|
|||
return
|
||||
}
|
||||
|
||||
//发送POST请求
|
||||
//url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
//content:请求放回的内容
|
||||
// 发送POST请求
|
||||
// url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
// content:请求放回的内容
|
||||
func Post(url string, data []byte, contentType string, head map[string]string) (content string) {
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||
req.Header.Add("content-type", contentType)
|
||||
for k, v := range head {
|
||||
|
@ -113,9 +111,9 @@ func Post(url string, data []byte, contentType string, head map[string]string) (
|
|||
return
|
||||
}
|
||||
|
||||
//发送POST请求
|
||||
//url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
//content:请求放回的内容
|
||||
// 发送POST请求
|
||||
// url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
// content:请求放回的内容
|
||||
func ZeroTierGet(url string, head map[string]string) (content string, code int) {
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
for k, v := range head {
|
||||
|
@ -138,11 +136,10 @@ func ZeroTierGet(url string, head map[string]string) (content string, code int)
|
|||
return
|
||||
}
|
||||
|
||||
//发送GET请求
|
||||
//url:请求地址
|
||||
//response:请求返回的内容
|
||||
// 发送GET请求
|
||||
// url:请求地址
|
||||
// response:请求返回的内容
|
||||
func OasisGet(url string) (response string) {
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
t := make(chan string)
|
||||
|
@ -155,5 +152,4 @@ func OasisGet(url string) (response string) {
|
|||
head["Authorization"] = <-t
|
||||
|
||||
return Get(url, head)
|
||||
|
||||
}
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-06-02 15:09:38
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-06-27 15:47:49
|
||||
* @FilePath: /CasaOS/pkg/utils/loger/log.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package loger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
var loggers *zap.Logger
|
||||
|
||||
func getFileLogWriter() (writeSyncer zapcore.WriteSyncer) {
|
||||
// 使用 lumberjack 实现 log rotate
|
||||
lumberJackLogger := &lumberjack.Logger{
|
||||
Filename: filepath.Join(config.AppInfo.LogPath, fmt.Sprintf("%s.%s",
|
||||
config.AppInfo.LogSaveName,
|
||||
config.AppInfo.LogFileExt,
|
||||
)),
|
||||
MaxSize: 10,
|
||||
MaxBackups: 60,
|
||||
MaxAge: 1,
|
||||
Compress: true,
|
||||
}
|
||||
|
||||
return zapcore.AddSync(lumberJackLogger)
|
||||
}
|
||||
|
||||
func LogInit() {
|
||||
encoderConfig := zap.NewProductionEncoderConfig()
|
||||
encoderConfig.EncodeTime = zapcore.EpochTimeEncoder
|
||||
encoder := zapcore.NewJSONEncoder(encoderConfig)
|
||||
fileWriteSyncer := getFileLogWriter()
|
||||
core := zapcore.NewTee(
|
||||
zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.InfoLevel),
|
||||
zapcore.NewCore(encoder, fileWriteSyncer, zapcore.InfoLevel),
|
||||
)
|
||||
loggers = zap.New(core)
|
||||
|
||||
}
|
||||
|
||||
func Info(message string, fields ...zap.Field) {
|
||||
callerFields := getCallerInfoForLog()
|
||||
fields = append(fields, callerFields...)
|
||||
loggers.Info(message, fields...)
|
||||
}
|
||||
|
||||
func Debug(message string, fields ...zap.Field) {
|
||||
callerFields := getCallerInfoForLog()
|
||||
fields = append(fields, callerFields...)
|
||||
loggers.Debug(message, fields...)
|
||||
}
|
||||
|
||||
func Error(message string, fields ...zap.Field) {
|
||||
callerFields := getCallerInfoForLog()
|
||||
fields = append(fields, callerFields...)
|
||||
loggers.Error(message, fields...)
|
||||
}
|
||||
|
||||
func Warn(message string, fields ...zap.Field) {
|
||||
callerFields := getCallerInfoForLog()
|
||||
fields = append(fields, callerFields...)
|
||||
loggers.Warn(message, fields...)
|
||||
}
|
||||
|
||||
func getCallerInfoForLog() (callerFields []zap.Field) {
|
||||
|
||||
pc, file, line, ok := runtime.Caller(2) // 回溯两层,拿到写日志的调用方的函数信息
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
funcName := runtime.FuncForPC(pc).Name()
|
||||
funcName = path.Base(funcName) //Base函数返回路径的最后一个元素,只保留函数名
|
||||
|
||||
callerFields = append(callerFields, zap.String("func", funcName), zap.String("file", file), zap.Int("line", line))
|
||||
return
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package port
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// 获取可用端口
|
||||
func GetAvailablePort(t string) (int, error) {
|
||||
address := fmt.Sprintf("%s:0", "0.0.0.0")
|
||||
if t == "udp" {
|
||||
add, err := net.ResolveUDPAddr(t, address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
listener, err := net.ListenUDP(t, add)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer listener.Close()
|
||||
return listener.LocalAddr().(*net.UDPAddr).Port, nil
|
||||
} else {
|
||||
add, err := net.ResolveTCPAddr(t, address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
listener, err := net.ListenTCP(t, add)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer listener.Close()
|
||||
return listener.Addr().(*net.TCPAddr).Port, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 判断端口是否可以(未被占用)
|
||||
// param t tcp/udp
|
||||
func IsPortAvailable(port int, t string) bool {
|
||||
address := fmt.Sprintf("%s:%d", "0.0.0.0", port)
|
||||
if t == "udp" {
|
||||
sadd, err := net.ResolveUDPAddr("udp", address)
|
||||
uc, err := net.ListenUDP("udp", sadd)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return false
|
||||
} else {
|
||||
defer uc.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
} else {
|
||||
listener, err := net.Listen(t, address)
|
||||
|
||||
if err != nil {
|
||||
//log.Infof("port %s is taken: %s", address, err)
|
||||
return false
|
||||
}
|
||||
defer listener.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package port
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPortAvailable(t *testing.T) {
|
||||
// fmt.Println(PortAvailable())
|
||||
//fmt.Println(IsPortAvailable(6881,"tcp"))
|
||||
p, _ := GetAvailablePort("udp")
|
||||
fmt.Println("udp", p)
|
||||
fmt.Println(IsPortAvailable(p, "udp"))
|
||||
|
||||
t1, _ := GetAvailablePort("tcp")
|
||||
fmt.Println("tcp", t1)
|
||||
fmt.Println(IsPortAvailable(t1, "tcp"))
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package random
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RandomString(n int, onlyLetter bool) string {
|
||||
|
||||
var letters []rune
|
||||
|
||||
if onlyLetter {
|
||||
letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
} else {
|
||||
letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
}
|
||||
|
||||
b := make([]rune, n)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package random
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRandomString(t *testing.T) {
|
||||
fmt.Println(RandomString(6, true))
|
||||
}
|
|
@ -17,12 +17,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/samba"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"go.uber.org/zap"
|
||||
|
@ -38,7 +38,7 @@ func InitInfo() {
|
|||
if file.Exists(config.AppInfo.DBPath + "/baseinfo.conf") {
|
||||
err := json.Unmarshal(file.ReadFullFile(config.AppInfo.DBPath+"/baseinfo.conf"), &mb)
|
||||
if err != nil {
|
||||
loger.Error("baseinfo.conf", zap.String("error", err.Error()))
|
||||
logger.Error("baseinfo.conf", zap.String("error", err.Error()))
|
||||
}
|
||||
}
|
||||
if file.Exists("/etc/CHANNEL") {
|
||||
|
@ -47,14 +47,14 @@ func InitInfo() {
|
|||
}
|
||||
mac, err := service.MyService.System().GetMacAddress()
|
||||
if err != nil {
|
||||
loger.Error("GetMacAddress", zap.String("error", err.Error()))
|
||||
logger.Error("GetMacAddress", zap.String("error", err.Error()))
|
||||
}
|
||||
mb.Hash = encryption.GetMD5ByStr(mac)
|
||||
mb.Version = types.CURRENTVERSION
|
||||
os.Remove(config.AppInfo.DBPath + "/baseinfo.conf")
|
||||
by, err := json.Marshal(mb)
|
||||
if err != nil {
|
||||
loger.Error("init info err", zap.Any("err", err))
|
||||
logger.Error("init info err", zap.Any("err", err))
|
||||
return
|
||||
}
|
||||
file.WriteToFullPath(by, config.AppInfo.DBPath+"/baseinfo.conf", 0o666)
|
||||
|
@ -68,7 +68,7 @@ func InitNetworkMount() {
|
|||
directories, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password)
|
||||
if err != nil {
|
||||
service.MyService.Connections().DeleteConnection(fmt.Sprint(connection.ID))
|
||||
loger.Error("mount samba err", zap.Any("err", err), zap.Any("info", connection))
|
||||
logger.Error("mount samba err", zap.Any("err", err), zap.Any("info", connection))
|
||||
continue
|
||||
}
|
||||
baseHostPath := "/mnt/" + connection.Host
|
||||
|
|
|
@ -54,7 +54,6 @@ func SendMemBySocket() {
|
|||
}
|
||||
|
||||
func SendAllHardwareStatusBySocket() {
|
||||
|
||||
netList := service.MyService.System().GetNetInfo()
|
||||
newNet := []model.IOCountersStat{}
|
||||
nets := service.MyService.System().GetNet(true)
|
||||
|
@ -91,7 +90,6 @@ func SendAllHardwareStatusBySocket() {
|
|||
memInfo := service.MyService.System().GetMemInfo()
|
||||
|
||||
service.MyService.Notify().SendAllHardwareStatusBySocket(memInfo, cpuData, newNet)
|
||||
|
||||
}
|
||||
|
||||
// func MonitoryUSB() {
|
||||
|
@ -99,7 +97,7 @@ func SendAllHardwareStatusBySocket() {
|
|||
|
||||
// conn := new(netlink.UEventConn)
|
||||
// if err := conn.Connect(netlink.UdevEvent); err != nil {
|
||||
// loger.Error("udev err", zap.Any("Unable to connect to Netlink Kobject UEvent socket", err))
|
||||
// logger.Error("udev err", zap.Any("Unable to connect to Netlink Kobject UEvent socket", err))
|
||||
// }
|
||||
// defer conn.Close()
|
||||
|
||||
|
@ -124,7 +122,7 @@ func SendAllHardwareStatusBySocket() {
|
|||
// continue
|
||||
// }
|
||||
// case err := <-errors:
|
||||
// loger.Error("udev err", zap.Any("err", err))
|
||||
// logger.Error("udev err", zap.Any("err", err))
|
||||
// }
|
||||
// }
|
||||
|
||||
|
|
|
@ -58,68 +58,6 @@ func InitRouter() *gin.Engine {
|
|||
|
||||
v1Group.Use(jwt.ExceptLocalhost())
|
||||
{
|
||||
// v1UsersGroup := v1Group.Group("/users")
|
||||
// v1UsersGroup.Use()
|
||||
// {
|
||||
// v1UsersGroup.GET("/current", v1.GetUserInfo)
|
||||
// v1UsersGroup.PUT("/current", v1.PutUserInfo)
|
||||
// v1UsersGroup.PUT("/current/password", v1.PutUserPassword)
|
||||
|
||||
// v1UsersGroup.GET("/current/custom/:key", v1.GetUserCustomConf)
|
||||
// v1UsersGroup.POST("/current/custom/:key", v1.PostUserCustomConf)
|
||||
// v1UsersGroup.DELETE("/current/custom/:key", v1.DeleteUserCustomConf)
|
||||
|
||||
// v1UsersGroup.POST("/current/image/:key", v1.PostUserUploadImage)
|
||||
// v1UsersGroup.PUT("/current/image/:key", v1.PutUserImage)
|
||||
// //v1UserGroup.POST("/file/image/:key", v1.PostUserFileImage)
|
||||
// v1UsersGroup.DELETE("/current/image", v1.DeleteUserImage)
|
||||
|
||||
// //v1UserGroup.PUT("/avatar", v1.PutUserAvatar)
|
||||
// //v1UserGroup.GET("/avatar", v1.GetUserAvatar)
|
||||
// v1UsersGroup.DELETE("/:id", v1.DeleteUser)
|
||||
// v1UsersGroup.GET("/:username", v1.GetUserInfoByUsername)
|
||||
// v1UsersGroup.DELETE("", v1.DeleteUserAll)
|
||||
// }
|
||||
|
||||
v1AppsGroup := v1Group.Group("/apps")
|
||||
v1AppsGroup.Use()
|
||||
{
|
||||
v1AppsGroup.GET("", v1.AppList) // list
|
||||
v1AppsGroup.GET("/:id", v1.AppInfo)
|
||||
}
|
||||
v1ContainerGroup := v1Group.Group("/container")
|
||||
v1ContainerGroup.Use()
|
||||
{
|
||||
|
||||
v1ContainerGroup.GET("", v1.MyAppList) ///my/list
|
||||
v1ContainerGroup.GET("/usage", v1.AppUsageList)
|
||||
v1ContainerGroup.GET("/:id", v1.ContainerUpdateInfo) ///update/:id/info
|
||||
v1ContainerGroup.GET("/:id/logs", v1.ContainerLog) // /app/logs/:id
|
||||
v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) // app/install/config
|
||||
|
||||
v1ContainerGroup.GET("/:id/state", v1.GetContainerState) // app/state/:id ?state=install_progress
|
||||
// there are problems, temporarily do not deal with
|
||||
v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) // app/terminal/:id
|
||||
v1ContainerGroup.POST("", v1.InstallApp) // app/install
|
||||
// v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id
|
||||
|
||||
v1ContainerGroup.PUT("/:id", v1.UpdateSetting) ///update/:id/setting
|
||||
|
||||
v1ContainerGroup.PUT("/:id/state", v1.ChangAppState) // /app/state/:id
|
||||
v1ContainerGroup.DELETE("/:id", v1.UnInstallApp) // app/uninstall/:id
|
||||
// Not used
|
||||
v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate)
|
||||
// Not used
|
||||
v1ContainerGroup.POST("/share", v1.ShareAppFile)
|
||||
v1ContainerGroup.GET("/info", v1.GetDockerDaemonConfiguration)
|
||||
v1ContainerGroup.PUT("/info", v1.PutDockerDaemonConfiguration)
|
||||
|
||||
}
|
||||
v1AppCategoriesGroup := v1Group.Group("/app-categories")
|
||||
v1AppCategoriesGroup.Use()
|
||||
{
|
||||
v1AppCategoriesGroup.GET("", v1.CategoryList)
|
||||
}
|
||||
|
||||
v1SysGroup := v1Group.Group("/sys")
|
||||
v1SysGroup.Use()
|
||||
|
@ -148,7 +86,6 @@ func InitRouter() *gin.Engine {
|
|||
|
||||
v1SysGroup.GET("/server-info", nil)
|
||||
v1SysGroup.PUT("/server-info", nil)
|
||||
v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus)
|
||||
// v1SysGroup.GET("/port", v1.GetCasaOSPort)
|
||||
// v1SysGroup.PUT("/port", v1.PutCasaOSPort)
|
||||
v1SysGroup.GET("/proxy", v1.GetSystemProxy)
|
||||
|
@ -222,6 +159,8 @@ func InitRouter() *gin.Engine {
|
|||
v1NotifyGroup.POST("/:path", v1.PostNotifyMessage)
|
||||
// merge to system
|
||||
v1NotifyGroup.POST("/system_status", v1.PostSystemStatusNotify)
|
||||
v1NotifyGroup.POST("/install_app", v1.PostInstallAppNotify)
|
||||
v1NotifyGroup.POST("/uninstall_app", v1.PostUninstallAppNotify)
|
||||
}
|
||||
}
|
||||
return r
|
||||
|
|
|
@ -14,15 +14,14 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/model/notify"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
f "github.com/ambelovsky/gosf"
|
||||
)
|
||||
|
||||
func SocketInit(msg chan notify.Message) {
|
||||
|
||||
// set socket port
|
||||
socketPort := 0
|
||||
if len(config.ServerInfo.SocketPort) == 0 {
|
||||
|
@ -51,10 +50,9 @@ func SocketInit(msg chan notify.Message) {
|
|||
f.Broadcast("", v.Path, &v.Msg)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
}(msg)
|
||||
|
||||
f.Startup(map[string]interface{}{
|
||||
"port": socketPort})
|
||||
|
||||
"port": socketPort,
|
||||
})
|
||||
}
|
||||
|
|
355
route/v1/app.go
355
route/v1/app.go
|
@ -1,355 +0,0 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
dockerRootDirFilePath = "/var/lib/casaos/docker_root"
|
||||
dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json"
|
||||
)
|
||||
|
||||
// @Summary 获取远程列表
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Param index query int false "页码"
|
||||
// @Param size query int false "每页数量"
|
||||
// @Param category_id query int false "分类id"
|
||||
// @Param type query string false "rank,new"
|
||||
// @Param key query string false "search key"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/list [get]
|
||||
func AppList(c *gin.Context) {
|
||||
// service.MyService.Docker().DockerContainerCommit("test2")
|
||||
|
||||
index := c.DefaultQuery("index", "1")
|
||||
size := c.DefaultQuery("size", "10000")
|
||||
t := c.DefaultQuery("type", "rank")
|
||||
categoryId := c.DefaultQuery("category_id", "0")
|
||||
key := c.DefaultQuery("key", "")
|
||||
if len(index) == 0 || len(size) == 0 || len(t) == 0 || len(categoryId) == 0 {
|
||||
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
collection, err := service.MyService.Casa().GetServerList(index, size, t, categoryId, key)
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
// for i := 0; i < len(recommend); i++ {
|
||||
// ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
|
||||
// if ct != nil {
|
||||
// recommend[i].State = ct.State
|
||||
// }
|
||||
// }
|
||||
// for i := 0; i < len(list); i++ {
|
||||
// ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
|
||||
// if ct != nil {
|
||||
// list[i].State = ct.State
|
||||
// }
|
||||
// }
|
||||
// for i := 0; i < len(community); i++ {
|
||||
// ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
|
||||
// if ct != nil {
|
||||
// community[i].State = ct.State
|
||||
// }
|
||||
// }
|
||||
data := make(map[string]interface{}, 3)
|
||||
data["recommend"] = collection.Recommend
|
||||
data["list"] = collection.List
|
||||
data["community"] = collection.Community
|
||||
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 获取一个可用端口
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Param type query string true "端口类型 udp/tcp"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/getport [get]
|
||||
func GetPort(c *gin.Context) {
|
||||
t := c.DefaultQuery("type", "tcp")
|
||||
var p int
|
||||
ok := true
|
||||
for ok {
|
||||
p, _ = port2.GetAvailablePort(t)
|
||||
ok = !port2.IsPortAvailable(p, t)
|
||||
}
|
||||
// @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
|
||||
}
|
||||
|
||||
// @Summary 检查端口是否可用
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Param port path int true "端口号"
|
||||
// @Param type query string true "端口类型 udp/tcp"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/check/{port} [get]
|
||||
func PortCheck(c *gin.Context) {
|
||||
p, _ := strconv.Atoi(c.Param("port"))
|
||||
t := c.DefaultQuery("type", "tcp")
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port2.IsPortAvailable(p, t)})
|
||||
}
|
||||
|
||||
// @Summary 我的应用列表
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Param index query int false "index"
|
||||
// @Param size query int false "size"
|
||||
// @Param position query bool false "是否是首页应用"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/my/list [get]
|
||||
func MyAppList(c *gin.Context) {
|
||||
index, _ := strconv.Atoi(c.DefaultQuery("index", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "0"))
|
||||
position, _ := strconv.ParseBool(c.DefaultQuery("position", "true"))
|
||||
list, unTranslation := service.MyService.App().GetMyList(index, size, position)
|
||||
data := make(map[string]interface{}, 2)
|
||||
data["casaos_apps"] = list
|
||||
data["local_apps"] = unTranslation
|
||||
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary my app hardware usage list
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/usage [get]
|
||||
func AppUsageList(c *gin.Context) {
|
||||
list := service.MyService.App().GetHardwareUsage()
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
|
||||
// c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: nil})
|
||||
}
|
||||
|
||||
// @Summary 应用详情
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Param id path int true "id"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/appinfo/{id} [get]
|
||||
func AppInfo(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
language := c.GetHeader("Language")
|
||||
info, err := service.MyService.Casa().GetServerAppInfo(id, "", language)
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
if info.NetworkModel != "host" {
|
||||
for i := 0; i < len(info.Ports); i++ {
|
||||
if p, _ := strconv.Atoi(info.Ports[i].ContainerPort); port2.IsPortAvailable(p, info.Ports[i].Protocol) {
|
||||
info.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
} else {
|
||||
if info.Ports[i].Protocol == "tcp" {
|
||||
if p, err := port2.GetAvailablePort("tcp"); err == nil {
|
||||
info.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
} else if info.Ports[i].Protocol == "upd" {
|
||||
if p, err := port2.GetAvailablePort("udp"); err == nil {
|
||||
info.Ports[i].CommendPort = strconv.Itoa(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if info.Ports[i].Type == 0 {
|
||||
info.PortMap = info.Ports[i].CommendPort
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(info.Ports); i++ {
|
||||
if info.Ports[i].Type == 0 {
|
||||
info.PortMap = info.Ports[i].ContainerPort
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(info.Devices); i++ {
|
||||
if !file.CheckNotExist(info.Devices[i].ContainerPath) {
|
||||
info.Devices[i].Path = info.Devices[i].ContainerPath
|
||||
}
|
||||
}
|
||||
// if len(info.Tip) > 0 {
|
||||
// info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip)
|
||||
// }
|
||||
|
||||
// portOrder := func(c1, c2 *model.Ports) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
// envOrder := func(c1, c2 *model.Envs) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
// volOrder := func(c1, c2 *model.Volume) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
// devOrder := func(c1, c2 *model.Devices) bool {
|
||||
// return c1.Type < c2.Type
|
||||
// }
|
||||
|
||||
// sort
|
||||
// if info.NetworkModel != "host" {
|
||||
// sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts)
|
||||
// sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts)
|
||||
// }
|
||||
|
||||
// sort.EnvSort(envOrder).Sort(info.Envs)
|
||||
// sort.VolSort(volOrder).Sort(info.Volumes.([]model.PathMap))
|
||||
// sort.DevSort(devOrder).Sort(info.Devices)
|
||||
info.Image += ":" + info.ImageVersion
|
||||
info.MaxMemory = (service.MyService.System().GetMemInfo()["total"]).(uint64) >> 20
|
||||
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info})
|
||||
}
|
||||
|
||||
// @Summary 获取远程分类列表
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/category [get]
|
||||
func CategoryList(c *gin.Context) {
|
||||
list, err := service.MyService.Casa().GetServerCategoryList()
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
var count uint = 0
|
||||
for _, category := range list {
|
||||
count += category.Count
|
||||
}
|
||||
|
||||
rear := append([]model.CategoryList{}, list[0:]...)
|
||||
list = append(list[:0], model.CategoryList{Count: count, Name: "All", Font: "apps"})
|
||||
list = append(list, rear...)
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @Summary 分享该应用配置
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/share [post]
|
||||
func ShareAppFile(c *gin.Context) {
|
||||
str, _ := ioutil.ReadAll(c.Request.Body)
|
||||
content := service.MyService.Casa().ShareAppFile(str)
|
||||
c.JSON(common_err.SUCCESS, json.RawMessage(content))
|
||||
}
|
||||
|
||||
func GetDockerDaemonConfiguration(c *gin.Context) {
|
||||
// info, err := service.MyService.Docker().GetDockerInfo()
|
||||
// if err != nil {
|
||||
// c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
// return
|
||||
// }
|
||||
data := make(map[string]interface{})
|
||||
|
||||
if file.Exists(dockerRootDirFilePath) {
|
||||
buf := file.ReadFullFile(dockerRootDirFilePath)
|
||||
err := json.Unmarshal(buf, &data)
|
||||
if err != nil {
|
||||
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
func PutDockerDaemonConfiguration(c *gin.Context) {
|
||||
request := make(map[string]interface{})
|
||||
if err := c.BindJSON(&request); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
|
||||
return
|
||||
}
|
||||
|
||||
value, ok := request["docker_root_dir"]
|
||||
if !ok {
|
||||
c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "`docker_root_dir` should not empty"})
|
||||
return
|
||||
}
|
||||
|
||||
dockerConfig := model.DockerDaemonConfigurationModel{}
|
||||
if file.Exists(dockerDaemonConfigurationFilePath) {
|
||||
byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath)
|
||||
err := json.Unmarshal(byteResult, &dockerConfig)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
dockerRootDir := value.(string)
|
||||
if dockerRootDir == "/" {
|
||||
dockerConfig.Root = "" // omitempty - empty string will not be serialized
|
||||
} else {
|
||||
if !file.Exists(dockerRootDir) {
|
||||
c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS), Data: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
|
||||
return
|
||||
}
|
||||
|
||||
dockerConfig.Root = filepath.Join(dockerRootDir, "docker")
|
||||
|
||||
if err := file.IsNotExistMkDir(dockerConfig.Root); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to create " + dockerConfig.Root, Data: err})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if buf, err := json.Marshal(request); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker root json", Data: err})
|
||||
return
|
||||
} else {
|
||||
if err := file.WriteToFullPath(buf, dockerRootDirFilePath, 0o644); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write " + dockerRootDirFilePath, Data: err})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if buf, err := json.Marshal(dockerConfig); err != nil {
|
||||
c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker config", Data: dockerConfig})
|
||||
return
|
||||
} else {
|
||||
if err := file.WriteToFullPath(buf, dockerDaemonConfigurationFilePath, 0o644); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write to " + dockerDaemonConfigurationFilePath, Data: err})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
println(command.ExecResultStr("systemctl daemon-reload"))
|
||||
println(command.ExecResultStr("systemctl restart docker"))
|
||||
|
||||
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: request})
|
||||
}
|
1267
route/v1/docker.go
1267
route/v1/docker.go
File diff suppressed because it is too large
Load diff
|
@ -15,10 +15,10 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
|
@ -222,19 +222,6 @@ func DirPath(c *gin.Context) {
|
|||
for _, v := range shares {
|
||||
sharesMap[v.Path] = fmt.Sprint(v.ID)
|
||||
}
|
||||
if path == "/DATA/AppData" {
|
||||
list := service.MyService.Docker().DockerContainerList()
|
||||
apps := make(map[string]string, len(list))
|
||||
for _, v := range list {
|
||||
apps[strings.ReplaceAll(v.Names[0], "/", "")] = strings.ReplaceAll(v.Names[0], "/", "")
|
||||
}
|
||||
for i := 0; i < len(info); i++ {
|
||||
if v, ok := apps[info[i].Name]; ok {
|
||||
info[i].Label = v
|
||||
info[i].Type = "application"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(info); i++ {
|
||||
if v, ok := sharesMap[info[i].Path]; ok {
|
||||
|
@ -403,7 +390,7 @@ func PostFileUpload(c *gin.Context) {
|
|||
hash := file.GetHashByContent([]byte(fileName))
|
||||
|
||||
if len(path) == 0 {
|
||||
loger.Error("path should not be empty")
|
||||
logger.Error("path should not be empty")
|
||||
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
@ -413,7 +400,7 @@ func PostFileUpload(c *gin.Context) {
|
|||
dirPath = strings.TrimSuffix(relative, fileName)
|
||||
tempDir += dirPath
|
||||
if err := file.MkDir(path + "/" + dirPath); err != nil {
|
||||
loger.Error("error when trying to create `"+path+"/"+dirPath+"`", zap.Error(err))
|
||||
logger.Error("error when trying to create `"+path+"/"+dirPath+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
@ -423,7 +410,7 @@ func PostFileUpload(c *gin.Context) {
|
|||
|
||||
if !file.CheckNotExist(tempDir + chunkNumber) {
|
||||
if err := file.RMDir(tempDir + chunkNumber); err != nil {
|
||||
loger.Error("error when trying to remove existing `"+tempDir+chunkNumber+"`", zap.Error(err))
|
||||
logger.Error("error when trying to remove existing `"+tempDir+chunkNumber+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
@ -431,14 +418,14 @@ func PostFileUpload(c *gin.Context) {
|
|||
|
||||
if totalChunks > 1 {
|
||||
if err := file.IsNotExistMkDir(tempDir); err != nil {
|
||||
loger.Error("error when trying to create `"+tempDir+"`", zap.Error(err))
|
||||
logger.Error("error when trying to create `"+tempDir+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
out, err := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0o644)
|
||||
if err != nil {
|
||||
loger.Error("error when trying to open `"+tempDir+chunkNumber+"` for creation", zap.Error(err))
|
||||
logger.Error("error when trying to open `"+tempDir+chunkNumber+"` for creation", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
@ -446,27 +433,27 @@ func PostFileUpload(c *gin.Context) {
|
|||
defer out.Close()
|
||||
|
||||
if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
|
||||
loger.Error("error when trying to write to `"+tempDir+chunkNumber+"`", zap.Error(err))
|
||||
logger.Error("error when trying to write to `"+tempDir+chunkNumber+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
fileNum, err := ioutil.ReadDir(tempDir)
|
||||
if err != nil {
|
||||
loger.Error("error when trying to read number of files under `"+tempDir+"`", zap.Error(err))
|
||||
logger.Error("error when trying to read number of files under `"+tempDir+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if totalChunks == len(fileNum) {
|
||||
if err := file.SpliceFiles(tempDir, path, totalChunks, 1); err != nil {
|
||||
loger.Error("error when trying to splice files under `"+tempDir+"`", zap.Error(err))
|
||||
logger.Error("error when trying to splice files under `"+tempDir+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := file.RMDir(tempDir); err != nil {
|
||||
loger.Error("error when trying to remove `"+tempDir+"`", zap.Error(err))
|
||||
logger.Error("error when trying to remove `"+tempDir+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
@ -474,7 +461,7 @@ func PostFileUpload(c *gin.Context) {
|
|||
} else {
|
||||
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644)
|
||||
if err != nil {
|
||||
loger.Error("error when trying to open `"+path+"` for creation", zap.Error(err))
|
||||
logger.Error("error when trying to open `"+path+"` for creation", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
@ -482,7 +469,7 @@ func PostFileUpload(c *gin.Context) {
|
|||
defer out.Close()
|
||||
|
||||
if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
|
||||
loger.Error("error when trying to write to `"+path+"`", zap.Error(err))
|
||||
logger.Error("error when trying to write to `"+path+"`", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
|
||||
return
|
||||
}
|
||||
|
|
56
route/v1/notify.go
Normal file
56
route/v1/notify.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/model/notify"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func PostNotifyMessage(c *gin.Context) {
|
||||
path := c.Param("path")
|
||||
message := make(map[string]interface{})
|
||||
if err := c.ShouldBind(&message); err != nil {
|
||||
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Notify().SendNotify(path, message)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
func PostSystemStatusNotify(c *gin.Context) {
|
||||
message := make(map[string]interface{})
|
||||
if err := c.ShouldBind(&message); err != nil {
|
||||
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Notify().SettingSystemTempData(message)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
func PostInstallAppNotify(c *gin.Context) {
|
||||
app := notify.Application{}
|
||||
if err := c.ShouldBind(&app); err != nil {
|
||||
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Notify().SendInstallAppBySocket(app)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
func PostUninstallAppNotify(c *gin.Context) {
|
||||
app := notify.Application{}
|
||||
if err := c.ShouldBind(&app); err != nil {
|
||||
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
service.MyService.Notify().SendUninstallAppBySocket(app)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func PostNotifyMessage(c *gin.Context) {
|
||||
path := c.Param("path")
|
||||
message := make(map[string]interface{})
|
||||
c.ShouldBind(&message)
|
||||
service.MyService.Notify().SendNotify(path, message)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
func PostSystemStatusNotify(c *gin.Context) {
|
||||
message := make(map[string]interface{})
|
||||
c.ShouldBind(&message)
|
||||
service.MyService.Notify().SettingSystemTempData(message)
|
||||
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
96
route/v1/ssh.go
Normal file
96
route/v1/ssh.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||
sshHelper "github.com/IceWhaleTech/CasaOS-Common/utils/ssh"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
modelCommon "github.com/IceWhaleTech/CasaOS-Common/model"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
CheckOrigin: func(r *http.Request) bool { return true },
|
||||
HandshakeTimeout: time.Duration(time.Second * 5),
|
||||
}
|
||||
|
||||
func PostSshLogin(c *gin.Context) {
|
||||
j := make(map[string]string)
|
||||
c.ShouldBind(&j)
|
||||
userName := j["username"]
|
||||
password := j["password"]
|
||||
port := j["port"]
|
||||
if userName == "" || password == "" || port == "" {
|
||||
c.JSON(common_err.CLIENT_ERROR, modelCommon.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "Username or password or port is empty"})
|
||||
return
|
||||
}
|
||||
_, err := sshHelper.NewSshClient(userName, password, port)
|
||||
if err != nil {
|
||||
c.JSON(common_err.CLIENT_ERROR, modelCommon.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Please check if the username and port are correct, and make sure that ssh server is installed."})
|
||||
logger.Error("connect ssh error", zap.Any("error", err))
|
||||
return
|
||||
}
|
||||
c.JSON(common_err.SUCCESS, modelCommon.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
|
||||
}
|
||||
|
||||
func WsSsh(c *gin.Context) {
|
||||
_, e := exec.LookPath("ssh")
|
||||
if e != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR, modelCommon.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "ssh server not found"})
|
||||
return
|
||||
}
|
||||
|
||||
userName := c.Query("username")
|
||||
password := c.Query("password")
|
||||
port := c.Query("port")
|
||||
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
logBuff := new(bytes.Buffer)
|
||||
|
||||
quitChan := make(chan bool, 3)
|
||||
// user := ""
|
||||
// password := ""
|
||||
var login int = 1
|
||||
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
|
||||
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
|
||||
var client *ssh.Client
|
||||
for login != 0 {
|
||||
|
||||
var err error
|
||||
if userName == "" || password == "" || port == "" {
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("username or password or port is empty"))
|
||||
}
|
||||
client, err = sshHelper.NewSshClient(userName, password, port)
|
||||
|
||||
if err != nil && client == nil {
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
|
||||
} else {
|
||||
login = 0
|
||||
}
|
||||
|
||||
}
|
||||
if client != nil {
|
||||
defer client.Close()
|
||||
}
|
||||
|
||||
ssConn, _ := sshHelper.NewSshConn(cols, rows, client)
|
||||
defer ssConn.Close()
|
||||
|
||||
go ssConn.ReceiveWsMsg(wsConn, logBuff, quitChan)
|
||||
go ssConn.SendComboOutput(wsConn, quitChan)
|
||||
go ssConn.SessionWait(quitChan)
|
||||
|
||||
<-quitChan
|
||||
}
|
|
@ -13,10 +13,10 @@ import (
|
|||
"unsafe"
|
||||
|
||||
http2 "github.com/IceWhaleTech/CasaOS-Common/utils/http"
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
|
@ -127,7 +127,7 @@ func PutCasaOSPort(c *gin.Context) {
|
|||
json := make(map[string]string)
|
||||
c.ShouldBind(&json)
|
||||
portStr := json["port"]
|
||||
port, err := strconv.Atoi(portStr)
|
||||
portNumber, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
c.JSON(common_err.SERVICE_ERROR,
|
||||
model.Result{
|
||||
|
@ -137,7 +137,7 @@ func PutCasaOSPort(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
isAvailable := port2.IsPortAvailable(port, "tcp")
|
||||
isAvailable := port.IsPortAvailable(portNumber, "tcp")
|
||||
if !isAvailable {
|
||||
c.JSON(common_err.SERVICE_ERROR,
|
||||
model.Result{
|
||||
|
@ -146,7 +146,7 @@ func PutCasaOSPort(c *gin.Context) {
|
|||
})
|
||||
return
|
||||
}
|
||||
service.MyService.System().UpSystemPort(strconv.Itoa(port))
|
||||
service.MyService.System().UpSystemPort(strconv.Itoa(portNumber))
|
||||
c.JSON(common_err.SUCCESS,
|
||||
model.Result{
|
||||
Success: common_err.SUCCESS,
|
||||
|
@ -165,40 +165,6 @@ func PostKillCasaOS(c *gin.Context) {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
func GetSystemAppsStatus(c *gin.Context) {
|
||||
systemAppList := service.MyService.App().GetSystemAppList()
|
||||
appList := []model2.MyAppList{}
|
||||
for _, v := range systemAppList {
|
||||
name := strings.ReplaceAll(v.Names[0], "/", "")
|
||||
if len(v.Labels["name"]) > 0 {
|
||||
name = v.Labels["name"]
|
||||
}
|
||||
appList = append(appList, model2.MyAppList{
|
||||
Name: name,
|
||||
Icon: v.Labels["icon"],
|
||||
State: v.State,
|
||||
CustomId: v.Labels["custom_id"],
|
||||
Id: v.ID,
|
||||
Port: v.Labels["web"],
|
||||
Index: v.Labels["index"],
|
||||
// Order: m.Labels["order"],
|
||||
Image: v.Image,
|
||||
Latest: false,
|
||||
// Type: m.Labels["origin"],
|
||||
// Slogan: m.Slogan,
|
||||
// Rely: m.Rely,
|
||||
Host: v.Labels["host"],
|
||||
Protocol: v.Labels["protocol"],
|
||||
})
|
||||
}
|
||||
c.JSON(common_err.SUCCESS,
|
||||
model.Result{
|
||||
Success: common_err.SUCCESS,
|
||||
Message: common_err.GetMsg(common_err.SUCCESS),
|
||||
Data: appList,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary get system hardware info
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
@ -228,7 +194,7 @@ func GetSystemUtilization(c *gin.Context) {
|
|||
data := make(map[string]interface{})
|
||||
cpu := service.MyService.System().GetCpuPercent()
|
||||
num := service.MyService.System().GetCpuCoreNum()
|
||||
var cpuModel = "arm"
|
||||
cpuModel := "arm"
|
||||
if cpu := service.MyService.System().GetCpuInfo(); len(cpu) > 0 {
|
||||
if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "intel") > 0 {
|
||||
cpuModel = "intel"
|
||||
|
@ -375,13 +341,46 @@ func PutSystemState(c *gin.Context) {
|
|||
time.Sleep(30 * time.Second)
|
||||
service.MyService.System().SystemShutdown()
|
||||
}()
|
||||
|
||||
} else if state == "restart" {
|
||||
go func() {
|
||||
time.Sleep(30 * time.Second)
|
||||
service.MyService.System().SystemReboot()
|
||||
}()
|
||||
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: "The operation will be executed after 30 seconds"})
|
||||
}
|
||||
|
||||
// @Summary 获取一个可用端口
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Param type query string true "端口类型 udp/tcp"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/getport [get]
|
||||
func GetPort(c *gin.Context) {
|
||||
t := c.DefaultQuery("type", "tcp")
|
||||
var p int
|
||||
ok := true
|
||||
for ok {
|
||||
p, _ = port.GetAvailablePort(t)
|
||||
ok = !port.IsPortAvailable(p, t)
|
||||
}
|
||||
// @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
|
||||
}
|
||||
|
||||
// @Summary 检查端口是否可用
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags app
|
||||
// @Param port path int true "端口号"
|
||||
// @Param type query string true "端口类型 udp/tcp"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/check/{port} [get]
|
||||
func PortCheck(c *gin.Context) {
|
||||
p, _ := strconv.Atoi(c.Param("port"))
|
||||
t := c.DefaultQuery("type", "tcp")
|
||||
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port.IsPortAvailable(p, t)})
|
||||
}
|
||||
|
|
480
service/app.go
480
service/app.go
|
@ -1,480 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
client2 "github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AppService interface {
|
||||
GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList)
|
||||
SaveContainer(m model2.AppListDBModel)
|
||||
GetUninstallInfo(id string) model2.AppListDBModel
|
||||
DeleteApp(id string)
|
||||
GetContainerInfo(id string) (types.Container, error)
|
||||
GetAppDBInfo(id string) model2.AppListDBModel
|
||||
UpdateApp(m model2.AppListDBModel)
|
||||
GetSimpleContainerInfo(id string) (types.Container, error)
|
||||
DelAppConfigDir(path string)
|
||||
GetSystemAppList() []types.Container
|
||||
GetHardwareUsageStream()
|
||||
GetHardwareUsage() []model.DockerStatsModel
|
||||
GetAppStats(id string) string
|
||||
GetAllDBApps() []model2.AppListDBModel
|
||||
ImportApplications(casaApp bool)
|
||||
CheckNewImage()
|
||||
}
|
||||
|
||||
type appStruct struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (a *appStruct) CheckNewImage() {
|
||||
list := MyService.Docker().DockerContainerList()
|
||||
for _, v := range list {
|
||||
inspect, err := MyService.Docker().DockerImageInfo(strings.Split(v.Image, ":")[0])
|
||||
if err != nil {
|
||||
NewVersionApp[v.ID] = inspect.ID
|
||||
continue
|
||||
}
|
||||
if inspect.ID == v.ImageID {
|
||||
delete(NewVersionApp, v.ID)
|
||||
continue
|
||||
}
|
||||
NewVersionApp[v.ID] = inspect.ID
|
||||
}
|
||||
|
||||
}
|
||||
func (a *appStruct) ImportApplications(casaApp bool) {
|
||||
if casaApp {
|
||||
list := MyService.App().GetAllDBApps()
|
||||
for _, app := range list {
|
||||
info, err := MyService.Docker().DockerContainerInfo(app.CustomId)
|
||||
if err != nil {
|
||||
MyService.App().DeleteApp(app.CustomId)
|
||||
continue
|
||||
}
|
||||
//info.NetworkSettings
|
||||
info.Config.Labels["casaos"] = "casaos"
|
||||
info.Config.Labels["web"] = app.PortMap
|
||||
info.Config.Labels["icon"] = app.Icon
|
||||
info.Config.Labels["desc"] = app.Description
|
||||
info.Config.Labels["index"] = app.Index
|
||||
info.Config.Labels["custom_id"] = app.CustomId
|
||||
info.Name = app.Title
|
||||
container_id, err := MyService.Docker().DockerContainerCopyCreate(info)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
MyService.App().DeleteApp(app.CustomId)
|
||||
MyService.Docker().DockerContainerStop(app.CustomId)
|
||||
MyService.Docker().DockerContainerRemove(app.CustomId, false)
|
||||
MyService.Docker().DockerContainerStart(container_id)
|
||||
|
||||
}
|
||||
} else {
|
||||
list := MyService.Docker().DockerContainerList()
|
||||
for _, app := range list {
|
||||
info, err := MyService.Docker().DockerContainerInfo(app.ID)
|
||||
if err != nil || info.Config.Labels["casaos"] == "casaos" {
|
||||
continue
|
||||
}
|
||||
info.Config.Labels["casaos"] = "casaos"
|
||||
info.Config.Labels["web"] = ""
|
||||
info.Config.Labels["icon"] = ""
|
||||
info.Config.Labels["desc"] = ""
|
||||
info.Config.Labels["index"] = ""
|
||||
info.Config.Labels["custom_id"] = uuid.NewV4().String()
|
||||
|
||||
_, err = MyService.Docker().DockerContainerCopyCreate(info)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// allcontainer := MyService.Docker().DockerContainerList()
|
||||
// for _, app := range allcontainer {
|
||||
// info, err := MyService.Docker().DockerContainerInfo(app.ID)
|
||||
// if err != nil {
|
||||
// continue
|
||||
// }
|
||||
// MyService.Docker().DockerContainerStop(app.ID)
|
||||
// MyService.Docker().DockerContainerRemove(app.ID, false)
|
||||
// //info.NetworkSettings
|
||||
// info.Config.Labels["custom_id"] = uuid.NewV4().String()
|
||||
// container_id, err := MyService.Docker().DockerContainerCopyCreate(info)
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// continue
|
||||
// }
|
||||
// MyService.Docker().DockerContainerStart(container_id)
|
||||
//}
|
||||
}
|
||||
|
||||
//获取我的应用列表
|
||||
func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
loger.Error("Failed to init client", zap.Any("err", err))
|
||||
}
|
||||
defer cli.Close()
|
||||
// fts := filters.NewArgs()
|
||||
// fts.Add("label", "casaos=casaos")
|
||||
//fts.Add("label", "casaos")
|
||||
//fts.Add("casaos", "casaos")
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
|
||||
if err != nil {
|
||||
loger.Error("Failed to get container_list", zap.Any("err", err))
|
||||
}
|
||||
//获取本地数据库应用
|
||||
|
||||
unTranslation := []model2.MyAppList{}
|
||||
|
||||
list := []model2.MyAppList{}
|
||||
|
||||
for _, m := range containers {
|
||||
if m.Labels["casaos"] == "casaos" {
|
||||
|
||||
_, newVersion := NewVersionApp[m.ID]
|
||||
name := strings.ReplaceAll(m.Names[0], "/", "")
|
||||
icon := m.Labels["icon"]
|
||||
if len(m.Labels["name"]) > 0 {
|
||||
name = m.Labels["name"]
|
||||
}
|
||||
if m.Labels["origin"] == "system" {
|
||||
name = strings.Split(m.Image, ":")[0]
|
||||
if len(strings.Split(name, "/")) > 1 {
|
||||
icon = "https://icon.casaos.io/main/all/" + strings.Split(name, "/")[1] + ".png"
|
||||
}
|
||||
}
|
||||
|
||||
list = append(list, model2.MyAppList{
|
||||
Name: name,
|
||||
Icon: icon,
|
||||
State: m.State,
|
||||
CustomId: m.Labels["custom_id"],
|
||||
Id: m.ID,
|
||||
Port: m.Labels["web"],
|
||||
Index: m.Labels["index"],
|
||||
//Order: m.Labels["order"],
|
||||
Image: m.Image,
|
||||
Latest: newVersion,
|
||||
//Type: m.Labels["origin"],
|
||||
//Slogan: m.Slogan,
|
||||
//Rely: m.Rely,
|
||||
Host: m.Labels["host"],
|
||||
Protocol: m.Labels["protocol"],
|
||||
})
|
||||
} else {
|
||||
unTranslation = append(unTranslation, model2.MyAppList{
|
||||
Name: strings.ReplaceAll(m.Names[0], "/", ""),
|
||||
Icon: "",
|
||||
State: m.State,
|
||||
CustomId: m.ID,
|
||||
Id: m.ID,
|
||||
Port: "",
|
||||
Latest: false,
|
||||
Host: "",
|
||||
Protocol: "",
|
||||
Image: m.Image,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//lMap := make(map[string]interface{})
|
||||
// for _, dbModel := range lm {
|
||||
// if position {
|
||||
// if dbModel.Position {
|
||||
// lMap[dbModel.ContainerId] = dbModel
|
||||
// }
|
||||
// } else {
|
||||
// lMap[dbModel.ContainerId] = dbModel
|
||||
// }
|
||||
// }
|
||||
// for _, container := range containers {
|
||||
|
||||
// if lMap[container.ID] != nil && container.Labels["origin"] != "system" {
|
||||
// m := lMap[container.ID].(model2.AppListDBModel)
|
||||
// if len(m.Label) == 0 {
|
||||
// m.Label = m.Title
|
||||
// }
|
||||
|
||||
// // info, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
// // var tm string
|
||||
// // if err != nil {
|
||||
// // tm = time.Now().String()
|
||||
// // } else {
|
||||
// // tm = info.State.StartedAt
|
||||
// //}
|
||||
// list = append(list, model2.MyAppList{
|
||||
// Name: m.Label,
|
||||
// Icon: m.Icon,
|
||||
// State: container.State,
|
||||
// CustomId: strings.ReplaceAll(container.Names[0], "/", ""),
|
||||
// Port: m.PortMap,
|
||||
// Index: m.Index,
|
||||
// //UpTime: tm,
|
||||
// Image: m.Image,
|
||||
// Slogan: m.Slogan,
|
||||
// //Rely: m.Rely,
|
||||
// })
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
return &list, &unTranslation
|
||||
|
||||
}
|
||||
|
||||
//system application list
|
||||
func (a *appStruct) GetSystemAppList() []types.Container {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
loger.Error("Failed to init client", zap.Any("err", err))
|
||||
}
|
||||
defer cli.Close()
|
||||
fts := filters.NewArgs()
|
||||
fts.Add("label", "origin=system")
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
|
||||
if err != nil {
|
||||
loger.Error("Failed to get container_list", zap.Any("err", err))
|
||||
}
|
||||
|
||||
//获取本地数据库应用
|
||||
|
||||
// var lm []model2.AppListDBModel
|
||||
// a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm)
|
||||
|
||||
//list := []model2.MyAppList{}
|
||||
//lMap := make(map[string]interface{})
|
||||
// for _, dbModel := range lm {
|
||||
// lMap[dbModel.ContainerId] = dbModel
|
||||
// }
|
||||
|
||||
return containers
|
||||
|
||||
}
|
||||
func (a *appStruct) GetAllDBApps() []model2.AppListDBModel {
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image,port_map").Find(&lm)
|
||||
return lm
|
||||
}
|
||||
|
||||
//获取我的应用列表
|
||||
func (a *appStruct) GetContainerInfo(id string) (types.Container, error) {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
loger.Error("Failed to init client", zap.Any("err", err))
|
||||
}
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("id", id)
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
|
||||
if err != nil {
|
||||
loger.Error("Failed to get container_list", zap.Any("err", err))
|
||||
}
|
||||
|
||||
if len(containers) > 0 {
|
||||
return containers[0], nil
|
||||
}
|
||||
return types.Container{}, nil
|
||||
|
||||
}
|
||||
|
||||
func (a *appStruct) GetSimpleContainerInfo(id string) (types.Container, error) {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return types.Container{}, err
|
||||
}
|
||||
defer cli.Close()
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("id", id)
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
|
||||
if err != nil {
|
||||
return types.Container{}, err
|
||||
}
|
||||
|
||||
if len(containers) > 0 {
|
||||
return containers[0], nil
|
||||
}
|
||||
return types.Container{}, errors.New("container not existent")
|
||||
}
|
||||
|
||||
//获取我的应用列表
|
||||
func (a *appStruct) GetAppDBInfo(id string) model2.AppListDBModel {
|
||||
var m model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).First(&m)
|
||||
return m
|
||||
}
|
||||
|
||||
//根据容器id获取镜像名称
|
||||
func (a *appStruct) GetUninstallInfo(id string) model2.AppListDBModel {
|
||||
var m model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("image,version,enable_upnp,ports,envs,volumes,origin").Where("custom_id = ?", id).First(&m)
|
||||
return m
|
||||
}
|
||||
|
||||
//创建容器成功后保存容器
|
||||
func (a *appStruct) SaveContainer(m model2.AppListDBModel) {
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Create(&m)
|
||||
}
|
||||
|
||||
func (a *appStruct) UpdateApp(m model2.AppListDBModel) {
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Save(&m)
|
||||
}
|
||||
|
||||
func (a *appStruct) DelAppConfigDir(path string) {
|
||||
command.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;DelAppConfigDir " + path)
|
||||
}
|
||||
|
||||
func (a *appStruct) DeleteApp(id string) {
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
|
||||
}
|
||||
|
||||
var dataStats sync.Map
|
||||
|
||||
var isFinish bool = false
|
||||
|
||||
func (a *appStruct) GetAppStats(id string) string {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer cli.Close()
|
||||
con, err := cli.ContainerStats(context.Background(), id, false)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
defer con.Body.Close()
|
||||
c, _ := ioutil.ReadAll(con.Body)
|
||||
return string(c)
|
||||
}
|
||||
|
||||
func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
|
||||
|
||||
stream := true
|
||||
for !isFinish {
|
||||
if stream {
|
||||
stream = false
|
||||
go func() {
|
||||
a.GetHardwareUsageStream()
|
||||
}()
|
||||
}
|
||||
runtime.Gosched()
|
||||
}
|
||||
list := []model.DockerStatsModel{}
|
||||
|
||||
dataStats.Range(func(key, value interface{}) bool {
|
||||
list = append(list, value.(model.DockerStatsModel))
|
||||
return true
|
||||
})
|
||||
return list
|
||||
|
||||
}
|
||||
|
||||
func (a *appStruct) GetHardwareUsageStream() {
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
fts := filters.NewArgs()
|
||||
fts.Add("label", "casaos=casaos")
|
||||
//fts.Add("status", "running")
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
|
||||
if err != nil {
|
||||
loger.Error("Failed to get container_list", zap.Any("err", err))
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
if i%10 == 0 {
|
||||
containers, err = cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
|
||||
if err != nil {
|
||||
loger.Error("Failed to get container_list", zap.Any("err", err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if config.CasaOSGlobalVariables.AppChange {
|
||||
config.CasaOSGlobalVariables.AppChange = false
|
||||
dataStats.Range(func(key, value interface{}) bool {
|
||||
dataStats.Delete(key)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
var temp sync.Map
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range containers {
|
||||
if v.State != "running" {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(v types.Container, i int) {
|
||||
defer wg.Done()
|
||||
stats, err := cli.ContainerStatsOneShot(ctx, v.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
decode := json.NewDecoder(stats.Body)
|
||||
var data interface{}
|
||||
if err := decode.Decode(&data); err == io.EOF {
|
||||
return
|
||||
}
|
||||
m, _ := dataStats.Load(v.ID)
|
||||
dockerStats := model.DockerStatsModel{}
|
||||
if m != nil {
|
||||
dockerStats.Previous = m.(model.DockerStatsModel).Data
|
||||
}
|
||||
dockerStats.Data = data
|
||||
dockerStats.Icon = v.Labels["icon"]
|
||||
dockerStats.Title = strings.ReplaceAll(v.Names[0], "/", "")
|
||||
|
||||
// @tiger - 不建议直接把依赖的数据结构封装返回。
|
||||
// 如果依赖的数据结构有变化,应该在这里适配或者保存,这样更加对客户端负责
|
||||
temp.Store(v.ID, dockerStats)
|
||||
if i == 99 {
|
||||
stats.Body.Close()
|
||||
}
|
||||
}(v, i)
|
||||
}
|
||||
wg.Wait()
|
||||
dataStats = temp
|
||||
isFinish = true
|
||||
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
isFinish = false
|
||||
cancel()
|
||||
}
|
||||
|
||||
func NewAppService(db *gorm.DB) AppService {
|
||||
return &appStruct{db: db}
|
||||
}
|
248
service/casa.go
248
service/casa.go
|
@ -1,266 +1,20 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tidwall/gjson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type CasaService interface {
|
||||
GetServerList(index, size, tp, categoryId, key string) (model.ServerAppListCollection, error)
|
||||
GetServerCategoryList() (list []model.CategoryList, err error)
|
||||
GetServerAppInfo(id, t string, language string) (model.ServerAppList, error)
|
||||
ShareAppFile(body []byte) string
|
||||
GetCasaosVersion() model.Version
|
||||
AsyncGetServerList() (collection model.ServerAppListCollection, err error)
|
||||
AsyncGetServerCategoryList() ([]model.CategoryList, error)
|
||||
}
|
||||
|
||||
type casaService struct {
|
||||
}
|
||||
|
||||
func (o *casaService) ShareAppFile(body []byte) string {
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
content := httper2.Post(config.ServerInfo.ServerApi+"/v1/community/add", body, "application/json", head)
|
||||
return content
|
||||
}
|
||||
|
||||
func (o *casaService) GetServerList(index, size, tp, categoryId, key string) (model.ServerAppListCollection, error) {
|
||||
|
||||
keyName := fmt.Sprintf("list_%s_%s_%s_%s_%s", index, size, tp, categoryId, "en")
|
||||
collection := model.ServerAppListCollection{}
|
||||
if result, ok := Cache.Get(keyName); ok {
|
||||
res, ok := result.(string)
|
||||
if ok {
|
||||
json2.Unmarshal([]byte(res), &collection)
|
||||
return collection, nil
|
||||
}
|
||||
}
|
||||
|
||||
collectionStr := file.ReadFullFile(config.AppInfo.DBPath + "/app_list.json")
|
||||
|
||||
err := json2.Unmarshal(collectionStr, &collection)
|
||||
if err != nil {
|
||||
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(collectionStr)))
|
||||
collection, err = o.AsyncGetServerList()
|
||||
if err != nil {
|
||||
return collection, err
|
||||
}
|
||||
}
|
||||
|
||||
go o.AsyncGetServerList()
|
||||
|
||||
if categoryId != "0" {
|
||||
categoryInt, _ := strconv.Atoi(categoryId)
|
||||
nList := []model.ServerAppList{}
|
||||
for _, v := range collection.List {
|
||||
if v.CategoryId == categoryInt {
|
||||
nList = append(nList, v)
|
||||
}
|
||||
}
|
||||
collection.List = nList
|
||||
nCommunity := []model.ServerAppList{}
|
||||
for _, v := range collection.Community {
|
||||
if v.CategoryId == categoryInt {
|
||||
nCommunity = append(nCommunity, v)
|
||||
}
|
||||
}
|
||||
collection.Community = nCommunity
|
||||
}
|
||||
if tp != "name" {
|
||||
if tp == "new" {
|
||||
sort.Slice(collection.List, func(i, j int) bool {
|
||||
return collection.List[i].CreatedAt.After(collection.List[j].CreatedAt)
|
||||
})
|
||||
sort.Slice(collection.Community, func(i, j int) bool {
|
||||
return collection.Community[i].CreatedAt.After(collection.Community[j].CreatedAt)
|
||||
})
|
||||
} else if tp == "rank" {
|
||||
sort.Slice(collection.List, func(i, j int) bool {
|
||||
return collection.List[i].QueryCount > collection.List[j].QueryCount
|
||||
})
|
||||
sort.Slice(collection.Community, func(i, j int) bool {
|
||||
return collection.Community[i].QueryCount > collection.Community[j].QueryCount
|
||||
})
|
||||
}
|
||||
}
|
||||
sizeInt, _ := strconv.Atoi(size)
|
||||
|
||||
if index != "1" {
|
||||
indexInt, _ := strconv.Atoi(index)
|
||||
collection.List = collection.List[(indexInt-1)*sizeInt : indexInt*sizeInt]
|
||||
collection.Community = collection.Community[(indexInt-1)*sizeInt : indexInt*sizeInt]
|
||||
} else {
|
||||
if len(collection.List) > sizeInt {
|
||||
collection.List = collection.List[:sizeInt]
|
||||
}
|
||||
if len(collection.Community) > sizeInt {
|
||||
collection.Community = collection.Community[:sizeInt]
|
||||
}
|
||||
}
|
||||
|
||||
if len(collection.List) > 0 {
|
||||
by, _ := json.Marshal(collection)
|
||||
Cache.Set(keyName, string(by), time.Minute*10)
|
||||
}
|
||||
|
||||
return collection, nil
|
||||
|
||||
}
|
||||
|
||||
func (o *casaService) AsyncGetServerList() (collection model.ServerAppListCollection, err error) {
|
||||
|
||||
results := file.ReadFullFile(config.AppInfo.DBPath + "/app_list.json")
|
||||
errr := json2.Unmarshal(results, &collection)
|
||||
if errr != nil {
|
||||
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
|
||||
}
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/newlist?index=1&size=1000&rank=name&category_id=0&key=&language=en", head)
|
||||
listModel := []model.ServerAppList{}
|
||||
communityModel := []model.ServerAppList{}
|
||||
recommendModel := []model.ServerAppList{}
|
||||
err = json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &listModel)
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommendModel)
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &communityModel)
|
||||
|
||||
if len(listModel) > 0 {
|
||||
collection.Community = communityModel
|
||||
collection.List = listModel
|
||||
collection.Recommend = recommendModel
|
||||
collection.Version = o.GetCasaosVersion().Version
|
||||
var by []byte
|
||||
by, err = json.Marshal(collection)
|
||||
if err != nil {
|
||||
loger.Error("marshal error", zap.Any("err", err))
|
||||
}
|
||||
file.WriteToPath(by, config.AppInfo.DBPath, "app_list.json")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// func (o *casaService) GetServerCategoryList() (list []model.ServerCategoryList) {
|
||||
|
||||
// keyName := fmt.Sprintf("category_list")
|
||||
// if result, ok := Cache.Get(keyName); ok {
|
||||
// res, ok := result.(string)
|
||||
// if ok {
|
||||
// json2.Unmarshal([]byte(gjson.Get(res, "data").String()), &list)
|
||||
// return list
|
||||
// }
|
||||
// }
|
||||
|
||||
// head := make(map[string]string)
|
||||
// head["Authorization"] = GetToken()
|
||||
|
||||
// listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
|
||||
|
||||
// json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
|
||||
// if len(list) > 0 {
|
||||
// Cache.Set(keyName, listS, time.Hour*24)
|
||||
// }
|
||||
// return list
|
||||
// }
|
||||
|
||||
func (o *casaService) GetServerCategoryList() (list []model.CategoryList, err error) {
|
||||
category := model.ServerCategoryList{}
|
||||
results := file.ReadFullFile(config.AppInfo.DBPath + "/app_category.json")
|
||||
err = json2.Unmarshal(results, &category)
|
||||
if err != nil {
|
||||
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
|
||||
return o.AsyncGetServerCategoryList()
|
||||
}
|
||||
go o.AsyncGetServerCategoryList()
|
||||
return category.Item, err
|
||||
}
|
||||
|
||||
func (o *casaService) AsyncGetServerCategoryList() ([]model.CategoryList, error) {
|
||||
list := model.ServerCategoryList{}
|
||||
results := file.ReadFullFile(config.AppInfo.DBPath + "/app_category.json")
|
||||
err := json2.Unmarshal(results, &list)
|
||||
if err != nil {
|
||||
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
|
||||
}
|
||||
item := []model.CategoryList{}
|
||||
head := make(map[string]string)
|
||||
head["Authorization"] = GetToken()
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
|
||||
if len(listS) == 0 {
|
||||
return item, errors.New("server error")
|
||||
}
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &item)
|
||||
if len(item) > 0 {
|
||||
list.Version = o.GetCasaosVersion().Version
|
||||
list.Item = item
|
||||
by, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
loger.Error("marshal error", zap.Any("err", err))
|
||||
}
|
||||
file.WriteToPath(by, config.AppInfo.DBPath, "app_category.json")
|
||||
}
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (o *casaService) GetServerAppInfo(id, t string, language string) (model.ServerAppList, error) {
|
||||
|
||||
head := make(map[string]string)
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id+"?t="+t+"&language="+language, head)
|
||||
|
||||
info := model.ServerAppList{}
|
||||
if infoS == "" {
|
||||
return info, errors.New("server error")
|
||||
}
|
||||
err := json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
|
||||
if err != nil {
|
||||
fmt.Println(infoS)
|
||||
return info, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
func GetToken() string {
|
||||
t := make(chan string)
|
||||
keyName := "casa_token"
|
||||
|
||||
var auth string
|
||||
if result, ok := Cache.Get(keyName); ok {
|
||||
auth, ok = result.(string)
|
||||
if ok {
|
||||
|
||||
return auth
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
|
||||
t <- gjson.Get(str, "data").String()
|
||||
}()
|
||||
auth = <-t
|
||||
|
||||
Cache.SetDefault(keyName, auth)
|
||||
return auth
|
||||
}
|
||||
type casaService struct{}
|
||||
|
||||
/**
|
||||
* @description: get remote version
|
||||
|
|
|
@ -1,962 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model/notify"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
|
||||
//"github.com/containerd/containerd/oci"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
client2 "github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
type DockerService interface {
|
||||
DockerPullImage(imageName string, icon, name string) error
|
||||
IsExistImage(imageName string) bool
|
||||
DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error)
|
||||
DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error)
|
||||
DockerContainerStart(name string) error
|
||||
DockerContainerStats(name string) (string, error)
|
||||
DockerListByName(name string) (*types.Container, error)
|
||||
DockerListByImage(image, version string) (*types.Container, error)
|
||||
DockerContainerInfo(name string) (*types.ContainerJSON, error)
|
||||
DockerImageRemove(name string) error
|
||||
DockerContainerRemove(name string, update bool) error
|
||||
DockerContainerStop(id string) error
|
||||
DockerContainerUpdateName(name, id string) (err error)
|
||||
DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
|
||||
DockerContainerLog(name string) ([]byte, error)
|
||||
DockerContainerCommit(name string)
|
||||
DockerContainerList() []types.Container
|
||||
DockerNetworkModelList() []types.NetworkResource
|
||||
DockerImageInfo(image string) (types.ImageInspect, error)
|
||||
GetNetWorkNameByNetWorkID(id string) (string, error)
|
||||
ContainerExecShell(container_id string) string
|
||||
GetDockerInfo() (types.Info, error)
|
||||
}
|
||||
|
||||
type dockerService struct {
|
||||
rootDir string
|
||||
}
|
||||
|
||||
func (ds *dockerService) DockerContainerList() []types.Container {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
|
||||
if err != nil {
|
||||
return containers
|
||||
}
|
||||
return containers
|
||||
}
|
||||
|
||||
func (ds *dockerService) ContainerExecShell(container_id string) string {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
exec, err := cli.ContainerExecCreate(context.Background(), container_id, types.ExecConfig{
|
||||
User: "1000:1000",
|
||||
Cmd: []string{"echo -e \"hellow\nworld\" >> /a.txt"},
|
||||
})
|
||||
if err != nil {
|
||||
os.Exit(5)
|
||||
}
|
||||
err = cli.ContainerExecStart(context.Background(), exec.ID, types.ExecStartCheck{})
|
||||
if err != nil {
|
||||
fmt.Println("exec script error ", err)
|
||||
}
|
||||
return exec.ID
|
||||
}
|
||||
|
||||
// 创建默认网络
|
||||
func DockerNetwork() {
|
||||
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
d, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
|
||||
|
||||
for _, resource := range d {
|
||||
if resource.Name == docker.NETWORKNAME {
|
||||
return
|
||||
}
|
||||
}
|
||||
cli.NetworkCreate(context.Background(), docker.NETWORKNAME, types.NetworkCreate{})
|
||||
}
|
||||
|
||||
// 根据网络id获取网络名
|
||||
func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("id", id)
|
||||
d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{Filters: filter})
|
||||
if err == nil && len(d) > 0 {
|
||||
return d[0].Name, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 拉取镜像
|
||||
func DockerPull() {
|
||||
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
|
||||
authConfig := types.AuthConfig{}
|
||||
encodedJSON, err := json2.Marshal(authConfig)
|
||||
fmt.Println(err)
|
||||
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
reader, err := cli.ImagePull(context.Background(), "swr.cn-north-4.myhuaweicloud.com/root/swr-demo-2048:latest", types.ImagePullOptions{RegistryAuth: authStr})
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(reader)
|
||||
fmt.Println(buf.String())
|
||||
|
||||
}
|
||||
|
||||
// 拉取镜像
|
||||
func DockerEx() {
|
||||
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
|
||||
importResponse, err := cli.ImageImport(context.Background(), types.ImageImportSource{
|
||||
Source: strings.NewReader("source"),
|
||||
SourceName: "image_source",
|
||||
}, "repository_name:imported", types.ImageImportOptions{
|
||||
Tag: "imported",
|
||||
Message: "A message",
|
||||
Changes: []string{"change1", "change2"},
|
||||
})
|
||||
|
||||
response, err := ioutil.ReadAll(importResponse)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
importResponse.Close()
|
||||
println(string(response))
|
||||
if string(response) != "response" {
|
||||
fmt.Printf("expected response to contain 'response', got %s", string(response))
|
||||
}
|
||||
}
|
||||
|
||||
//func DockerContainerSize() {
|
||||
// cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
// //but := bytes.Buffer{}
|
||||
// d, err := cli.ContainerExecCreate(context.Background(), "c3adcef92bae648890941ac00e6c4024d7f2959c2e629f0b581d6a19d77b5eda")
|
||||
// fmt.Println(d)
|
||||
// st, _ := ioutil.ReadAll(d.Body)
|
||||
// fmt.Println(string(st))
|
||||
// if err != nil {
|
||||
// fmt.Print(err)
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
func (ds *dockerService) DockerImageInfo(image string) (types.ImageInspect, error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return types.ImageInspect{}, err
|
||||
}
|
||||
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image)
|
||||
if err != nil {
|
||||
return inspect, err
|
||||
}
|
||||
return inspect, nil
|
||||
}
|
||||
|
||||
func MsqlExec(container string) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
ctx := context.Background()
|
||||
// 执行/bin/bash命令
|
||||
ir, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{
|
||||
AttachStdin: false,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Cmd: []string{"date"},
|
||||
Tty: true,
|
||||
Env: []string{"aaa=ddd"},
|
||||
})
|
||||
err = cli.ContainerExecStart(ctx, ir.ID, types.ExecStartCheck{})
|
||||
|
||||
fmt.Println(err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func Exec(container, row, col string) (hr types.HijackedResponse, err error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
ctx := context.Background()
|
||||
// 执行/bin/bash命令
|
||||
ir, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Env: []string{"COLUMNS=" + col, "LINES=" + row},
|
||||
Cmd: []string{"/bin/bash"},
|
||||
Tty: true,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 附加到上面创建的/bin/bash进程中
|
||||
hr, err = cli.ContainerExecAttach(ctx, ir.ID, types.ExecStartCheck{Detach: false, Tty: true})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DockerLog() {
|
||||
//cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
//ctx := context.Background()
|
||||
//ir, err := cli.ContainerLogs(ctx, "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{})
|
||||
//str, err := ioutil.ReadAll(ir)
|
||||
//fmt.Println(string(str))
|
||||
//fmt.Println(err)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
reader, err := client.ContainerLogs(ctx, "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
_, err = io.Copy(os.Stdout, reader)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DockerLogs() {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
i, err := cli.ContainerLogs(context.Background(), "79c6fa382c330b9149e2d28d24f4d2c231cdb8cfc0710c2d268ccee13c5b24f8", types.ContainerLogsOptions{
|
||||
ShowStderr: true,
|
||||
ShowStdout: true,
|
||||
Timestamps: false,
|
||||
Follow: true,
|
||||
Tail: "40",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer i.Close()
|
||||
|
||||
hdr := make([]byte, 8)
|
||||
for {
|
||||
_, err := i.Read(hdr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var w io.Writer
|
||||
switch hdr[0] {
|
||||
case 1:
|
||||
w = os.Stdout
|
||||
default:
|
||||
w = os.Stderr
|
||||
}
|
||||
count := binary.BigEndian.Uint32(hdr[4:])
|
||||
dat := make([]byte, count)
|
||||
_, err = i.Read(dat)
|
||||
fmt.Fprint(w, string(dat))
|
||||
}
|
||||
}
|
||||
|
||||
//正式内容
|
||||
|
||||
// 检查镜像是否存在
|
||||
func (ds *dockerService) IsExistImage(imageName string) bool {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer cli.Close()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("reference", imageName)
|
||||
|
||||
list, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
|
||||
|
||||
if err == nil && len(list) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 安装镜像
|
||||
func (ds *dockerService) DockerPullImage(imageName string, icon, name string) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
out, err := cli.ImagePull(context.Background(), imageName, types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
//io.Copy()
|
||||
buf := make([]byte, 2048*4)
|
||||
for {
|
||||
n, err := out.Read(buf)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
fmt.Println("read error:", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
if len(icon) > 0 && len(name) > 0 {
|
||||
notify := notify.Application{}
|
||||
notify.Icon = icon
|
||||
notify.Name = name
|
||||
notify.State = "PULLING"
|
||||
notify.Type = "INSTALL"
|
||||
notify.Finished = false
|
||||
notify.Success = true
|
||||
notify.Message = string(buf[:n])
|
||||
MyService.Notify().SendInstallAppBySocket(notify)
|
||||
}
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
func (ds *dockerService) DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cli.Close()
|
||||
container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return container.ID, err
|
||||
}
|
||||
|
||||
// param imageName 镜像名称
|
||||
// param containerDbId 数据库的id
|
||||
// param port 容器内部主端口
|
||||
// param mapPort 容器主端口映射到外部的端口
|
||||
// param tcp 容器其他tcp端口
|
||||
// param udp 容器其他udp端口
|
||||
func (ds *dockerService) DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error) {
|
||||
if len(m.NetworkModel) == 0 {
|
||||
m.NetworkModel = "bridge"
|
||||
}
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer cli.Close()
|
||||
ports := make(nat.PortSet)
|
||||
portMaps := make(nat.PortMap)
|
||||
// ports[nat.Port(fmt.Sprint(m.PortMap)+"/tcp")] = struct{}{}
|
||||
// if net != "host" {
|
||||
// portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}}
|
||||
// }
|
||||
//port := ""
|
||||
for _, portMap := range m.Ports {
|
||||
// if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
|
||||
// port = portMap.ContainerPort
|
||||
// }
|
||||
if portMap.Protocol == "tcp" {
|
||||
|
||||
tContainer, _ := strconv.Atoi(portMap.ContainerPort)
|
||||
if tContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
|
||||
if m.NetworkModel != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
} else if portMap.Protocol == "both" {
|
||||
|
||||
tContainer, _ := strconv.Atoi(portMap.ContainerPort)
|
||||
if tContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
|
||||
if m.NetworkModel != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
|
||||
uContainer, _ := strconv.Atoi(portMap.ContainerPort)
|
||||
if uContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
|
||||
if m.NetworkModel != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
uContainer, _ := strconv.Atoi(portMap.ContainerPort)
|
||||
if uContainer > 0 {
|
||||
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
|
||||
if m.NetworkModel != "host" {
|
||||
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var envArr []string
|
||||
var showENV []string
|
||||
showENV = append(showENV, "casaos")
|
||||
for _, e := range m.Envs {
|
||||
showENV = append(showENV, e.Name)
|
||||
if strings.HasPrefix(e.Value, "$") {
|
||||
envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone()))
|
||||
continue
|
||||
}
|
||||
if len(e.Value) > 0 {
|
||||
if e.Value == "port_map" {
|
||||
envArr = append(envArr, e.Name+"="+m.PortMap)
|
||||
continue
|
||||
}
|
||||
envArr = append(envArr, e.Name+"="+e.Value)
|
||||
}
|
||||
}
|
||||
|
||||
res := container.Resources{}
|
||||
if m.CpuShares > 0 {
|
||||
res.CPUShares = m.CpuShares
|
||||
}
|
||||
if m.Memory > 0 {
|
||||
res.Memory = m.Memory << 20
|
||||
}
|
||||
for _, p := range m.Devices {
|
||||
if len(p.Path) > 0 {
|
||||
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
|
||||
}
|
||||
}
|
||||
hostConfingBind := []string{}
|
||||
// volumes bind
|
||||
volumes := []mount.Mount{}
|
||||
for _, v := range m.Volumes {
|
||||
path := v.Path
|
||||
if len(path) == 0 {
|
||||
path = docker.GetDir(m.Label, v.Path)
|
||||
if len(path) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
path = strings.ReplaceAll(path, "$AppID", m.Label)
|
||||
//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
|
||||
//result1 := reg1.FindAllStringSubmatch(path, -1)
|
||||
//if len(result1) == 0 {
|
||||
err = file.IsNotExistMkDir(path)
|
||||
if err != nil {
|
||||
loger.Error("Failed to create a folder", zap.Any("err", err))
|
||||
continue
|
||||
}
|
||||
//}
|
||||
// else {
|
||||
// err = file.IsNotExistCreateFile(path)
|
||||
// if err != nil {
|
||||
// ds.log.Error("mkdir error", err)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
volumes = append(volumes, mount.Mount{
|
||||
Type: mount.TypeBind,
|
||||
Source: path,
|
||||
Target: v.ContainerPath,
|
||||
})
|
||||
|
||||
hostConfingBind = append(hostConfingBind, v.Path+":"+v.ContainerPath)
|
||||
}
|
||||
|
||||
rp := container.RestartPolicy{}
|
||||
|
||||
if len(m.Restart) > 0 {
|
||||
rp.Name = m.Restart
|
||||
}
|
||||
// healthTest := []string{}
|
||||
// if len(port) > 0 {
|
||||
// healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
|
||||
// }
|
||||
|
||||
// health := &container.HealthConfig{
|
||||
// Test: healthTest,
|
||||
// StartPeriod: 0,
|
||||
// Retries: 1000,
|
||||
// }
|
||||
// fmt.Print(health)
|
||||
if len(m.HostName) == 0 {
|
||||
m.HostName = m.Label
|
||||
}
|
||||
|
||||
info, err := cli.ContainerInspect(context.Background(), id)
|
||||
hostConfig := &container.HostConfig{}
|
||||
config := &container.Config{}
|
||||
config.Labels = map[string]string{}
|
||||
if err == nil {
|
||||
// info.HostConfig = &container.HostConfig{}
|
||||
// info.Config = &container.Config{}
|
||||
// info.NetworkSettings = &types.NetworkSettings{}
|
||||
hostConfig = info.HostConfig
|
||||
config = info.Config
|
||||
if config.Labels["casaos"] == "casaos" {
|
||||
config.Cmd = m.Cmd
|
||||
config.Image = m.Image
|
||||
config.Env = envArr
|
||||
config.Hostname = m.HostName
|
||||
config.ExposedPorts = ports
|
||||
}
|
||||
} else {
|
||||
config.Cmd = m.Cmd
|
||||
config.Image = m.Image
|
||||
config.Env = envArr
|
||||
config.Hostname = m.HostName
|
||||
config.ExposedPorts = ports
|
||||
}
|
||||
|
||||
config.Labels["origin"] = m.Origin
|
||||
config.Labels["casaos"] = "casaos"
|
||||
config.Labels["web"] = m.PortMap
|
||||
config.Labels["icon"] = m.Icon
|
||||
config.Labels["desc"] = m.Description
|
||||
config.Labels["index"] = m.Index
|
||||
config.Labels["custom_id"] = m.CustomId
|
||||
config.Labels["show_env"] = strings.Join(showENV, ",")
|
||||
config.Labels["protocol"] = m.Protocol
|
||||
config.Labels["host"] = m.Host
|
||||
config.Labels["name"] = m.Label
|
||||
//container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name)
|
||||
|
||||
hostConfig.Mounts = volumes
|
||||
hostConfig.Binds = []string{}
|
||||
hostConfig.Privileged = m.Privileged
|
||||
hostConfig.CapAdd = m.CapAdd
|
||||
hostConfig.NetworkMode = container.NetworkMode(m.NetworkModel)
|
||||
hostConfig.RestartPolicy = rp
|
||||
hostConfig.Resources = res
|
||||
//hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: , Privileged: m.Privileged, CapAdd: m.CapAdd}
|
||||
//if net != "host" {
|
||||
|
||||
hostConfig.PortBindings = portMaps
|
||||
//}
|
||||
containerDb, err := cli.ContainerCreate(context.Background(),
|
||||
config,
|
||||
hostConfig,
|
||||
&network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{m.NetworkModel: {NetworkID: "", Aliases: []string{}}}},
|
||||
nil,
|
||||
m.ContainerName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return containerDb.ID, err
|
||||
}
|
||||
|
||||
// 删除容器
|
||||
func (ds *dockerService) DockerContainerRemove(name string, update bool) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
|
||||
|
||||
//路径处理
|
||||
if !update {
|
||||
path := docker.GetDir(name, "/config")
|
||||
if !file.CheckNotExist(path) {
|
||||
file.RMDir(path)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除镜像
|
||||
func (ds *dockerService) DockerImageRemove(name string) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
imageList, err := cli.ImageList(context.Background(), types.ImageListOptions{})
|
||||
|
||||
imageId := ""
|
||||
|
||||
Loop:
|
||||
for _, ig := range imageList {
|
||||
for _, i := range ig.RepoTags {
|
||||
if i == name {
|
||||
imageId = ig.ID
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = cli.ImageRemove(context.Background(), imageId, types.ImageRemoveOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
func DockerImageRemove(name string) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
imageList, err := cli.ImageList(context.Background(), types.ImageListOptions{})
|
||||
imageId := ""
|
||||
|
||||
Loop:
|
||||
for _, ig := range imageList {
|
||||
fmt.Println(ig.RepoDigests)
|
||||
fmt.Println(ig.Containers)
|
||||
for _, i := range ig.RepoTags {
|
||||
if i == name {
|
||||
imageId = ig.ID
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = cli.ImageRemove(context.Background(), imageId, types.ImageRemoveOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
// 停止镜像
|
||||
func (ds *dockerService) DockerContainerStop(id string) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
err = cli.ContainerStop(context.Background(), id, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// 启动容器
|
||||
func (ds *dockerService) DockerContainerStart(name string) error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
err = cli.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
// 查看日志
|
||||
func (ds *dockerService) DockerContainerLog(name string) ([]byte, error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
defer cli.Close()
|
||||
//body, err := cli.ContainerAttach(context.Background(), name, types.ContainerAttachOptions{Logs: true, Stream: false, Stdin: false, Stdout: false, Stderr: false})
|
||||
body, err := cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
|
||||
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
|
||||
defer body.Close()
|
||||
content, err := ioutil.ReadAll(body)
|
||||
//content, err := ioutil.ReadAll(body)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func DockerContainerStats1() error {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
dss, err := cli.ContainerStats(context.Background(), "dockermysql", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dss.Body.Close()
|
||||
sts, err := ioutil.ReadAll(dss.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(sts))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取容器状态
|
||||
func (ds *dockerService) DockerContainerStats(name string) (string, error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cli.Close()
|
||||
dss, err := cli.ContainerStats(context.Background(), name, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer dss.Body.Close()
|
||||
sts, err := ioutil.ReadAll(dss.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(sts), nil
|
||||
}
|
||||
|
||||
// 备份容器
|
||||
func (ds *dockerService) DockerContainerCommit(name string) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer cli.Close()
|
||||
d, err := cli.ContainerInspect(context.Background(), name)
|
||||
dss, err := cli.ContainerCommit(context.Background(), name, types.ContainerCommitOptions{Reference: "test", Config: d.Config})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(dss)
|
||||
}
|
||||
|
||||
func (ds *dockerService) DockerListByName(name string) (*types.Container, error) {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("name", name)
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
return &types.Container{}, err
|
||||
}
|
||||
if len(containers) == 0 {
|
||||
return &types.Container{}, errors.New("not found")
|
||||
}
|
||||
return &containers[0], nil
|
||||
}
|
||||
|
||||
func (ds *dockerService) DockerListByImage(image, version string) (*types.Container, error) {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("ancestor", image+":"+version)
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(containers) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &containers[0], nil
|
||||
}
|
||||
|
||||
// 获取容器详情
|
||||
func (ds *dockerService) DockerContainerInfo(name string) (*types.ContainerJSON, error) {
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return &types.ContainerJSON{}, err
|
||||
}
|
||||
defer cli.Close()
|
||||
d, err := cli.ContainerInspect(context.Background(), name)
|
||||
if err != nil {
|
||||
return &types.ContainerJSON{}, err
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
// 更新容器
|
||||
// param shares cpu优先级
|
||||
// param containerDbId 数据库的id
|
||||
// param port 容器内部主端口
|
||||
// param mapPort 容器主端口映射到外部的端口
|
||||
// param tcp 容器其他tcp端口
|
||||
// param udp 容器其他udp端口
|
||||
func (ds *dockerService) DockerContainerUpdate(m model.CustomizationPostData, id string) (err error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
//重启策略
|
||||
rp := container.RestartPolicy{
|
||||
Name: "",
|
||||
MaximumRetryCount: 0,
|
||||
}
|
||||
if len(m.Restart) > 0 {
|
||||
rp.Name = m.Restart
|
||||
}
|
||||
res := container.Resources{}
|
||||
|
||||
if m.Memory > 0 {
|
||||
res.Memory = m.Memory * 1024 * 1024
|
||||
res.MemorySwap = -1
|
||||
}
|
||||
if m.CpuShares > 0 {
|
||||
res.CPUShares = m.CpuShares
|
||||
}
|
||||
for _, p := range m.Devices {
|
||||
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
|
||||
}
|
||||
_, err = cli.ContainerUpdate(context.Background(), id, container.UpdateConfig{RestartPolicy: rp, Resources: res})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 更新容器名称
|
||||
// param name 容器名称
|
||||
// param id 老的容器名称
|
||||
func (ds *dockerService) DockerContainerUpdateName(name, id string) (err error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
err = cli.ContainerRename(context.Background(), id, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取网络列表
|
||||
func (ds *dockerService) DockerNetworkModelList() []types.NetworkResource {
|
||||
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
networks, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
|
||||
return networks
|
||||
}
|
||||
func NewDockerService() DockerService {
|
||||
return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`)}
|
||||
}
|
||||
|
||||
func (ds *dockerService) GetDockerInfo() (types.Info, error) {
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return types.Info{}, err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
return cli.Info(context.Background())
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------test------------------------------------
|
||||
//func ServiceCreate() {
|
||||
// cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
// r, err := cli.ServiceCreate(context.Background(), swarm.ServiceSpec{}, types.ServiceCreateOptions{})
|
||||
// if err != nil {
|
||||
// fmt.Println("error", err)
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
||||
// func Containerd() {
|
||||
// // create a new client connected to the default socket path for containerd
|
||||
// cli, err := containerd.New("/run/containerd/containerd.sock")
|
||||
// if err != nil {
|
||||
// fmt.Println("111")
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
// defer cli.Close()
|
||||
|
||||
// // create a new context with an "example" namespace
|
||||
// ctx := namespaces.WithNamespace(context.Background(), "default")
|
||||
|
||||
// // pull the redis image from DockerHub
|
||||
// image, err := cli.Pull(ctx, "docker.io/library/busybox:latest", containerd.WithPullUnpack)
|
||||
// if err != nil {
|
||||
// fmt.Println("222")
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
||||
// // create a container
|
||||
// container, err := cli.NewContainer(
|
||||
// ctx,
|
||||
// "test1",
|
||||
// containerd.WithImage(image),
|
||||
// containerd.WithNewSnapshot("redis-server-snapshot1", image),
|
||||
// containerd.WithNewSpec(oci.WithImageConfig(image)),
|
||||
// )
|
||||
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
// defer container.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
|
||||
// // create a task from the container
|
||||
// task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
// defer task.Delete(ctx)
|
||||
|
||||
// // make sure we wait before calling start
|
||||
// exitStatusC, err := task.Wait(ctx)
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
||||
// // call start on the task to execute the redis server
|
||||
// if err = task.Start(ctx); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
||||
// fmt.Println("执行完成等待")
|
||||
// // sleep for a lil bit to see the logs
|
||||
// time.Sleep(3 * time.Second)
|
||||
|
||||
// // kill the process and get the exit status
|
||||
// if err = task.Kill(ctx, syscall.SIGTERM); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
|
||||
// // wait for the process to fully exit and print out the exit status
|
||||
|
||||
// status := <-exitStatusC
|
||||
// code, _, err := status.Result()
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
// fmt.Printf("redis-server exited with status: %d\n", code)
|
||||
|
||||
// }
|
|
@ -1,24 +0,0 @@
|
|||
package docker_base
|
||||
|
||||
import "github.com/IceWhaleTech/CasaOS/model"
|
||||
|
||||
//过滤mysql关键字
|
||||
func MysqlFilter(c MysqlConfig, envs model.EnvArray) model.EnvArray {
|
||||
for i := 0; i < len(envs); i++ {
|
||||
switch envs[i].Value {
|
||||
case "$MYSQL_HOST":
|
||||
envs[i].Value = c.DataBaseHost
|
||||
case "$MYSQL_PORT":
|
||||
envs[i].Value = c.DataBasePort
|
||||
case "$MYSQL_USERNAME":
|
||||
envs[i].Value = c.DataBaseUser
|
||||
case "$MYSQL_PASSWORD":
|
||||
envs[i].Value = c.DataBasePassword
|
||||
case "$MYSQL_DBNAME":
|
||||
envs[i].Value = c.DataBaseDB
|
||||
case "$MYSQL_HOST_AND_PORT":
|
||||
envs[i].Value = c.DataBaseHost + ":" + c.DataBasePort
|
||||
}
|
||||
}
|
||||
return envs
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package docker_base
|
||||
|
||||
type MysqlConfig struct {
|
||||
DataBaseHost string `json:"database_host"`
|
||||
DataBasePort string `json:"database_port"`
|
||||
DataBaseUser string `json:"database_user"`
|
||||
DataBasePassword string `json:"data_base_password"`
|
||||
DataBaseDB string `json:"data_base_db"`
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
package docker_base
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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/network"
|
||||
client2 "github.com/docker/docker/client"
|
||||
"time"
|
||||
)
|
||||
|
||||
//创建一个mysql数据库
|
||||
func MysqlCreate(mysqlConfig MysqlConfig, dbId string, cpuShares int64, memory int64) (string, error) {
|
||||
const imageName = "mysql"
|
||||
const imageVersion = "8"
|
||||
const imageNet = "oasis"
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cli.Close()
|
||||
_, err = cli.ImagePull(context.Background(), imageName+":"+imageVersion, types.ImagePullOptions{})
|
||||
|
||||
isExist := true
|
||||
//检查到镜像才继续
|
||||
for isExist {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("before", imageName+":"+imageVersion)
|
||||
list, e := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
|
||||
if e == nil && len(list) > 0 {
|
||||
isExist = false
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
var envArr = []string{"MYSQL_ROOT_PASSWORD=" + mysqlConfig.DataBasePassword, "MYSQL_DATABASE=" + mysqlConfig.DataBaseDB}
|
||||
|
||||
res := container.Resources{}
|
||||
if cpuShares > 0 {
|
||||
res.CPUShares = cpuShares
|
||||
}
|
||||
if memory > 0 {
|
||||
res.Memory = memory << 20
|
||||
}
|
||||
|
||||
rp := container.RestartPolicy{}
|
||||
|
||||
rp.Name = "always"
|
||||
|
||||
config := &container.Config{
|
||||
Image: imageName,
|
||||
Labels: map[string]string{"version": imageVersion, "author": "official"},
|
||||
Env: envArr,
|
||||
}
|
||||
hostConfig := &container.HostConfig{Resources: res, RestartPolicy: rp, NetworkMode: container.NetworkMode(imageNet)}
|
||||
|
||||
containerCreate, err := cli.ContainerCreate(context.Background(),
|
||||
config,
|
||||
hostConfig,
|
||||
&network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{imageNet: {NetworkID: ""}}},
|
||||
nil,
|
||||
dbId)
|
||||
|
||||
containerId := containerCreate.ID
|
||||
|
||||
//启动容器
|
||||
err = cli.ContainerStart(context.Background(), dbId, types.ContainerStartOptions{})
|
||||
if err != nil {
|
||||
return containerId, err
|
||||
}
|
||||
|
||||
return containerId, nil
|
||||
|
||||
}
|
||||
|
||||
func MysqlDelete(dbId string) error {
|
||||
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
err = cli.ContainerStop(context.Background(), dbId, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cli.ContainerRemove(context.Background(), dbId, types.ContainerRemoveOptions{})
|
||||
return err
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//func TestDockerImageInfo(t *testing.T) {
|
||||
// //DockerImageInfo()
|
||||
//
|
||||
// address, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:0", "0.0.0.0"))
|
||||
// if err != nil {
|
||||
// fmt.Println(0, err)
|
||||
// }
|
||||
//
|
||||
// listener, err := net.ListenTCP("tcp", address)
|
||||
// if err != nil {
|
||||
// fmt.Println(0, err)
|
||||
// }
|
||||
//
|
||||
// defer listener.Close()
|
||||
// fmt.Println(listener.Addr().(*net.TCPAddr).Port, nil)
|
||||
//
|
||||
//}
|
||||
|
||||
//func TestDockerNetwork(t *testing.T) {
|
||||
// DockerNetwork()
|
||||
//}
|
||||
//
|
||||
//func TestDockerPull(t *testing.T) {
|
||||
// DockerPull()
|
||||
//}
|
||||
//
|
||||
//func TestDockerLog(t *testing.T) {
|
||||
// DockerLog()
|
||||
//}
|
||||
//func TestDockerLogs(t *testing.T) {
|
||||
// DockerLogs()
|
||||
//}
|
||||
|
||||
func TestDockerContainerStats(t *testing.T) {
|
||||
fmt.Println(DockerContainerStats1())
|
||||
}
|
||||
|
||||
//func TestDockerImageRemove(t *testing.T) {
|
||||
// host, domain, tld := gotld.GetSubdomain("aaa.liru-05.top", 1)
|
||||
// fmt.Println(host)
|
||||
// fmt.Println(domain)
|
||||
// fmt.Println(tld)
|
||||
//}
|
|
@ -19,9 +19,9 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -78,8 +78,8 @@ func (w *writer) Write(p []byte) (n int, err error) {
|
|||
return w.w.Write(p)
|
||||
}
|
||||
}
|
||||
func FileOperate(k string) {
|
||||
|
||||
func FileOperate(k string) {
|
||||
list, ok := FileQueue.Load(k)
|
||||
if !ok {
|
||||
return
|
||||
|
@ -103,10 +103,10 @@ func FileOperate(k string) {
|
|||
}
|
||||
err := os.Rename(v.From, temp.To+"/"+lastPath)
|
||||
if err != nil {
|
||||
loger.Error("file move error", zap.Any("err", err))
|
||||
logger.Error("file move error", zap.Any("err", err))
|
||||
err = file.MoveFile(v.From, temp.To+"/"+lastPath)
|
||||
if err != nil {
|
||||
loger.Error("MoveFile error", zap.Any("err", err))
|
||||
logger.Error("MoveFile error", zap.Any("err", err))
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,6 @@ func CheckFileStatus() {
|
|||
}
|
||||
temp := item.(model.FileOperate)
|
||||
for i := 0; i < len(temp.Item); i++ {
|
||||
|
||||
if !temp.Item[i].Finished {
|
||||
size, err := file.GetFileOrDirSize(temp.To + "/" + filepath.Base(temp.Item[i].From))
|
||||
if err != nil {
|
||||
|
@ -166,7 +165,6 @@ func CheckFileStatus() {
|
|||
} else {
|
||||
total += temp.Item[i].ProcessedSize
|
||||
}
|
||||
|
||||
}
|
||||
temp.ProcessedSize = total
|
||||
FileQueue.Store(v, temp)
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-05-13 18:15:46
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-07-13 10:56:34
|
||||
* @FilePath: /CasaOS/service/model/o_container.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package model
|
||||
|
||||
const CONTAINERTABLENAME = "o_container"
|
||||
|
||||
//Soon to be removed
|
||||
type AppListDBModel struct {
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
Title string `json:"title"`
|
||||
// ScreenshotLink model.Strings `gorm:"type:json" json:"screenshot_link,omitempty"`
|
||||
ScreenshotLink string `json:"screenshot_link"`
|
||||
Slogan string `json:"slogan"`
|
||||
Description string `json:"description"`
|
||||
//Tags model.Strings `gorm:"type:json" json:"tags"`
|
||||
Tags string `json:"tags"`
|
||||
Icon string `json:"icon"`
|
||||
Version string `json:"version"`
|
||||
ContainerId string `json:"container_id,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Index string `json:"index"`
|
||||
CreatedAt string `gorm:"<-:create;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt string `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at"`
|
||||
//Port string `json:"port,omitempty"`
|
||||
PortMap string `json:"port_map"`
|
||||
Label string `json:"label"`
|
||||
EnableUPNP bool `json:"enable_upnp"`
|
||||
Envs string `json:"envs"`
|
||||
Ports string `json:"ports"`
|
||||
Volumes string `json:"volumes"`
|
||||
Devices string `json:"devices"`
|
||||
//Envs []model.Env `json:"envs"`
|
||||
//Ports []model.PortMap `gorm:"type:json" json:"ports"`
|
||||
//Volumes []model.PathMap `gorm:"type:json" json:"volumes"`
|
||||
//Devices []model.PathMap `gorm:"type:json" json:"device"`
|
||||
Position bool `json:"position"`
|
||||
NetModel string `json:"net_model"`
|
||||
CpuShares int64 `json:"cpu_shares"`
|
||||
Memory int64 `json:"memory"`
|
||||
Restart string `json:"restart"`
|
||||
//Rely model.MapStrings `gorm:"type:json" json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
|
||||
Origin string `json:"origin"`
|
||||
HostName string `json:"host_name"`
|
||||
Privileged bool `json:"privileged"`
|
||||
CapAdd string `json:"cap_add"`
|
||||
Cmd string `gorm:"type:json" json:"cmd"`
|
||||
}
|
||||
|
||||
func (p *AppListDBModel) TableName() string {
|
||||
return "o_container"
|
||||
}
|
||||
|
||||
type MyAppList struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
State string `json:"state"`
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
Index string `json:"index"`
|
||||
//Order string `json:"order"`
|
||||
Port string `json:"port"`
|
||||
Slogan string `json:"slogan"`
|
||||
Type string `json:"type"`
|
||||
//Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
|
||||
Image string `json:"image"`
|
||||
Volumes string `json:"volumes"`
|
||||
Latest bool `json:"latest"`
|
||||
Host string `json:"host"`
|
||||
Protocol string `json:"protocol"`
|
||||
}
|
|
@ -1,33 +1,17 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"github.com/IceWhaleTech/CasaOS/service/docker_base"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RelyDBModel struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
CustomId string ` json:"custom_id"`
|
||||
ContainerCustomId string `json:"container_custom_id"`
|
||||
Config MysqlConfigs `json:"config"`
|
||||
ContainerId string `json:"container_id,omitempty"`
|
||||
Type int `json:"type"` //目前暂未使用
|
||||
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
|
||||
}
|
||||
|
||||
/****************使gorm支持[]string结构*******************/
|
||||
type MysqlConfigs docker_base.MysqlConfig
|
||||
|
||||
func (c MysqlConfigs) Value() (driver.Value, error) {
|
||||
b, err := json.Marshal(c)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func (c *MysqlConfigs) Scan(input interface{}) error {
|
||||
return json.Unmarshal(input.([]byte), c)
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
CustomId string ` json:"custom_id"`
|
||||
ContainerCustomId string `json:"container_custom_id"`
|
||||
ContainerId string `json:"container_id,omitempty"`
|
||||
Type int `json:"type"` // 目前暂未使用
|
||||
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
|
||||
}
|
||||
|
||||
/****************使gorm支持[]string结构*******************/
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
notifyCommon "github.com/IceWhaleTech/CasaOS-Common/model/notify"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/model/notify"
|
||||
"github.com/IceWhaleTech/CasaOS/service/model"
|
||||
|
@ -15,24 +16,26 @@ import (
|
|||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var NotifyMsg chan notify.Message
|
||||
var ClientCount int = 0
|
||||
var (
|
||||
NotifyMsg chan notify.Message
|
||||
ClientCount int
|
||||
)
|
||||
|
||||
type NotifyServer interface {
|
||||
GetLog(id string) model.AppNotify
|
||||
AddLog(log model.AppNotify)
|
||||
UpdateLog(log model.AppNotify)
|
||||
UpdateLogByCustomId(log model.AppNotify)
|
||||
UpdateLogByCustomID(log model.AppNotify)
|
||||
DelLog(id string)
|
||||
GetList(c int) (list []model.AppNotify)
|
||||
MarkRead(id string, state int)
|
||||
// SendText(m model.AppNotify)
|
||||
SendUninstallAppBySocket(app notify.Application)
|
||||
SendUninstallAppBySocket(app notifyCommon.Application)
|
||||
SendNetInfoBySocket(netList []model2.IOCountersStat)
|
||||
SendCPUInfoBySocket(cpu map[string]interface{})
|
||||
SendMemInfoBySocket(mem map[string]interface{})
|
||||
SendFileOperateNotify(nowSend bool)
|
||||
SendInstallAppBySocket(app notify.Application)
|
||||
SendInstallAppBySocket(app notifyCommon.Application)
|
||||
SendAllHardwareStatusBySocket(mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat)
|
||||
SendStorageBySocket(message notify.StorageMessage)
|
||||
SendNotify(path string, message map[string]interface{})
|
||||
|
@ -62,7 +65,6 @@ func (i *notifyServer) SendNotify(path string, message map[string]interface{}) {
|
|||
notify.Msg = msg
|
||||
|
||||
NotifyMsg <- notify
|
||||
|
||||
}
|
||||
|
||||
func (i *notifyServer) SendStorageBySocket(message notify.StorageMessage) {
|
||||
|
@ -80,8 +82,8 @@ func (i *notifyServer) SendStorageBySocket(message notify.StorageMessage) {
|
|||
|
||||
NotifyMsg <- notify
|
||||
}
|
||||
func (i *notifyServer) SendAllHardwareStatusBySocket(mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat) {
|
||||
|
||||
func (i *notifyServer) SendAllHardwareStatusBySocket(mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat) {
|
||||
body := make(map[string]interface{})
|
||||
|
||||
body["sys_mem"] = mem
|
||||
|
@ -104,12 +106,10 @@ func (i *notifyServer) SendAllHardwareStatusBySocket(mem map[string]interface{},
|
|||
notify.Msg = msg
|
||||
|
||||
NotifyMsg <- notify
|
||||
|
||||
}
|
||||
|
||||
// Send periodic broadcast messages
|
||||
func (i *notifyServer) SendFileOperateNotify(nowSend bool) {
|
||||
|
||||
if nowSend {
|
||||
|
||||
len := 0
|
||||
|
@ -259,7 +259,6 @@ func (i *notifyServer) SendFileOperateNotify(nowSend bool) {
|
|||
time.Sleep(time.Second * 3)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (i *notifyServer) SendMemInfoBySocket(mem map[string]interface{}) {
|
||||
|
@ -278,7 +277,7 @@ func (i *notifyServer) SendMemInfoBySocket(mem map[string]interface{}) {
|
|||
NotifyMsg <- notify
|
||||
}
|
||||
|
||||
func (i *notifyServer) SendInstallAppBySocket(app notify.Application) {
|
||||
func (i *notifyServer) SendInstallAppBySocket(app notifyCommon.Application) {
|
||||
body := make(map[string]interface{})
|
||||
body["data"] = app
|
||||
|
||||
|
@ -309,6 +308,7 @@ func (i *notifyServer) SendCPUInfoBySocket(cpu map[string]interface{}) {
|
|||
|
||||
NotifyMsg <- notify
|
||||
}
|
||||
|
||||
func (i *notifyServer) SendNetInfoBySocket(netList []model2.IOCountersStat) {
|
||||
body := make(map[string]interface{})
|
||||
body["data"] = netList
|
||||
|
@ -325,7 +325,7 @@ func (i *notifyServer) SendNetInfoBySocket(netList []model2.IOCountersStat) {
|
|||
NotifyMsg <- notify
|
||||
}
|
||||
|
||||
func (i *notifyServer) SendUninstallAppBySocket(app notify.Application) {
|
||||
func (i *notifyServer) SendUninstallAppBySocket(app notifyCommon.Application) {
|
||||
body := make(map[string]interface{})
|
||||
body["data"] = app
|
||||
|
||||
|
@ -358,17 +358,20 @@ func (i *notifyServer) AddLog(log model.AppNotify) {
|
|||
func (i *notifyServer) UpdateLog(log model.AppNotify) {
|
||||
i.db.Save(&log)
|
||||
}
|
||||
func (i *notifyServer) UpdateLogByCustomId(log model.AppNotify) {
|
||||
|
||||
func (i *notifyServer) UpdateLogByCustomID(log model.AppNotify) {
|
||||
if len(log.CustomId) == 0 {
|
||||
return
|
||||
}
|
||||
i.db.Model(&model.AppNotify{}).Select("*").Where("custom_id = ? ", log.CustomId).Updates(log)
|
||||
}
|
||||
|
||||
func (i *notifyServer) GetLog(id string) model.AppNotify {
|
||||
var log model.AppNotify
|
||||
i.db.Where("custom_id = ? ", id).First(&log)
|
||||
return log
|
||||
}
|
||||
|
||||
func (i *notifyServer) MarkRead(id string, state int) {
|
||||
if id == "0" {
|
||||
i.db.Model(&model.AppNotify{}).Where("1 = ?", 1).Update("state", state)
|
||||
|
@ -376,6 +379,7 @@ func (i *notifyServer) MarkRead(id string, state int) {
|
|||
}
|
||||
i.db.Model(&model.AppNotify{}).Where("id = ? ", id).Update("state", state)
|
||||
}
|
||||
|
||||
func (i *notifyServer) DelLog(id string) {
|
||||
var log model.AppNotify
|
||||
i.db.Where("custom_id = ?", id).Delete(&log)
|
||||
|
@ -444,10 +448,9 @@ func SendMeg() {
|
|||
|
||||
// }
|
||||
func (i *notifyServer) GetSystemTempMap() map[string]interface{} {
|
||||
|
||||
return i.SystemTempMap
|
||||
|
||||
}
|
||||
|
||||
func NewNotifyService(db *gorm.DB) NotifyServer {
|
||||
return ¬ifyServer{db: db, SystemTempMap: make(map[string]interface{})}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,13 @@ var Cache *cache.Cache
|
|||
|
||||
var MyService Repository
|
||||
|
||||
var WebSocketConns []*websocket.Conn
|
||||
var NewVersionApp map[string]string
|
||||
var SocketRun bool
|
||||
var (
|
||||
WebSocketConns []*websocket.Conn
|
||||
SocketRun bool
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
App() AppService
|
||||
//User() UserService
|
||||
Docker() DockerService
|
||||
// User() UserService
|
||||
Casa() CasaService
|
||||
Notify() NotifyServer
|
||||
Rely() RelyService
|
||||
|
@ -39,7 +38,6 @@ type Repository interface {
|
|||
}
|
||||
|
||||
func NewService(db *gorm.DB, RuntimePath string) Repository {
|
||||
|
||||
gatewayManagement, err := external.NewManagementService(RuntimePath)
|
||||
if err != nil && len(RuntimePath) > 0 {
|
||||
panic(err)
|
||||
|
@ -47,8 +45,6 @@ func NewService(db *gorm.DB, RuntimePath string) Repository {
|
|||
|
||||
return &store{
|
||||
gateway: gatewayManagement,
|
||||
app: NewAppService(db),
|
||||
docker: NewDockerService(),
|
||||
casa: NewCasaService(),
|
||||
notify: NewNotifyService(db),
|
||||
rely: NewRelyService(db),
|
||||
|
@ -60,8 +56,6 @@ func NewService(db *gorm.DB, RuntimePath string) Repository {
|
|||
|
||||
type store struct {
|
||||
db *gorm.DB
|
||||
app AppService
|
||||
docker DockerService
|
||||
casa CasaService
|
||||
notify NotifyServer
|
||||
rely RelyService
|
||||
|
@ -74,9 +68,11 @@ type store struct {
|
|||
func (c *store) Gateway() external.ManagementService {
|
||||
return c.gateway
|
||||
}
|
||||
|
||||
func (s *store) Connections() ConnectionsService {
|
||||
return s.connections
|
||||
}
|
||||
|
||||
func (s *store) Shares() SharesService {
|
||||
return s.shares
|
||||
}
|
||||
|
@ -88,19 +84,11 @@ func (c *store) Rely() RelyService {
|
|||
func (c *store) System() SystemService {
|
||||
return c.system
|
||||
}
|
||||
|
||||
func (c *store) Notify() NotifyServer {
|
||||
|
||||
return c.notify
|
||||
}
|
||||
|
||||
func (c *store) App() AppService {
|
||||
return c.app
|
||||
}
|
||||
|
||||
func (c *store) Docker() DockerService {
|
||||
return c.docker
|
||||
}
|
||||
|
||||
func (c *store) Casa() CasaService {
|
||||
return c.casa
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
|
@ -66,6 +66,7 @@ func (c *systemService) GetMacAddress() (string, error) {
|
|||
inter := interfaces[0]
|
||||
return inter.HardwareAddr, nil
|
||||
}
|
||||
|
||||
func (c *systemService) MkdirAll(path string) (int, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
|
@ -227,15 +228,15 @@ func (s *systemService) UpdateSystemVersion(version string) {
|
|||
os.Remove(config.AppInfo.LogPath + "/upgrade.log")
|
||||
}
|
||||
file.CreateFile(config.AppInfo.LogPath + "/upgrade.log")
|
||||
//go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash")
|
||||
// go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash")
|
||||
if len(config.ServerInfo.UpdateUrl) > 0 {
|
||||
go command2.OnlyExec("curl -fsSL " + config.ServerInfo.UpdateUrl + " | bash")
|
||||
} else {
|
||||
go command2.OnlyExec("curl -fsSL https://get.casaos.io/update | bash")
|
||||
}
|
||||
|
||||
//s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
|
||||
//s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
|
||||
// s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
|
||||
// s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
|
||||
}
|
||||
|
||||
func (s *systemService) UpdateAssist() {
|
||||
|
@ -328,17 +329,17 @@ func GetCPUThermalZone() string {
|
|||
name = strings.TrimSuffix(string(file.ReadFullFile(path+"/type")), "\n")
|
||||
for _, s := range cpu_types {
|
||||
if strings.HasPrefix(name, s) {
|
||||
loger.Info(fmt.Sprintf("CPU thermal zone found: %s, path: %s.", name, path))
|
||||
logger.Info(fmt.Sprintf("CPU thermal zone found: %s, path: %s.", name, path))
|
||||
Cache.SetDefault(keyName, path)
|
||||
return path
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(name) > 0 { //proves at least one zone
|
||||
loger.Warn("CPU thermal zone not matched. Default to thermal_zone0.")
|
||||
if len(name) > 0 { // proves at least one zone
|
||||
logger.Info("CPU thermal zone not matched. Default to thermal_zone0.")
|
||||
path = stub + "0"
|
||||
} else {
|
||||
loger.Error("No CPU thermal zones found. CPU temp will not be displayed.")
|
||||
logger.Error("No CPU thermal zones found. CPU temp will not be displayed.")
|
||||
path = ""
|
||||
}
|
||||
break
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
*/
|
||||
package types
|
||||
|
||||
const CURRENTVERSION = "0.3.8"
|
||||
const CURRENTVERSION = "0.4.0"
|
||||
|
||||
const BODY = " "
|
||||
|
|
Loading…
Reference in a new issue