package v1

import (
	"bytes"
	json2 "encoding/json"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/IceWhaleTech/CasaOS/model"
	"github.com/IceWhaleTech/CasaOS/pkg/config"
	"github.com/IceWhaleTech/CasaOS/pkg/docker"
	upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
	ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
	port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
	"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
	"github.com/IceWhaleTech/CasaOS/service"
	"github.com/IceWhaleTech/CasaOS/service/docker_base"
	model2 "github.com/IceWhaleTech/CasaOS/service/model"
	"github.com/IceWhaleTech/CasaOS/types"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/jinzhu/copier"
	uuid "github.com/satori/go.uuid"
	"github.com/tidwall/gjson"
	"golang.org/x/crypto/ssh"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:   1024,
	WriteBufferSize:  1024,
	CheckOrigin:      func(r *http.Request) bool { return true },
	HandshakeTimeout: time.Duration(time.Second * 5),
}

func DockerTerminal(c *gin.Context) {
	col := c.DefaultQuery("cols", "100")
	row := c.DefaultQuery("rows", "30")
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}
	defer conn.Close()
	container := c.Param("id")
	hr, err := service.Exec(container, row, col)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}

	defer hr.Close()

	defer func() {
		hr.Conn.Write([]byte("exit\r"))
	}()
	go func() {
		docker.WsWriterCopy(hr.Conn, conn)
	}()
	docker.WsReaderCopy(conn, hr.Conn)
}

func WsSsh(c *gin.Context) {
	wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)

	var 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

		wsConn.WriteMessage(websocket.TextMessage, []byte("login:"))
		user = docker.ReceiveWsMsgUser(wsConn, logBuff)
		wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
		wsConn.WriteMessage(websocket.TextMessage, []byte("password:"))
		password = docker.ReceiveWsMsgPassword(wsConn, logBuff)
		wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
		client, err = docker.NewSshClient(user, password)

		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, _ := docker.NewSshConn(cols, rows, client)
	defer ssConn.Close()

	go ssConn.ReceiveWsMsg(wsConn, logBuff, quitChan)
	go ssConn.SendComboOutput(wsConn, quitChan)
	go ssConn.SessionWait(quitChan)

	<-quitChan

}

func SpeedPush(c *gin.Context) {

}

func InstallApp(c *gin.Context) {
	appId := c.Param("id")
	var appInfo model.ServerAppList
	m := model.CustomizationPostData{}
	c.BindJSON(&m)

	const CUSTOM = "custom"
	var dockerImage string
	var dockerImageVersion string

	if len(m.PortMap) > 0 && m.PortMap != "0" {

		portMap, _ := strconv.Atoi(m.PortMap)
		if !port2.IsPortAvailable(portMap, "tcp") {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
			return
		}
	}

	imageArr := strings.Split(m.Image, ":")
	if len(imageArr) == 2 {
		dockerImage = imageArr[0]
		dockerImageVersion = imageArr[1]
	} else {
		dockerImage = m.Image
		dockerImageVersion = "latest"
	}
	if m.Origin != "custom" {
		appInfo = service.MyService.OAPI().GetServerAppInfo(appId)

	} else {

		appInfo.Title = m.Label
		appInfo.Description = m.Description
		appInfo.Icon = m.Icon
		appInfo.ScreenshotLink = model.Strings{}
		appInfo.NetworkModel = m.NetworkModel
		appInfo.Tags = model.Strings{}
		appInfo.Tagline = ""
		appInfo.Index = m.Index

	}

	for _, u := range m.Ports {

		if u.Protocol == "udp" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "tcp" {

			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "both" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		}

	}

	for _, device := range m.Devices {
		if file.CheckNotExist(device.Path) {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
			return
		}

	}

	id := uuid.NewV4().String()

	var relyMap = make(map[string]string)
	go func() {
		installLog := model2.AppNotify{}
		installLog.State = 0
		installLog.CustomId = id
		installLog.Message = "installing rely"
		installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
		installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
		installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
		service.MyService.Notify().AddLog(installLog)
		if m.Origin != "custom" {
			for _, plugin := range appInfo.Plugins {
				if plugin == "mysql" {
					mid := uuid.NewV4().String()
					mc := docker_base.MysqlConfig{}
					mc.DataBasePassword = random.RandomString(6, false)
					mc.DataBaseDB = appInfo.Title
					mc.DataBaseUser = "root"
					mc.DataBasePort = "3306"
					mysqlContainerId, err := docker_base.MysqlCreate(mc, mid, m.CpuShares, m.Memory)
					if len(mysqlContainerId) > 0 && err == nil {

						mc.DataBaseHost = mid

						m.Envs = docker_base.MysqlFilter(mc, m.Envs)

						rely := model2.RelyDBModel{}
						rely.Type = types.RELY_TYPE_MYSQL
						rely.ContainerId = mysqlContainerId
						rely.CustomId = mid
						rely.ContainerCustomId = id
						var mysqlConfig model2.MysqlConfigs

						copier.Copy(&mysqlConfig, &mc)
						rely.Config = mysqlConfig
						service.MyService.Rely().Create(rely)

						relyMap["mysql"] = mid

					} else {
						docker_base.MysqlDelete(mysqlContainerId)
						installLog.State = 0
						installLog.Message = err.Error()
						service.MyService.Notify().UpdateLog(installLog)
					}
				}
			}
		}

		installLog.Message = "pulling"
		service.MyService.Notify().UpdateLog(installLog)

		err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
		if err != nil {
			installLog.State = 0
			installLog.Message = err.Error()
			installLog.Type = types.NOTIFY_TYPE_ERROR
			service.MyService.Notify().UpdateLog(installLog)
			return
		}

		for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
			time.Sleep(time.Second)
		}

		containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
		installLog.Name = appInfo.Title
		installLog.Icon = appInfo.Icon
		if err != nil {

			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {

			installLog.Message = "starting"
			service.MyService.Notify().UpdateLog(installLog)
		}

		err = service.MyService.Docker().DockerContainerStart(id)
		if err != nil {

			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {

			if m.Origin != CUSTOM {
				installLog.Message = "setting upnp"
			} else {
				installLog.Message = "nearing completion"
			}
			service.MyService.Notify().UpdateLog(installLog)
		}

		if m.Origin != CUSTOM {

			if m.EnableUPNP {
				upnp, err := upnp2.Gateway()
				if err == nil {
					for _, p := range m.Ports {
						if p.Protocol == "udp" {
							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "UDP")
							time.Sleep(time.Millisecond * 200)
						} else if p.Protocol == "tcp" {
							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "TCP")
							time.Sleep(time.Millisecond * 200)
						} else if p.Protocol == "both" {

							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "UDP")
							time.Sleep(time.Millisecond * 200)

							upnp.AddPortMapping(tComment, tComment, "TCP")
							time.Sleep(time.Millisecond * 200)
						}

					}

				}
				if err != nil {

					installLog.State = 0
					installLog.Type = types.NOTIFY_TYPE_ERROR
					installLog.Message = err.Error()
					service.MyService.Notify().UpdateLog(installLog)
				} else {

					installLog.Message = "checking"
					service.MyService.Notify().UpdateLog(installLog)
				}
			}
		}

		container, err := service.MyService.Docker().DockerContainerInfo(id)
		if err != nil && container.ContainerJSONBase.State.Running {

			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {

			installLog.Message = "installed"
			service.MyService.Notify().UpdateLog(installLog)
		}

		rely := model.MapStrings{}

		copier.Copy(&rely, &relyMap)
		if m.Origin != "custom" {
			for i := 0; i < len(m.Volumes); i++ {
				m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].ContainerPath)
			}
		}

		portsStr, _ := json2.Marshal(m.Ports)
		envsStr, _ := json2.Marshal(m.Envs)
		volumesStr, _ := json2.Marshal(m.Volumes)
		devicesStr, _ := json2.Marshal(m.Devices)

		md := model2.AppListDBModel{
			CustomId: id,
			Title:    appInfo.Title,

			Slogan:      appInfo.Tagline,
			Description: appInfo.Description,

			Icon:        appInfo.Icon,
			Version:     dockerImageVersion,
			ContainerId: containerId,
			Image:       dockerImage,
			Index:       appInfo.Index,

			PortMap:    m.PortMap,
			Label:      m.Label,
			EnableUPNP: m.EnableUPNP,
			Ports:      string(portsStr),
			Envs:       string(envsStr),
			Volumes:    string(volumesStr),
			Position:   m.Position,
			NetModel:   appInfo.NetworkModel,
			Restart:    m.Restart,
			CpuShares:  m.CpuShares,
			Memory:     m.Memory,
			Devices:    string(devicesStr),

			Origin:    m.Origin,
			CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
			UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
		}

		service.MyService.App().SaveContainer(md)
		config.CasaOSGlobalVariables.AppChange = true

	}()

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})

}

