aboutsummaryrefslogtreecommitdiff
path: root/worker.go
diff options
context:
space:
mode:
Diffstat (limited to 'worker.go')
-rw-r--r--worker.go114
1 files changed, 109 insertions, 5 deletions
diff --git a/worker.go b/worker.go
index 004e6e2..007bc52 100644
--- a/worker.go
+++ b/worker.go
@@ -4,26 +4,45 @@
package lilin
import (
+ "bytes"
+ "encoding/json"
+ "io"
"log"
+ "net/http"
"os"
"path/filepath"
"strings"
+ "time"
"git.sr.ht/~shulhan/pakakeh.go/lib/ini"
)
// worker contains the report of all services.
type worker struct {
+ // httpc client for notification for kind is mattermost.
+ httpc *http.Client
+
+ cfg ServerConfig
+
// Internal service status, where key is service name.
Services map[string]*Service `ini:"service"`
reportq chan ScanReport
+ // notifq contains queue for notification.
+ notifq chan ScanReport
+
Reports Reports
}
+type mattermostWebhook struct {
+ Channel string `json:"channel"`
+ Text string `json:"text"`
+}
+
func newWorker(cfg ServerConfig) (wrk *worker, err error) {
wrk = &worker{
+ cfg: cfg,
Services: make(map[string]*Service),
}
@@ -41,11 +60,17 @@ func newWorker(cfg ServerConfig) (wrk *worker, err error) {
return nil, err
}
}
- return wrk, nil
-}
-type serviceConfigs struct {
- Config map[string]ServiceConfig `ini:"service"`
+ for _, notifConfig := range cfg.Notifs {
+ switch notifConfig.Kind {
+ case notifKindMattermost:
+ wrk.httpc = &http.Client{
+ Timeout: 5 * time.Second,
+ }
+ }
+ }
+
+ return wrk, nil
}
// loadServiceDir Load all the service configurations.
@@ -101,12 +126,15 @@ func (wrk *worker) loadServiceDir(cfg ServerConfig) (err error) {
// Once new report coming, notify the upstream through the passed channel.
func (wrk *worker) start(updateq chan<- struct{}) {
wrk.reportq = make(chan ScanReport, len(wrk.Services)+1)
+ wrk.notifq = make(chan ScanReport, len(wrk.Services)+1)
var svc *Service
for _, svc = range wrk.Services {
- go svc.Start(wrk.reportq)
+ go svc.Start(wrk.reportq, wrk.notifq)
}
+ go wrk.handlePushNotif()
+
var scanReport ScanReport
var ok bool
for {
@@ -120,6 +148,7 @@ func (wrk *worker) start(updateq chan<- struct{}) {
}
func (wrk *worker) stop() {
+ close(wrk.notifq)
close(wrk.reportq)
var svc *Service
@@ -136,3 +165,78 @@ func (wrk *worker) stop() {
}
}
}
+
+// handlePushNotif consume the failed ScanReport from notifq to be forwarded
+// to the all notification defined in NotifConfig.
+func (wrk *worker) handlePushNotif() {
+ for scanReport := range wrk.notifq {
+ for _, notifConfig := range wrk.cfg.Notifs {
+ switch notifConfig.Kind {
+ case notifKindMattermost:
+ wrk.pushNotifMattermost(notifConfig, &scanReport)
+ }
+ }
+ }
+}
+
+func (wrk *worker) pushNotifMattermost(
+ notifConfig *NotifConfig,
+ scanReport *ScanReport,
+) {
+ var logp = `pushNotifMattermost`
+ var text strings.Builder
+ var err error
+ if scanReport.Success {
+ err = notifConfig.upTmpl.Execute(&text, scanReport)
+ if err != nil {
+ log.Printf(`%s: %s`, logp, err)
+ return
+ }
+ } else {
+ err = notifConfig.downTmpl.Execute(&text, scanReport)
+ if err != nil {
+ log.Printf(`%s: %s`, logp, err)
+ return
+ }
+ }
+
+ var msg = mattermostWebhook{
+ Channel: notifConfig.Channel,
+ Text: text.String(),
+ }
+ var body []byte
+ body, err = json.Marshal(&msg)
+ if err != nil {
+ log.Printf(`%s: %s`, logp, err)
+ return
+ }
+
+ var req = &http.Request{
+ Method: http.MethodPost,
+ URL: notifConfig.webhookURL,
+ Header: http.Header{
+ `Content-Type`: []string{
+ `application/json`,
+ },
+ },
+ Body: io.NopCloser(bytes.NewReader(body)),
+ }
+
+ var resp *http.Response
+ resp, err = wrk.httpc.Do(req)
+ if err != nil {
+ log.Printf(`%s: %s`, logp, err)
+ }
+
+ if resp.StatusCode == 200 {
+ log.Printf(`%s: send %q`, logp, body)
+ return
+ }
+
+ body, err = io.ReadAll(resp.Body)
+ if err != nil {
+ log.Printf(`%s: %s`, logp, err)
+ }
+
+ log.Printf(`%s: fail with status code %d: %s`, logp, resp.StatusCode, body)
+}