Files
jx-callback/business/jxstore/event/event_tcp.go
suyl fee78529dd aa
2021-07-09 15:59:26 +08:00

529 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
const (
heartText = "1e000f02000151"
printText = "1e00180200"
printSuccessText = "1e001802000150"
printErrWithoutPaper = "05"
printMsgAlreadySend = 2 //已经发出打印消息
printMsgSuccess = 1 //打印成功
printMsgWait = 0 //待打印
printMsgFail = -1 //打印失败(打印机报出)
printMsgErr = -2 //京西报出
heartErrNormal = "00" //正常
heartErrWithoutPaper = "04" //心跳错,缺纸
heartErrHot = "08" //过热
printerStatusOnlineWithoutPaper = 2 //在线缺纸
printerStatusOnline = 1 //在线
printerStatusOffline = -1 //离线
)
//标签
const (
signBR = "<br>" //换行
signCenter = "<center>" //居中
signLeft = "<left>" //居左
signRight = "<right>" //居右
signBig = "<b>" //字体放大
signHighBig = "<hb>" //字体纵向放大
signWideBig = "<wb>" //字体横向放大
signQrCenter = "<qrc>" //二维码居中
signQrLeft = "<qrl>" //二维码居左
signQrRight = "<qrr>" //二维码居右
signSound = "<sound>" //声音
hexSignBROrEXE = "0a"
hexSignCenter = "1b6101"
hexSignLeft = "1b6100"
hexSignRight = "1b6102"
hexSignNormal = "1b2100"
hexSignBig = "1b2130"
hexSignHighBig = "1b2110"
hexSignWideBig = "1b2120"
hexSignQrCenter = "1d5802"
hexSignQrLeft = "1d5800"
hexSignQrRight = "1d5804"
hexSignQr = "1b5a000106" //"1b5a000106" 0600 : 后面二维码的字节数
hexSignQrEnd = "000a1b40" //000a0a0a1b40
hexSignSound = "1d6b40"
byteSignBR = "3c62723e" //换行
byteSignCenter = "3c63656e7465723e" //居中
byteSignLeft = "3c6c6566743e" //居左
byteSignRight = "3c72696768743e" //居右
byteSignBig = "3c623e" //字体放大
byteSignHighBig = "3c68623e" //字体纵向放大
byteSignWideBig = "3c77623e" //字体横向放大
byteSignQrCenter = "3c7172633e"
byteSignQrLeft = "3c71726c3e"
byteSignQrRight = "3c7172723e"
byteSignSound = "3c736f756e643e"
byteSignCenterE = "3c2f63656e7465723e" //居中
byteSignLeftE = "3c2f6c6566743e" //居左
byteSignRightE = "3c2f72696768743e" //居右
byteSignBigE = "3c2f623e" //字体放大
byteSignHighBigE = "3c2f68623e" //字体纵向放大
byteSignWideBigE = "3c2f77623e" //字体横向放大
byteSignQrCenterE = "3c2f7172633e"
byteSignQrLeftE = "3c2f71726c3e"
byteSignQrRightE = "3c2f7172723e"
byteSignSoundE = "3c2f736f756e643e"
)
var (
tcpClient = &TcpClient{}
printErrMap = map[string]string{
printErrWithoutPaper: "打印机缺纸!",
}
signMap = map[string]string{
byteSignBR: hexSignBROrEXE,
}
regexpQrc = regexp.MustCompile(byteSignQrCenter + "(.*?)" + byteSignQrCenterE)
regexpQrl = regexp.MustCompile(byteSignQrLeft + "(.*?)" + byteSignQrLeftE)
regexpQrr = regexp.MustCompile(byteSignQrRight + "(.*?)" + byteSignQrRightE)
regexpSound = regexp.MustCompile(byteSignSound + "(.*?)" + byteSignSoundE)
)
type PrintInfo struct {
C net.Conn
Status int // 2 //在线缺纸 1 //在线 -1 //离线
}
//连接的客户端,吧每个客户端都放进来
type TcpClient struct {
Clients map[string]*PrintInfo
s *sync.RWMutex
}
type GetPrintStatus struct {
PrintNo string //打印机编号
AppID int
}
func ListenTcp() {
tcpClient.Clients = make(map[string]*PrintInfo)
l, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println("listen error:", err)
return
}
globals.SugarLogger.Debugf("begin listenTcp port 8000......")
go HandleTcpMessages()
for {
c, err := l.Accept()
if err != nil {
fmt.Println("accept error:", err)
break
}
go handleConn(c)
}
}
func 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: %v", string(buffer[:n]))
if printStatus != nil {
var status int
if tcpClient.Clients[printStatus.PrintNo] != nil {
status = tcpClient.Clients[printStatus.PrintNo].Status
} else {
status = printerStatusOffline
}
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)
if tcpClient.Clients[printNo] == nil {
printInfo := &PrintInfo{
C: c,
Status: printStatus2JxStatus(data[len(data)-8 : len(data)-6]),
}
tcpClient.Clients[printNo] = printInfo
//新开机的打印失败和错误的
var (
db = dao.GetDB()
)
prints, _ := dao.GetPrintMsgsFail(db, time.Now().Add(-time.Hour*3), time.Now())
for _, printMsg := range prints {
var (
data []byte
c net.Conn
)
if printMsg != nil {
if err = checkPrintMsg(printMsg); err == nil {
if c != nil {
if _, err = c.Write(data); err != nil {
globals.SugarLogger.Debugf("handleTcpMessages err [%v]", err)
delete(tcpClient.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")
}
}
}
}
}
} else {
//改变打印机状态
//changePrinterStatus(printNo, printerStatusOnline)
if tcpClient.Clients[printNo] != nil {
status := printStatus2JxStatus(data[len(data)-8 : len(data)-6])
if tcpClient.Clients[printNo].Status != status {
tcpClient.Clients[printNo].Status = status
}
}
}
} else if strings.Contains(data, printText) {
globals.SugarLogger.Debugf("handleConn print: %v", data)
changePrintMsg(data)
}
}
}
func printStatus2JxStatus(printStatus string) (status int) {
if printStatus == heartErrWithoutPaper {
return printerStatusOnlineWithoutPaper
} else if printStatus == heartErrNormal {
return printerStatusOnline
}
return status
}
func changePrintMsg(data string) (err error) {
var (
db = dao.GetDB()
printNo, comment string
orderNo int64
status int
printMsg = &model.PrintMsg{}
)
//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 tcpClient.Clients[printNo] == nil {
return err
}
if printMsg, err = dao.GetPrintMsg(db, printNo, orderNo); err != nil {
globals.SugarLogger.Debugf("changePrintMsg err :[%v]", err)
return
} else if printMsg == nil {
globals.SugarLogger.Debugf("changePrintMsg err ,not found printMsg printNo:[%v], orderNo :[%v]", printNo, orderNo)
} else if printMsg.Status != status {
printMsg.Comment = comment
printMsg.Status = status
dao.UpdateEntity(db, printMsg, "Comment", "Status")
}
return err
}
func HandleTcpMessages() {
var (
db = dao.GetDB()
offset, pageSize = 0, 1
)
for {
//一直读?
var err error
time.Sleep(time.Second / 2)
prints, _ := dao.GetPrintMsgs(db, []int{printMsgWait, printMsgAlreadySend}, time.Now().Add(-time.Hour*3), time.Now(), offset, pageSize)
for _, printMsg := range prints {
var (
data []byte
c net.Conn
)
if printMsg != nil {
if err = checkPrintMsg(printMsg); err == nil {
if tcpClient.Clients[printMsg.PrintNo] != nil {
if tcpClient.Clients[printMsg.PrintNo].C != nil {
c = tcpClient.Clients[printMsg.PrintNo].C
data, err = buildMsg(printMsg)
}
}
//else {
// changePrinterStatus(printMsg.PrintNo, printerStatusOffline)
//}
}
} else {
err = fmt.Errorf("未查询到此printMsg")
}
if err != nil {
printMsg.Status = printMsgErr
printMsg.Comment = err.Error()
dao.UpdateEntity(db, printMsg, "Status", "Comment")
delete(tcpClient.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)
delete(tcpClient.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")
}
}
}
}
}
}
func changePrinterStatus(printNo string, status int) (err error) {
var (
printer = &model.Printer{}
db = dao.GetDB()
)
sql := `
SELECT * FROM printer WHERE print_no = ?
`
sqlParams := []interface{}{printNo}
if err = dao.GetRow(db, printer, sql, sqlParams); err == nil {
if printer.ID != 0 {
if printer.Status != status {
dao.UpdateEntity(db, printer, "Status")
}
}
}
return err
}
func buildMsg(printMsg *model.PrintMsg) (data []byte, err error) {
var (
content = printMsg.Content
orderNo = printMsg.OrderNo
str = "1e"
const1 = "0200ff50"
printInit = "1b40" //打印机初始化
//voice = "1d6b401dfd001a01015b7631365d736f756e64622cc4fad3d0d0c2b6a9b5a5c0b1" //语音,中国
check = "ff"
//qr = "1d58021b5a0001061600747470733a2f2f7777772e62616964752e636f6d2f1b000A0A0A1B40"
orderNoHexH, orderNoHexL, printData string
)
//写入数据
orderNoHexH, orderNoHexL = int2h8l8(int64(orderNo))
printDataGBK, _ := jxutils.Utf8ToGbk([]byte(content))
printData = hex.EncodeToString(printDataGBK)
printData = replaceContent(printData, printMsg)
lenData := int64(len(str) + len(const1) + len(orderNoHexH) + len(orderNoHexL) + len(printInit) + len(check) + len(hexSignBROrEXE) + 4 + len(printData))
x1, x2 := int2h8l8(lenData / 2)
dataStr := str + x1 + x2 + const1 + orderNoHexH + orderNoHexL + printInit + printData + hexSignBROrEXE + check
return jxutils.Hextob(dataStr), err
}
//内容中的标签替换成指令
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 固定
soundPerfix := "[v" + utils.Int2Str(printer.Volume*2) + "]" + printer.Sound + ","
hexPrefix, _ := jxutils.Utf8ToGbk([]byte(soundPerfix))
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+"0101"+hexPrefixStr)
}
}
}
return result
}
func checkPrintMsg(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)
}
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)
}