tester-websvc-v2/TesterWebSvc.go

289 lines
6.8 KiB
Go
Raw Permalink Normal View History

2025-07-28 09:43:13 +08:00
package main
import (
"flag"
"fmt"
"html"
"io"
"log"
"net/http"
"os"
"sort"
"strings"
"time"
re2 "github.com/dlclark/regexp2"
ini "gopkg.in/ini.v1"
)
var ver string = "2.0.3"
var vsn bool = false
var cfg *ini.File
var (
uri string
server string
port string
plantCode string
funcName string
input string
output string
timeout int
debug bool = false
)
func init() {
flag.BoolVar(&vsn, "v", false, "Show Program Version")
flag.BoolVar(&debug, "d", false, "Show Debug Messages")
flag.IntVar(&timeout, "t", 10, "Timeout in Seconds")
flag.StringVar(&server, "s", "127.0.0.1", "Web Service Server")
flag.StringVar(&port, "p", "80", "Web Service Listen Port")
flag.StringVar(&plantCode, "x", "", "PlantCode Suffix in Web Service URL")
flag.StringVar(&funcName, "f", "", "Function Name")
flag.StringVar(&input, "i", "./TesterWebSvc.ini", "Input Filename")
flag.StringVar(&output, "o", "./TesterWebSvcResult.ini", "Output Filename")
flag.Parse()
}
func main() {
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
log.SetOutput(os.Stdout)
if vsn {
fmt.Printf("%s, Version: %s\r\n", os.Args[0], ver)
os.Exit(0)
}
if funcName == "" {
log.Println("[ERR] Missing Function Name.")
os.Exit(1)
}
if input == "" || output == "" {
log.Println("[ERR] Missing Input and/or Output Filename.")
os.Exit(1)
}
if plantCode != "" {
plantCode = "." + plantCode
}
uri = fmt.Sprintf("http://%s:%s/Tester.WebService%s/WebService.asmx", server, port, plantCode)
var err error
cfg, err = ini.Load(input)
if err != nil {
log.Printf("[ERR] %v\r\n", err)
os.Exit(1)
}
keys := cfg.Section("SFC").KeyStrings()
if len(keys) == 0 {
log.Printf("[ERR] Invalid Config: %s\r\n", input)
os.Exit(1)
}
args := make(map[string]string, 0)
for _, k := range keys {
v := cfg.Section("SFC").Key(k).MustString("")
args[k] = strings.TrimSpace(v)
}
if debug {
log.Printf("[MSG] WebSvcUrl:\t%s\r\n", uri)
log.Printf("[MSG] Function:\t%s\r\n", funcName)
log.Printf("[MSG] Arguments:\t%#v\r\n", args)
}
argStr := ""
for k, v := range args {
argStr = argStr + "<" + k + ">" + v + "</" + k + ">"
}
if funcName == "Complete" {
argStr = argStr + fmt.Sprintf("<TrnDatas><TrnData>%s</TrnData></TrnDatas>", args["UnitSerialNumber"])
}
result, err := _TesterWebService(funcName, argStr)
if err != nil {
log.Printf("[ERR] %#v\r\n", err)
os.Exit(1)
}
if debug {
log.Printf("[MSG] Result:\t%#v\r\n", result)
}
// 对结果集按Map的Key名称排序
resultKeys := make([]string, 0, len(result))
for k := range result {
resultKeys = append(resultKeys, k)
}
sort.Strings(resultKeys)
// 将排序后的结果集写入 Output File
content := fmt.Sprintf("[%s]\r\n", "SFC")
for _, rk := range resultKeys {
content = content + rk + "=" + result[rk] + "\r\n"
}
fo, err := os.OpenFile(output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
log.Printf("[ERR] %v\r\n", err)
os.Exit(1)
}
defer fo.Close()
_, err = fo.WriteString(content)
if err != nil {
log.Printf("[ERR] %v\r\n", err)
os.Exit(1)
}
fo.Sync()
}
func _TesterWebService(funcName string, argStr string) (map[string]string, error) {
result := make(map[string]string, 0)
xmlXSI := `"http://www.w3.org/2001/XMLSchema-instance"`
xmlXSD := `"http://www.w3.org/2001/XMLSchema"`
xmlSCH := `"http://schemas.xmlsoap.org/soap/envelope/"`
reqStr := fmt.Sprintf(`<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi=%s xmlns:xsd=%s xmlns:soap=%s>
<soap:Body>
<%s xmlns="http://localhost/Tester.WebService/WebService">
%s
</%s>
</soap:Body>
</soap:Envelope>`,
xmlXSI, xmlXSD, xmlSCH, funcName, argStr, funcName)
client := http.Client{
Timeout: time.Second * time.Duration(timeout),
}
req, err := http.NewRequest("POST", uri, strings.NewReader(reqStr))
if err != nil {
return result, err
}
defer req.Body.Close()
req.Header.Set("User-Agent", "TesterWebSvcClient-TE")
req.Header.Set("SOAPAction", "http://localhost/Tester.WebService/WebService/"+funcName)
req.Header.Set("Content-Type", "text/xml; charset=utf-8")
res, err := client.Do(req)
if err != nil {
return result, err
}
resByte, err := io.ReadAll(res.Body)
if err != nil {
return result, err
}
resStr := string(resByte)
switch funcName {
case "GetKeyInfoFromView":
result, err = _ParseInfoNameValues(resStr, funcName)
if err != nil {
result["RESULT"] = "NG, ParseInfoNameValues: " + err.Error()
return result, err
}
default:
result, err = _ParseWebServiceResult(resStr, funcName)
if err != nil {
result["RESULT"] = "NG, ParseWebServiceResult: " + err.Error()
return result, err
}
}
if len(result) == 0 {
result["RESULT"] = fmt.Sprintf("NG, %s: Empty Response.", funcName)
}
return result, nil
}
// Parse SFCS Web Service Result
func _ParseWebServiceResult(src, fnc string) (map[string]string, error) {
ret := make(map[string]string, 0)
reg, err := re2.Compile(`<(\S{1,})( xmlns=.*){0,1}>([^<>]{1,})</\1>`, 0)
if err != nil {
ret["RESULT"] = "NG"
ret["ErrMsg"] = err.Error()
return ret, err
}
tch, err := reg.FindStringMatch(src)
if err != nil {
ret["RESULT"] = "NG"
ret["ErrMsg"] = err.Error()
return ret, err
}
for tch != nil {
grp := tch.Groups()
if len(grp) == 4 {
tag := html.UnescapeString(grp[1].String())
txt := html.UnescapeString(grp[3].String())
if tag == fnc+"Result" || tag == "Result" || tag == "result" || tag == "faultstring" {
tag = "RESULT"
}
ret[tag] = txt
}
tch, _ = reg.FindNextMatch(tch)
}
return ret, nil
}
// Parse SFCS Web Service Result - InfoName Pairs
func _ParseInfoNameValues(src, fnc string) (map[string]string, error) {
ret := make(map[string]string, 0)
reg, err := re2.Compile(`<([^:]{1,})>([^<>]{1,})</\1>`, 0)
if err != nil {
ret["RESULT"] = "NG"
ret["ErrMsg"] = err.Error()
return ret, err
}
tch, err := reg.FindStringMatch(src)
if err != nil {
ret["RESULT"] = "NG"
ret["ErrMsg"] = err.Error()
return ret, err
}
for tch != nil {
grp := tch.Groups()
if len(grp) == 3 {
tag := grp[1].String()
txt := grp[2].String()
if tag == fnc+"Result" || tag == "Result" || tag == "result" || tag == "faultstring" {
tag = "RESULT"
ret[tag] = txt
}
}
tch, _ = reg.FindNextMatch(tch)
}
// Parse Info Name/Values Sets
regNV, err := re2.Compile(`<InfoName>([^<>]{1,})</InfoName>\s*<InfoValue>([^<>]{1,})</InfoValue>`, 0)
if err != nil {
ret["RESULT"] = "NG"
ret["ErrMsg"] = err.Error()
return ret, err
}
tchNV, err := regNV.FindStringMatch(src)
if err != nil {
ret["RESULT"] = "NG"
ret["ErrMsg"] = err.Error()
return ret, err
}
for tchNV != nil {
grp := tchNV.Groups()
if len(grp) == 3 {
name := html.UnescapeString(grp[1].String())
value := html.UnescapeString(grp[2].String())
if strings.TrimSpace(name) != "" {
ret[name] = value
}
}
tchNV, _ = regNV.FindNextMatch(tchNV)
}
return ret, nil
}