package event import ( "encoding/hex" "encoding/json" "fmt" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals" "io" "net" "strconv" "strings" "time" ) //入口 func ListenTcp() { t := NewTcpClient() l, err := net.Listen("tcp", ":8000") if err != nil { fmt.Println("listen error:", err) return } globals.SugarLogger.Debugf("begin listenTcp port 8000......") go t.HandleTcpMessages() go t.HandleCheckTcpHeart() //go t.doPrint2() //go t.doPrint(printMsgChanFail) for { c, err := l.Accept() if err != nil { fmt.Println("accept error:", err) break } go t.handleConn(c) } } func (t *TcpClient) handleConn(c net.Conn) { var ( printNo string //打印机编号 printStatus *GetPrintStatus ) if c == nil { globals.SugarLogger.Debugf("conn is nil") return } defer c.Close() buffer := make([]byte, 1024) for { n, err := c.Read(buffer) if err != nil { if err == io.EOF { fmt.Println("connection close") } else { fmt.Println("ReadString err", err) } return } //也可能是查状态的 if err = json.Unmarshal(buffer[:n], &printStatus); err == nil { fmt.Println("handleConn msg: ", string(buffer[:n])) if printStatus != nil { status := t.getPrintStatus(printStatus.PrintNo) //if t.Clients[printStatus.PrintNo] != nil { // status = t.Clients[printStatus.PrintNo].Status //} else { // status = printerStatusOffline //} //globals.SugarLogger.Debugf("handleConn getstatus :%v", utils.Format4Output(t.Clients[printStatus.PrintNo], true)) c.Write([]byte(utils.Int2Str(status))) c.Close() } } //看是心跳还是打印返回 data := hex.EncodeToString(buffer[:n]) //证明是心跳 if strings.Contains(data, heartText) { globals.SugarLogger.Debugf("handleConn heart: %v", data) printNoData, _ := hex.DecodeString(data[len(heartText) : len(data)-8]) printNo = string(printNoData) globals.SugarLogger.Debugf("handleConn printno :[%v]", printNo) status := printStatus2JxStatus(data[len(data)-8 : len(data)-6]) //if t.Clients[printNo] == nil { //printInfo := &PrintInfo{ // C: c, // Status: printStatus2JxStatus(data[len(data)-8 : len(data)-6]), // StatusTime: time.Now(), //} //t.Lock() //t.Clients[printNo] = printInfo //t.Unlock() t.addConn(c, printNo, status) //t.buildCallBackMap(printNo) //t.buildMsgMap(printNo) go t.doPrint2(printNo) changePrinterStatus(printNo, status) if status == printerStatusOnline { t.printFail() } //} else { //改变打印机状态 //t.Lock() //if t.Clients[printNo] != nil { // if t.Clients[printNo].Status != status { // t.Clients[printNo].Status = status // } // t.Clients[printNo].StatusTime = time.Now() //} //t.Unlock() //changePrinterStatus(printNo, status) if t.getPrintStatus(printNo) != status { t.setPrintStatus(printNo, status) } globals.SugarLogger.Debugf("handleConn print model %v", utils.Format4Output(t.Clients[printNo], true)) //} } else if strings.Contains(data, printText) { globals.SugarLogger.Debugf("handleConn print callback: %v", data) _, printNo = getCallbackMsgInfo(data) t.addCallbackChan(printNo, data) //printMsgCallbackChan <- printMsgCallbackMap //changePrintMsg(data) } } } func changePrinterStatus(printNo string, status int) { var ( db = dao.GetDB() ) if printer, err := dao.GetPrinter(db, printNo); err == nil && printer != nil { feilds := []string{} if printer.Status != status { printer.Status = status feilds = append(feilds, "Status") } isOnline := 0 if status == printerStatusOnline || status == printerStatusOnlineWithoutPaper { isOnline = model.YES } else { isOnline = model.NO } if isOnline != printer.IsOnline { printer.IsOnline = isOnline feilds = append(feilds, "IsOnline") } if len(feilds) > 0 { dao.UpdateEntity(db, printer, feilds...) } } } func (t *TcpClient) printFail() (err error) { //新开机的打印失败和错误的 var ( db = dao.GetDB() ) prints, _ := dao.GetPrintMsgs(db, []int{printMsgFail, printMsgErr, printMsgAlreadyLoad, printMsgAlreadySend}, time.Now().Add(-time.Hour*3), time.Now(), 0, 999) for _, printMsg := range prints { t.addMsgChan(printMsg) } return err } func printStatus2JxStatus(printStatus string) (status int) { if printStatus == heartErrWithoutPaper { return printerStatusOnlineWithoutPaper } else if printStatus == heartErrNormal { return printerStatusOnline } return status } func getCallbackMsgInfo(data string) (orderNo int64, printNo string) { orderNo = h8l82int(data[len(data)-6:len(data)-4], data[len(data)-4:len(data)-2]) printNoData, _ := hex.DecodeString(data[len(printSuccessText) : len(data)-6]) printNo = string(printNoData) return orderNo, printNo } func (t *TcpClient) changePrintMsg(data string, orderNo int64, printNo string) (err error) { var ( db = dao.GetDB() //printNo, comment string //orderNo int64 status int ) //1、先找出打印机编号和订单序列号,这两个确定唯一一条消息? //orderNo = h8l82int(data[len(data)-6:len(data)-4], data[len(data)-4:len(data)-2]) //printNoData, _ := hex.DecodeString(data[len(printSuccessText) : len(data)-6]) //printNo = string(printNoData) //2、打印成功改变打印表的状态 if strings.Contains(data, printSuccessText) { //1e001802000150323032313036313530303030313000013c status = printMsgSuccess } else { //打印失败也改变状态并更新失败原因 status = printMsgFail comment = printErrMap[data[12:14]] } if printMsgs, err := dao.GetPrintMsgNoPage(db, printNo, orderNo); err != nil { globals.SugarLogger.Debugf("changePrintMsg err :[%v]", err) return err } else if len(printMsgs) == 0 { globals.SugarLogger.Debugf("changePrintMsg err ,not found printMsg printNo:[%v], orderNo :[%v]", printNo, orderNo) } else if len(printMsgs) > 0 { for _, v := range printMsgs { v.Comment = comment v.Status = status dao.UpdateEntity(db, v, "Comment", "Status") } } return err } func (t *TcpClient) HandleTcpMessages() { var ( db = dao.GetDB() offset, pageSize = 0, 1 ) for { //一直读? prints, _ := dao.GetPrintMsgs(db, []int{printMsgWait}, time.Now().Add(-time.Hour*3), time.Now(), offset, pageSize) for _, printMsg := range prints { t.addMsgChan(printMsg) printMsg.Status = printMsgAlreadyLoad dao.UpdateEntity(db, printMsg, "Status") } } } func (t *TcpClient) doPrint2(key string) (err error) { var ( db = dao.GetDB() ) if !t.isExistMsg(key) { return err } for { select { case printMsg := <-t.MsgMap[key]: var ( data []byte c net.Conn ) if printMsg != nil { if err = checkPrintMsg(db, printMsg); err == nil { //t.Lock() //if t.Clients[printMsg.PrintNo] != nil { // if t.Clients[printMsg.PrintNo].Status == printerStatusOnline { // if t.Clients[printMsg.PrintNo].C != nil { // c = t.Clients[printMsg.PrintNo].C // data, err = buildMsg(printMsg) // } // } else if t.Clients[printMsg.PrintNo].Status == printerStatusOffline { // err = fmt.Errorf("打印机离线!") // } else if t.Clients[printMsg.PrintNo].Status == printerStatusOnlineWithoutPaper { // err = fmt.Errorf("打印机缺纸!") // } //} //t.Unlock() status := t.getPrintStatus(printMsg.PrintNo) switch status { case printerStatusOnline: if c = t.getPrintConn(printMsg.PrintNo); c != nil { data, err = buildMsg(printMsg) } case printerStatusOffline: err = fmt.Errorf("打印机离线!") case printerStatusOnlineWithoutPaper: err = fmt.Errorf("打印机缺纸!") default: err = fmt.Errorf("打印机状态未知!") } } } else { err = fmt.Errorf("未查询到此printMsg") } if err != nil { globals.SugarLogger.Debugf("doPrint2 err printNo:%s, msgID:%s, printInfo: %v, err: %s", printMsg.PrintNo, printMsg.MsgID, utils.Format4Output(t.Clients[printMsg.PrintNo], true), err.Error()) //t.delConn(printMsg.PrintNo) printMsg.Status = printMsgErr printMsg.Comment = err.Error() dao.UpdateEntity(db, printMsg, "Status", "Comment") //delete(t.Clients, printMsg.PrintNo) //if c != nil { // c.Close() //} } else { if c != nil { if _, err = c.Write(data); err != nil { globals.SugarLogger.Debugf("handleTcpMessages err [%v]", err) t.delConn(printMsg.PrintNo) //delete(t.Clients, printMsg.PrintNo) //c.Close() } else { globals.SugarLogger.Debugf("handleTcpMessages success, data: %v", hex.EncodeToString(data)) //printMsg.Status = printMsgAlreadySend //dao.UpdateEntity(db, printMsg, "Status") dataStr := <-t.CallBackMap[printMsg.PrintNo] a, b := getCallbackMsgInfo(dataStr) t.changePrintMsg(dataStr, a, b) //dataStr := <-printMsgCallbackChan } } } } } return err } func (t *TcpClient) HandleCheckTcpHeart() { for { keys := []string{} t.RLock() for k, v := range t.Clients { if time.Now().Sub(v.StatusTime) > time.Minute+time.Second { v.Status = printerStatusOffline keys = append(keys, k) } } t.RUnlock() for _, v := range keys { changePrinterStatus(v, printerStatusOffline) if t.isExist(v) { t.Lock() delete(t.Clients, v) t.Unlock() } } } } func buildMsg(printMsg *model.PrintMsg) (data []byte, err error) { var ( content = printMsg.Content orderNo = printMsg.OrderNo str = "1e" const1 = "0200ff50" printInit = "1b40" //打印机初始化 //voice = "1d6b401dfd001a01015b7631365d736f756e64622cc4fad3d0d0c2b6a9b5a5c0b1" //语音,中国 //qr = "1d58021b5a0001061600747470733a2f2f7777772e62616964752e636f6d2f1b000A0A0A1B40" orderNoHexH, orderNoHexL, printData string ) //写入数据 orderNoHexH, orderNoHexL = int2h8l8(int64(orderNo)) printDataGBK, _ := jxutils.Utf8ToGbk([]byte(replaceContentOther(content))) printData = hex.EncodeToString(printDataGBK) printData = replaceContent(printData, printMsg) lenData := int64(len(str) + len(const1) + len(orderNoHexH) + len(orderNoHexL) + len(printInit) + 2 + 4 + len(printData)) x1, x2 := int2h8l8(lenData / 2) dataStr := str + x1 + x2 + const1 + orderNoHexH + orderNoHexL + printInit + printData check := getCheckSum(dataStr) return jxutils.Hextob(dataStr + check), err } func replaceContentOther(content string) string { return strings.ReplaceAll(content, "⃣️", " ") } func getCheckSum(str string) (check string) { var sum int64 for i := 0; i < len(str); i = i + 2 { b := string(str[i]) + string(str[i+1]) bt, _ := strconv.ParseInt(b, 16, 32) sum += bt } _, check = int2h8l8(sum) return check } //内容中的标签替换成指令 func replaceContent(content string, printMsg *model.PrintMsg) (result string) { var ( lenqr int hexLenqr string ) result = content for k, v := range signMap { if strings.Contains(result, k) { result = strings.ReplaceAll(result, k, v) } } if strings.Contains(result, byteSignCenter) && strings.Contains(result, byteSignCenterE) { result = strings.ReplaceAll(result, byteSignCenter, hexSignCenter) result = strings.ReplaceAll(result, byteSignCenterE, hexSignBROrEXE+hexSignLeft) } if strings.Contains(result, byteSignLeft) && strings.Contains(result, byteSignLeftE) { result = strings.ReplaceAll(result, byteSignLeft, hexSignLeft) result = strings.ReplaceAll(result, byteSignLeftE, hexSignBROrEXE+hexSignLeft) } if strings.Contains(result, byteSignRight) && strings.Contains(result, byteSignRightE) { result = strings.ReplaceAll(result, byteSignRight, hexSignRight) result = strings.ReplaceAll(result, byteSignRightE, hexSignBROrEXE+hexSignLeft) } if strings.Contains(result, byteSignBig) && strings.Contains(result, byteSignBigE) { result = strings.ReplaceAll(result, byteSignBig, hexSignBig) result = strings.ReplaceAll(result, byteSignBigE, hexSignBROrEXE+hexSignNormal) } if strings.Contains(result, byteSignHighBig) && strings.Contains(result, byteSignHighBigE) { result = strings.ReplaceAll(result, byteSignHighBig, hexSignHighBig) result = strings.ReplaceAll(result, byteSignHighBigE, hexSignBROrEXE+hexSignNormal) } if strings.Contains(result, byteSignWideBig) && strings.Contains(result, byteSignWideBigE) { result = strings.ReplaceAll(result, byteSignWideBig, hexSignWideBig) result = strings.ReplaceAll(result, byteSignWideBigE, hexSignBROrEXE+hexSignNormal) } if strings.Contains(result, byteSignQrCenter) && strings.Contains(result, byteSignQrCenterE) { if qrs := regexpQrc.FindStringSubmatch(result); len(qrs) > 0 { lenqr = len(qrs[1]) / 2 hexLenqr = fmt.Sprintf("%x", lenqr) if len(hexLenqr) < 2 { hexLenqr = "0" + hexLenqr } } result = strings.ReplaceAll(result, byteSignQrCenter, hexSignQrCenter+hexSignQr+hexLenqr+"00") result = strings.ReplaceAll(result, byteSignQrCenterE, hexSignQrEnd) } if strings.Contains(result, byteSignQrLeft) && strings.Contains(result, byteSignQrLeftE) { if qrs := regexpQrl.FindStringSubmatch(result); len(qrs) > 0 { lenqr = len(qrs[1]) / 2 hexLenqr = fmt.Sprintf("%x", lenqr) if len(hexLenqr) < 2 { hexLenqr = "0" + hexLenqr } } result = strings.ReplaceAll(result, byteSignQrLeft, hexSignQrLeft+hexSignQr+hexLenqr+"00") result = strings.ReplaceAll(result, byteSignQrLeftE, hexSignQrEnd) } if strings.Contains(result, byteSignQrRight) && strings.Contains(result, byteSignQrRightE) { if qrs := regexpQrr.FindStringSubmatch(result); len(qrs) > 0 { lenqr = len(qrs[1]) hexLenqr = fmt.Sprintf("%x", lenqr) if len(hexLenqr) < 2 { hexLenqr = "0" + hexLenqr } } result = strings.ReplaceAll(result, byteSignQrRight, hexSignQrRight+hexSignQr+hexLenqr+"00") result = strings.ReplaceAll(result, byteSignQrRightE, hexSignQrEnd) } if strings.Contains(result, byteSignSound) && strings.Contains(result, byteSignSoundE) { if sounds := regexpSound.FindStringSubmatch(result); len(sounds) > 0 { sound := sounds[1] if printer, _ := dao.GetPrinter(dao.GetDB(), printMsg.PrintNo); printer != nil { //先把结束标签消了 result = strings.ReplaceAll(result, byteSignSoundE, "") //fd 固定 //001a (声音数据长度高八位低八位) //0101 固定 soundPrefix := "" if printer.Sound != "" { soundPrefix = "[v" + utils.Int2Str(printer.Volume*2) + "]" + printer.Sound } else { soundPrefix = "[v" + utils.Int2Str(printer.Volume*2) + "]" } hexPrefix, _ := jxutils.Utf8ToGbk([]byte(soundPrefix)) hexPrefixStr := hex.EncodeToString(hexPrefix) realSound := hexPrefixStr + sound allLen := fmt.Sprintf("%x", (len("fd001a0101")+len(realSound))/2) if len(allLen) < 2 { allLen = "0" + allLen } soundLenH, soundLenX := int2h8l8(int64((len(realSound) + len("0101")) / 2)) result = strings.ReplaceAll(result, byteSignSound, hexSignSound+allLen+"fd"+soundLenH+soundLenX+"0100"+hexPrefixStr) } } } return result } func checkPrintMsg(db *dao.DaoDB, printMsg *model.PrintMsg) (err error) { if printMsg.Content == "" { return fmt.Errorf("此打印信息内容为空!printMsg printNo:[%v], orderNo :[%v]", printMsg.PrintNo, printMsg.OrderNo) } if printMsg.PrintNo == "" { return fmt.Errorf("此打印信息打印机编号为空!printMsg printNo:[%v], orderNo :[%v]", printMsg.PrintNo, printMsg.OrderNo) } if printMsg.OrderNo == 0 { return fmt.Errorf("此打印信息订单序号为空!printMsg printNo:[%v], orderNo :[%v]", printMsg.PrintNo, printMsg.OrderNo) } if printer, err := dao.GetPrinter(db, printMsg.PrintNo); err == nil { if printer != nil { if printer.FlowFlag == 1 { return fmt.Errorf("此打印机当月流量已用完,请及时充值!printNo:[%v]", printMsg.PrintNo) } } } return err } func int2h8l8(i int64) (h, l string) { origin2 := fmt.Sprintf("%b", i) flag := 16 - len(origin2) for i := 0; i < flag; i++ { origin2 = "0" + origin2 } begin8 := origin2[:8] end8 := origin2[8:] r1, _ := strconv.ParseInt(begin8, 2, 32) r2, _ := strconv.ParseInt(end8, 2, 32) h = fmt.Sprintf("%x", r1) l = fmt.Sprintf("%x", r2) if len(h) < 2 { h = "0" + h } if len(l) < 2 { l = "0" + l } return h, l } func h8l82int(h, l string) (i int64) { s1, s2 := xtob(h), xtob(l) flag1 := 8 - len(s1) flag2 := 8 - len(s2) for m := 0; m < flag1; m++ { s1 = "0" + s1 } for j := 0; j < flag2; j++ { s2 = "0" + s2 } i, _ = strconv.ParseInt(s1+s2, 2, 10) return i } func xtob(x string) string { base, _ := strconv.ParseInt(x, 16, 10) return strconv.FormatInt(base, 2) }