apiserver/ews/ews.go
2023-11-25 14:02:30 +08:00

518 lines
13 KiB
Go

package ews
import (
"APIServer/cnf"
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
)
type EWS struct{}
type UutInfo struct {
USN string
MAC string
IPAddr string
Relay string
Item string
Status string
Message string
PartNO string
MfgMO string
MfgSKU string
MfgLine string
MfgStage string
FirstAck string
LastAck string
LastChg string
LastTrn string
}
func (e *EWS) SetUutInfo(cfg cnf.Cfg, logger *log.Logger, host string, addr string, uri string, params map[string]string) map[string]string {
if cfg.Settings.LogRequest {
logger.Printf("[MSG] %s; %s; Request: %#v\r\n", addr, uri, params)
}
rst := map[string]string{"RESULT": ""}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s",
cfg.MySQL.User,
cfg.MySQL.Password,
cfg.MySQL.Server,
cfg.MySQL.Port,
cfg.MySQL.Database,
)
dbo, err := sql.Open("mysql", dsn)
if err != nil {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
defer dbo.Close()
err = dbo.Ping()
if err != nil {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
rec := dbo.QueryRow(
fmt.Sprintf(`SELECT usn,mac,ipaddr,relay,item,status,message,partno,mo,sku,line,stage,first_ack,last_ack,last_change,last_transfer
FROM uutinfo
WHERE usn='%s';`, params["USN"]))
ui := new(UutInfo)
err = rec.Scan(
&ui.USN,
&ui.MAC,
&ui.IPAddr,
&ui.Relay,
&ui.Item,
&ui.Status,
&ui.Message,
&ui.PartNO,
&ui.MfgMO,
&ui.MfgSKU,
&ui.MfgLine,
&ui.MfgStage,
&ui.FirstAck,
&ui.LastAck,
&ui.LastChg,
&ui.LastTrn,
)
//如果在uutinfo表中未查找到此USN的记录, 则新增一条此USN的记录
if err == sql.ErrNoRows {
dmlInsert := fmt.Sprintf("INSERT INTO uutinfo (usn,mac,ipaddr,relay,item,status,message,partno,mo,sku,line,stage,first_ack,last_ack,last_change) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%s,%s,%s);",
params["USN"],
params["MAC"],
addr,
host,
params["ITEM"],
params["STATUS"],
params["MESSAGE"],
params["PARTNO"],
params["MO"],
params["SKU"],
params["LINE"],
params["STAGE"],
"NOW()",
"NOW()",
"NOW()",
)
_, err = dbo.Exec(dmlInsert)
if err != nil {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
if cfg.Settings.LogResponse {
logger.Printf("[MSG] %s; %s; Response: %#v\r\n", addr, uri, rst)
}
rst["RESULT"] = "OK"
rst["ErrMsg"] = "Inserted 1 new record."
return rst
}
//如果此USN的记录存在与uutinfo表中, 且此USN的MAC/Item/Status/Message已变化, 则:
//1. 备份此USN对应记录行到uutinfobkup表
//2. 更新uutinfo表中对应USN记录的MAC/Item/Status/Message/PartNO/MO/SKU/Line/Stage
//3. 更新uutinfo表中此USN记录行的last_ack和last_change栏位为当前时间
extFlag := false
chgFlag := false
_, extFlag = params["MAC"]
if extFlag && params["MAC"] != ui.MAC {
chgFlag = true
}
_, extFlag = params["ITEM"]
if extFlag && params["ITEM"] != ui.Item {
chgFlag = true
}
_, extFlag = params["STATUS"]
if extFlag && params["STATUS"] != ui.Status {
chgFlag = true
}
_, extFlag = params["MESSAGE"]
if extFlag && params["MESSAGE"] != ui.Message {
chgFlag = true
}
if chgFlag {
tx, err := dbo.Begin()
if err != nil {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
stmt, err := tx.Prepare("INSERT INTO uutinfobkup (usn,mac,ipaddr,relay,item,status,message,partno,mo,sku,line,stage,first_ack,last_ack,last_change) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);")
if err != nil {
tx.Rollback()
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
defer stmt.Close()
_, err = stmt.Exec(
ui.USN,
ui.MAC,
addr,
host,
ui.Item,
ui.Status,
ui.Message,
ui.PartNO,
ui.MfgMO,
ui.MfgSKU,
ui.MfgLine,
ui.MfgStage,
ui.FirstAck,
ui.LastAck,
ui.LastChg,
)
if err != nil {
tx.Rollback()
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
stmt, err = tx.Prepare("UPDATE uutinfo SET mac=?, ipaddr=?, relay=?, item=?, status=?, message=?, partno=?, mo=?, sku=?, line=?, stage=?, last_ack=NOW(), last_change=NOW() WHERE usn=?;")
if err != nil {
tx.Rollback()
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
defer stmt.Close()
_, err = stmt.Exec(
params["MAC"],
addr,
host,
params["ITEM"],
params["STATUS"],
params["MESSAGE"],
params["PARTNO"],
params["MO"],
params["SKU"],
params["LINE"],
params["STAGE"],
params["USN"],
)
if err != nil {
tx.Rollback()
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
err = tx.Commit()
if err != nil {
tx.Rollback()
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
if cfg.Settings.LogResponse {
logger.Printf("[MSG] %s; %s; Response: %#v\r\n", addr, uri, rst)
}
rst["RESULT"] = "OK"
rst["ErrMsg"] = "Updated and backed up 1 record."
return rst
}
//如果此USN的记录存在与uutinfo表中, 且MAC/Item/Status/Message未变化, 则更新此USN记录的ipaddr,relay,stage, 并更新last_ack栏位为当前时间
dmlUpdate := fmt.Sprintf("UPDATE uutinfo SET ipaddr='%s', relay='%s', stage='%s', last_ack=NOW() WHERE usn='%s'",
addr, host, params["STAGE"], params["USN"])
_, err = dbo.Exec(dmlUpdate)
if err != nil {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = err.Error()
return rst
}
if cfg.Settings.LogResponse {
logger.Printf("[MSG] %s; %s; Response: %#v\r\n", addr, uri, rst)
}
rst["RESULT"] = "OK"
rst["ErrMsg"] = "Updated 1 record."
return rst
}
func (e *EWS) GetUutInfo(cfg cnf.Cfg, logger *log.Logger, host string, addr string, uri string, params map[string]string) map[string]string {
if cfg.Settings.LogRequest {
logger.Printf("[MSG] %s; %s; Request: %#v\r\n", addr, uri, params)
}
rst := map[string]string{"RESULT": ""}
if params["USN"] == "" {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, "Invalid Parameters !")
rst["RESULT"] = "NG"
rst["ErrMsg"] = e.SimpleMsgHTML("red", "Invalid Parameters !")
return rst
}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s",
cfg.MySQL.User,
cfg.MySQL.Password,
cfg.MySQL.Server,
cfg.MySQL.Port,
cfg.MySQL.Database,
)
dbo, err := sql.Open("mysql", dsn)
if err != nil {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = e.SimpleMsgHTML("red", err.Error())
return rst
}
defer dbo.Close()
err = dbo.Ping()
if err != nil {
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", addr, uri, params, err.Error())
rst["RESULT"] = "NG"
rst["ErrMsg"] = e.SimpleMsgHTML("red", err.Error())
return rst
}
ui := new(UutInfo)
partNO := ""
mfgMO := ""
mfgSKU := ""
fstAck := ""
lstAck := ""
//Get Last Record
last := ""
row := dbo.QueryRow(
fmt.Sprintf(`SELECT usn,mac,ipaddr,relay,item,status,message,partno,mo,sku,line,stage,first_ack,last_ack,last_change,last_transfer
FROM uutinfo
WHERE usn='%s';`, params["USN"]))
err = row.Scan(
&ui.USN,
&ui.MAC,
&ui.IPAddr,
&ui.Relay,
&ui.Item,
&ui.Status,
&ui.Message,
&ui.PartNO,
&ui.MfgMO,
&ui.MfgSKU,
&ui.MfgLine,
&ui.MfgStage,
&ui.FirstAck,
&ui.LastAck,
&ui.LastChg,
&ui.LastTrn,
)
if err == nil {
last = fmt.Sprintf(`<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>`,
ui.USN, ui.MAC, ui.IPAddr, ui.Relay, ui.Item, ui.Status, ui.Message, ui.LastChg)
partNO = ui.PartNO
mfgMO = ui.MfgMO
mfgSKU = ui.MfgSKU
fstAck = ui.FirstAck
lstAck = ui.LastAck
}
//Get Location Information
loc, locTime := "", ""
if last != "" {
qry := dbo.QueryRow(fmt.Sprintf(`SELECT CONCAT_WS('-',line,col,row,num) AS loc, update_time FROM locinfo WHERE mac='%s'`, ui.MAC))
qry.Scan(&loc, &locTime)
}
//Get History Records
bkup := ""
rows, err := dbo.Query(
fmt.Sprintf(`SELECT usn,mac,ipaddr,relay,item,status,message,partno,mo,sku,line,stage,first_ack,last_ack,last_change,last_transfer
FROM uutinfobkup
WHERE usn='%s' ORDER BY seqid ASC;`, params["USN"]))
if err == nil {
for rows.Next() {
err := rows.Scan(
&ui.USN,
&ui.MAC,
&ui.IPAddr,
&ui.Relay,
&ui.Item,
&ui.Status,
&ui.Message,
&ui.PartNO,
&ui.MfgMO,
&ui.MfgSKU,
&ui.MfgLine,
&ui.MfgStage,
&ui.FirstAck,
&ui.LastAck,
&ui.LastChg,
&ui.LastTrn,
)
if err != nil {
break
}
temp := fmt.Sprintf(`<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>%s`,
ui.USN, ui.MAC, ui.IPAddr, ui.Relay, ui.Item, ui.Status, ui.Message, ui.LastChg, "\r\n")
bkup = bkup + temp
}
}
defer rows.Close()
//Get Misc. Info
if partNO == "" {
partNO = ui.PartNO
}
if mfgMO == "" {
mfgMO = ui.MfgMO
}
if mfgSKU == "" {
mfgSKU = ui.MfgSKU
}
if fstAck == "" {
fstAck = ui.FirstAck
}
if lstAck == "" {
lstAck = ui.LastAck
}
misc := ""
misc = fmt.Sprintf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",
partNO, mfgMO, mfgSKU, fstAck, lstAck)
rst["RESULT"] = "OK"
rst["ErrMsg"] = e.TemplateHTML(loc, locTime, misc, last, bkup)
if cfg.Settings.LogResponse {
logger.Printf("[MSG] %s; %s; Response: Length=%s\r\n", addr, uri, rst["RESULT"])
}
return rst
}
func (e *EWS) SimpleMsgHTML(clr, msg string) string {
resp := fmt.Sprintf(`<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<head>
<style>pre {word-wrap: break-word;}</style>
<style>body {font-family: Calibri; font-size: 14px;}</style>
</head>
<body>
<br/><span style="color: %s;">%s</span><br/>
</body>
</html>`, clr, msg)
return resp
}
func (e *EWS) TemplateHTML(loc, locTime, misc, last, bkup string) string {
if loc == "" {
loc = `<span style="color: red; font-size: 14px; font-family: Consolas;">Unknown</span>`
}
if misc == "" {
misc = `<span style="color: red;">NO Records !</span>`
}
if bkup == "" {
bkup = `<span style="color: red;">NO Records !</span>`
}
resp := fmt.Sprintf(`<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test Records</title>
<style type="text/css">
table {
border: 1px solid rgb(81, 130, 187);
border-collapse: separate;
border-spacing: 0px;
position: static;
}
th {
background-color: rgb(81, 130, 187);
color: #fff;
border: 1px solid rgb(81, 130, 187);
padding: 5px 10px;
font-size: 12px;
font-family: Verdana;
font-weight: bold;
}
tr {
border: 1px solid rgb(81, 130, 187);
}
td {
color: #000;
padding: 5px 10px;
font-size: 12px;
font-family: Consolas;
}
span {
font-size: 14px;
font-family: Consolas;
}
</style>
<body>
<span style="font-weight: bold; font-size: 16px;">Location Info</span>
<table>
<tr>
<th>Location</th>
<th>Location Time</th>
</tr>
<tr>
<td>%s</td>
<td>%s</td>
</tr>
</table>
<br/>
<span style="font-weight: bold; font-size: 16px;">Misc. Info</span>
<br/>
<table>
<tr>
<th>Part NO.</th>
<th>MO</th>
<th>SKU</th>
<th>First Ack</th>
<th>Last Ack</th>
</tr>
%s
</table>
<br/>
<span style="font-weight: bold; font-size: 16px;">测试记录</span>
<br/>
<table>
<tr>
<th>USN</th>
<th>MAC</th>
<th>IP Address</th>
<th>Server</th>
<th>Test Item</th>
<th>Status</th>
<th>Message</th>
<th>Last Change</th>
</tr>
%s
%s
</table>
</body>
</html>`, loc, locTime, misc, bkup, last)
return resp
}