func UnInstallApp(c *gin.Context) {
	appId := c.Param("id")

	if len(appId) == 0 {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
		return
	}
	info := service.MyService.App().GetUninstallInfo(appId)

	err := service.MyService.Docker().DockerContainerStop(appId)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
		return
	}

	err = service.MyService.Docker().DockerContainerRemove(appId, false)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
		return
	}

	service.MyService.Docker().DockerImageRemove(info.Image + ":" + info.Version)

	service.MyService.App().RemoveContainerById(appId)
	if info.Origin != "custom" {

		vol := gjson.Get(info.Volumes, "#.host")
		for _, v := range vol.Array() {
			if strings.Contains(v.String(), appId) {
				service.MyService.App().DelAppConfigDir(v.String())
			}
		}

		service.MyService.Notify().DelLog(appId)

	}
	config.CasaOSGlobalVariables.AppChange = true
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})

}

func ChangAppState(c *gin.Context) {
	appId := c.Param("id")
	state := c.DefaultPostForm("state", "stop")
	var err error
	if state == "stop" {
		err = service.MyService.Docker().DockerContainerStop(appId)
	} else if state == "start" {
		err = service.MyService.Docker().DockerContainerStart(appId)
	} else if state == "restart" {
		err = service.MyService.Docker().DockerContainerStop(appId)
		err = service.MyService.Docker().DockerContainerStart(appId)
	}
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}
	info, err := service.MyService.App().GetContainerInfo(appId)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info.State})
}

func ContainerLog(c *gin.Context) {
	appId := c.Param("id")
	log, _ := service.MyService.Docker().DockerContainerLog(appId)
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: log})
}

func GetInstallSpeed(c *gin.Context) {
	id := c.Param("id")
	b := service.MyService.Notify().GetLog(id)
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: b})
}

func GetContainerState(c *gin.Context) {
	id := c.Param("id")
	t := c.DefaultQuery("type", "0")
	containerInfo, e := service.MyService.App().GetSimpleContainerInfo(id)
	if e != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: e.Error()})
		return
	}

	var data = make(map[string]interface{})

	data["state"] = containerInfo.State

	if t == "1" {
		appInfo := service.MyService.App().GetAppDBInfo(id)
		data["app"] = appInfo
	}

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

func UpdateSetting(c *gin.Context) {
	id := c.Param("id")
	const CUSTOM = "custom"
	m := model.CustomizationPostData{}
	c.BindJSON(&m)

	if len(id) == 0 {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
		return
	}
	var cpd model.CustomizationPostData

	copier.Copy(&cpd, &m)

	appInfo := service.MyService.App().GetAppDBInfo(id)

	var containerId string
	containerId = appInfo.ContainerId

	service.MyService.Docker().DockerContainerStop(id)

	portMap, _ := strconv.Atoi(m.PortMap)
	if !port2.IsPortAvailable(portMap, "tcp") {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
		return
	}

	for _, u := range m.Ports {

		if u.Protocol == "udp" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "tcp" {
			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "both" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}

			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		}

	}

	portsStr, _ := json2.Marshal(m.Ports)

	envsStr, _ := json2.Marshal(m.Envs)
	volumesStr, _ := json2.Marshal(m.Volumes)
	devicesStr, _ := json2.Marshal(m.Devices)
	if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {

		var newUUid = uuid.NewV4().String()
		var err error

		containerId, err = service.MyService.Docker().DockerContainerCreate(appInfo.Image+":"+appInfo.Version, newUUid, cpd, m.NetworkModel)

		if err != nil {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
			return
		}

		err = service.MyService.Docker().DockerContainerRemove(id, true)
		if err != nil {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
			return
		}

		service.MyService.Docker().DockerContainerUpdateName(appInfo.CustomId, newUUid)
		if err != nil {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
			return
		}

	} else if !reflect.DeepEqual(string(devicesStr), appInfo.Devices) || m.CpuShares != appInfo.CpuShares || m.Memory != appInfo.Memory || m.Restart != appInfo.Restart {
		service.MyService.Docker().DockerContainerUpdate(cpd, id)
	}

	err := service.MyService.Docker().DockerContainerStart(id)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
		return
	}

	if m.Origin != CUSTOM {

	}

	appInfo.ContainerId = containerId
	appInfo.PortMap = m.PortMap
	appInfo.Label = m.Label
	appInfo.Index = m.Index
	appInfo.Ports = string(portsStr)
	appInfo.Envs = string(envsStr)
	appInfo.Icon = m.Icon
	appInfo.Volumes = string(volumesStr)
	appInfo.Devices = string(devicesStr)
	appInfo.NetModel = m.NetworkModel
	appInfo.Position = m.Position
	appInfo.EnableUPNP = m.EnableUPNP
	appInfo.Restart = m.Restart
	appInfo.Memory = m.Memory
	appInfo.CpuShares = m.CpuShares
	appInfo.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
	service.MyService.App().UpdateApp(appInfo)

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

