siked 1 жил өмнө
parent
commit
5adb306dd0

+ 40 - 10
Handle/Handle.go

@@ -6,15 +6,19 @@ import (
 	"Yunlot/logs"
 	"Yunlot/models/Device"
 	"Yunlot/models/Product"
+	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"go.mongodb.org/mongo-driver/bson"
 	"plugin"
 	"reflect"
+	"time"
 )
 
 // 设备->平台
 func PullHandle(Device_r *Device.Device, topicName string, message []byte) lib.JSONR {
+	DeviceRealLogR_ := []string{}
+
 	var Rt_r = lib.JSONR{Code: 200, Msg: "ok"}
 
 	// 设备协议
@@ -26,6 +30,13 @@ func PullHandle(Device_r *Device.Device, topicName string, message []byte) lib.J
 		return Rt_r
 	}
 
+	//  加入设备日志  类型
+	if message[0] == '{' {
+		DeviceRealLogR_ = append(DeviceRealLogR_, "<-接收["+topicName+"]\\r\\n"+time.Now().Format("15:04:05")+"\\r\\n"+string(message)) //  加入设备日志
+	} else {
+		DeviceRealLogR_ = append(DeviceRealLogR_, "<-接收["+topicName+"]\\r\\n"+time.Now().Format("15:04:05")+"\\r\\n"+hex.EncodeToString(message)) //  加入设备日志
+	}
+
 	messagejson := string(message)
 	// 是否加载转换协议
 	if ProductProt_r.T_lang != 0 && len(ProductProt_r.T_analysis) != 0 {
@@ -50,6 +61,7 @@ func PullHandle(Device_r *Device.Device, topicName string, message []byte) lib.J
 		// 开始处理
 		logs.Println("协议后:", messagejson)
 
+		DeviceRealLogR_ = append(DeviceRealLogR_, "<-转换["+topicName+"]\\r\\n"+time.Now().Format("15:04:05")+"\\r\\n"+messagejson) //  加入设备日志
 	}
 
 	//logs.Println("首字符:", string(f[0]))
@@ -112,13 +124,20 @@ func PullHandle(Device_r *Device.Device, topicName string, message []byte) lib.J
 	//	Device_r.UpdateTime.NowDbTime()
 	//	Device_r.Update("T_data", "UpdateTime")
 	//}
+	//logs.Println("DeviceRealLogR_:",DeviceRealLogR_)
+	// 更新设备记录日志
+	v, is := logs.DeviceRealLogMap[Device_r.T_sn]
+	if is {
+		v.Data = append(v.Data, DeviceRealLogR_...)
+		logs.DeviceRealLogMap[Device_r.T_sn] = v
+	}
 
 	return Rt_r
 }
 
 // 平台->设备
 func PushHandle(Device_r *Device.Device, topicName string, message string) (string, []byte) {
-
+	DeviceRealLogR_ := []string{}
 	// 设备协议
 	ProductProt_r := Product.ProductProt{Id: Device_r.T_ProductJson.T_prot}
 	if !ProductProt_r.Read() {
@@ -143,17 +162,22 @@ func PushHandle(Device_r *Device.Device, topicName string, message string) (stri
 			logs.PrintlnError("PushHandle:", err)
 			return "", []byte{}
 		}
+		DeviceRealLogR_ = append(DeviceRealLogR_, "->转换["+topicName+"]\\r\\n"+time.Now().Format("15:04:05")+"\\r\\n"+message) //  加入设备日志
 		// 类型转换
 		topicName_r, byte_r = s.(func(sn string, b string) (string, []byte))(topicName, message)
+		// 开始处理
+		logs.Println("协议后:", byte_r)
 
 	}
 
 	// 无效消息,不用推送
 	if len(topicName_r) == 0 || len(byte_r) == 0 {
+		logs.Println("无效消息,不用推送!", len(topicName_r), len(byte_r))
 		return "", []byte{}
 	}
 
 	// 长连接 网关
+	logs.Println("ProductProt_r.T_mode:", ProductProt_r.T_mode)
 	switch ProductProt_r.T_mode {
 	case 1: //mqtt
 		// 如果 订阅地址与发布相同,在后面强行加 _reply,避免发布后无法收到消息
@@ -162,18 +186,24 @@ func PushHandle(Device_r *Device.Device, topicName string, message string) (stri
 		}
 		lib.Mqtt_publish(topicName_r, byte_r) // 返回数据
 		break
-		//case 2: //tcp
-		//
-		//	break
-		//case 3: //CoAP
-		//
-		//	break
-		//case 4: //websocket
-		//
-		//	break
+	case 2: //tcp
+		lib.TCP_publish(Device_r.T_sn, byte_r)
+		break
 
 	}
 
+	if byte_r[0] == '{' {
+		DeviceRealLogR_ = append(DeviceRealLogR_, "->推送["+topicName_r+"]\\r\\n"+time.Now().Format("15:04:05")+"\\r\\n"+string(byte_r)) //  加入设备日志
+	} else {
+		DeviceRealLogR_ = append(DeviceRealLogR_, "->推送["+topicName_r+"]\\r\\n"+time.Now().Format("15:04:05")+"\\r\\n"+hex.EncodeToString(byte_r)) //  加入设备日志
+	}
+	// 更新设备记录日志
+	v, is := logs.DeviceRealLogMap[Device_r.T_sn]
+	if is {
+		v.Data = append(v.Data, DeviceRealLogR_...)
+		logs.DeviceRealLogMap[Device_r.T_sn] = v
+	}
+
 	return topicName_r, byte_r
 
 }

