Compare commits
	
		
			No commits in common. "master" and "v1.1.2" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
				
			|||||||
/watchdog
 | 
					/watchdog
 | 
				
			||||||
/cmd/watchdog/watchdog
 | 
					/cmd/watchdog/watchdog
 | 
				
			||||||
xversion.go
 | 
					xversion.go
 | 
				
			||||||
*.json
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										140
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								README.md
									
									
									
									
									
								
							@ -11,85 +11,7 @@ Can work with email, text (sms), push notifications, etc.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Install
 | 
					# Install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Downloads
 | 
					Git:
 | 
				
			||||||
 | 
					 | 
				
			||||||
### MacOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MacOS (darwin): [64-bit Download ](https://rootprojects.org/watchdog/dist/darwin/amd64/watchdog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
curl https://rootprojects.org/watchdog/dist/darwin/amd64/watchdog -o watchdog
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Windows
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<details>
 | 
					 | 
				
			||||||
<summary>See download options</summary>
 | 
					 | 
				
			||||||
Windows 10: [64-bit Download](https://rootprojects.org/watchdog/dist/windows/amd64/watchdog.exe)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
powershell.exe $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest https://rootprojects.org/watchdog/dist/windows/amd64/watchdog.exe -OutFile watchdog.exe
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Windows 7: [32-bit Download](https://rootprojects.org/watchdog/dist/windows/386/watchdog.exe)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
powershell.exe "(New-Object Net.WebClient).DownloadFile('https://rootprojects.org/watchdog/dist/windows/386/watchdog.exe', 'watchdog.exe')"
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</details>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Linux
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<details>
 | 
					 | 
				
			||||||
<summary>See download options</summary>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Linux (64-bit): [Download](https://rootprojects.org/watchdog/dist/linux/amd64/watchdog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
curl https://rootprojects.org/watchdog/dist/linux/amd64/watchdog -o watchdog
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Linux (32-bit): [Download](https://rootprojects.org/watchdog/dist/linux/386/watchdog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
curl https://rootprojects.org/watchdog/dist/linux/386/watchdog -o watchdog
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</details>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Raspberry Pi (Linux ARM)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<details>
 | 
					 | 
				
			||||||
<summary>See download options</summary>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RPi 4 (64-bit armv8): [Download](https://rootprojects.org/watchdog/dist/linux/armv8/watchdog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
curl https://rootprojects.org/watchdog/dist/linux/armv8/watchdog -o watchdog`
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RPi 3 (armv7): [Download](https://rootprojects.org/watchdog/dist/linux/armv7/watchdog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
curl https://rootprojects.org/watchdog/dist/linux/armv7/watchdog -o watchdog
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ARMv6: [Download](https://rootprojects.org/watchdog/dist/linux/armv6/watchdog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
curl https://rootprojects.org/watchdog/dist/linux/armv6/watchdog -o watchdog
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RPi Zero (armv5): [Download](https://rootprojects.org/watchdog/dist/linux/armv5/watchdog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
curl https://rootprojects.org/watchdog/dist/linux/armv5/watchdog -o watchdog
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</details>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Git:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
git clone https://git.coolaj86.com/coolaj86/watchdog.go.git
 | 
					git clone https://git.coolaj86.com/coolaj86/watchdog.go.git
 | 
				
			||||||
@ -99,6 +21,19 @@ pushd cmd/watchdog
 | 
				
			|||||||
go build -mod=vendor
 | 
					go build -mod=vendor
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Zip:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Linux
 | 
				
			||||||
 | 
					  - [watchdog-v1.1.0-linux-amd64.zip](https://git.rootprojects.org/root/watchdog.go/releases/download/v1.1.0-linux/watchdog-v1.1.0-linux-amd64.zip)
 | 
				
			||||||
 | 
					  - [watchdog-v1.1.0-linux-386.zip](https://git.rootprojects.org/root/watchdog.go/releases/download/v1.1.0-linux/watchdog-v1.1.0-linux-386.zip)
 | 
				
			||||||
 | 
					  - [watchdog-v1.1.0-linux-armv7.zip](https://git.rootprojects.org/root/watchdog.go/releases/download/v1.1.0-linux/watchdog-v1.1.0-linux-armv7.zip)
 | 
				
			||||||
 | 
					  - [watchdog-v1.1.0-linux-armv5.zip](https://git.rootprojects.org/root/watchdog.go/releases/download/v1.1.0-linux/watchdog-v1.1.0-linux-armv5.zip)
 | 
				
			||||||
 | 
					- MacOS
 | 
				
			||||||
 | 
					  - [watchdog-v1.1.0-darwin-amd64.zip](https://git.rootprojects.org/root/watchdog.go/releases/download/v1.1.0-macos/watchdog-v1.1.0-darwin-amd64.zip)
 | 
				
			||||||
 | 
					- Windows
 | 
				
			||||||
 | 
					  - [watchdog-v1.1.0-windows-amd64.zip](https://git.rootprojects.org/root/watchdog.go/releases/download/v1.1.0-windows/watchdog-v1.1.0-windows-amd64.zip)
 | 
				
			||||||
 | 
					  - [watchdog-v1.1.0-windows-386.zip](https://git.rootprojects.org/root/watchdog.go/releases/download/v1.1.0-windows/watchdog-v1.1.0-windows-386.zip)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Usage
 | 
					# Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Mac, Linux:
 | 
					Mac, Linux:
 | 
				
			||||||
@ -113,15 +48,6 @@ Windows:
 | 
				
			|||||||
watchdog.exe -c config.json
 | 
					watchdog.exe -c config.json
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Changelog
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- v1.2.0
 | 
					 | 
				
			||||||
  - report when sites come back up
 | 
					 | 
				
			||||||
  - and more template vars
 | 
					 | 
				
			||||||
  - and localization for status
 | 
					 | 
				
			||||||
- v1.1.0 support `json` request bodies (for Pushbullet)
 | 
					 | 
				
			||||||
- v1.0.0 support Twilio and Mailgun
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Getting Started
 | 
					# Getting Started
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<details>
 | 
					<details>
 | 
				
			||||||
@ -152,23 +78,6 @@ Be careful of "smart quotes" and HTML entities:
 | 
				
			|||||||
- `We’re Open!` is not `We're Open!`
 | 
					- `We’re Open!` is not `We're Open!`
 | 
				
			||||||
- Neither is `We're Open!` nor `We're Open!`
 | 
					- Neither is `We're Open!` nor `We're Open!`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Leave empty for No Content pages, such as redirects.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `badwords`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The opposite of `keywords`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
If a literal, exact match of badwords exists as part of the response, the site is considered to be down.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Ignored if empty.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `localizations`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Normally `{{ .Status }}` will be `"up"` or `"down"` and `{{ .Message }}` will be `"is down"` or `"came back up"`.
 | 
					 | 
				
			||||||
Localizations allow you to swap that out for something else.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
I added this so that I could use "🔥🔥🔥" and "👍" for myself without imposing upon others.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `webhooks`
 | 
					### `webhooks`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This references the arbitrary `name` of a webhook in the `webhooks` array.
 | 
					This references the arbitrary `name` of a webhook in the `webhooks` array.
 | 
				
			||||||
@ -205,10 +114,7 @@ command="systemctl restart foo.service",no-port-forwarding,no-x11-forwarding,no-
 | 
				
			|||||||
<details>
 | 
					<details>
 | 
				
			||||||
  <summary>{{ .Name }} and other template variables</summary>
 | 
					  <summary>{{ .Name }} and other template variables</summary>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `{{ .Name }}` is the name of your site.
 | 
					`{{ .Name }}` is the only template variable right now.
 | 
				
			||||||
- `{{ .Message }}` is either `went down` or `came back up`.
 | 
					 | 
				
			||||||
- `{{ .Status }}` is either `up` or `down`.
 | 
					 | 
				
			||||||
- `{{ .Watchdog }}` is the name of your watchdog (useful if you have multiple).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
It refers to the name of the watch, which is "Example Site" in the sample config below.
 | 
					It refers to the name of the watch, which is "Example Site" in the sample config below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -328,13 +234,11 @@ The examples below are shown with Mailgun, Pushbullet, and Twilio, as taken from
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "watchdog": "Monitor A",
 | 
					 | 
				
			||||||
  "watches": [
 | 
					  "watches": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "name": "Example Site",
 | 
					      "name": "Example Site",
 | 
				
			||||||
      "url": "https://example.com/",
 | 
					      "url": "https://example.com/",
 | 
				
			||||||
      "keywords": "My Site",
 | 
					      "keywords": "My Site",
 | 
				
			||||||
      "badwords": "Could not connect to database.",
 | 
					 | 
				
			||||||
      "webhooks": ["my_mailgun", "my_pushbullet", "my_twilio"],
 | 
					      "webhooks": ["my_mailgun", "my_pushbullet", "my_twilio"],
 | 
				
			||||||
      "recover_script": "systemctl restart example-site"
 | 
					      "recover_script": "systemctl restart example-site"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -354,8 +258,8 @@ The examples below are shown with Mailgun, Pushbullet, and Twilio, as taken from
 | 
				
			|||||||
      "form": {
 | 
					      "form": {
 | 
				
			||||||
        "from": "Watchdog <watchdog@my.example.com>",
 | 
					        "from": "Watchdog <watchdog@my.example.com>",
 | 
				
			||||||
        "to": "jon.doe@gmail.com",
 | 
					        "to": "jon.doe@gmail.com",
 | 
				
			||||||
        "subject": "[{{ .Watchdog }}] {{ .Name }} {{ .Message }}.",
 | 
					        "subject": "{{ .Name }} is down.",
 | 
				
			||||||
        "text": "{{ .Name }} {{ .Message }}. Reported by {{ .Watchdog }}."
 | 
					        "text": "The system is down. Check up on {{ .Name }} ASAP."
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -367,8 +271,8 @@ The examples below are shown with Mailgun, Pushbullet, and Twilio, as taken from
 | 
				
			|||||||
        "User-Agent": "Watchdog/1.0"
 | 
					        "User-Agent": "Watchdog/1.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "json": {
 | 
					      "json": {
 | 
				
			||||||
        "body": "The system {{ .Message }}. Check up on {{ .Name }} ASAP.",
 | 
					        "body": "The system is down. Check up on {{ .Name }} ASAP.",
 | 
				
			||||||
        "title": "{{ .Name }} {{ .Message }}.",
 | 
					        "title": "{{ .Name }} is down.",
 | 
				
			||||||
        "type": "note"
 | 
					        "type": "note"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -389,11 +293,7 @@ The examples below are shown with Mailgun, Pushbullet, and Twilio, as taken from
 | 
				
			|||||||
        "Body": "[{{ .Name }}] The system is down. The system is down."
 | 
					        "Body": "[{{ .Name }}] The system is down. The system is down."
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ],
 | 
					  ]
 | 
				
			||||||
  "localizations": {
 | 
					 | 
				
			||||||
    "up": "👍",
 | 
					 | 
				
			||||||
    "down": "🔥🔥🔥"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										48
									
								
								build-all.sh
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								build-all.sh
									
									
									
									
									
								
							@ -1,48 +0,0 @@
 | 
				
			|||||||
#GOOS=windows GOARCH=amd64 go install
 | 
					 | 
				
			||||||
#go tool dist list
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# TODO move this into tools/build.go
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export CGO_ENABLED=0
 | 
					 | 
				
			||||||
exe=watchdog
 | 
					 | 
				
			||||||
distpre=../..
 | 
					 | 
				
			||||||
gocmd=.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo ""
 | 
					 | 
				
			||||||
go generate -mod=vendor ./...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pushd cmd/${exe}
 | 
					 | 
				
			||||||
echo ""
 | 
					 | 
				
			||||||
echo "Windows amd64"
 | 
					 | 
				
			||||||
#GOOS=windows GOARCH=amd64 go build -mod=vendor -o ${distpre}/dist/windows/amd64/${exe}.exe -ldflags "-H=windowsgui" $gocmd
 | 
					 | 
				
			||||||
#GOOS=windows GOARCH=amd64 go build -mod=vendor -o ${distpre}/dist/windows/amd64/${exe}.debug.exe
 | 
					 | 
				
			||||||
GOOS=windows GOARCH=amd64 go build -mod=vendor -o ${distpre}/dist/windows/amd64/${exe}.exe
 | 
					 | 
				
			||||||
echo "Windows 386"
 | 
					 | 
				
			||||||
#GOOS=windows GOARCH=386 go build -mod=vendor -o ${distpre}/dist/windows/386/${exe}.exe -ldflags "-H=windowsgui" $gocmd
 | 
					 | 
				
			||||||
#GOOS=windows GOARCH=386 go build -mod=vendor -o ${distpre}/dist/windows/386/${exe}.debug.exe
 | 
					 | 
				
			||||||
GOOS=windows GOARCH=386 go build -mod=vendor -o ${distpre}/dist/windows/386/${exe}.exe
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo ""
 | 
					 | 
				
			||||||
echo "Darwin (macOS) amd64"
 | 
					 | 
				
			||||||
GOOS=darwin GOARCH=amd64 go build -mod=vendor -o ${distpre}/dist/darwin/amd64/${exe} $gocmd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo ""
 | 
					 | 
				
			||||||
echo "Linux amd64"
 | 
					 | 
				
			||||||
GOOS=linux GOARCH=amd64 go build -mod=vendor -o ${distpre}/dist/linux/amd64/${exe} $gocmd
 | 
					 | 
				
			||||||
echo "Linux 386"
 | 
					 | 
				
			||||||
GOOS=linux GOARCH=386 go build -mod=vendor -o ${distpre}/dist/linux/386/${exe} $gocmd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo ""
 | 
					 | 
				
			||||||
echo "RPi 4 (64-bit) ARMv8"
 | 
					 | 
				
			||||||
GOOS=linux GOARCH=arm64 go build -mod=vendor -o ${distpre}/dist/linux/armv8/${exe} $gocmd
 | 
					 | 
				
			||||||
echo "RPi 3 B+ ARMv7"
 | 
					 | 
				
			||||||
GOOS=linux GOARCH=arm GOARM=7 go build -mod=vendor -o ${distpre}/dist/linux/armv7/${exe} $gocmd
 | 
					 | 
				
			||||||
echo "ARMv6"
 | 
					 | 
				
			||||||
GOOS=linux GOARCH=arm GOARM=6 go build -mod=vendor -o ${distpre}/dist/linux/armv6/${exe} $gocmd
 | 
					 | 
				
			||||||
echo "RPi Zero ARMv5"
 | 
					 | 
				
			||||||
GOOS=linux GOARCH=arm GOARM=5 go build -mod=vendor -o ${distpre}/dist/linux/armv5/${exe} $gocmd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo ""
 | 
					 | 
				
			||||||
popd
 | 
					 | 
				
			||||||
rsync -av ./dist/ ubuntu@rootprojects.org:/srv/www/rootprojects.org/$exe/dist/
 | 
					 | 
				
			||||||
# https://rootprojects.org/serviceman/dist/windows/amd64/serviceman.exe
 | 
					 | 
				
			||||||
							
								
								
									
										45
									
								
								build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								build.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export CGO_ENABLED=0
 | 
				
			||||||
 | 
					#GOOS=windows GOARCH=amd64 go install
 | 
				
			||||||
 | 
					go tool dist list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gocmd=watchdog.go
 | 
				
			||||||
 | 
					golib=""
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					echo "Windows amd64"
 | 
				
			||||||
 | 
					GOOS=windows GOARCH=amd64 go build -o dist/windows-amd64/watchdog.exe $gocmd $golib
 | 
				
			||||||
 | 
					echo "Windows 386"
 | 
				
			||||||
 | 
					GOOS=windows GOARCH=386 go build -o dist/windows-386/watchdog.exe $gocmd $golib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					echo "Darwin (macOS) amd64"
 | 
				
			||||||
 | 
					GOOS=darwin GOARCH=amd64 go build -o dist/darwin-amd64/watchdog $gocmd $golib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					echo "Linux amd64"
 | 
				
			||||||
 | 
					GOOS=linux GOARCH=amd64 go build -o dist/linux-amd64/watchdog $gocmd $golib
 | 
				
			||||||
 | 
					echo "Linux 386"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					GOOS=linux GOARCH=386 go build -o dist/linux-386/watchdog $gocmd $golib
 | 
				
			||||||
 | 
					echo "RPi 3 B+ ARMv7"
 | 
				
			||||||
 | 
					GOOS=linux GOARCH=arm GOARM=7 go build -o dist/linux-armv7/watchdog $gocmd $golib
 | 
				
			||||||
 | 
					echo "RPi Zero ARMv5"
 | 
				
			||||||
 | 
					GOOS=linux GOARCH=arm GOARM=5 go build -o dist/linux-armv5/watchdog $gocmd $golib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					my_ver=$(git describe --tags)
 | 
				
			||||||
 | 
					pushd dist
 | 
				
			||||||
 | 
					  ls -d *-* | while read my_dist
 | 
				
			||||||
 | 
					  do
 | 
				
			||||||
 | 
					    if [ -d "$my_dist" ]; then
 | 
				
			||||||
 | 
					      #tar -czvf watchdog-$my_ver-$my_dist.tar.gz $my_dist
 | 
				
			||||||
 | 
					      zip -r watchdog-$my_ver-$my_dist.zip $my_dist
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					  done
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
@ -1,8 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Fallback to recent version if not in a git repository
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	GitRev = "d5c026948cf134997c7260e78d4bd5864ac5b9b3"
 | 
					 | 
				
			||||||
	GitVersion = "v1.1.3"
 | 
					 | 
				
			||||||
	GitTimestamp = "2019-06-21T01:03:19-06:00"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -11,10 +11,14 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	watchdog "git.rootprojects.org/root/go-watchdog"
 | 
						watchdog "git.rootprojects.org/root/watchdog.go"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var GitRev, GitVersion, GitTimestamp string
 | 
					var (
 | 
				
			||||||
 | 
						GitRev       = "00000000"
 | 
				
			||||||
 | 
						GitVersion   = "v0.0.0"
 | 
				
			||||||
 | 
						GitTimestamp = "0000-00-00T00:00:00Z"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func usage() {
 | 
					func usage() {
 | 
				
			||||||
	fmt.Println("Usage: watchdog -c config.json")
 | 
						fmt.Println("Usage: watchdog -c config.json")
 | 
				
			||||||
@ -69,7 +73,7 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	done := make(chan struct{}, 1)
 | 
						done := make(chan struct{}, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allWebhooks := make(map[string]watchdog.Webhook)
 | 
						allWebhooks := make(map[string]watchdog.ConfigWebhook)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i := range config.Webhooks {
 | 
						for i := range config.Webhooks {
 | 
				
			||||||
		h := config.Webhooks[i]
 | 
							h := config.Webhooks[i]
 | 
				
			||||||
@ -83,12 +87,9 @@ func main() {
 | 
				
			|||||||
		logQueue <- fmt.Sprintf("Watching '%s'", c.Name)
 | 
							logQueue <- fmt.Sprintf("Watching '%s'", c.Name)
 | 
				
			||||||
		go func(c watchdog.ConfigWatch) {
 | 
							go func(c watchdog.ConfigWatch) {
 | 
				
			||||||
			d := watchdog.New(&watchdog.Dog{
 | 
								d := watchdog.New(&watchdog.Dog{
 | 
				
			||||||
				Watchdog:      config.Watchdog,
 | 
					 | 
				
			||||||
				Name:        c.Name,
 | 
									Name:        c.Name,
 | 
				
			||||||
				CheckURL:    c.URL,
 | 
									CheckURL:    c.URL,
 | 
				
			||||||
				Keywords:    c.Keywords,
 | 
									Keywords:    c.Keywords,
 | 
				
			||||||
				Badwords:      c.Badwords,
 | 
					 | 
				
			||||||
				Localizations: config.Localizations,
 | 
					 | 
				
			||||||
				Recover:     c.RecoverScript,
 | 
									Recover:     c.RecoverScript,
 | 
				
			||||||
				Webhooks:    c.Webhooks,
 | 
									Webhooks:    c.Webhooks,
 | 
				
			||||||
				AllWebhooks: allWebhooks,
 | 
									AllWebhooks: allWebhooks,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								doc.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								doc.go
									
									
									
									
									
								
							@ -5,5 +5,5 @@
 | 
				
			|||||||
// The git tag version describes the state of the binary,
 | 
					// The git tag version describes the state of the binary,
 | 
				
			||||||
// not the state of the library. The API is not yet stable.
 | 
					// not the state of the library. The API is not yet stable.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// See https://git.rootproject.org/root/go-watchdog for pre-built binaries.
 | 
					// See https://git.rootproject.org/root/watchdog.go for pre-built binaries.
 | 
				
			||||||
package watchdog
 | 
					package watchdog
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@ -1,5 +1,5 @@
 | 
				
			|||||||
module git.rootprojects.org/root/go-watchdog
 | 
					module git.rootprojects.org/root/watchdog.go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go 1.12
 | 
					go 1.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require git.rootprojects.org/root/go-gitver v1.1.1
 | 
					require git.rootprojects.org/root/go-gitver v1.1.0
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@ -1,2 +1,2 @@
 | 
				
			|||||||
git.rootprojects.org/root/go-gitver v1.1.1 h1:5b0lxnTYnft5hqpln0XCrJaGPH0SKzhPaazVAvAlZ8I=
 | 
					git.rootprojects.org/root/go-gitver v1.1.0 h1:ANQUnUXYgbDR+WaMcI+PQQjLnxlCbAZCD/zivkrf8fY=
 | 
				
			||||||
git.rootprojects.org/root/go-gitver v1.1.1/go.mod h1:Rj1v3TBhvdaSphFEqMynUYwAz/4f+wY/+syBTvRrmlI=
 | 
					git.rootprojects.org/root/go-gitver v1.1.0/go.mod h1:Rj1v3TBhvdaSphFEqMynUYwAz/4f+wY/+syBTvRrmlI=
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/git.rootprojects.org/root/go-gitver/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/git.rootprojects.org/root/go-gitver/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -60,7 +60,7 @@ You don't have to use `mod vendor`, but I highly recommend it.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Options
 | 
					# Options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```txt
 | 
					```
 | 
				
			||||||
version           print version and exit
 | 
					version           print version and exit
 | 
				
			||||||
--fail            exit with non-zero status code on failure
 | 
					--fail            exit with non-zero status code on failure
 | 
				
			||||||
--package <name>  will set the package name
 | 
					--package <name>  will set the package name
 | 
				
			||||||
@ -69,7 +69,7 @@ version           print version and exit
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ENVs
 | 
					ENVs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```
 | 
				
			||||||
# Alias for --fail
 | 
					# Alias for --fail
 | 
				
			||||||
GITVER_FAIL=true
 | 
					GITVER_FAIL=true
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/git.rootprojects.org/root/go-gitver/gitver.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/git.rootprojects.org/root/go-gitver/gitver.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -209,9 +209,9 @@ package {{ .Package }}
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	GitRev = "{{ .GitRev }}"
 | 
						GitRev = "{{ .GitRev }}"
 | 
				
			||||||
  {{- if .Version }}
 | 
						if "" != "{{ .Version }}" {
 | 
				
			||||||
		GitVersion = "{{ .Version }}"
 | 
							GitVersion = "{{ .Version }}"
 | 
				
			||||||
	{{ end -}}
 | 
						}
 | 
				
			||||||
	GitTimestamp = "{{ .Timestamp }}"
 | 
						GitTimestamp = "{{ .Timestamp }}"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
`))
 | 
					`))
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,2 @@
 | 
				
			|||||||
# git.rootprojects.org/root/go-gitver v1.1.1
 | 
					# git.rootprojects.org/root/go-gitver v1.1.0
 | 
				
			||||||
git.rootprojects.org/root/go-gitver
 | 
					git.rootprojects.org/root/go-gitver
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										214
									
								
								watchdog.go
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								watchdog.go
									
									
									
									
									
								
							@ -14,56 +14,24 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Status int
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	StatusDown Status = iota
 | 
					 | 
				
			||||||
	StatusUp
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s Status) String() string {
 | 
					 | 
				
			||||||
	// ... just wishing Go had enums like Rust...
 | 
					 | 
				
			||||||
	switch s {
 | 
					 | 
				
			||||||
	case StatusUp:
 | 
					 | 
				
			||||||
		return "up"
 | 
					 | 
				
			||||||
	case StatusDown:
 | 
					 | 
				
			||||||
		return "down"
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return "[[internal error]]"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	MessageDown   = "went down"
 | 
					 | 
				
			||||||
	MessageUp     = "came back up"
 | 
					 | 
				
			||||||
	MessageHiccup = "hiccupped"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Dog struct {
 | 
					type Dog struct {
 | 
				
			||||||
	Watchdog      string
 | 
					 | 
				
			||||||
	Name         string
 | 
						Name         string
 | 
				
			||||||
	CheckURL     string
 | 
						CheckURL     string
 | 
				
			||||||
	Keywords     string
 | 
						Keywords     string
 | 
				
			||||||
	Badwords      string
 | 
					 | 
				
			||||||
	Localizations map[string]string
 | 
					 | 
				
			||||||
	Recover      string
 | 
						Recover      string
 | 
				
			||||||
	Webhooks     []string
 | 
						Webhooks     []string
 | 
				
			||||||
	AllWebhooks   map[string]Webhook
 | 
						AllWebhooks  map[string]ConfigWebhook
 | 
				
			||||||
	Logger       chan string
 | 
						Logger       chan string
 | 
				
			||||||
	status        Status
 | 
					 | 
				
			||||||
	changed       bool
 | 
					 | 
				
			||||||
	error        error
 | 
						error        error
 | 
				
			||||||
	//failures      int
 | 
						failures     int
 | 
				
			||||||
	//passes        int
 | 
						passes       int
 | 
				
			||||||
	//lastFailed    time.Time
 | 
						lastFailed   time.Time
 | 
				
			||||||
	//lastPassed    time.Time
 | 
						lastPassed   time.Time
 | 
				
			||||||
	//lastNotified time.Time
 | 
						lastNotified time.Time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func New(d *Dog) *Dog {
 | 
					func New(d *Dog) *Dog {
 | 
				
			||||||
	//d.lastPassed = time.Now().Add(-5 * time.Minute)
 | 
						d.lastPassed = time.Now().Add(-5 * time.Minute)
 | 
				
			||||||
	d.status = StatusUp
 | 
					 | 
				
			||||||
	d.changed = false
 | 
					 | 
				
			||||||
	return d
 | 
						return d
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -76,87 +44,64 @@ func (d *Dog) Watch() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Now that I've added the ability to notify when a server is back up
 | 
					 | 
				
			||||||
// this definitely needs some refactoring. It's bad now.
 | 
					 | 
				
			||||||
func (d *Dog) watch() {
 | 
					func (d *Dog) watch() {
 | 
				
			||||||
	d.Logger <- fmt.Sprintf("Check: '%s'", d.Name)
 | 
						d.Logger <- fmt.Sprintf("Check: '%s'", d.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This may be up or down
 | 
						err := d.check()
 | 
				
			||||||
	err := d.hardcheck()
 | 
					 | 
				
			||||||
	if nil == err {
 | 
						if nil == err {
 | 
				
			||||||
		d.Logger <- fmt.Sprintf("Up: '%s'", d.Name)
 | 
					 | 
				
			||||||
		// if it's down, coming up, notify
 | 
					 | 
				
			||||||
		if d.changed {
 | 
					 | 
				
			||||||
			d.notify(MessageUp)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If being down is a change, check to see if it's just a hiccup
 | 
						time.Sleep(time.Duration(2) * time.Second)
 | 
				
			||||||
	if d.changed {
 | 
						err2 := d.check()
 | 
				
			||||||
		time.Sleep(time.Duration(5) * time.Second)
 | 
					 | 
				
			||||||
		err2 := d.softcheck()
 | 
					 | 
				
			||||||
	if nil != err2 {
 | 
						if nil != err2 {
 | 
				
			||||||
			// it's really down
 | 
					 | 
				
			||||||
		d.Logger <- fmt.Sprintf("Down: '%s': %s", d.Name, err2)
 | 
							d.Logger <- fmt.Sprintf("Down: '%s': %s", d.Name, err2)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
			// it's not really down, so reset the change info
 | 
					 | 
				
			||||||
			d.changed = false
 | 
					 | 
				
			||||||
			d.status = StatusUp
 | 
					 | 
				
			||||||
			// and notify of the hiccup
 | 
					 | 
				
			||||||
		d.Logger <- fmt.Sprintf("Hiccup: '%s': %s", d.Name, err)
 | 
							d.Logger <- fmt.Sprintf("Hiccup: '%s': %s", d.Name, err)
 | 
				
			||||||
			d.notify(MessageHiccup)
 | 
					 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO what if the server is flip-flopping rapidly?
 | 
					 | 
				
			||||||
	// how to rate limit?
 | 
					 | 
				
			||||||
	// "{{ .Server }} is on cooldown for 30 minutes"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// * We've had success since the last notification
 | 
					 | 
				
			||||||
	// * It's been at least 5 minutes since the last notification
 | 
					 | 
				
			||||||
	//fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
 | 
					 | 
				
			||||||
	//if d.lastPassed.After(d.lastNotified) && d.lastNotified.Before(fiveMinutesAgo) {
 | 
					 | 
				
			||||||
	//}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						failure := false
 | 
				
			||||||
	t := 10
 | 
						t := 10
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		// try to recover, then backoff exponentially
 | 
					 | 
				
			||||||
		d.recover()
 | 
							d.recover()
 | 
				
			||||||
		time.Sleep(time.Duration(t) * time.Second)
 | 
							time.Sleep(time.Duration(t) * time.Second)
 | 
				
			||||||
 | 
							// backoff
 | 
				
			||||||
		t *= 2
 | 
							t *= 2
 | 
				
			||||||
		if t > 120 {
 | 
							err := d.check()
 | 
				
			||||||
			t = 120
 | 
							if nil != err {
 | 
				
			||||||
 | 
								d.Logger <- fmt.Sprintf("Unrecoverable: '%s': %s", d.Name, err)
 | 
				
			||||||
 | 
								failure = true
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								failure = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err := d.softcheck()
 | 
							// We should notify if
 | 
				
			||||||
		if nil != err {
 | 
							// * We've had success since the last notification
 | 
				
			||||||
			// this is down, and we know it's down
 | 
							// * It's been at least 5 minutes since the last notification
 | 
				
			||||||
			d.status = StatusDown
 | 
							fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
 | 
				
			||||||
			d.Logger <- fmt.Sprintf("Unrecoverable: '%s': %s", d.Name, err)
 | 
							if d.lastPassed.After(d.lastNotified) && d.lastNotified.Before(fiveMinutesAgo) {
 | 
				
			||||||
			if d.changed {
 | 
								d.notify(failure)
 | 
				
			||||||
				d.changed = false
 | 
					 | 
				
			||||||
				d.notify(MessageDown)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		} else {
 | 
							if !failure || d.failures >= 5 {
 | 
				
			||||||
			// it came back up
 | 
								// go back to the main 5-minute loop
 | 
				
			||||||
			d.status = StatusUp
 | 
					 | 
				
			||||||
			d.Logger <- fmt.Sprintf("Up: '%s'", d.Name)
 | 
					 | 
				
			||||||
			if d.changed {
 | 
					 | 
				
			||||||
				// and the downtime was short - just a recovery
 | 
					 | 
				
			||||||
				d.notify(MessageHiccup)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				// and the downtime was some time
 | 
					 | 
				
			||||||
				d.notify(MessageUp)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			d.changed = false
 | 
					 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Dog) softcheck() error {
 | 
					func (d *Dog) check() error {
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if nil != err {
 | 
				
			||||||
 | 
								d.failures += 1
 | 
				
			||||||
 | 
								d.lastFailed = time.Now()
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								d.lastPassed = time.Now()
 | 
				
			||||||
 | 
								d.passes += 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	client := NewHTTPClient()
 | 
						client := NewHTTPClient()
 | 
				
			||||||
	response, err := client.Get(d.CheckURL)
 | 
						response, err := client.Get(d.CheckURL)
 | 
				
			||||||
	if nil != err {
 | 
						if nil != err {
 | 
				
			||||||
@ -170,52 +115,18 @@ func (d *Dog) softcheck() error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Note: empty matches empty as true, so this works for checking redirects
 | 
					 | 
				
			||||||
	if !bytes.Contains(b, []byte(d.Keywords)) {
 | 
						if !bytes.Contains(b, []byte(d.Keywords)) {
 | 
				
			||||||
		err = fmt.Errorf("Down: '%s' Not Found for '%s'", d.Keywords, d.Name)
 | 
							err = fmt.Errorf("Down: '%s' Not Found for '%s'", d.Keywords, d.Name)
 | 
				
			||||||
		d.Logger <- fmt.Sprintf("%s", err)
 | 
							d.Logger <- fmt.Sprintf("%s", err)
 | 
				
			||||||
		d.error = err
 | 
							d.error = err
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						} else {
 | 
				
			||||||
 | 
							d.Logger <- fmt.Sprintf("Up: '%s'", d.Name)
 | 
				
			||||||
	if "" != d.Badwords {
 | 
					 | 
				
			||||||
		if bytes.Contains(b, []byte(d.Badwords)) {
 | 
					 | 
				
			||||||
			err = fmt.Errorf("Down: '%s' Found for '%s'", d.Badwords, d.Name)
 | 
					 | 
				
			||||||
			d.Logger <- fmt.Sprintf("%s", err)
 | 
					 | 
				
			||||||
			d.error = err
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Dog) hardcheck() error {
 | 
					 | 
				
			||||||
	previousStatus := d.status
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err := d.softcheck()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Are we up, or down?
 | 
					 | 
				
			||||||
	if nil != err {
 | 
					 | 
				
			||||||
		d.status = StatusDown
 | 
					 | 
				
			||||||
		//d.failures += 1
 | 
					 | 
				
			||||||
		//d.lastFailed = time.Now()
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		d.status = StatusUp
 | 
					 | 
				
			||||||
		//d.lastPassed = time.Now()
 | 
					 | 
				
			||||||
		//d.passes += 1
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Has that changed?
 | 
					 | 
				
			||||||
	if previousStatus != d.status {
 | 
					 | 
				
			||||||
		d.changed = true
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		d.changed = false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (d *Dog) recover() {
 | 
					func (d *Dog) recover() {
 | 
				
			||||||
	if "" == d.Recover {
 | 
						if "" == d.Recover {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@ -243,9 +154,9 @@ func (d *Dog) recover() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Dog) notify(msg string) {
 | 
					func (d *Dog) notify(hardFail bool) {
 | 
				
			||||||
	d.Logger <- fmt.Sprintf("Notifying the authorities of %s's status change", d.Name)
 | 
						d.Logger <- fmt.Sprintf("Notifying the authorities of %s's failure", d.Name)
 | 
				
			||||||
	//d.lastNotified = time.Now()
 | 
						d.lastNotified = time.Now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i := range d.Webhooks {
 | 
						for i := range d.Webhooks {
 | 
				
			||||||
		name := d.Webhooks[i]
 | 
							name := d.Webhooks[i]
 | 
				
			||||||
@ -261,11 +172,6 @@ func (d *Dog) notify(msg string) {
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		d.notifyOne(h, msg)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (d *Dog) notifyOne(h Webhook, msg string) {
 | 
					 | 
				
			||||||
		// TODO do this in main on config init
 | 
							// TODO do this in main on config init
 | 
				
			||||||
		if "" == h.Method {
 | 
							if "" == h.Method {
 | 
				
			||||||
			h.Method = "POST"
 | 
								h.Method = "POST"
 | 
				
			||||||
@ -280,10 +186,7 @@ func (d *Dog) notifyOne(h Webhook, msg string) {
 | 
				
			|||||||
				v := h.Form[k]
 | 
									v := h.Form[k]
 | 
				
			||||||
				// because `{{` gets urlencoded
 | 
									// because `{{` gets urlencoded
 | 
				
			||||||
				//k = strings.Replace(k, "{{ .Name }}", d.Name, -1)
 | 
									//k = strings.Replace(k, "{{ .Name }}", d.Name, -1)
 | 
				
			||||||
			v = strings.Replace(v, "{{ .Watchdog }}", d.Watchdog, -1)
 | 
					 | 
				
			||||||
				v = strings.Replace(v, "{{ .Name }}", d.Name, -1)
 | 
									v = strings.Replace(v, "{{ .Name }}", d.Name, -1)
 | 
				
			||||||
			v = strings.Replace(v, "{{ .Status }}", d.localize(d.status.String()), -1)
 | 
					 | 
				
			||||||
			v = strings.Replace(v, "{{ .Message }}", d.localize(msg), -1)
 | 
					 | 
				
			||||||
				d.Logger <- fmt.Sprintf("[HEADER] %s: %s", k, v)
 | 
									d.Logger <- fmt.Sprintf("[HEADER] %s: %s", k, v)
 | 
				
			||||||
				form.Set(k, v)
 | 
									form.Set(k, v)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -292,22 +195,17 @@ func (d *Dog) notifyOne(h Webhook, msg string) {
 | 
				
			|||||||
			bodyBuf, err := json.Marshal(h.JSON)
 | 
								bodyBuf, err := json.Marshal(h.JSON)
 | 
				
			||||||
			if nil != err {
 | 
								if nil != err {
 | 
				
			||||||
				d.Logger <- fmt.Sprintf("[Notify] JSON Marshal Error for '%s': %s", h.Name, err)
 | 
									d.Logger <- fmt.Sprintf("[Notify] JSON Marshal Error for '%s': %s", h.Name, err)
 | 
				
			||||||
			return
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// `{{` should be left alone
 | 
								// `{{` should be left alone
 | 
				
			||||||
		v := string(bodyBuf)
 | 
								body = strings.NewReader(strings.Replace(string(bodyBuf), "{{ .Name }}", d.Name, -1))
 | 
				
			||||||
		v = strings.Replace(v, "{{ .Watchdog }}", d.Watchdog, -1)
 | 
					 | 
				
			||||||
		v = strings.Replace(v, "{{ .Name }}", d.Name, -1)
 | 
					 | 
				
			||||||
		v = strings.Replace(v, "{{ .Status }}", d.localize(d.status.String()), -1)
 | 
					 | 
				
			||||||
		v = strings.Replace(v, "{{ .Message }}", d.localize(msg), -1)
 | 
					 | 
				
			||||||
		body = strings.NewReader(v)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		client := NewHTTPClient()
 | 
							client := NewHTTPClient()
 | 
				
			||||||
		req, err := http.NewRequest(h.Method, h.URL, body)
 | 
							req, err := http.NewRequest(h.Method, h.URL, body)
 | 
				
			||||||
		if nil != err {
 | 
							if nil != err {
 | 
				
			||||||
			d.Logger <- fmt.Sprintf("[Notify] HTTP Client Network Error for '%s': %s", h.Name, err)
 | 
								d.Logger <- fmt.Sprintf("[Notify] HTTP Client Network Error for '%s': %s", h.Name, err)
 | 
				
			||||||
		return
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if 0 != len(h.Form) {
 | 
							if 0 != len(h.Form) {
 | 
				
			||||||
@ -336,12 +234,12 @@ func (d *Dog) notifyOne(h Webhook, msg string) {
 | 
				
			|||||||
		resp, err := client.Do(req)
 | 
							resp, err := client.Do(req)
 | 
				
			||||||
		if nil != err {
 | 
							if nil != err {
 | 
				
			||||||
			d.Logger <- fmt.Sprintf("[Notify] HTTP Client Error for '%s': %s", h.Name, err)
 | 
								d.Logger <- fmt.Sprintf("[Notify] HTTP Client Error for '%s': %s", h.Name, err)
 | 
				
			||||||
		return
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
 | 
							if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
 | 
				
			||||||
			d.Logger <- fmt.Sprintf("[Notify] Response Error for '%s': %s", h.Name, resp.Status)
 | 
								d.Logger <- fmt.Sprintf("[Notify] Response Error for '%s': %s", h.Name, resp.Status)
 | 
				
			||||||
		return
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO json vs xml vs txt
 | 
							// TODO json vs xml vs txt
 | 
				
			||||||
@ -351,38 +249,28 @@ func (d *Dog) notifyOne(h Webhook, msg string) {
 | 
				
			|||||||
		err = decoder.Decode(&data)
 | 
							err = decoder.Decode(&data)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			d.Logger <- fmt.Sprintf("[Notify] Response Body Error for '%s': %s", h.Name, resp.Status)
 | 
								d.Logger <- fmt.Sprintf("[Notify] Response Body Error for '%s': %s", h.Name, resp.Status)
 | 
				
			||||||
		return
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO some sort of way to determine if data is successful (keywords)
 | 
							// TODO some sort of way to determine if data is successful (keywords)
 | 
				
			||||||
		d.Logger <- fmt.Sprintf("[Notify] Success? %#v", data)
 | 
							d.Logger <- fmt.Sprintf("[Notify] Success? %#v", data)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
func (d *Dog) localize(msg string) string {
 | 
					 | 
				
			||||||
	for k := range d.Localizations {
 | 
					 | 
				
			||||||
		if k == msg {
 | 
					 | 
				
			||||||
			return d.Localizations[k]
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return msg
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	Watchdog      string            `json:"watchdog"`
 | 
					 | 
				
			||||||
	Watches  []ConfigWatch   `json:"watches"`
 | 
						Watches  []ConfigWatch   `json:"watches"`
 | 
				
			||||||
	Webhooks      []Webhook         `json:"webhooks"`
 | 
						Webhooks []ConfigWebhook `json:"webhooks"`
 | 
				
			||||||
	Localizations map[string]string `json:"localizations"`
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ConfigWatch struct {
 | 
					type ConfigWatch struct {
 | 
				
			||||||
	Name          string   `json:"name"`
 | 
						Name          string   `json:"name"`
 | 
				
			||||||
	URL           string   `json:"url"`
 | 
						URL           string   `json:"url"`
 | 
				
			||||||
	Keywords      string   `json:"keywords"`
 | 
						Keywords      string   `json:"keywords"`
 | 
				
			||||||
	Badwords      string   `json:"badwords"`
 | 
					 | 
				
			||||||
	Webhooks      []string `json:"webhooks"`
 | 
						Webhooks      []string `json:"webhooks"`
 | 
				
			||||||
	RecoverScript string   `json:"recover_script"`
 | 
						RecoverScript string   `json:"recover_script"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Webhook struct {
 | 
					type ConfigWebhook struct {
 | 
				
			||||||
	Name    string              `json:"name"`
 | 
						Name    string              `json:"name"`
 | 
				
			||||||
	Method  string              `json:"method"`
 | 
						Method  string              `json:"method"`
 | 
				
			||||||
	URL     string              `json:"url"`
 | 
						URL     string              `json:"url"`
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user