func ContainerInfo(c *gin.Context) {
	appId := c.Param("id")
	appInfo := service.MyService.App().GetAppDBInfo(appId)
	containerInfo, _ := service.MyService.Docker().DockerContainerStats(appId)
	var cpuModel = "arm"
	if cpu := service.MyService.ZiMa().GetCpuInfo(); len(cpu) > 0 {
		if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "intel") > 0 {
			cpuModel = "intel"
		} else if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "amd") > 0 {
			cpuModel = "amd"
		}
	}

	info, err := service.MyService.Docker().DockerContainerInfo(appId)
	if err != nil {

		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
		return
	}
	con := struct {
		Status    string `json:"status"`
		StartedAt string `json:"started_at"`
		CPUShares int64  `json:"cpu_shares"`
		Memory    int64  `json:"memory"`
		Restart   string `json:"restart"`
	}{Status: info.State.Status, StartedAt: info.State.StartedAt, CPUShares: info.HostConfig.CPUShares, Memory: info.HostConfig.Memory >> 20, Restart: info.HostConfig.RestartPolicy.Name}
	data := make(map[string]interface{}, 5)
	data["app"] = appInfo
	data["cpu"] = cpuModel
	data["memory"] = service.MyService.ZiMa().GetMemInfo().Total
	data["container"] = json2.RawMessage(containerInfo)
	data["info"] = con
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

func GetDockerInstallConfig(c *gin.Context) {
	networks := service.MyService.Docker().DockerNetworkModelList()
	data := make(map[string]interface{}, 2)
	list := []map[string]string{}
	for _, network := range networks {
		if network.Driver != "null" {
			list = append(list, map[string]string{"name": network.Name, "driver": network.Driver, "id": network.ID})
		}
	}
	data["networks"] = list
	data["memory"] = service.MyService.ZiMa().GetMemInfo()
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

func ContainerRelyInfo(c *gin.Context) {
	id := c.Param("id")
	appInfo := service.MyService.Rely().GetInfo(id)
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: appInfo})
}

func ContainerUpdateInfo(c *gin.Context) {
	appId := c.Param("id")
	appInfo := service.MyService.App().GetAppDBInfo(appId)

	info, err := service.MyService.Docker().DockerContainerInfo(appId)
	if err != nil {

		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
		return
	}
	var port model.PortArray
	json2.Unmarshal([]byte(appInfo.Ports), &port)

	var envs model.EnvArray
	json2.Unmarshal([]byte(appInfo.Envs), &envs)

	var vol model.PathArray
	json2.Unmarshal([]byte(appInfo.Volumes), &vol)

	for i := 0; i < len(vol); i++ {
		vol[i].Path = strings.ReplaceAll(vol[i].Path, "$AppID", appId)
	}

	var dir model.PathArray
	json2.Unmarshal([]byte(appInfo.Devices), &dir)

	m := model.CustomizationPostData{}
	m.Index = appInfo.Index
	m.Icon = appInfo.Icon
	m.Ports = port
	m.Image = appInfo.Image + ":" + appInfo.Version
	m.Origin = appInfo.Origin
	m.NetworkModel = appInfo.NetModel
	m.Description = appInfo.Description
	m.Label = appInfo.Label
	m.PortMap = appInfo.PortMap
	m.Devices = dir 
	m.Envs = envs
	m.Memory = info.HostConfig.Memory >> 20
	m.CpuShares = info.HostConfig.CPUShares
	m.Volumes = vol 
	m.Restart = info.HostConfig.RestartPolicy.Name
	m.EnableUPNP = appInfo.EnableUPNP
	m.Position = appInfo.Position

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
}
package v1

import (
	"bytes"
	json2 "encoding/json"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/IceWhaleTech/CasaOS/model"
	"github.com/IceWhaleTech/CasaOS/pkg/config"
	"github.com/IceWhaleTech/CasaOS/pkg/docker"
	upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
	ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
	port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
	"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
	"github.com/IceWhaleTech/CasaOS/service"
	"github.com/IceWhaleTech/CasaOS/service/docker_base"
	model2 "github.com/IceWhaleTech/CasaOS/service/model"
	"github.com/IceWhaleTech/CasaOS/types"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/jinzhu/copier"
	uuid "github.com/satori/go.uuid"
	"github.com/tidwall/gjson"
	"golang.org/x/crypto/ssh"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:   1024,
	WriteBufferSize:  1024,
	CheckOrigin:      func(r *http.Request) bool { return true },
	HandshakeTimeout: time.Duration(time.Second * 5),
}

//打开docker的terminal
func DockerTerminal(c *gin.Context) {
	col := c.DefaultQuery("cols", "100")
	row := c.DefaultQuery("rows", "30")
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}
	defer conn.Close()
	container := c.Param("id")
	hr, err := service.Exec(container, row, col)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}
	// 关闭I/O流
	defer hr.Close()
	// 退出进程
	defer func() {
		hr.Conn.Write([]byte("exit\r"))
	}()
	go func() {
		docker.WsWriterCopy(hr.Conn, conn)
	}()
	docker.WsReaderCopy(conn, hr.Conn)
}