+ 2 - 1
Handle/Relay.go

@@ -18,7 +18,8 @@ func Relay(Device_r *Device.Device, JointTab string, ArticleSlide *bson.M) {
 			x := value.(map[string]interface{})
 
 			//  替换发布号变量
-			T_pub := strings.Replace(lib.To_string(x["T_pub"]), "{$sn}", Device_r.T_sn, -1)
+			T_pub := strings.Replace(lib.To_string(x["T_pub"]), "{$sn}", Device_r.T_sn, -1) //  {$sn} :代表当前数据设备编号SN
+			T_pub = strings.Replace(T_pub, "{$project}", Device_r.T_project, -1)            //  {$project}:代表设备项目服务
 			if len(T_pub) == 0 {
 				logs.Println("订阅号错误!")
 				return

+ 122 - 18
Handle/TcpServer/Server.go

@@ -1,20 +1,30 @@
 package TcpServer
 
 import (
+	"Yunlot/Handle"
+	"Yunlot/conf"
+	"Yunlot/lib"
+	"Yunlot/lib/TcpServerLib"
+	"Yunlot/logs"
+	"Yunlot/models/Device"
 	"container/list"
+	"encoding/json"
 	"fmt"
+	"net"
+	"strconv"
+	"strings"
 	"time"
 )
 
-
 var SessionS list.List
+
 func TcpServer() {
 	//SessionS = list.New()
 
-	fmt.Println("TcpServer")
-
+	logs.Println("============TcpServer==============")
+	logs.Println("TCPServer_Port:" + fmt.Sprintf(":%d", conf.TCPServer_Port))
 
-	server := NewServer(":1452")
+	server := TcpServerLib.NewServer(fmt.Sprintf(":%d", conf.TCPServer_Port))
 
 	server.OnNewClient(OnNewClient)
 	server.OnClientConnectionClosed(OnClientConnectionClosed)
@@ -24,39 +34,133 @@ func TcpServer() {
 	go Polling()
 }
 
-func Polling()  {
+func Polling() {
 
-	for true{
+	for true {
 		for i := SessionS.Front(); i != nil; i = i.Next() {
-			t := i.Value.(*Session)
+			t := i.Value.(*TcpServerLib.Session)
 
-			if t.Device.T_sn == "" {
+			if len(t.Device_Sn) == 0 {
 				t.Verify_num += 1
 				if t.Verify_num > 10 {
 					t.Close()
 					SessionS.Remove(i)
-					fmt.Println("Polling 删除")
+					logs.Println("Polling 删除", t.Conn().LocalAddr().String())
 				}
 			}
-
 		}
-
 		time.Sleep(time.Second * 1)
 	}
 
 }
 
-func OnNewClient(c *Session) {
-	fmt.Println("OnNewClient")
+func OnNewClient(c *TcpServerLib.Session) {
+	logs.Println("OnNewClient")
 	SessionS.PushBack(c)
-	c.Send("ok!")
+	//c.Send(string([]byte{0xff,0x00,0xff}))
+	//c.Send("ok")
+}
+
+func OnClientConnectionClosed(c *TcpServerLib.Session, closeCase int) {
+	logs.Println("OnClientConnectionClosed:", closeCase)
+	// 离线
+	if len(c.Device_Sn) != 0 {
+		if _, is := lib.TcpMap[c.Device_Sn]; !is {
+			delete(lib.TcpMap, c.Device_Sn)
+		}
+
+		r_Device := Device.Device{T_sn: c.Device_Sn}
+		if !r_Device.Read_Tidy() {
+			return
+		}
+
+		r_Device.T_online = 2
+		// 同步参数
+		r_Device.Update("T_online")
+
+		var Device_online_r map[string]interface{}
+		Device_online_r = make(map[string]interface{})
+		Device_online_r["online"] = r_Device.T_online
+		Device_online_r["msg"] = "设备离线[" + ToReason(closeCase) + "]"
+		Device_online_r["time"] = time.Now().Format("2006-01-02 15:04:05")
+
+		Handle.AnalysisMap(&r_Device, map[string]interface{}{"online": Device_online_r}, "")
+
+	}
+
 }
+func ToReason(str int) (Reason string) {
+	switch str {
+	case 1:
+		Reason = "客户端主动断开"
+		break
+	default:
+		Reason = "客户端异常断开[" + strconv.Itoa(str) + "]"
+		break
+	}
 
-func OnClientConnectionClosed(c *Session, closeCase int) {
-	fmt.Println("OnClientConnectionClosed:",closeCase)
+	return Reason
 }
 
-func OnNewMessage(c *Session, packetData []byte) {
-	fmt.Println("OnNewMessage:",packetData)
+func OnNewMessage(c *TcpServerLib.Session, packetData []byte) {
+	if len(c.Device_Sn) == 0 {
+
+		packetData_l := strings.Split(string(packetData), "&")
+		if len(packetData_l) != 2 {
+			logs.Println("登录验证 长度失败:", packetData_l, len(packetData_l))
+			c.Send("e")
+			return
+		}
+		Devicer := Device.Device{T_sn: packetData_l[0]}
+		if !Devicer.Read_Tidy() {
+			logs.Println("登录验证 SN失败:", packetData_l, len(packetData_l))
+			c.Send("e")
+			return
+		}
+		if Devicer.T_password != packetData_l[1] {
+			logs.Println("登录验证 秘钥失败:", packetData_l, len(packetData_l))
+			c.Send("e")
+			return
+		}
+
+		c.Send("ok")
+		c.Device_Sn = Devicer.T_sn
+
+		lib.TcpMap[Devicer.T_sn] = c // 更新 MAP
+
+		//  更新状态
+
+		Devicer.T_online = 1
+		// 同步参数
+		Devicer.Update("T_online")
+
+		// 获取客户端IP地址
+		clientIP, _, _ := net.SplitHostPort(c.Conn().RemoteAddr().String())
+		fmt.Println("Client IP:", clientIP)
+
+		var Device_online_r map[string]interface{}
+		Device_online_r = make(map[string]interface{})
+		Device_online_r["online"] = Devicer.T_online
+		Device_online_r["msg"] = "设备主动上线[" + clientIP + "]"
+		Device_online_r["time"] = time.Now().Format("2006-01-02 15:04:05")
+
+		Handle.AnalysisMap(&Devicer, map[string]interface{}{"online": Device_online_r}, "")
+		return
+	}
+
+	Device_r := Device.Device{T_sn: c.Device_Sn}
+	if !Device_r.Read_Tidy() {
+		c.Send("e")
+		return
+	}
+
+	logs.Println("OnNewMessage:", string(packetData))
+
+	Rt_r := Handle.PullHandle(&Device_r, c.Device_Sn, packetData)
+
+	// 返回
+	data, _ := json.Marshal(Rt_r)
+
+	Handle.PushHandle(&Device_r, c.Device_Sn, string(data))
 
 }

+ 2 - 1
conf/app.conf

@@ -29,7 +29,7 @@ Mongodb_Password = "yunlot123"
 ; Redis_address = "172.17.0.5:8379"
 Redis_address = "127.0.0.1:6379"
 Redis_password = ""
-Redis_dbNum = "1"
+Redis_dbNum = "9"
 
 # Mqtt
 MqttServer_Open = 1
@@ -41,6 +41,7 @@ MqttServer_Password = "8f9qRNixEMhCVrF"
 
 # TCP
 TCPServer_Open = 1
+TCPServer_Port = 8082
 
 # HTTP
 HTTPServer_Open = 1

+ 10 - 1
conf/config.go

@@ -5,7 +5,15 @@ import (
 )
 
 func init() {
-	beego.LoadAppConfig("ini", "a/conf/app.conf")
+	//configFilePath, err := filepath.Abs("app.conf")
+	//if err != nil {
+	//	logs.Println("configFilePathError", err)
+	//}
+	//logs.Println("configFilePath:",configFilePath)
+	//err = beego.LoadAppConfig("ini", configFilePath)
+	//if err != nil {
+	//	logs.Println("loadConfigFileError", err)
+	//}
 }
 
 var HTTPPort, _ = beego.AppConfig.Int("HTTPPort")
@@ -34,6 +42,7 @@ var MqttServer_ClientID, _ = beego.AppConfig.String("MqttServer_ClientID")
 
 // Mqtt
 var TCPServer_Open, _ = beego.AppConfig.Int("TCPServer_Open")
+var TCPServer_Port, _ = beego.AppConfig.Int("TCPServer_Port")
 
 // HTTPServer_Open
 var HTTPServer_Open, _ = beego.AppConfig.Int("HTTPServer_Open")

+ 50 - 15
controllers/Device.go

@@ -3,9 +3,11 @@ package controllers
 import (
 	"Yunlot/Handle"
 	"Yunlot/lib"
+	"Yunlot/logs"
 	"Yunlot/models/Device"
 	"Yunlot/models/Product"
 	beego "github.com/beego/beego/v2/server/web"
+	"time"
 )
 
 type DeviceController struct {
@@ -19,6 +21,13 @@ func (c *DeviceController) List() {
 	Devicer := Device.Device{}
 	c.ParseForm(&Devicer)
 
+	ProductTyper := Product.ProductType{T_ProductID: Devicer.T_ProductID}
+	if !ProductTyper.Read() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "ProductID E!"}
+		c.ServeJSON()
+		return
+	}
+
 	Device_r, Total := Devicer.Lists(PageIndex, PageSize)
 
 	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: lib.C_Page(Device_r, PageIndex, PageSize, Total)}
@@ -81,7 +90,7 @@ func (c *DeviceController) Update() {
 	Devicer.Read_Tidy()
 	c.ParseForm(&Devicer)
 
-	if !Devicer.Update("T_state") {
+	if !Devicer.Update("T_state", "T_project") {
 		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "E!"}
 		c.ServeJSON()
 		return
@@ -92,20 +101,21 @@ func (c *DeviceController) Update() {
 	return
 }
 
-func (c *DeviceController) Delete() {
-	Devicer := Device.Device{}
-	c.ParseForm(&Devicer)
-
-	if !Devicer.Delete() {
-		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "E!"}
-		c.ServeJSON()
-		return
-	}
-
-	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!"}
-	c.ServeJSON()
-	return
-}
+//
+//func (c *DeviceController) Delete() {
+//	Devicer := Device.Device{}
+//	c.ParseForm(&Devicer)
+//
+//	if !Devicer.Delete() {
+//		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "E!"}
+//		c.ServeJSON()
+//		return
+//	}
+//
+//	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!"}
+//	c.ServeJSON()
+//	return
+//}
 
 func (c *DeviceController) Get() {
 	Devicer := Device.Device{}
@@ -166,3 +176,28 @@ func (c *DeviceController) DataList() {
 	c.ServeJSON()
 	return
 }
+
+func (c *DeviceController) GetLog() {
+	Devicer := Device.Device{}
+	c.ParseForm(&Devicer)
+
+	if !Devicer.Read_Tidy() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "SN E!"}
+		c.ServeJSON()
+		return
+	}
+
+	v, is := logs.DeviceRealLogMap[Devicer.T_sn]
+	if !is {
+		logs.DeviceRealLogMap[Devicer.T_sn] = logs.DeviceRealLogR{Time: time.Now(), Data: []string{}}
+		c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: []string{}}
+		c.ServeJSON()
+		return
+	}
+	v.Time = time.Now()
+	logs.DeviceRealLogMap[Devicer.T_sn] = v
+
+	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: v.Data}
+	c.ServeJSON()
+	return
+}

+ 128 - 0
controllers/ProductOTA.go

@@ -0,0 +1,128 @@
+package controllers
+
+import (
+	"Yunlot/Handle"
+	"Yunlot/lib"
+	"Yunlot/logs"
+	"Yunlot/models/Device"
+	"Yunlot/models/Product"
+	"encoding/json"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+type ProductOTAController struct {
+	beego.Controller
+}
+
+func (c *ProductOTAController) List() {
+	PageIndex, _ := c.GetInt("PageIndex", 0)
+	PageSize, _ := c.GetInt("PageSize", 10)
+
+	ProductOTAr := Product.ProductOTA{}
+	c.ParseForm(&ProductOTAr)
+
+	// 验证 TOKEY
+	if c.Ctx.Input.Host() != "127.0.0.1" {
+		if len(ProductOTAr.T_tokey) != 8 {
+			c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	ProductOTA_r, Total := ProductOTAr.Lists(PageIndex, PageSize)
+
+	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: lib.C_Page(ProductOTA_r, PageIndex, PageSize, Total)}
+	c.ServeJSON()
+	return
+}
+
+func (c *ProductOTAController) Get() {
+	ProductOTAr := Product.ProductOTA{}
+	c.ParseForm(&ProductOTAr)
+
+	if !ProductOTAr.Read() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "ID E!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 验证 TOKEY
+	if ProductOTAr.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: ProductOTAr}
+	c.ServeJSON()
+	return
+}
+
+func (c *ProductOTAController) Add() {
+	ProductOTA_r := Product.ProductOTA{}
+	c.ParseForm(&ProductOTA_r)
+
+	if len(ProductOTA_r.T_tokey) != 8 {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
+	go func() {
+		device := Device.Device{T_ProductID: ProductOTA_r.T_ProductID}
+		Device_list := device.Lists_All()
+
+		var T_datajson map[string]interface{}
+		T_datajson = make(map[string]interface{})
+		T_datajson["name"] = ProductOTA_r.T_name
+		T_datajson["version"] = ProductOTA_r.T_version
+		T_datajson["file"] = ProductOTA_r.T_file
+		T_datajson["md5"] = ProductOTA_r.T_file
+		T_datajson["size"] = ProductOTA_r.T_file
+		T_datajson["publish"] = ProductOTA_r.T_publish
+		T_datajson["describe"] = ProductOTA_r.T_describe
+
+		b, _ := json.Marshal(map[string]interface{}{"upgrade": T_datajson})
+
+		for _, v := range Device_list {
+			logs.Println("全量发布:", v.T_sn, string(b))
+			Handle.PushHandle(&v, v.T_sn, string(b))
+		}
+
+	}()
+
+	ProductOTA_r.Id = 0
+	ProductOTA_r.Add()
+
+	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: ProductOTA_r}
+	c.ServeJSON()
+	return
+}
+
+func (c *ProductOTAController) Delete() {
+	ProductOTAr := Product.ProductOTA{}
+	c.ParseForm(&ProductOTAr)
+	if !ProductOTAr.Read() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "ID E!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 验证 TOKEY
+	if ProductOTAr.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
+	if !ProductOTAr.Delete() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "E!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}

+ 50 - 1
controllers/ProductProt.go

@@ -28,6 +28,13 @@ func (c *ProductProtController) Get() {
 		return
 	}
 
+	// 验证 TOKEY
+	if ProductProt.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
 	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: ProductProt}
 	c.ServeJSON()
 	return
@@ -40,6 +47,15 @@ func (c *ProductProtController) List() {
 	ProductProtr := Product.ProductProt{}
 	c.ParseForm(&ProductProtr)
 
+	// 验证 TOKEY
+	if c.Ctx.Input.Host() != "127.0.0.1" {
+		if len(ProductProtr.T_tokey) != 8 {
+			c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
 	ProductProt_r, Total := ProductProtr.Lists(PageIndex, PageSize)
 
 	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: lib.C_Page(ProductProt_r, PageIndex, PageSize, Total)}
@@ -50,6 +66,13 @@ func (c *ProductProtController) List() {
 func (c *ProductProtController) Add() {
 	ProductProt_r := Product.ProductProt{}
 	c.ParseForm(&ProductProt_r)
+
+	if len(ProductProt_r.T_tokey) != 8 {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
 	ProductProt_r.Id = 0
 	ProductProt_r.Add()
 
@@ -59,7 +82,22 @@ func (c *ProductProtController) Add() {
 }
 
 func (c *ProductProtController) Update() {
-	ProductProtr := Product.ProductProt{}
+
+	Id, _ := c.GetInt("Id", 0)
+	ProductProtr := Product.ProductProt{Id: Id}
+	if !ProductProtr.Read() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_ProductID E!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 验证 TOKEY
+	if ProductProtr.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
 	c.ParseForm(&ProductProtr)
 
 	if !ProductProtr.Update("T_name", "T_mode", "T_lang", "T_analysis", "T_text", "T_describe") {
@@ -76,7 +114,18 @@ func (c *ProductProtController) Update() {
 func (c *ProductProtController) Delete() {
 	ProductProtr := Product.ProductProt{}
 	c.ParseForm(&ProductProtr)
+	if !ProductProtr.Read() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "ID E!"}
+		c.ServeJSON()
+		return
+	}
 
+	// 验证 TOKEY
+	if ProductProtr.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
 	if !ProductProtr.Delete() {
 		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "E!"}
 		c.ServeJSON()

+ 43 - 0
controllers/ProductType.go

@@ -12,12 +12,22 @@ type ProductTypeController struct {
 }
 
 func (c *ProductTypeController) List() {
+
 	PageIndex, _ := c.GetInt("PageIndex", 0)
 	PageSize, _ := c.GetInt("PageSize", 10)
 
 	ProductTyper := Product.ProductType{}
 	c.ParseForm(&ProductTyper)
 
+	// 验证 TOKEY
+	if c.Ctx.Input.Host() != "127.0.0.1" {
+		if len(ProductTyper.T_tokey) != 8 {
+			c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
 	ProductType_r, Total := ProductTyper.Lists(PageIndex, PageSize)
 
 	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: lib.C_Page(ProductType_r, PageIndex, PageSize, Total)}
@@ -35,6 +45,13 @@ func (c *ProductTypeController) Get() {
 		return
 	}
 
+	// 验证 TOKEY
+	if ProductTyper.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
 	c.Data["json"] = lib.JSONR{Code: lib.Success, Msg: "ok!", Data: ProductTyper}
 	c.ServeJSON()
 	return
@@ -44,6 +61,12 @@ func (c *ProductTypeController) Add() {
 	ProductType_r := Product.ProductType{}
 	c.ParseForm(&ProductType_r)
 
+	if len(ProductType_r.T_tokey) != 8 {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
 	ProductType_r.T_ProductID = lib.GetRandstring(8, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 0)
 	ProductType_r.T_akey = lib.GetRandstring(32, "", 0)
 
@@ -63,6 +86,13 @@ func (c *ProductTypeController) Update() {
 		return
 	}
 
+	// 验证 TOKEY
+	if ProductTyper.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
 	c.ParseForm(&ProductTyper)
 
 	if !ProductTyper.Update("T_name", "T_img", "T_prot", "T_TabData", "T_RelayData") {
@@ -81,6 +111,19 @@ func (c *ProductTypeController) Delete() {
 	ProductTyper := Product.ProductType{}
 	c.ParseForm(&ProductTyper)
 
+	if !ProductTyper.Read() {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_ProductID E!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 验证 TOKEY
+	if ProductTyper.T_tokey != c.GetString("T_tokey") {
+		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "T_tokey!"}
+		c.ServeJSON()
+		return
+	}
+
 	if !ProductTyper.Delete() {
 		c.Data["json"] = lib.JSONR{Code: lib.Error, Msg: "E!"}
 		c.ServeJSON()

+ 1 - 1
Handle/TcpServer/binaryReadWrite.go → lib/TcpServerLib/binaryReadWrite.go

@@ -1,4 +1,4 @@
-package TcpServer
+package TcpServerLib
 
 import (
 	"encoding/binary"

+ 1 - 1
Handle/TcpServer/define.go → lib/TcpServerLib/define.go

@@ -1,4 +1,4 @@
-package TcpServer
+package TcpServerLib
 
 const (
 	MAX_RECEIVE_BUFFER_SIZE = 4012

+ 1 - 1
Handle/TcpServer/packet.go → lib/TcpServerLib/packet.go

@@ -1,4 +1,4 @@
-package TcpServer
+package TcpServerLib
 
 // protocol Id
 const (

+ 26 - 21
Handle/TcpServer/session.go → lib/TcpServerLib/session.go

@@ -1,43 +1,48 @@
-package TcpServer
+package TcpServerLib
 
 import (
-	"Yunlot/models/Device"
 	"net"
 )
 
 // Session holds info about connection
 type Session struct {
-	conn   net.Conn
-	Server *server
-	Device Device.Device
-	Verify_num  int
+	conn       net.Conn
+	Server     *server
+	Device_Sn  string
+	Verify_num int
 }
 
 func (session *Session) handleTcpRead() {
 	session.Server.onNewClientCallback(session)
 
-	var startRecvPos int16
-	var result int
+	//var startRecvPos int16
+	//var result int
 	recviveBuff := make([]byte, MAX_RECEIVE_BUFFER_SIZE)
 
 	for {
-		recvBytes, err := session.conn.Read(recviveBuff[startRecvPos:])
+		recvBytes, err := session.conn.Read(recviveBuff)
+
 		if err != nil {
+			/*logs.PrintlnError("TCP - handleTcpRead",err)
+			continue;*/
+			//logs.PrintlnError("TCP - handleTcpRead",err)
 			session.closeProcess(NET_CLOSE_REMOTE)
 			return
 		}
-
-		if recvBytes < HEADER_SIZE {
-			session.closeProcess(NET_CLOSE_RECV_TOO_SMALL_RECV_DATA)
-			return
-		}
-
-		readAbleByte := int16(startRecvPos) + int16(recvBytes)
-		startRecvPos, result = session.makePacket(readAbleByte, recviveBuff)
-		if result != NET_ERROR_NONE {
-			session.closeProcess(result)
-			return
-		}
+		//logs.Println("recvBytes:",recvBytes)
+		session.Server.onNewMessage(session, recviveBuff[:recvBytes])
+		//
+		//if recvBytes < HEADER_SIZE {
+		//	session.closeProcess(NET_CLOSE_RECV_TOO_SMALL_RECV_DATA)
+		//	return
+		//}
+		//
+		//readAbleByte := int16(startRecvPos) + int16(recvBytes)
+		//startRecvPos, result = session.makePacket(readAbleByte, recviveBuff)
+		//if result != NET_ERROR_NONE {
+		//	session.closeProcess(result)
+		//	return
+		//}
 
 	}
 }

+ 1 - 1
Handle/TcpServer/tcpServer.go → lib/TcpServerLib/tcpServer.go

@@ -1,4 +1,4 @@
-package TcpServer
+package TcpServerLib
 
 import (
 	"github.com/davecgh/go-spew/spew"

+ 19 - 0
lib/lib.go

@@ -1,6 +1,7 @@
 package lib
 
 import (
+	"Yunlot/lib/TcpServerLib"
 	"Yunlot/logs"
 	"bytes"
 	"crypto/sha256"
@@ -28,10 +29,12 @@ var Nats *nats.Conn
 var MqttClient *client.Client
 var TopicMap map[string]bool
 var PluginMap map[string]*plugin.Plugin
+var TcpMap map[string]*TcpServerLib.Session
 
 func init() {
 	TopicMap = make(map[string]bool)
 	PluginMap = make(map[string]*plugin.Plugin)
+	TcpMap = make(map[string]*TcpServerLib.Session)
 }
 
 const Success = 200
@@ -477,3 +480,19 @@ func Json_key(topicNameList []string, topicNameI int, articleSlide map[string]in
 
 	return articleSlide[topicNameList[topicNameI]]
 }
+
+// 发送数据
+func TCP_publish(T_sn string, byte_r []byte) {
+
+	logs.PrintlnMqtt("TCP-> " + T_sn + ":" + string(byte_r))
+
+	if v, is := TcpMap[T_sn]; is {
+		err := v.Send(string(byte_r))
+		if err != nil {
+			logs.PrintlnError("TCP", "发送消息失败 [TCP_publish]", "-> "+T_sn+" "+string(byte_r))
+		}
+	} else {
+		logs.PrintlnError("TCP", "TcpMap[T_sn] 不存在,发送消息失败 [TCP_publish]", "-> "+T_sn+" "+string(byte_r))
+	}
+
+}

+ 25 - 0
logs/LogPrintln.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"github.com/astaxie/beego/logs"
 	"runtime"
+	"time"
 )
 
 var Test = true
@@ -13,7 +14,30 @@ var logxMqtt *logs.BeeLogger
 var logxData *logs.BeeLogger
 var logxOrm *logs.BeeLogger
 
+var DeviceRealLogMap map[string]DeviceRealLogR // 设备实时日志
+
+type DeviceRealLogR struct {
+	Time time.Time //
+	Data []string  // 泛型数组
+}
+
 func init() {
+	DeviceRealLogMap = make(map[string]DeviceRealLogR)
+
+	go func() {
+		for true {
+			for key, value := range DeviceRealLogMap {
+				subM := time.Now().Sub(value.Time)
+				fmt.Println(key+"日志-", subM.Minutes(), "分钟")
+				if subM.Minutes() > 3 {
+					delete(DeviceRealLogMap, key) // 删除日志
+				}
+			}
+
+			time.Sleep(time.Minute * 1)
+		}
+
+	}()
 
 	if runtime.GOOS == "windows" {
 		Test = true
@@ -35,6 +59,7 @@ func init() {
 
 	logxOrm = logs.NewLogger()
 	logxOrm.SetLogger(logs.AdapterFile, `{"filename":"logs/Orm/logx.log"}`)
+
 	//if !Test {
 	//	orm2.DebugLog = orm2.NewLog(logxOrm)
 	//}

+ 2 - 1
main.go

@@ -20,6 +20,7 @@ import (
 )
 
 func init() {
+
 	logs.Println("MysqlServer:" + conf.MysqlServer_Username + ":" + conf.MysqlServer_Password + "@tcp(" + conf.MysqlServer_UrlPort + ")/" + conf.MysqlServer_Database + "?charset=utf8mb4&loc=Local&parseTime=True")
 
 	orm.RegisterDriver("mysql", orm.DRMySQL)
@@ -59,7 +60,7 @@ func main() {
 		mode := Product.ProductMode{
 			Id:         2,
 			T_name:     "TCP",
-			T_address:  "TCP://bj-3-mqtt.iot-api.com:1883",
+			T_address:  fmt.Sprintf("TCP:%d", conf.TCPServer_Port),
 			T_describe: "TCP 接入方式为设备和云平台提供双向连接,设备既可上报属性数据,也可接收云端的消息下发。",
 			T_state:    1,
 		}

+ 1 - 0
models/Device/Device.go

@@ -21,6 +21,7 @@ type Device struct {
 	T_sn          string                 `orm:"size(256);pk" json:"T_sn" form:"T_sn"`                     // Sn
 	T_password    string                 `orm:"size(256);" json:"T_password" form:"T_password"`           // 密码
 	T_online      int                    `orm:"size(1);index;default(3)" json:"T_online" form:"T_online"` // 在线状态  1 在线  2 离线   3 未激活
+	T_project     string                 `orm:"size(256);default('')" json:"T_project" form:"T_project"`  // 项目地址
 	T_ProductID   string                 `orm:"size(8);index" json:"T_ProductID" form:"T_ProductID"`      // 产品类型
 	T_ProductJson Product.ProductType    `orm:"-" json:"T_ProductJson"`                                   // 产品类型 json
 	T_data        string                 `orm:"column(t_data);type(text);default('')" json:"T_data" `     // 设备数据

+ 107 - 0
models/Product/ProductOTA.go

@@ -0,0 +1,107 @@
+package Product
+
+import (
+	"Yunlot/logs"
+	"Yunlot/models"
+	"github.com/astaxie/beego/cache"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+)
+
+// OTA
+type ProductOTA struct {
+	Id          int    `orm:"column(ID);size(11);auto;pk" json:"Id" form:"Id"`
+	T_tokey     string `orm:"size(8);index" json:"T_tokey" form:"T_tokey"`                // 用户识别码(8位) ,管理员可以为空
+	T_ProductID string `orm:"size(8);index" json:"T_ProductID" form:"T_ProductID"`        // 产品型号 随机生成(8位)
+	T_name      string `orm:"size(256);" json:"T_name" form:"T_name"`                     // 固件名称
+	T_version   string `orm:"size(200);" json:"T_version" form:"T_version"`               // 版本
+	T_file      string `orm:"type(text);default('')" json:"T_file" form:"T_file"`         // 文件
+	T_md5       string `orm:"type(text);default('')" json:"T_md5" form:"T_md5"`           // 文件 MD5
+	T_size      int    `orm:"size(256);" json:"T_size" form:"T_size"`                     // 文件大小  字节
+	T_describe  string `orm:"type(text);default('')" json:"T_describe" form:"T_describe"` // 描述
+	T_publish   bool   `orm:"" json:"T_publish" form:"T_publish"`                         // 全量发布(类型所有设备 全部更新)默认:不发布 \ 全量发布
+
+	CreateTime models.Time `orm:"column(create_time);type(timestamp);auto_now_add" json:"CreateTime"`
+}
+
+func (t *ProductOTA) TableName() string {
+	return "ProductOTA" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redis_ProductOTA cache.Cache
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(ProductOTA))
+
+}
+
+// 添加
+func (t *ProductOTA) Add() (is bool) {
+	o := orm.NewOrm()
+
+	id, err := o.Insert(t)
+	if err != nil {
+		return false
+	}
+
+	println(id)
+	return true
+}
+
+// 获取
+func (t *ProductOTA) Read() (bool bool) {
+	o := orm.NewOrm()
+	err := o.Read(t) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		return false
+	}
+
+	return true
+}
+
+// 删除
+func (t *ProductOTA) Delete() bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(t); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 获取列表
+func (t *ProductOTA) Lists(PageIndex int, PageSize int) (r []ProductOTA, Total int64) {
+
+	o := orm.NewOrm()
+
+	// 也可以直接使用 Model 结构体作为表名
+	qs := o.QueryTable(new(ProductOTA))
+	var offset int64
+	if PageIndex <= 1 {
+		offset = 0
+	} else {
+		offset = int64((PageIndex - 1) * PageSize)
+	}
+
+	// 筛选参数
+	cond := orm.NewCondition()
+	if len(t.T_name) > 0 {
+		cond = cond.And("T_name__icontains", t.T_name) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+	}
+	if len(t.T_version) > 0 {
+		cond = cond.And("T_version__icontains", t.T_version) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+	}
+	if len(t.T_tokey) == 8 {
+		cond = cond.And("T_tokey", t.T_tokey) // 用户识别码
+	}
+	// 执行
+	qs.Limit(PageSize, offset).SetCond((*orm2.Condition)(cond)).All(&r)
+	Total, _ = qs.SetCond((*orm2.Condition)(cond)).Count()
+
+	return r, Total
+}

+ 10 - 4
models/Product/ProductProt.go

@@ -15,9 +15,10 @@ import (
 
 // 产品协议
 type ProductProt struct {
-	Id     int    `orm:"column(ID);size(11);auto;pk" json:"Id" form:"Id"`
-	T_name string `orm:"size(256);" json:"T_name" form:"T_name"`         // 协议名称
-	T_mode int    `orm:"size(1);default(0)" json:"T_Mode" form:"T_mode"` //接入方式  0:Mqtt  1:http  2:tcp  3:CoAP  4:websocket
+	Id      int    `orm:"column(ID);size(11);auto;pk" json:"Id" form:"Id"`
+	T_tokey string `orm:"size(8);index" json:"T_tokey" form:"T_tokey"`    // 用户识别码(8位) ,管理员可以为空
+	T_name  string `orm:"size(256);" json:"T_name" form:"T_name"`         // 协议名称
+	T_mode  int    `orm:"size(1);default(0)" json:"T_mode" form:"T_mode"` //接入方式  0:Mqtt  1:http  2:tcp  3:CoAP  4:websocket
 	//T_prot     int    `orm:"size(1);default(0)" json:"T_Prot" form:"T_prot"`                              //接入协议ID  0:统一协议
 	T_lang     int    `orm:"size(1);default(1)" json:"T_lang" form:"T_lang"`                                  //编程语言 0: 无解析 1: go   2: C
 	T_analysis string `orm:"size(100);default(yunlot-pxxxx-v1.19-01.so)" json:"T_analysis" form:"T_analysis"` //数据解析
@@ -159,6 +160,9 @@ func (t *ProductProt) Lists(PageIndex int, PageSize int) (r []ProductProt, Total
 	if len(t.T_name) > 0 {
 		cond = cond.And("T_name__icontains", t.T_name) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
 	}
+	if len(t.T_tokey) == 8 {
+		cond = cond.And("T_tokey", t.T_tokey) // 用户识别码
+	}
 
 	// 执行
 	qs.Limit(PageSize, offset).SetCond((*orm2.Condition)(cond)).All(&r)
@@ -183,7 +187,9 @@ func (t *ProductProt) Lists_All() (r []ProductProt) {
 	if len(t.T_name) > 0 {
 		cond = cond.And("T_name__icontains", t.T_name) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
 	}
-
+	if len(t.T_tokey) == 8 {
+		cond = cond.And("T_tokey", t.T_tokey) // 用户识别码
+	}
 	// 执行
 	qs.SetCond((*orm2.Condition)(cond)).All(&r)
 

+ 7 - 1
models/Product/ProductType.go

@@ -17,6 +17,7 @@ import (
 // 产品类型
 type ProductType struct {
 	T_ProductID string `orm:"size(8);pk" json:"T_ProductID" form:"T_ProductID"` // 产品型号 随机生成(8位)
+	T_tokey     string `orm:"size(8);index" json:"T_tokey" form:"T_tokey"`      // 用户识别码(8位) ,管理员可以为空
 	T_name      string `orm:"size(256);" json:"T_name" form:"T_name"`           // 产品名称
 	T_img       string `orm:"size(200);" json:"T_img" form:"T_img"`             // 图片
 	T_akey      string `orm:"size(56);" json:"T_akey" `                         // 授权密钥
@@ -249,6 +250,9 @@ func (t *ProductType) Lists(PageIndex int, PageSize int) (r []ProductType, Total
 	if len(t.T_ProductID) > 0 {
 		cond = cond.And("T_ProductID", t.T_ProductID) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
 	}
+	if len(t.T_tokey) == 8 {
+		cond = cond.And("T_tokey", t.T_tokey) // 用户识别码
+	}
 
 	// 执行
 	qs.Limit(PageSize, offset).SetCond((*orm2.Condition)(cond)).All(&r)
@@ -288,7 +292,9 @@ func (t *ProductType) Lists_All() (r []ProductType) {
 	if len(t.T_ProductID) > 0 {
 		cond = cond.And("T_ProductID", t.T_ProductID) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
 	}
-
+	if len(t.T_tokey) == 8 {
+		cond = cond.And("T_tokey", t.T_tokey) // 用户识别码
+	}
 	// 执行
 	qs.SetCond((*orm2.Condition)(cond)).All(&r)
 	for i, _ := range r {

+ 1 - 0
routers/Device.go

@@ -17,5 +17,6 @@ func init() {
 	beego.Router(prefix+"/Device/Delete", &controllers.DeviceController{}, "*:Delete") // 获取未读消息
 
 	beego.Router(prefix+"/Device/Data", &controllers.DeviceController{}, "*:DataList") // 获取未读消息
+	beego.Router(prefix+"/Device/GetLog", &controllers.DeviceController{}, "*:GetLog") // 获取未读消息
 
 }

+ 6 - 0
routers/Product.go

@@ -24,4 +24,10 @@ func init() {
 	beego.Router(prefix+"/ProductProt/Update", &controllers.ProductProtController{}, "*:Update") // 获取未读消息
 	beego.Router(prefix+"/ProductProt/Delete", &controllers.ProductProtController{}, "*:Delete") // 获取未读消息
 
+	// 产品OTA
+	beego.Router(prefix+"/ProductOTA/Add", &controllers.ProductOTAController{}, "*:Add")       // 获取未读消息
+	beego.Router(prefix+"/ProductOTA/Get", &controllers.ProductOTAController{}, "*:Get")       // 获取未读消息
+	beego.Router(prefix+"/ProductOTA/List", &controllers.ProductOTAController{}, "*:List")     // 获取未读消息
+	beego.Router(prefix+"/ProductOTA/Delete", &controllers.ProductOTAController{}, "*:Delete") // 获取未读消息
+
 }