Files
acp/report.go
2022-12-12 01:05:31 +08:00

106 lines
2.0 KiB
Go

package acp
import (
"fmt"
"path"
"sync"
"unsafe"
jsoniter "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
)
type ReportGetter func() *Report
func NewReportGetter() (EventHandler, ReportGetter) {
var lock sync.Mutex
jobs := make(map[string]*Job, 8)
errors := make([]*Error, 0)
handler := func(ev Event) {
switch e := ev.(type) {
case *EventUpdateJob:
lock.Lock()
defer lock.Unlock()
key := path.Join(e.Job.Path...)
jobs[key] = e.Job
case *EventReportError:
lock.Lock()
defer lock.Unlock()
errors = append(errors, e.Error)
}
}
getter := func() *Report {
lock.Lock()
defer lock.Unlock()
jobsCopyed := make([]*Job, 0, len(jobs))
for _, j := range jobs {
jobsCopyed = append(jobsCopyed, j)
}
errorsCopyed := make([]*Error, 0, len(jobs))
errorsCopyed = append(errorsCopyed, errors...)
return &Report{
Jobs: jobsCopyed,
Errors: errorsCopyed,
}
}
return handler, getter
}
type Report struct {
Jobs []*Job `json:"files,omitempty"`
Errors []*Error `json:"errors,omitempty"`
}
func (r *Report) ToJSONString(indent bool) string {
if indent {
buf, _ := reportJSON.MarshalIndent(r, "", "\t")
return string(buf)
}
buf, _ := reportJSON.Marshal(r)
return string(buf)
}
var (
reportJSON jsoniter.API
)
type errValCoder struct{}
func (*errValCoder) IsEmpty(ptr unsafe.Pointer) bool {
val := (*error)(ptr)
return *val == nil
}
func (*errValCoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
val := (*error)(ptr)
stream.WriteString((*val).Error())
}
func (*errValCoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
val := (*error)(ptr)
*val = fmt.Errorf(iter.ReadString())
}
func init() {
reportJSON = jsoniter.Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
}.Froze()
var emptyErr error
reportJSON.RegisterExtension(jsoniter.EncoderExtension{
reflect2.TypeOf(emptyErr): &errValCoder{},
})
reportJSON.RegisterExtension(jsoniter.DecoderExtension{
reflect2.TypeOf(emptyErr): &errValCoder{},
})
}