| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"log" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"os/exec" | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func usage() { | 
					
						
							| 
									
										
										
										
											2019-06-10 03:22:00 -06:00
										 |  |  | 	fmt.Println("Usage: watchdog -c config.json") | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func main() { | 
					
						
							|  |  |  | 	if 3 != len(os.Args) { | 
					
						
							|  |  |  | 		usage() | 
					
						
							|  |  |  | 		os.Exit(1) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if "-c" != os.Args[1] { | 
					
						
							|  |  |  | 		usage() | 
					
						
							|  |  |  | 		os.Exit(1) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	filename := os.Args[2] | 
					
						
							|  |  |  | 	f, err := os.Open(filename) | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							|  |  |  | 		log.Fatal(err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	configFile, err := ioutil.ReadAll(f) | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							|  |  |  | 		log.Fatal(err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config := &Config{} | 
					
						
							|  |  |  | 	err = json.Unmarshal(configFile, config) | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							|  |  |  | 		log.Fatal(err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//fmt.Printf("%#v\n", config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	done := make(chan struct{}, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	allWebhooks := make(map[string]ConfigWebhook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := range config.Webhooks { | 
					
						
							|  |  |  | 		h := config.Webhooks[i] | 
					
						
							|  |  |  | 		allWebhooks[h.Name] = h | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	logQueue := make(chan string, 10) | 
					
						
							|  |  |  | 	go logger(logQueue) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	for i := range config.Watches { | 
					
						
							|  |  |  | 		c := config.Watches[i] | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		logQueue <- fmt.Sprintf("Watching '%s'", c.Name) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		go func(c ConfigWatch) { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			d := New(&Dog{ | 
					
						
							|  |  |  | 				Name:        c.Name, | 
					
						
							|  |  |  | 				CheckURL:    c.URL, | 
					
						
							|  |  |  | 				Keywords:    c.Keywords, | 
					
						
							|  |  |  | 				Recover:     c.RecoverScript, | 
					
						
							|  |  |  | 				Webhooks:    c.Webhooks, | 
					
						
							|  |  |  | 				AllWebhooks: allWebhooks, | 
					
						
							|  |  |  | 				logger:      logQueue, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			d.Watch() | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		}(config.Watches[i]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if 0 == len(config.Watches) { | 
					
						
							|  |  |  | 		log.Fatal("Nothing to watch") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	<-done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Dog struct { | 
					
						
							|  |  |  | 	Name         string | 
					
						
							|  |  |  | 	CheckURL     string | 
					
						
							|  |  |  | 	Keywords     string | 
					
						
							|  |  |  | 	Recover      string | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	Webhooks     []string | 
					
						
							|  |  |  | 	AllWebhooks  map[string]ConfigWebhook | 
					
						
							|  |  |  | 	logger       chan string | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	error        error | 
					
						
							|  |  |  | 	failures     int | 
					
						
							|  |  |  | 	passes       int | 
					
						
							|  |  |  | 	lastFailed   time.Time | 
					
						
							|  |  |  | 	lastPassed   time.Time | 
					
						
							|  |  |  | 	lastNotified time.Time | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | func New(d *Dog) *Dog { | 
					
						
							|  |  |  | 	d.lastPassed = time.Now().Add(-5 * time.Minute) | 
					
						
							|  |  |  | 	return d | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | func (d *Dog) Watch() { | 
					
						
							|  |  |  | 	d.watch() | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		// TODO set cancellable callback ? | 
					
						
							|  |  |  | 		time.Sleep(5 * time.Minute) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		d.watch() | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | func (d *Dog) watch() { | 
					
						
							|  |  |  | 	d.logger <- fmt.Sprintf("Check: '%s'", d.Name) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	err := d.check() | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	if nil == err { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	failure := false | 
					
						
							|  |  |  | 	t := 10 | 
					
						
							|  |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		d.recover() | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		time.Sleep(time.Duration(t) * time.Second) | 
					
						
							|  |  |  | 		// backoff | 
					
						
							|  |  |  | 		t *= 2 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		err := d.check() | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		if nil != err { | 
					
						
							|  |  |  | 			failure = true | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			failure = false | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		// We should notify if | 
					
						
							|  |  |  | 		// * We've had success since the last notification | 
					
						
							|  |  |  | 		// * It's been at least 5 minutes since the last notification | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		fiveMinutesAgo := time.Now().Add(-5 * time.Minute) | 
					
						
							|  |  |  | 		if d.lastPassed.After(d.lastNotified) && d.lastNotified.Before(fiveMinutesAgo) { | 
					
						
							|  |  |  | 			d.notify(failure) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 		if !failure || d.failures >= 5 { | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 			// go back to the main 5-minute loop | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | func (d *Dog) check() error { | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	var err error | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if nil != err { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			d.failures += 1 | 
					
						
							|  |  |  | 			d.lastFailed = time.Now() | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			d.lastPassed = time.Now() | 
					
						
							|  |  |  | 			d.passes += 1 | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	client := NewHTTPClient() | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	response, err := client.Get(d.CheckURL) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	if nil != err { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		d.error = fmt.Errorf("Connection Failure: " + err.Error()) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b, err := ioutil.ReadAll(response.Body) | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		d.error = fmt.Errorf("Network Failure: " + err.Error()) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	if !bytes.Contains(b, []byte(d.Keywords)) { | 
					
						
							|  |  |  | 		err = fmt.Errorf("Down: '%s' Not Found for '%s'", d.Keywords, d.Name) | 
					
						
							|  |  |  | 		d.logger <- fmt.Sprintf("%s", err) | 
					
						
							|  |  |  | 		d.error = err | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		d.logger <- fmt.Sprintf("Up: '%s'", d.Name) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | func (d *Dog) recover() { | 
					
						
							|  |  |  | 	if "" == d.Recover { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | 
					
						
							|  |  |  | 	cmd := exec.CommandContext(ctx, "bash") | 
					
						
							|  |  |  | 	pipe, err := cmd.StdinPipe() | 
					
						
							|  |  |  | 	pipe.Write([]byte(d.Recover)) | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							|  |  |  | 		d.logger <- fmt.Sprintf("[Recover] Could not write to bash '%s': %s", d.Recover, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = cmd.Start() | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							|  |  |  | 		d.logger <- fmt.Sprintf("[Recover] Could not start '%s': %s", d.Recover, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = pipe.Close() | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							|  |  |  | 		d.logger <- fmt.Sprintf("[Recover] Could not close '%s': %s", d.Recover, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = cmd.Wait() | 
					
						
							|  |  |  | 	cancel() | 
					
						
							|  |  |  | 	if nil != err { | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 		d.logger <- fmt.Sprintf("[Recover] '%s' failed for '%s': %s", d.Recover, d.Name, err) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *Dog) notify(hardFail bool) { | 
					
						
							|  |  |  | 	d.logger <- fmt.Sprintf("Notifying the authorities of %s's failure", d.Name) | 
					
						
							|  |  |  | 	d.lastNotified = time.Now() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := range d.Webhooks { | 
					
						
							|  |  |  | 		name := d.Webhooks[i] | 
					
						
							|  |  |  | 		if "" == name { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		h, ok := d.AllWebhooks[name] | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			// TODO check in main when config is read | 
					
						
							|  |  |  | 			d.Webhooks[i] = "" | 
					
						
							|  |  |  | 			d.logger <- fmt.Sprintf("[Warning] Could not find webhook '%s' for '%s'", name, h.Name) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// TODO do this in main on config init | 
					
						
							|  |  |  | 		if "" == h.Method { | 
					
						
							|  |  |  | 			h.Method = "POST" | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var body *strings.Reader | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 		var err error | 
					
						
							|  |  |  | 		// TODO real templates | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		if 0 != len(h.Form) { | 
					
						
							|  |  |  | 			form := url.Values{} | 
					
						
							|  |  |  | 			for k := range h.Form { | 
					
						
							|  |  |  | 				v := h.Form[k] | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 				// because `{{` gets urlencoded | 
					
						
							|  |  |  | 				//k = strings.Replace(k, "{{ .Name }}", d.Name, -1) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 				v = strings.Replace(v, "{{ .Name }}", d.Name, -1) | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 				d.logger <- fmt.Sprintf("[HEADER] %s: %s", k, v) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 				form.Set(k, v) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			body = strings.NewReader(form.Encode()) | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 		} else if 0 != len(h.JSON) { | 
					
						
							|  |  |  | 			bodyBuf, err := json.Marshal(h.JSON) | 
					
						
							|  |  |  | 			if nil != err { | 
					
						
							|  |  |  | 				d.logger <- fmt.Sprintf("[Notify] JSON Marshal Error for '%s': %s", h.Name, err) | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// `{{` should be left alone | 
					
						
							|  |  |  | 			body = strings.NewReader(strings.Replace(string(bodyBuf), "{{ .Name }}", d.Name, -1)) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		client := NewHTTPClient() | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		req, err := http.NewRequest(h.Method, h.URL, body) | 
					
						
							|  |  |  | 		if nil != err { | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 			d.logger <- fmt.Sprintf("[Notify] HTTP Client Network Error for '%s': %s", h.Name, err) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if 0 != len(h.Form) { | 
					
						
							| 
									
										
										
										
											2019-06-09 02:04:23 -06:00
										 |  |  | 			req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 		} else if 0 != len(h.JSON) { | 
					
						
							|  |  |  | 			req.Header.Set("Content-Type", "application/json") | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if 0 != len(h.Auth) { | 
					
						
							|  |  |  | 			user := h.Auth["user"] | 
					
						
							| 
									
										
										
										
											2019-06-09 02:04:23 -06:00
										 |  |  | 			if "" == user { | 
					
						
							|  |  |  | 				user = h.Auth["username"] | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			pass := h.Auth["pass"] | 
					
						
							| 
									
										
										
										
											2019-06-09 02:04:23 -06:00
										 |  |  | 			if "" == user { | 
					
						
							|  |  |  | 				pass = h.Auth["password"] | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			req.SetBasicAuth(user, pass) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-09 02:04:23 -06:00
										 |  |  | 		req.Header.Set("User-Agent", "Watchdog/1.0") | 
					
						
							|  |  |  | 		for k := range h.Headers { | 
					
						
							|  |  |  | 			req.Header.Set(k, h.Headers[k]) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		resp, err := client.Do(req) | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		if nil != err { | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 			d.logger <- fmt.Sprintf("[Notify] HTTP Client Error for '%s': %s", h.Name, err) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if !(resp.StatusCode >= 200 && resp.StatusCode < 300) { | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 			d.logger <- fmt.Sprintf("[Notify] Response Error for '%s': %s", h.Name, resp.Status) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// TODO json vs xml vs txt | 
					
						
							|  |  |  | 		var data map[string]interface{} | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		req.Header.Add("Accept", "application/json") | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		decoder := json.NewDecoder(resp.Body) | 
					
						
							|  |  |  | 		err = decoder.Decode(&data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 			d.logger <- fmt.Sprintf("[Notify] Response Body Error for '%s': %s", h.Name, resp.Status) | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 		// TODO some sort of way to determine if data is successful (keywords) | 
					
						
							|  |  |  | 		d.logger <- fmt.Sprintf("[Notify] Success? %#v", data) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Config struct { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	Watches  []ConfigWatch   `json:"watches"` | 
					
						
							|  |  |  | 	Webhooks []ConfigWebhook `json:"webhooks"` | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ConfigWatch struct { | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	Name          string   `json:"name"` | 
					
						
							|  |  |  | 	URL           string   `json:"url"` | 
					
						
							|  |  |  | 	Keywords      string   `json:"keywords"` | 
					
						
							|  |  |  | 	Webhooks      []string `json:"webhooks"` | 
					
						
							|  |  |  | 	RecoverScript string   `json:"recover_script"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ConfigWebhook struct { | 
					
						
							|  |  |  | 	Name    string              `json:"name"` | 
					
						
							|  |  |  | 	Method  string              `json:"method"` | 
					
						
							|  |  |  | 	URL     string              `json:"url"` | 
					
						
							|  |  |  | 	Auth    map[string]string   `json:"auth"` | 
					
						
							| 
									
										
										
										
											2019-06-09 02:04:23 -06:00
										 |  |  | 	Headers map[string]string   `json:"headers"` | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	Form    map[string]string   `json:"form"` | 
					
						
							| 
									
										
										
										
											2019-06-12 00:52:33 -06:00
										 |  |  | 	JSON    map[string]string   `json:"json"` | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | 	Config  map[string]string   `json:"config"` | 
					
						
							|  |  |  | 	Configs []map[string]string `json:"configs"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-09 02:04:23 -06:00
										 |  |  | // The default http client uses unsafe defaults | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | func NewHTTPClient() *http.Client { | 
					
						
							|  |  |  | 	transport := &http.Transport{ | 
					
						
							|  |  |  | 		Dial: (&net.Dialer{ | 
					
						
							|  |  |  | 			Timeout: 10 * time.Second, | 
					
						
							|  |  |  | 		}).Dial, | 
					
						
							|  |  |  | 		TLSHandshakeTimeout: 5 * time.Second, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	client := &http.Client{ | 
					
						
							|  |  |  | 		Timeout:   time.Second * 5, | 
					
						
							|  |  |  | 		Transport: transport, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return client | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-09 02:04:23 -06:00
										 |  |  | // This is so that the log messages don't trample | 
					
						
							|  |  |  | // over each other when they happen simultaneously. | 
					
						
							| 
									
										
										
										
											2019-06-08 03:11:42 -06:00
										 |  |  | func logger(msgs chan string) { | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		msg := <-msgs | 
					
						
							|  |  |  | 		log.Println(msg) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-07 20:37:53 -06:00
										 |  |  | } |