//打开本机的ssh接口
func WsSsh(c *gin.Context) {
	wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)

	var 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

		wsConn.WriteMessage(websocket.TextMessage, []byte("login:"))
		user = docker.ReceiveWsMsgUser(wsConn, logBuff)
		wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
		wsConn.WriteMessage(websocket.TextMessage, []byte("password:"))
		password = docker.ReceiveWsMsgPassword(wsConn, logBuff)
		wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
		client, err = docker.NewSshClient(user, password)

		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, _ := docker.NewSshConn(cols, rows, client)
	defer ssConn.Close()

	go ssConn.ReceiveWsMsg(wsConn, logBuff, quitChan)
	go ssConn.SendComboOutput(wsConn, quitChan)
	go ssConn.SessionWait(quitChan)

	<-quitChan

}

//安装进度推送
func SpeedPush(c *gin.Context) {
	//token := c.Query("token")
	//if len(token) == 0 || token != config.UserInfo.Token {
	//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_AUTH_TOKEN, Message: oasis_err2.GetMsg(oasis_err2.ERROR_AUTH_TOKEN)})
	//	return
	//}

	//ws, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
	//defer ws.Close()
	//
	//for {
	//	select {
	//	case msg := <-WSMSG:
	//		ws.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintln(msg)))
	//	}
	//}
}

// @Summary 安装app(该接口需要post json数据)
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Param  id path int true "id"
// @Param  port formData int true "主端口"
// @Param  tcp formData string false "tcp端口"
// @Param  udp formData string false "udp端口"
// @Param  env formData string false "环境变量"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/install/{id} [post]
func InstallApp(c *gin.Context) {
	appId := c.Param("id")
	var appInfo model.ServerAppList
	m := model.CustomizationPostData{}
	c.BindJSON(&m)

	const CUSTOM = "custom"
	var dockerImage string
	var dockerImageVersion string
	//检查端口
	if len(m.PortMap) > 0 && m.PortMap != "0" {
		//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
		portMap, _ := strconv.Atoi(m.PortMap)
		if !port2.IsPortAvailable(portMap, "tcp") {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
			return
		}
	}
	//if len(m.Port) == 0 || m.Port == "0" {
	//	m.Port = m.PortMap
	//}

	imageArr := strings.Split(m.Image, ":")
	if len(imageArr) == 2 {
		dockerImage = imageArr[0]
		dockerImageVersion = imageArr[1]
	} else {
		dockerImage = m.Image
		dockerImageVersion = "latest"
	}
	if m.Origin != "custom" {
		appInfo = service.MyService.OAPI().GetServerAppInfo(appId)

	} else {

		appInfo.Title = m.Label
		appInfo.Description = m.Description
		appInfo.Icon = m.Icon
		appInfo.ScreenshotLink = model.Strings{}
		appInfo.NetworkModel = m.NetworkModel
		appInfo.Tags = model.Strings{}
		appInfo.Tagline = ""
		appInfo.Index = m.Index

	}

	for _, u := range m.Ports {

		if u.Protocol == "udp" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "tcp" {

			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "both" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		}

	}

	for _, device := range m.Devices {
		if file.CheckNotExist(device.Path) {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
			return
		}

	}
	//restart := c.PostForm("restart") //always 总是重启,   unless-stopped 除非用户手动停止容器，否则总是重新启动,    on-failure:仅当容器退出代码非零时重新启动
	//if len(restart) > 0 {
	//
	//}
	//
	//privileged := c.PostForm("privileged") //是否处于特权模式
	//if len(privileged) > 0 {
	//
	//}
	id := uuid.NewV4().String()

	var relyMap = make(map[string]string)
	go func() {
		installLog := model2.AppNotify{}
		installLog.State = 0
		installLog.CustomId = id
		installLog.Message = "installing rely"
		installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
		installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
		installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
		service.MyService.Notify().AddLog(installLog)
		if m.Origin != "custom" {
			for _, plugin := range appInfo.Plugins {
				if plugin == "mysql" {
					mid := uuid.NewV4().String()
					mc := docker_base.MysqlConfig{}
					mc.DataBasePassword = random.RandomString(6, false)
					mc.DataBaseDB = appInfo.Title
					mc.DataBaseUser = "root"
					mc.DataBasePort = "3306"
					mysqlContainerId, err := docker_base.MysqlCreate(mc, mid, m.CpuShares, m.Memory)
					if len(mysqlContainerId) > 0 && err == nil {

						mc.DataBaseHost = mid

						m.Envs = docker_base.MysqlFilter(mc, m.Envs)

						rely := model2.RelyDBModel{}
						rely.Type = types.RELY_TYPE_MYSQL
						rely.ContainerId = mysqlContainerId
						rely.CustomId = mid
						rely.ContainerCustomId = id
						var mysqlConfig model2.MysqlConfigs

						//结构体转换
						copier.Copy(&mysqlConfig, &mc)
						rely.Config = mysqlConfig
						service.MyService.Rely().Create(rely)

						relyMap["mysql"] = mid

					} else {
						docker_base.MysqlDelete(mysqlContainerId)
						installLog.State = 0
						installLog.Message = err.Error()
						service.MyService.Notify().UpdateLog(installLog)
					}
				}
			}
		}

		installLog.Message = "pulling"
		service.MyService.Notify().UpdateLog(installLog)

		// step：下载镜像
		err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
		if err != nil {
			installLog.State = 0
			installLog.Message = err.Error()
			installLog.Type = types.NOTIFY_TYPE_ERROR
			service.MyService.Notify().UpdateLog(installLog)
			return
		}

		for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
			time.Sleep(time.Second)
		}

		//if  {

		//}

		//step：创建容器
		// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetworkModel)
		// if err != nil {
		// 	//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
		// 	installLog.State = 0
		// 	installLog.Speed = 75
		// 	installLog.Type = types.NOTIFY_TYPE_ERROR
		// 	installLog.Message = err.Error()
		// 	service.MyService.Notify().UpdateLog(installLog)
		// 	return
		// }
		containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
		installLog.Name = appInfo.Title
		installLog.Icon = appInfo.Icon
		if err != nil {
			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {
			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
			installLog.Message = "starting"
			service.MyService.Notify().UpdateLog(installLog)
		}

		//		echo -e "hellow\nworld" >>

		//step：启动容器
		err = service.MyService.Docker().DockerContainerStart(id)
		if err != nil {
			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {
			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
			if m.Origin != CUSTOM {
				installLog.Message = "setting upnp"
			} else {
				installLog.Message = "nearing completion"
			}
			service.MyService.Notify().UpdateLog(installLog)
		}

		if m.Origin != CUSTOM {
			//step:启动upnp
			if m.EnableUPNP {
				upnp, err := upnp2.Gateway()
				if err == nil {
					for _, p := range m.Ports {
						if p.Protocol == "udp" {
							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "UDP")
							time.Sleep(time.Millisecond * 200)
						} else if p.Protocol == "tcp" {
							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "TCP")
							time.Sleep(time.Millisecond * 200)
						} else if p.Protocol == "both" {

							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "UDP")
							time.Sleep(time.Millisecond * 200)

							upnp.AddPortMapping(tComment, tComment, "TCP")
							time.Sleep(time.Millisecond * 200)
						}

					}

				}
				if err != nil {
					//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
					installLog.State = 0
					installLog.Type = types.NOTIFY_TYPE_ERROR
					installLog.Message = err.Error()
					service.MyService.Notify().UpdateLog(installLog)
				} else {
					//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100)
					installLog.Message = "checking"
					service.MyService.Notify().UpdateLog(installLog)
				}
			}
		}

		//step: 启动成功     检查容器状态确认启动成功
		container, err := service.MyService.Docker().DockerContainerInfo(id)
		if err != nil && container.ContainerJSONBase.State.Running {
			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {
			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
			installLog.Message = "installed"
			service.MyService.Notify().UpdateLog(installLog)
		}

		rely := model.MapStrings{}

		copier.Copy(&rely, &relyMap)
		if m.Origin != "custom" {
			for i := 0; i < len(m.Volumes); i++ {
				m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].ContainerPath)
			}
		}

		portsStr, _ := json2.Marshal(m.Ports)
		envsStr, _ := json2.Marshal(m.Envs)
		volumesStr, _ := json2.Marshal(m.Volumes)
		devicesStr, _ := json2.Marshal(m.Devices)
		//step: 保存数据到数据库
		md := model2.AppListDBModel{
			CustomId: id,
			Title:    appInfo.Title,
			//ScreenshotLink: appInfo.ScreenshotLink,
			Slogan:      appInfo.Tagline,
			Description: appInfo.Description,
			//Tags:           appInfo.Tags,
			Icon:        appInfo.Icon,
			Version:     dockerImageVersion,
			ContainerId: containerId,
			Image:       dockerImage,
			Index:       appInfo.Index,
			//Port:           m.Port,
			PortMap:    m.PortMap,
			Label:      m.Label,
			EnableUPNP: m.EnableUPNP,
			Ports:      string(portsStr),
			Envs:       string(envsStr),
			Volumes:    string(volumesStr),
			Position:   m.Position,
			NetModel:   appInfo.NetworkModel,
			Restart:    m.Restart,
			CpuShares:  m.CpuShares,
			Memory:     m.Memory,
			Devices:    string(devicesStr),
			//Rely:       rely,
			Origin:    m.Origin,
			CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
			UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
		}
		//if appInfo.NetworkModel == "host" {
		//	m.PortMap = m.Port
		//}
		service.MyService.App().SaveContainer(md)
		config.CasaOSGlobalVariables.AppChange = true

	}()

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})

}

