Index: milo/common/error.go |
diff --git a/milo/common/error.go b/milo/common/error.go |
index 291e9a60fd7dd2e67b5a76573278821e4c2d29f2..b3e2e05869eba0c03530cb295cd542577772e12a 100644 |
--- a/milo/common/error.go |
+++ b/milo/common/error.go |
@@ -15,16 +15,80 @@ |
package common |
import ( |
- "github.com/luci/luci-go/server/router" |
- "github.com/luci/luci-go/server/templates" |
+ "net/http" |
+ |
+ "github.com/luci/luci-go/common/errors" |
+) |
+ |
+// ErrorCode represents milo's internal error code system. The subsystems in |
+// milo can attach an ErrorCode to an error (using ErrorTag), and then the html |
+// and grpc frontends know how to render the error in a way that will help the |
+// user. |
+type ErrorCode int |
+ |
+const ( |
+ // CodeUnknown means an error happened, but we weren't able to classify it. |
+ CodeUnknown ErrorCode = iota |
+ |
+ // CodeUnauthorized occurs when a user isn't logged in, but needs to be to |
+ // proceed further. |
+ CodeUnauthorized |
+ |
+ // CodeNoAccess occurs when the currently logged-in user is not permitted to |
+ // see the resource. |
+ CodeNoAccess |
+ |
+ // CodeNotFound occurs when we weren't able to find the build that the |
+ // user asked for. |
+ CodeNotFound |
+ |
+ // CodeParameterError occurs when one or more of the user-provided parameters |
+ // was malformed. |
+ CodeParameterError |
) |
-// ErrorPage writes an error page into c.Writer with an http code "code" |
-// and custom message. |
-func ErrorPage(c *router.Context, code int, message string) { |
- c.Writer.WriteHeader(code) |
- templates.MustRender(c.Context, c.Writer, "pages/error.html", templates.Args{ |
- "Code": code, |
- "Message": message, |
- }) |
+var httpCode = map[ErrorCode]int{ |
+ CodeUnauthorized: http.StatusUnauthorized, |
+ CodeNoAccess: http.StatusForbidden, |
+ CodeNotFound: http.StatusNotFound, |
+ CodeParameterError: http.StatusBadRequest, |
+} |
+ |
+// HTTPStatus returns an HTTP Status code corresponding to this ErrorCode. |
+func (c ErrorCode) HTTPStatus() int { |
+ if ret, ok := httpCode[c]; ok { |
+ return ret |
+ } |
+ return http.StatusInternalServerError |
} |
+ |
+// Tag returns an errors.TagValue for this code. |
+func (c ErrorCode) Tag() errors.TagValue { |
+ return ErrorTag.With(c) |
+} |
+ |
+// GenerateErrorTagValue implements errors.TagValueGenerator so that ErrorCodes |
+// can be used like: |
+// errors.Annotate(err).Tag(CodeNotFound) |
+// errors.New("terrible thing", CodeNotFound) |
+func (c ErrorCode) GenerateErrorTagValue() errors.TagValue { |
+ return ErrorTag.With(c) |
+} |
+ |
+type errorTag struct{ Key errors.TagKey } |
+ |
+func (t *errorTag) In(err error) ErrorCode { |
+ v, ok := errors.TagValueIn(t.Key, err) |
+ if ok { |
+ return v.(ErrorCode) |
+ } |
+ return CodeUnknown |
+} |
+ |
+func (t *errorTag) With(value ErrorCode) errors.TagValue { |
+ return errors.TagValue{Key: t.Key, Value: value} |
+} |
+ |
+// ErrorTag should be used to tag errors in the milo ecosystem to categorize |
+// them so they can be rendered properly in the frontend. |
+var ErrorTag = errorTag{errors.NewTagKey("holds a milo ErrorCode")} |