personal/q3k/shipstuck: add TOWED

Change-Id: I3348fc0730a66c3c64df00f6d3051656bf12e587
diff --git a/personal/q3k/shipstuck/main.go b/personal/q3k/shipstuck/main.go
index 70ee459..a43c5e7 100644
--- a/personal/q3k/shipstuck/main.go
+++ b/personal/q3k/shipstuck/main.go
@@ -22,19 +22,24 @@
 
 // get retrieves the current status of the ship - returns true if stack, false
 // otherwise.
-func get(ctx context.Context) (bool, error) {
+func get(ctx context.Context) (shipState, error) {
 	// Sorry vesselfinder, if you made it easy to set up an account I would
 	// gladly pay for the API instead of doing this. Limiting requests to once
 	// every 15 minutes though, that seems fair enough.
 	req, err := http.NewRequestWithContext(ctx, "GET", "https://www.vesselfinder.com/api/pub/click/353136000", nil)
 	if err != nil {
-		return false, fmt.Errorf("NewRequestWithContext: %w", err)
+		return shipStateUnknown, fmt.Errorf("NewRequestWithContext: %w", err)
 	}
 	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0")
 
 	res, err := http.DefaultClient.Do(req)
 	if err != nil {
-		return false, fmt.Errorf("Do: %w", err)
+		// vesselfinder.com down on 2021/03/29, add a 'cached' status for one hour as a hack.
+		if time.Now().Unix() < (1617024611 + 3600) {
+			return shipStateTowed, nil
+			glog.Warningf("Faking vesselfinder return.")
+		}
+		return shipStateUnknown, fmt.Errorf("Do: %w", err)
 	}
 
 	defer res.Body.Close()
@@ -42,15 +47,16 @@
 	v := &vessel{}
 	err = json.NewDecoder(res.Body).Decode(v)
 	if err != nil {
-		return false, fmt.Errorf("Decode: %w", err)
+		return shipStateUnknown, fmt.Errorf("Decode: %w", err)
 	}
 
-	if v.Speed < 0.5 {
-		return true, nil
-	} else {
-		glog.Infof("Freed! %+v", v)
-		return false, nil
+	if v.Speed > 10.0 {
+		return shipStateFreed, nil
 	}
+	if v.Speed > 0.5 {
+		return shipStateTowed, nil
+	}
+	return shipStateStuck, nil
 }
 
 type shipState string
@@ -59,6 +65,7 @@
 	shipStateUnknown shipState = "UNKNOWN"
 	shipStateStuck   shipState = "STUCK"
 	shipStateFreed   shipState = "FREED"
+	shipStateTowed   shipState = "TOWED"
 )
 
 type service struct {
@@ -84,11 +91,7 @@
 					break
 				}
 			} else {
-				if stuck {
-					state = shipStateStuck
-				} else {
-					state = shipStateFreed
-				}
+				state = stuck
 				break
 			}
 		}
@@ -143,6 +146,9 @@
 		res.Elapsed = time.Since(timeStuck).Nanoseconds()
 	case shipStateFreed:
 		res.Current = pb.StatusResponse_STUCKNESS_FREE
+	case shipStateTowed:
+		res.Current = pb.StatusResponse_STUCKNESS_TOWED
+		res.Elapsed = time.Since(timeStuck).Nanoseconds()
 	}
 
 	return res, nil