//// @Summary 自定义安装app(该接口需要post json数据)
//// @Produce  application/json
//// @Accept application/json
//// @Tags app
//// @Param  id path int true "id"
//// @Param  port formData int true "主端口"
//// @Param  tcp formData string false "tcp端口"
//// @Param  udp formData string false "udp端口"
//// @Param  env formData string false "环境变量"
//// @Security ApiKeyAuth
//// @Success 200 {string} string "ok"
//// @Router /app/install/{id} [post]
//func CustomInstallApp(c *gin.Context) {
//	//appId := c.Param("id")
//	//	appInfo := service.MyService.App().GetServerAppInfo(appId)
//
//	m := model.CustomizationPostData{}
//	c.BindJSON(&m)
//	//检查端口
//	if len(m.PortMap) == 0 || m.PortMap == "0" {
//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
//		return
//	}
//	if len(m.Port) == 0 || m.Port == "0" {
//		m.Port = m.PortMap
//	}
//
//	portMap, _ := strconv.Atoi(m.PortMap)
//	if !port2.IsPortAvailable(portMap, "tcp") {
//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
//		return
//	}
//
//	for _, u := range m.Udp {
//		t, _ := strconv.Atoi(u.CommendPort)
//		if !port2.IsPortAvailable(t, "udp") {
//			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
//			return
//		}
//	}
//
//	for _, t := range m.Tcp {
//		te, _ := strconv.Atoi(t.CommendPort)
//		if !port2.IsPortAvailable(te, "tcp") {
//			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + t.CommendPort})
//			return
//		}
//	}
//
//	//restart := c.PostForm("restart") //always 总是重启,   unless-stopped 除非用户手动停止容器，否则总是重新启动,    on-failure:仅当容器退出代码非零时重新启动
//	//if len(restart) > 0 {
//	//
//	//}
//	//
//	//privileged := c.PostForm("privileged") //是否处于特权模式
//	//if len(privileged) > 0 {
//	//
//	//}
//
//	err := service.MyService.Docker().DockerPullImage(m.Image)
//	if err != nil {
//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PULL_IMAGE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PULL_IMAGE_ERROR)})
//	}
//
//	id := uuid.NewV4().String()
//
//	var relyMap = make(map[string]string)
//	go func() {
//		installLog := model2.AppNotify{}
//		installLog.CustomId = id
//		installLog.State = 0
//		installLog.Message = "installing rely"
//		installLog.Speed = 30
//		installLog.CreatedAt = time.Now()
//		installLog.UpdatedAt = time.Now()
//		service.MyService.Notify().AddLog(installLog)
//
//		for !service.MyService.Docker().IsExistImage(m.Image) {
//			time.Sleep(time.Second)
//		}
//
//		installLog.Speed = 50
//		installLog.Message = "pulling"
//		service.MyService.Notify().UpdateLog(installLog)
//		// step：下载镜像
//
//		var cpd model.PostData
//		copier.Copy(&cpd, &m)
//		//step：创建容器
//		containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, id, cpd, m.NetworkModel, m.Image, "custom")
//		installLog.ContainerId = containerId
//		if err != nil {
//			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
//			installLog.State = 0
//			installLog.Speed = 80
//			installLog.Message = err.Error()
//			service.MyService.Notify().UpdateLog(installLog)
//			return
//		} else {
//			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
//			installLog.Speed = 80
//			installLog.Message = "starting"
//			service.MyService.Notify().UpdateLog(installLog)
//		}
//
//		//step：启动容器
//		err = service.MyService.Docker().DockerContainerStart(id)
//		if err != nil {
//			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
//			installLog.State = 0
//			installLog.Speed = 90
//			installLog.Message = err.Error()
//			service.MyService.Notify().UpdateLog(installLog)
//			return
//		} else {
//			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
//			installLog.Speed = 90
//			installLog.Message = "setting upnp"
//			service.MyService.Notify().UpdateLog(installLog)
//		}
//
//		//step: 启动成功     检查容器状态确认启动成功
//		containerStatus, err := service.MyService.Docker().DockerContainerInfo(id)
//		if err != nil && containerStatus.ContainerJSONBase.State.Running {
//			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
//			installLog.State = 0
//			installLog.Speed = 100
//			installLog.Message = err.Error()
//			service.MyService.Notify().UpdateLog(installLog)
//			return
//		} else {
//			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
//			installLog.Speed = 100
//			installLog.Message = "installed"
//			service.MyService.Notify().UpdateLog(installLog)
//		}
//
//		rely := model.MapStrings{}
//
//		copier.Copy(&rely, &relyMap)
//
//		//step: 保存数据到数据库
//		md := model2.AppListDBModel{
//			CustomId: id,
//			Title:    m.Label,
//			//			ScreenshotLink: []string,
//			Slogan:      "",
//			Description: m.Description,
//			//			Tags:           ,
//			Icon:        m.Icon,
//			Version:     m.Image,
//			ContainerId: containerId,
//			Image:       m.Image,
//			Index:       "",
//			Port:        m.Port,
//			PortMap:     m.PortMap,
//			Label:       m.Label,
//			EnableUPNP:  m.EnableUPNP,
//			UdpPorts:    m.Udp,
//			TcpPorts:    m.Tcp,
//			Envs:        m.Envs,
//			Volumes:     m.Volumes,
//			Position:    m.Position,
//			NetModel:    m.NetworkModel,
//			Restart:     m.Restart,
//			CpuShares:   m.CpuShares,
//			Memory:      m.Memory,
//			Devices:     m.Devices,
//			Rely:        rely,
//			Origin:      "custom",
//		}
//		if m.NetworkModel == "host" {
//			m.PortMap = m.Port
//		}
//		service.MyService.App().SaveContainer(md)
//
//	}()
//
//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})
//
//}

