package tcp import ( "encoding/hex" "errors" "fmt" "go.uber.org/zap" "gorm.io/gorm" "net" Dev "server/dao/devices" deviceDao "server/dao/devices" promodel "server/model/common/devices" "server/protocol" "server/utils/logger" "strings" "time" ) var ( Devices = make(map[string]*Device) // 存储连接的全局 map ) type Device struct { Info deviceDao.Screens Conn net.Conn LastTime time.Time } // 实例所有设备 func InitDevices() { // 将数据库中的设备全部离线 devs, _ := deviceDao.QueryAllScreens() for _, screen := range devs { if screen.Status != 0 { screen.Status = 0 now := time.Now() screen.LastOfflineTime = &now } Devices[screen.Sn] = &Device{Info: screen} } } func (s *Device) Start(conn net.Conn) { s.Conn = conn go s.Process() } func (s *Device) Process() { // 函数执行完之后关闭连接 defer s.Conn.Close() for { buf := make([]byte, 256) // 将tcp连接读取到的数据读取到byte数组中, 返回读取到的byte的数目 n, err := s.Conn.Read(buf) if err != nil { // 从客户端读取数据的过程中发生错误 这里如果没读到可以视为设备离线了 logger.Logger.Errorf("read from client failed [离线了], err:%v", err) break } data := hex.EncodeToString(buf[:n]) if !strings.Contains(strings.ToLower(data), "fe5c4b89") { continue } switch data[16:18] { case "61": // fe5c4b89 2a000000 62 00000000 17000000 31 23 32303233(年) 3035(月) 3135(日) 3031(星期) 3038(时) 3334(分) 3135(秒) 23 303630(心跳包时间) 23 ffff //目前登录只做查找设备的操作 (假登录) buffer := protocol.AuthDataPack{}.AuthLogin() // 通过sn 查设备是否存在 不存在return 存在就保存con 和 info _, err := deviceDao.QueryScreenBySn(data[34:50]) if errors.Is(err, gorm.ErrRecordNotFound) { logger.Logger.Errorf("Process[case '61'] SN not found \n") break } s.Conn.Write(buffer.Bytes()) case "91": dev := Devices[data[34:50]] if dev.Info.Status == 0 { state := 1 //上线 则修改数据库上线时间 err := Dev.UpdateScreensStatusAndOnline(dev.Info.Sn, state) if err != nil { logger.Logger.Error("Process[case '91'] UpdateScreensStatusAndOnline err", zap.Error(err)) continue } dev.Info.Status = 1 now := time.Now() dev.Info.LastOnlineTime = &now logger.Logger.Debugf("设备 [%v] 上线", dev.Info.ScreensName) // 登录 } dev.Conn = s.Conn dev.LastTime = time.Now() logger.Logger.Debugf("设备 [%v] 心跳", dev.Info.ScreensName) default: fmt.Println("读取:", data) } } } func IsOnline() { t := time.NewTicker(1 * time.Minute) //每分钟 for { select { case <-t.C: for _, device := range Devices { //符合条件 if (time.Now().Add(-5*time.Minute).After(device.LastTime) || device.LastTime.IsZero()) && device.Info.Status != 0 { //修改数据库和内存 //离线 state := 0 err := Dev.UpdateScreensStatusAndOffline(device.Info.Sn, state) if err != nil { logger.Logger.Error("[Handle] UpdateScreensStatus err", zap.Error(err)) continue } device.Info.Status = 0 now := time.Now() device.Info.LastOfflineTime = &now logger.Logger.Debugf("设备 [%v] 离线了...", device.Info.ScreensName) } } } } } func (s *Device) SwitchScreen(onOff int) error { if s.Conn == nil { return errors.New("connection is nil") } pack := protocol.SwitchDataPack{Type: 0x52} //熄屏 if onOff == 1 { pack = protocol.SwitchDataPack{Type: 0x51} //亮屏 } buf := pack.SwitchScreens() //获取开关屏指令 _, err := s.Conn.Write(buf.Bytes()) if err != nil { logger.Logger.Errorf("SwitchScreen write failed, err:%v", err) return err } return nil } func (s *Device) SendInternalCode(content []promodel.InternalCodeContent) error { if s.Conn == nil { return errors.New("connection is nil") } pack := protocol.InternalCodeDataPack{} //获取要写入连接的字节数组 buf := pack.SendInternalCode(content) _, err := s.Conn.Write(buf.Bytes()) if err != nil { logger.Logger.Errorf("SendInternalCode write failed, err:%v", err) return err } return nil } func (s *Device) VoiceBroad(broad string) error { if s.Conn == nil { return errors.New("connection is nil") } pack := protocol.VoiceBroadDataPack{} buf := pack.VoiceBroad(broad) _, err := s.Conn.Write(buf.Bytes()) if err != nil { logger.Logger.Errorf("VoiceBroad write failed, err:%v", err) return err } return nil } func (s *Device) SetBrightness(bright byte) error { if s.Conn == nil { return errors.New("connection is nil") } pack := protocol.SetBrightnessDataPack{} buf := pack.SetBrightness(bright) _, err := s.Conn.Write(buf.Bytes()) if err != nil { logger.Logger.Errorf("SetBrightness write failed, err:%v", err) return err } return nil } func SwitchScreen(sn string, onOff int) error { device := Devices[sn] err := device.SwitchScreen(onOff) if err != nil { return err } return nil } func SendInternalCode(sn string, content []promodel.InternalCodeContent) error { device := Devices[sn] err := device.SendInternalCode(content) if err != nil { return err } return nil } func VoiceBroad(sn string, broad string) error { device := Devices[sn] err := device.VoiceBroad(broad) if err != nil { return err } return nil } func SetBrightness(sn string, bright int) error { device := Devices[sn] err := device.SetBrightness(brightnessMap[bright]) if err != nil { return err } return nil } var brightnessMap = map[int]byte{ 0: 0x19, 10: 0x18, 20: 0x16, 30: 0x14, 40: 0x12, 50: 0x10, 60: 0x08, 70: 0x06, 80: 0x04, 90: 0x02, 100: 0x00, }