package parser import ( "encoding/json" "fmt" "io/ioutil" "strings" ) type jsonObject map[string]interface{} type jsonArray []interface{} type Request struct { Log []string `json:"log"` Sheet Sheet `json:"sheet"` } type Sheet struct { LogID string `json:"log_id"` Date string `json:"date"` Target string `json:"target"` Memory string `json:"memory"` StartLine string `json:"start_line"` Hardware []SheetEntry `json:"hardware"` OS []SheetEntry `json:"os"` Device []SheetEntry `json:"device"` } type SheetEntry struct { Title string `json:"title"` Check [][]string `json:"check"` ErrorMessage []string `json:"error_message"` } type Parser struct { InChan chan string OutChan chan jsonObject } func New() *Parser { parser := &Parser{} return parser } func (p *Parser) Parse(request *Request) string { p.start() for _, line := range request.Log { p.InChan <- line } p.stop() return p.makeResult(request.Sheet) } func (p *Parser) start() { p.InChan = make(chan string, 100) p.OutChan = make(chan jsonObject, 1) // Go parse functions inputChanList := make([]chan string, len(parseFuncList)) outputChanList := make([]chan jsonObject, len(parseFuncList)) for i, parseFunc := range parseFuncList { f := parseFunc inputChan := make(chan string, 10) outputChan := make(chan jsonObject, 1) inputChanList[i] = inputChan outputChanList[i] = outputChan go func() { defer func() { if r := recover(); r != nil { //p.Fatal("Internal Error", r, string(debug.Stack())) } for range inputChan { } close(outputChan) }() f(inputChan, outputChan) }() } // Broadcast input go func() { for input := range p.InChan { for _, inputChan := range inputChanList { inputChan <- input } } for _, inputChan := range inputChanList { close(inputChan) } }() // Merge output go func() { output := make(jsonObject) for _, outputChan := range outputChanList { for parsed := range outputChan { output[parsed["type"].(string)] = parsed } } p.OutChan <- output close(p.OutChan) }() } func (p *Parser) stop() { close(p.InChan) } func (p *Parser) makeReport(result jsonObject, checklist []SheetEntry) ([]jsonObject, bool) { var report []jsonObject totalPass := true for _, entry := range checklist { reportEntry := make(jsonObject) reportEntry["title"] = entry.Title pass := true for _, c := range entry.Check { o, ok := result[c[0]].(jsonObject) if !ok { reportEntry["result"] = "FAIL" reportEntry["message"] = entry.ErrorMessage[0] pass = false break } switch o[c[1]].(type) { case string: if len(c[2]) > 0 { v, ok := o[c[1]].(string) if !ok { reportEntry["result"] = "FAIL" reportEntry["message"] = entry.ErrorMessage[0] pass = false break } if strings.Compare(v, c[2]) != 0 { reportEntry["result"] = "FAIL" reportEntry["message"] = entry.ErrorMessage[0] pass = false break } } case []string: if len(c[2]) > 0 { l, ok := o[c[1]].([]string) if !ok { reportEntry["result"] = "FAIL" reportEntry["message"] = entry.ErrorMessage[0] pass = false break } found := false for _, v := range l { if strings.Compare(v, c[2]) == 0 { found = true } } if !found { reportEntry["result"] = "FAIL" reportEntry["message"] = entry.ErrorMessage[0] pass = false break } } case []jsonObject: if len(c[2]) > 0 { list, ok := o[c[1]].([]jsonObject) if !ok { reportEntry["result"] = "FAIL" reportEntry["message"] = entry.ErrorMessage[0] pass = false break } found := false for _, v := range list { label := v["label"].(string) if strings.Compare(label, c[2]) == 0 { found = true } } if !found { reportEntry["result"] = "FAIL" reportEntry["message"] = entry.ErrorMessage[0] pass = false break } } default: fmt.Printf("%v fail (type: %T)\n", c[1], o[c[1]]) reportEntry["result"] = "FAIL" pass = false } } if pass { reportEntry["result"] = "PASS" } else { totalPass = false } report = append(report, reportEntry) } return report, totalPass } func (p *Parser) makeResult(sheet Sheet) string { output := make(jsonObject) result := <-p.OutChan report := make(jsonObject) pass := true totalPass := true result["memory_size"] = sheet.Memory report["log_id"] = sheet.LogID report["date"] = sheet.Date report["target"] = sheet.Target report["hardware"], pass = p.makeReport(result, sheet.Hardware) totalPass = totalPass && pass report["os"], pass = p.makeReport(result, sheet.OS) totalPass = totalPass && pass report["device"], pass = p.makeReport(result, sheet.Device) totalPass = totalPass && pass if totalPass { report["pass"] = "PASS" } output["result"] = result output["report"] = report b, err := json.MarshalIndent(output, "", " ") if err == nil { ioutil.WriteFile("anal-kernel-response.json", b, 0644) } return string(b) }