// @Summary 卸载app
// @Produce  application/json
// @Accept multipart/form-data
// @Tags app
// @Param  id path string true "容器id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/uninstall/{id} [delete]
func UnInstallApp(c *gin.Context) {
	appId := c.Param("id")

	if len(appId) == 0 {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
		return
	}
	info := service.MyService.App().GetUninstallInfo(appId)

	//step：停止容器
	err := service.MyService.Docker().DockerContainerStop(appId)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
		return
	}

	//step：删除容器
	err = service.MyService.Docker().DockerContainerRemove(appId, false)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
		return
	}

	//存在镜像正在使用的情况
	// step：删除镜像
	service.MyService.Docker().DockerImageRemove(info.Image + ":" + info.Version)

	//step: 删除本地数据
	service.MyService.App().RemoveContainerById(appId)
	if info.Origin != "custom" {

		//step: 删除文件夹
		vol := gjson.Get(info.Volumes, "#.host")
		for _, v := range vol.Array() {
			if strings.Contains(v.String(), appId) {
				service.MyService.App().DelAppConfigDir(v.String())
			}
		}

		//step: 删除install log
		service.MyService.Notify().DelLog(appId)

		//	for k, v := range info.Rely {
		//
		//		if k == "mysql" {
		//			docker_base.MysqlDelete(v)
		//			service.MyService.Rely().Delete(v)
		//		}
		//	}

		//if info.EnableUPNP {
		//	upnp, err := upnp2.Gateway()
		//	if err == nil {
		//		for _, p := range info.Ports {
		//			if p.Protocol == "udp" {
		//				upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//				upnp.LocalHost = ip_helper2.GetLoclIp()
		//				tComment, _ := strconv.Atoi(p.CommendPort)
		//				upnp.DelPortMapping(tComment, "UDP")
		//				time.Sleep(time.Millisecond * 200)
		//			} else if p.Protocol == "tcp" {
		//				upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//				upnp.LocalHost = ip_helper2.GetLoclIp()
		//				tComment, _ := strconv.Atoi(p.CommendPort)
		//				upnp.DelPortMapping(tComment, "TCP")
		//				time.Sleep(time.Millisecond * 200)
		//			} else if p.Protocol == "both" {
		//				upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//				upnp.LocalHost = ip_helper2.GetLoclIp()
		//				tComment, _ := strconv.Atoi(p.CommendPort)
		//				upnp.DelPortMapping(tComment, "UDP")
		//
		//				upnp.DelPortMapping(tComment, "TCP")
		//				time.Sleep(time.Millisecond * 200)
		//			}
		//		}
		//	}
		//}
	}
	config.CasaOSGlobalVariables.AppChange = true
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})

}

// @Summary 修改app状态
// @Produce  application/json
// @Accept multipart/form-data
// @Tags app
// @Param  id path string true "appid"
// @Param  state query string false "是否停止 start stop restart"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/state/{id} [put]
func ChangAppState(c *gin.Context) {
	appId := c.Param("id")
	state := c.DefaultPostForm("state", "stop")
	var err error
	if state == "stop" {
		err = service.MyService.Docker().DockerContainerStop(appId)
	} else if state == "start" {
		err = service.MyService.Docker().DockerContainerStart(appId)
	} else if state == "restart" {
		err = service.MyService.Docker().DockerContainerStop(appId)
		err = service.MyService.Docker().DockerContainerStart(appId)
	}
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}
	info, err := service.MyService.App().GetContainerInfo(appId)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
		return
	}
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info.State})
}

// @Summary 查看容器日志
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Param  id path string true "appid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/logs/{id} [get]
func ContainerLog(c *gin.Context) {
	appId := c.Param("id")
	log, _ := service.MyService.Docker().DockerContainerLog(appId)
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: log})
}

