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" //过热
printerStatusOnline = 1 //在线
printerStatusOffline = -1 //离线
)
//标签
const (
//
:换行符
// :切刀指令(主动切纸,仅限切刀打印机使用才有效果)
// :打印LOGO指令(前提是预先在机器内置LOGO图片)
// :钱箱或者外置音响指令
//:居中放大
//:放大一倍
//:居中
//:字体变高一倍
//:字体变宽一倍
//:二维码(单个订单,最多只能打印一个二维码)
//:右对齐
//:字体加粗
)
var (
tcpClient = &TcpClient{}
printErrMap = map[string]string{
printErrWithoutPaper: "打印机缺纸!",
}
)
//连接的客户端,吧每个客户端都放进来
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) {
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) {
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"
orderNoHexH, orderNoHexL, printData string
)
//写入数据
content = replaceContent(content)
orderNoHexH, orderNoHexL = int2h8l8(int64(orderNo))
printDataGBK, _ := jxutils.Utf8ToGbk([]byte(content))
printData = hex.EncodeToString(printDataGBK)
lenData := int64(len(str) + len(const1) + len(orderNoHexH) + len(orderNoHexL) + len(printInit) + len(voice) + len(check) + 4 + len(printData))
x1, x2 := int2h8l8(lenData / 2)
dataStr := str + x1 + x2 + const1 + orderNoHexH + orderNoHexL + printInit + voice + printData + check
return jxutils.Hextob(dataStr), err
}
func replaceContent(content string) (result string) {
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)
}