CasaOS/service/app.go

357 lines
9.4 KiB
Go
Raw Normal View History

2021-09-26 02:35:02 +00:00
package service
import (
"context"
"encoding/json"
"io"
2021-12-06 09:08:36 +00:00
"io/ioutil"
"runtime"
"strings"
2021-12-06 09:08:36 +00:00
"sync"
"time"
"github.com/IceWhaleTech/CasaOS/model"
2021-09-27 06:17:36 +00:00
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
2021-09-26 02:35:02 +00:00
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
client2 "github.com/docker/docker/client"
"github.com/pkg/errors"
"gorm.io/gorm"
)
type AppService interface {
GetMyList(index, size int, position bool) *[]model2.MyAppList
SaveContainer(m model2.AppListDBModel)
GetUninstallInfo(id string) model2.AppListDBModel
RemoveContainerById(id string)
GetContainerInfo(name string) (types.Container, error)
GetAppDBInfo(id string) model2.AppListDBModel
UpdateApp(m model2.AppListDBModel)
GetSimpleContainerInfo(name string) (types.Container, error)
2021-11-25 11:41:25 +00:00
DelAppConfigDir(path string)
GetSystemAppList() *[]model2.MyAppList
GetHardwareUsageSteam()
GetHardwareUsage() []model.DockerStatsModel
GetAppStats(id string) string
2021-09-26 02:35:02 +00:00
}
type appStruct struct {
db *gorm.DB
log loger2.OLog
}
//获取我的应用列表
func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
//获取docker应用
2021-12-29 08:42:20 +00:00
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
2021-09-26 02:35:02 +00:00
if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
}
defer cli.Close()
fts := filters.NewArgs()
fts.Add("label", "origin")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil {
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
}
//获取本地数据库应用
var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image").Find(&lm)
2021-09-26 02:35:02 +00:00
list := []model2.MyAppList{}
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" {
2021-12-03 08:48:07 +00:00
m := lMap[container.ID].(model2.AppListDBModel)
if len(m.Label) == 0 {
m.Label = m.Title
}
2021-12-29 08:42:20 +00:00
// 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,
2021-12-29 08:42:20 +00:00
//UpTime: tm,
Image: m.Image,
Slogan: m.Slogan,
//Rely: m.Rely,
})
}
}
return &list
}
//system application list
func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
//获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", 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 {
2021-12-29 08:42:20 +00:00
a.log.Error("获取docker容器失败", "app.sys", "line:123", 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
}
2021-09-26 02:35:02 +00:00
for _, container := range containers {
if lMap[container.ID] != nil {
2021-12-03 08:48:07 +00:00
m := lMap[container.ID].(model2.AppListDBModel)
2021-09-26 02:35:02 +00:00
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,
2021-09-26 02:35:02 +00:00
Slogan: m.Slogan,
Volumes: m.Volumes,
2021-09-26 02:35:02 +00:00
//Rely: m.Rely,
})
}
}
return &list
}
//获取我的应用列表
func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
//获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
}
filters := filters.NewArgs()
filters.Add("name", name)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
if err != nil {
2021-12-29 08:42:20 +00:00
a.log.Error("获取docker容器失败", "app.getcontainerinfo", "line:182", err)
2021-09-26 02:35:02 +00:00
}
if len(containers) > 0 {
return containers[0], nil
}
return types.Container{}, nil
}
func (a *appStruct) GetSimpleContainerInfo(name 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("name", name)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
2021-12-03 08:48:07 +00:00
if err != nil {
return types.Container{}, err
}
2021-09-26 02:35:02 +00:00
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)
}
2021-11-25 11:41:25 +00:00
func (a *appStruct) DelAppConfigDir(path string) {
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;DelAppConfigDir " + path)
2021-09-26 02:35:02 +00:00
}
func (a *appStruct) RemoveContainerById(id string) {
a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
}
2021-12-10 09:14:01 +00:00
var dataStats sync.Map
var isFinish bool = false
2021-12-06 09:08:36 +00:00
func (a *appStruct) GetAppStats(id string) string {
2021-12-06 09:08:36 +00:00
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return ""
2021-12-06 09:08:36 +00:00
}
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)
}
2021-12-06 09:08:36 +00:00
func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
steam := true
for !isFinish {
if steam {
steam = false
go func() {
a.GetHardwareUsageSteam()
}()
}
runtime.Gosched()
2021-12-06 09:08:36 +00:00
}
list := []model.DockerStatsModel{}
2021-12-10 09:14:01 +00:00
dataStats.Range(func(key, value interface{}) bool {
list = append(list, value.(model.DockerStatsModel))
return true
})
return list
2021-12-06 09:08:36 +00:00
}
func (a *appStruct) GetHardwareUsageSteam() {
2021-12-06 09:08:36 +00:00
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return
2021-12-06 09:08:36 +00:00
}
defer cli.Close()
2021-12-06 09:08:36 +00:00
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
var lm []model2.AppListDBModel
2021-12-10 06:17:36 +00:00
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
for i := 0; i < 100; i++ {
2021-12-10 06:17:36 +00:00
if config.CasaOSGlobalVariables.AppChange {
lm = []model2.AppListDBModel{}
config.CasaOSGlobalVariables.AppChange = false
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
2021-12-10 09:14:01 +00:00
dataApps := dataStats
dataStats.Range(func(key, value interface{}) bool {
dataStats.Delete(key)
return true
})
2021-12-10 06:17:36 +00:00
for _, v := range lm {
2021-12-10 09:14:01 +00:00
m, _ := dataApps.Load(v.ContainerId)
if m != nil {
dataStats.Store(v.ContainerId, m)
2021-12-10 06:17:36 +00:00
}
}
}
var wg sync.WaitGroup
for _, v := range lm {
wg.Add(1)
2021-12-10 09:14:01 +00:00
go func(v model2.AppListDBModel, i int) {
defer wg.Done()
stats, err := cli.ContainerStats(ctx, v.ContainerId, true)
if err != nil {
return
}
decode := json.NewDecoder(stats.Body)
var data interface{}
if err := decode.Decode(&data); err == io.EOF {
return
}
2021-12-10 09:14:01 +00:00
m, _ := dataStats.Load(v.ContainerId)
dockerStats := model.DockerStatsModel{}
2021-12-10 09:14:01 +00:00
if m != nil {
dockerStats.Pre = m.(model.DockerStatsModel).Data
}
dockerStats.Data = data
dockerStats.Icon = v.Icon
2021-12-10 06:17:36 +00:00
if len(v.Label) > 0 {
dockerStats.Title = v.Label
} else {
dockerStats.Title = v.Title
}
2021-12-10 09:14:01 +00:00
dataStats.Store(v.ContainerId, dockerStats)
2021-12-10 08:33:39 +00:00
if i == 99 {
stats.Body.Close()
}
2021-12-10 09:14:01 +00:00
}(v, i)
}
wg.Wait()
isFinish = true
2021-12-10 08:33:39 +00:00
time.Sleep(time.Second * 3)
}
isFinish = false
cancel()
2021-12-06 09:08:36 +00:00
}
2021-09-26 02:35:02 +00:00
func NewAppService(db *gorm.DB, logger loger2.OLog) AppService {
return &appStruct{db: db, log: logger}
}