// @Summary 获取安装进度
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Param  id path string true "容器id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/speed/{id} [get]
func GetInstallSpeed(c *gin.Context) {
	id := c.Param("id")
	b := service.MyService.Notify().GetLog(id)
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: b})
}

// @Summary 获取容器状态
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Param  id path string true "容器id"
// @Param  type query string false "type=1"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/state/{id} [get]
func GetContainerState(c *gin.Context) {
	id := c.Param("id")
	t := c.DefaultQuery("type", "0")
	containerInfo, e := service.MyService.App().GetSimpleContainerInfo(id)
	if e != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: e.Error()})
		return
	}

	var data = make(map[string]interface{})

	data["state"] = containerInfo.State

	if t == "1" {
		appInfo := service.MyService.App().GetAppDBInfo(id)
		data["app"] = appInfo
	}

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

// @Summary 更新设置
// @Produce  application/json
// @Accept multipart/form-data
// @Tags app
// @Param  id path string true "容器id"
// @Param  shares formData string false "cpu权重"
// @Param  mem formData string false "内存大小MB"
// @Param  restart formData string false "重启策略"
// @Param  label formData string false "应用名称"
// @Param  position formData bool true "是否放到首页"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/update/{id}/setting [put]
func UpdateSetting(c *gin.Context) {
	id := c.Param("id")
	const CUSTOM = "custom"
	m := model.CustomizationPostData{}
	c.BindJSON(&m)

	if len(id) == 0 {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
		return
	}
	var cpd model.CustomizationPostData

	copier.Copy(&cpd, &m)

	appInfo := service.MyService.App().GetAppDBInfo(id)

	var containerId string
	containerId = appInfo.ContainerId

	service.MyService.Docker().DockerContainerStop(id)

	portMap, _ := strconv.Atoi(m.PortMap)
	if !port2.IsPortAvailable(portMap, "tcp") {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
		return
	}

	for _, u := range m.Ports {

		if u.Protocol == "udp" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "tcp" {
			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "both" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}

			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		}

	}

	//如果容器端口均未修改,这不进行处理
	portsStr, _ := json2.Marshal(m.Ports)

	envsStr, _ := json2.Marshal(m.Envs)
	volumesStr, _ := json2.Marshal(m.Volumes)
	devicesStr, _ := json2.Marshal(m.Devices)
	if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {

		var newUUid = uuid.NewV4().String()
		var err error

		// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetModel)
		// if err != nil {
		// 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
		// 	return
		// }
		containerId, err = service.MyService.Docker().DockerContainerCreate(appInfo.Image+":"+appInfo.Version, newUUid, cpd, m.NetworkModel)

		if err != nil {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
			return
		}

		err = service.MyService.Docker().DockerContainerRemove(id, true)
		if err != nil {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
			return
		}

		service.MyService.Docker().DockerContainerUpdateName(appInfo.CustomId, newUUid)
		if err != nil {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
			return
		}

	} else if !reflect.DeepEqual(string(devicesStr), appInfo.Devices) || m.CpuShares != appInfo.CpuShares || m.Memory != appInfo.Memory || m.Restart != appInfo.Restart {
		service.MyService.Docker().DockerContainerUpdate(cpd, id)
	}

	err := service.MyService.Docker().DockerContainerStart(id)
	if err != nil {
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
		return
	}
	//更新upnp
	if m.Origin != CUSTOM {
		//if appInfo.EnableUPNP != appInfo.EnableUPNP {
		//	if appInfo.EnableUPNP {
		//		upnp, err := upnp2.Gateway()
		//		if err == nil {
		//
		//			for _, p := range appInfo.Ports {
		//				if p.Protocol == "udp" {
		//					upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//					upnp.LocalHost = ip_helper2.GetLoclIp()
		//					tComment, _ := strconv.Atoi(p.CommendPort)
		//					upnp.AddPortMapping(tComment, tComment, "UDP")
		//					time.Sleep(time.Millisecond * 200)
		//				} else if p.Protocol == "tcp" {
		//					upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//					upnp.LocalHost = ip_helper2.GetLoclIp()
		//					tComment, _ := strconv.Atoi(p.CommendPort)
		//					upnp.AddPortMapping(tComment, tComment, "TCP")
		//					time.Sleep(time.Millisecond * 200)
		//				} else if p.Protocol == "both" {
		//					upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//					upnp.LocalHost = ip_helper2.GetLoclIp()
		//					tComment, _ := strconv.Atoi(p.CommendPort)
		//					upnp.AddPortMapping(tComment, tComment, "UDP")
		//					time.Sleep(time.Millisecond * 200)
		//
		//					upnp.AddPortMapping(tComment, tComment, "TCP")
		//					time.Sleep(time.Millisecond * 200)
		//				}
		//			}
		//		}
		//	} else {
		//		upnp, err := upnp2.Gateway()
		//		if err == nil {
		//			for _, p := range appInfo.Ports {
		//				if p.Protocol == "udp" {
		//
		//					upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//					upnp.LocalHost = ip_helper2.GetLoclIp()
		//					tComment, _ := strconv.Atoi(p.CommendPort)
		//					upnp.DelPortMapping(tComment, "UDP")
		//					time.Sleep(time.Millisecond * 200)
		//				} else if p.Protocol == "tcp" {
		//					upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//					upnp.LocalHost = ip_helper2.GetLoclIp()
		//					tComment, _ := strconv.Atoi(p.CommendPort)
		//					upnp.DelPortMapping(tComment, "TCP")
		//					time.Sleep(time.Millisecond * 200)
		//				} else if p.Protocol == "both" {
		//					upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
		//					upnp.LocalHost = ip_helper2.GetLoclIp()
		//					tComment, _ := strconv.Atoi(p.CommendPort)
		//					upnp.DelPortMapping(tComment, "UDP")
		//					time.Sleep(time.Millisecond * 200)
		//
		//					upnp.DelPortMapping(tComment, "TCP")
		//					time.Sleep(time.Millisecond * 200)
		//				}
		//			}
		//		}
		//	}
		//}
	}

	appInfo.ContainerId = containerId
	appInfo.PortMap = m.PortMap
	appInfo.Label = m.Label
	appInfo.Index = m.Index
	appInfo.Ports = string(portsStr)
	appInfo.Envs = string(envsStr)
	appInfo.Icon = m.Icon
	appInfo.Volumes = string(volumesStr)
	appInfo.Devices = string(devicesStr)
	appInfo.NetModel = m.NetworkModel
	appInfo.Position = m.Position
	appInfo.EnableUPNP = m.EnableUPNP
	appInfo.Restart = m.Restart
	appInfo.Memory = m.Memory
	appInfo.CpuShares = m.CpuShares
	appInfo.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
	service.MyService.App().UpdateApp(appInfo)

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

