393 lines
12 KiB
Go
393 lines
12 KiB
Go
package event
|
||
|
||
import (
|
||
"encoding/hex"
|
||
"fmt"
|
||
"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"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
const (
|
||
heartText = "1e000f02000151"
|
||
printText = "1e00180200"
|
||
printSuccessText = "1e001802000150"
|
||
|
||
printErrWithoutPaper = "05"
|
||
|
||
printMsgAlreadySend = 2 //已经发出打印消息
|
||
printMsgSuccess = 1 //打印成功
|
||
printMsgWait = 0 //待打印
|
||
printMsgFail = -1 //打印失败(打印机报出)
|
||
printMsgErr = -2 //京西报出
|
||
|
||
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>" //二维码居右
|
||
|
||
hexSignCenter = "1b6101"
|
||
hexSignLeft = "1b6100"
|
||
hexSignRight = "1b6102"
|
||
hexSignNormal = "1b2100"
|
||
hexSignBig = "1b2130"
|
||
hexSignHighBig = "1b2110"
|
||
hexSignWideBig = "1b2120"
|
||
hexSignQrCenter = "1d5802"
|
||
hexSignQrLeft = "1d5800"
|
||
hexSignQrRight = "1d5804"
|
||
hexSignQr = "1b5a0001061600"
|
||
hexSignQrEnd = "000a0a0a1b40"
|
||
|
||
byteSignBR = "3c62723e" //换行
|
||
byteSignCenter = "3c63656e7465723e" //居中
|
||
byteSignLeft = "3c6c6566743e" //居左
|
||
byteSignRight = "3c72696768743e" //居右
|
||
byteSignBig = "3c623e" //字体放大
|
||
byteSignHighBig = "3c68623e" //字体纵向放大
|
||
byteSignWideBig = "3c77623e" //字体横向放大
|
||
byteSignQrCenter = "3c7172633e"
|
||
byteSignQrLeft = "3c71726c3e"
|
||
byteSignQrRight = "3c7172723e"
|
||
|
||
byteSignCenterE = "3c2f63656e7465723e" //居中
|
||
byteSignLeftE = "3c2f6c6566743e" //居左
|
||
byteSignRightE = "3c2f72696768743e" //居右
|
||
byteSignBigE = "3c2f623e" //字体放大
|
||
byteSignHighBigE = "3c2f68623e" //字体纵向放大
|
||
byteSignWideBigE = "3c2f77623e" //字体横向放大
|
||
byteSignQrCenterE = "3c2f7172633e"
|
||
byteSignQrLeftE = "3c2f71726c3e"
|
||
byteSignQrRightE = "3c2f7172723e"
|
||
)
|
||
|
||
var (
|
||
tcpClient = &TcpClient{}
|
||
|
||
printErrMap = map[string]string{
|
||
printErrWithoutPaper: "打印机缺纸!",
|
||
}
|
||
|
||
signMap = map[string]string{
|
||
byteSignBR: "0a",
|
||
}
|
||
)
|
||
|
||
//连接的客户端,吧每个客户端都放进来
|
||
type TcpClient struct {
|
||
Clients map[string]net.Conn
|
||
s *sync.RWMutex
|
||
}
|
||
|
||
func ListenTcp() {
|
||
tcpClient.Clients = make(map[string]net.Conn)
|
||
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 //打印机编号
|
||
)
|
||
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
|
||
}
|
||
//看是心跳还是打印返回
|
||
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 {
|
||
tcpClient.Clients[printNo] = c
|
||
} else {
|
||
//改变打印机状态
|
||
changePrinterStatus(printNo, printerStatusOnline)
|
||
}
|
||
} else if strings.Contains(data, printText) {
|
||
globals.SugarLogger.Debugf("handleConn print: %v", data)
|
||
changePrintMsg(data)
|
||
}
|
||
}
|
||
}
|
||
|
||
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, 10
|
||
)
|
||
for {
|
||
//一直读?
|
||
var err error
|
||
time.Sleep(time.Second / 2)
|
||
prints, _ := dao.GetPrintMsgs(db, printMsgWait, 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 {
|
||
c = tcpClient.Clients[printMsg.PrintNo]
|
||
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)
|
||
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 = "1b59415501" //语音响一次
|
||
check = "ff"
|
||
qr = "1d58021b5a0001061600747470733a2f2f7777772e62616964752e636f6d2f1b000A0A0A1B400a0a1b402d2d2d2d2d2d2d2d62626161616161616161"
|
||
orderNoHexH, orderNoHexL, printData string
|
||
)
|
||
//写入数据
|
||
orderNoHexH, orderNoHexL = int2h8l8(int64(orderNo))
|
||
printDataGBK, _ := jxutils.Utf8ToGbk([]byte(content))
|
||
printData = hex.EncodeToString(printDataGBK)
|
||
printData = replaceContent(printData)
|
||
lenData := int64(len(str) + len(const1) + len(orderNoHexH) + len(orderNoHexL) + len(printInit) + len(voice) + len(check) + 4 + len(printData) + len(qr))
|
||
x1, x2 := int2h8l8(lenData / 2)
|
||
dataStr := str + x1 + x2 + const1 + orderNoHexH + orderNoHexL + printInit + voice + printData + qr + check
|
||
return jxutils.Hextob(dataStr), err
|
||
}
|
||
|
||
//内容中的标签替换成指令
|
||
func replaceContent(content string) (result 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, hexSignLeft)
|
||
}
|
||
if strings.Contains(result, byteSignLeft) && strings.Contains(result, byteSignLeftE) {
|
||
result = strings.ReplaceAll(result, byteSignLeft, hexSignLeft)
|
||
result = strings.ReplaceAll(result, byteSignLeftE, hexSignLeft)
|
||
}
|
||
if strings.Contains(result, byteSignRight) && strings.Contains(result, byteSignRightE) {
|
||
result = strings.ReplaceAll(result, byteSignRight, hexSignRight)
|
||
result = strings.ReplaceAll(result, byteSignRightE, hexSignLeft)
|
||
}
|
||
if strings.Contains(result, byteSignBig) && strings.Contains(result, byteSignBigE) {
|
||
result = strings.ReplaceAll(result, byteSignBig, hexSignBig)
|
||
result = strings.ReplaceAll(result, byteSignBigE, hexSignNormal)
|
||
}
|
||
if strings.Contains(result, byteSignHighBig) && strings.Contains(result, byteSignHighBigE) {
|
||
result = strings.ReplaceAll(result, byteSignHighBig, hexSignHighBig)
|
||
result = strings.ReplaceAll(result, byteSignHighBigE, hexSignNormal)
|
||
}
|
||
if strings.Contains(result, byteSignWideBig) && strings.Contains(result, byteSignWideBigE) {
|
||
result = strings.ReplaceAll(result, byteSignWideBig, hexSignWideBig)
|
||
result = strings.ReplaceAll(result, byteSignWideBigE, hexSignNormal)
|
||
}
|
||
if strings.Contains(result, byteSignQrCenter) && strings.Contains(result, byteSignQrCenterE) {
|
||
result = strings.ReplaceAll(result, byteSignQrCenter, hexSignQrCenter+hexSignQr)
|
||
result = strings.ReplaceAll(result, byteSignQrCenterE, hexSignQrEnd)
|
||
}
|
||
if strings.Contains(result, byteSignQrLeft) && strings.Contains(result, byteSignQrLeftE) {
|
||
result = strings.ReplaceAll(result, byteSignQrLeft, hexSignQrLeft+hexSignQr)
|
||
result = strings.ReplaceAll(result, byteSignQrLeftE, hexSignQrEnd)
|
||
}
|
||
if strings.Contains(result, byteSignQrRight) && strings.Contains(result, byteSignQrRightE) {
|
||
result = strings.ReplaceAll(result, byteSignQrRight, hexSignQrRight+hexSignQr)
|
||
result = strings.ReplaceAll(result, byteSignQrRightE, hexSignQrEnd)
|
||
}
|
||
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)
|
||
}
|