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 + "" } if funcName == "Complete" { argStr = argStr + fmt.Sprintf("%s", 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(` <%s xmlns="http://localhost/Tester.WebService/WebService"> %s `, 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,})`, 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,})`, 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(`([^<>]{1,})\s*([^<>]{1,})`, 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 }