// @Summary 获取容器详情
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Param  id path string true "appid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/info/{id} [get]
func ContainerInfo(c *gin.Context) {
	appId := c.Param("id")
	appInfo := service.MyService.App().GetAppDBInfo(appId)
	containerInfo, _ := service.MyService.Docker().DockerContainerStats(appId)
	var cpuModel = "arm"
	if cpu := service.MyService.ZiMa().GetCpuInfo(); len(cpu) > 0 {
		if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "intel") > 0 {
			cpuModel = "intel"
		} else if strings.Count(strings.ToLower(strings.TrimSpace(cpu[0].ModelName)), "amd") > 0 {
			cpuModel = "amd"
		}
	}

	info, err := service.MyService.Docker().DockerContainerInfo(appId)
	if err != nil {
		//todo 需要自定义错误
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
		return
	}
	con := struct {
		Status    string `json:"status"`
		StartedAt string `json:"started_at"`
		CPUShares int64  `json:"cpu_shares"`
		Memory    int64  `json:"memory"`
		Restart   string `json:"restart"`
	}{Status: info.State.Status, StartedAt: info.State.StartedAt, CPUShares: info.HostConfig.CPUShares, Memory: info.HostConfig.Memory >> 20, Restart: info.HostConfig.RestartPolicy.Name}
	data := make(map[string]interface{}, 5)
	data["app"] = appInfo
	data["cpu"] = cpuModel
	data["memory"] = service.MyService.ZiMa().GetMemInfo().Total
	data["container"] = json2.RawMessage(containerInfo)
	data["info"] = con
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

// @Summary 获取安装所需要的数据
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/install/config [get]
func GetDockerInstallConfig(c *gin.Context) {
	networks := service.MyService.Docker().DockerNetworkModelList()
	data := make(map[string]interface{}, 2)
	list := []map[string]string{}
	for _, network := range networks {
		if network.Driver != "null" {
			list = append(list, map[string]string{"name": network.Name, "driver": network.Driver, "id": network.ID})
		}
	}
	data["networks"] = list
	data["memory"] = service.MyService.ZiMa().GetMemInfo()
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

// @Summary 获取依赖数据
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Param  id path string true "rely id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/rely/{id}/info [get]
func ContainerRelyInfo(c *gin.Context) {
	id := c.Param("id")
	appInfo := service.MyService.Rely().GetInfo(id)
	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: appInfo})
}

// @Summary 获取可更新数据
// @Produce  application/json
// @Accept application/json
// @Tags app
// @Param  id path string true "appid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/update/{id}/info [get]
func ContainerUpdateInfo(c *gin.Context) {
	appId := c.Param("id")
	appInfo := service.MyService.App().GetAppDBInfo(appId)

	info, err := service.MyService.Docker().DockerContainerInfo(appId)
	if err != nil {
		//todo 需要自定义错误
		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
		return
	}
	var port model.PortArray
	json2.Unmarshal([]byte(appInfo.Ports), &port)

	var envs model.EnvArray
	json2.Unmarshal([]byte(appInfo.Envs), &envs)

	var vol model.PathArray
	json2.Unmarshal([]byte(appInfo.Volumes), &vol)

	for i := 0; i < len(vol); i++ {
		vol[i].Path = strings.ReplaceAll(vol[i].Path, "$AppID", appId)
	}

	var dir model.PathArray
	json2.Unmarshal([]byte(appInfo.Devices), &dir)

	//volumesStr, _ := json2.Marshal(m.Volumes)
	//devicesStr, _ := json2.Marshal(m.Devices)
	m := model.CustomizationPostData{}
	m.Index = appInfo.Index
	m.Icon = appInfo.Icon
	m.Ports = port
	m.Image = appInfo.Image + ":" + appInfo.Version
	m.Origin = appInfo.Origin
	m.NetworkModel = appInfo.NetModel
	m.Description = appInfo.Description
	m.Label = appInfo.Label
	m.PortMap = appInfo.PortMap
	m.Devices = dir //appInfo.Devices
	m.Envs = envs
	m.Memory = info.HostConfig.Memory >> 20
	m.CpuShares = info.HostConfig.CPUShares
	m.Volumes = vol //appInfo.Volumes
	m.Restart = info.HostConfig.RestartPolicy.Name
	m.EnableUPNP = appInfo.EnableUPNP
	m.Position = appInfo.Position

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
}

////准备安装(暂时不需要)
//func ReadyInstall(c *gin.Context) {
//	_, tcp, udp := service.MyService.GetManifestJsonByRepo()
//	data := make(map[string]interface{}, 2)
//	if t := gjson.Parse(tcp).Array(); len(t) > 0 {
//		//tcpList := []model.TcpPorts{}
//		//e := json2.Unmarshal([]byte(tcp), tcpList)
//		//if e!=nil {
//		//	return
//		//}
//		//for _, port := range tcpList {
//		//	if port.ContainerPort>0&&port.ExtranetPort {
//		//
//		//	}
//		//}
//		var inarr []interface{}
//		for _, result := range t {
//
//			var p int
//			ok := true
//			for ok {
//				p, _ = port.GetAvailablePort()
//				ok = !port.IsPortAvailable(p)
//			}
//			pm := model.PortMap{gjson.Get(result.Raw, "container_port").Int(), p}
//			inarr = append(inarr, pm)
//		}
//		data["tcp"] = inarr
//	}
//	if u := gjson.Parse(udp).Array(); len(u) > 0 {
//		//udpList := []model.UdpPorts{}
//		//e := json2.Unmarshal([]byte(udp), udpList)
//		//if e != nil {
//		//	return
//		//}
//		var inarr []model.PortMap
//		for _, result := range u {
//			var p int
//			ok := true
//			for ok {
//				p, _ = port.GetAvailablePort()
//				ok = !port.IsPortAvailable(p)
//			}
//			pm := model.PortMap{gjson.Get(result.Raw, "container_port").Int(), p}
//			inarr = append(inarr, pm)
//		}
//		data["udp"] = inarr
//	}
//	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
//}
