538 lines
16 KiB
Go
538 lines
16 KiB
Go
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 HandleTcpMessages()
|
||
go t.HandleCheckTcpHeart()
|
||
go t.doPrint2(printMsgChan)
|
||
//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)
|
||
changePrinterStatus(printNo, status)
|
||
if status == printerStatusOnline {
|
||
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)
|
||
}
|
||
}
|
||
} else if strings.Contains(data, printText) {
|
||
globals.SugarLogger.Debugf("handleConn print callback: %v", data)
|
||
_, printNo = getCallbackMsgInfo(data)
|
||
t.CallBackMap[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 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 {
|
||
printMsgChan <- 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 !t.isExist(printNo) {
|
||
return err
|
||
}
|
||
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 HandleTcpMessages() {
|
||
var (
|
||
db = dao.GetDB()
|
||
offset, pageSize = 0, 10
|
||
)
|
||
for {
|
||
//一直读?
|
||
prints, _ := dao.GetPrintMsgs(db, []int{printMsgWait}, time.Now().Add(-time.Hour*3), time.Now(), offset, pageSize)
|
||
for _, printMsg := range prints {
|
||
printMsgChan <- printMsg
|
||
printMsg.Status = printMsgAlreadyLoad
|
||
dao.UpdateEntity(db, printMsg, "Status")
|
||
}
|
||
}
|
||
}
|
||
|
||
func (t *TcpClient) doPrint2(printMsgChan chan *model.PrintMsg) (err error) {
|
||
var (
|
||
db = dao.GetDB()
|
||
)
|
||
for {
|
||
select {
|
||
case printMsg := <-printMsgChan:
|
||
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 {
|
||
fmt.Println("111111111111111111111111111111111111111111111", err)
|
||
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", "Comment")
|
||
if t.CallBackMap[printMsg.PrintNo] != nil {
|
||
t.RLock()
|
||
select {
|
||
case dataStr := <-t.CallBackMap[printMsg.PrintNo]:
|
||
a, b := getCallbackMsgInfo(dataStr)
|
||
t.changePrintMsg(dataStr, a, b)
|
||
case <-timeoutChan:
|
||
}
|
||
t.RUnlock()
|
||
|
||
}
|
||
//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)
|
||
}
|