From 966d3b95b7b78b3e6fdf502d026e1fa70547de40 Mon Sep 17 00:00:00 2001 From: Kegsay Date: Mon, 20 Feb 2017 17:20:49 +0000 Subject: [PATCH] Add error package and some Matrix errors (#13) Terse function names are used to make usage not stutter. For example: ```go err := error.Forbidden("you shall not pass") ``` At the moment they are all the same fundamental `MatrixError` type. This will be bad if we ever want to `switch` based on the kind of error. I'm hoping we won't ever need to introspect into errors like this: ideally these errors would be created purely for immediately being returned in an HTTP response. `MatrixError` implements the `error` interface. --- .../dendrite/clientapi/jsonerror/jsonerror.go | 62 +++++++++++++++++++ .../clientapi/jsonerror/jsonerror_test.go | 30 +++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror.go create mode 100644 src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror_test.go diff --git a/src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror.go b/src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror.go new file mode 100644 index 000000000..a0111197c --- /dev/null +++ b/src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror.go @@ -0,0 +1,62 @@ +package jsonerror + +import "fmt" + +// MatrixError represents the "standard error response" in Matrix. +// http://matrix.org/docs/spec/client_server/r0.2.0.html#api-standards +type MatrixError struct { + ErrCode string `json:"errcode"` + Err string `json:"error"` +} + +func (e *MatrixError) Error() string { + return fmt.Sprintf("%s: %s", e.ErrCode, e.Err) +} + +// Forbidden is an error when the client tries to access a resource +// they are not allowed to access. +func Forbidden(msg string) *MatrixError { + return &MatrixError{"M_FORBIDDEN", msg} +} + +// BadJSON is an error when the client supplies malformed JSON. +func BadJSON(msg string) *MatrixError { + return &MatrixError{"M_BAD_JSON", msg} +} + +// NotJSON is an error when the client supplies something that is not JSON +// to a JSON endpoint. +func NotJSON(msg string) *MatrixError { + return &MatrixError{"M_NOT_JSON", msg} +} + +// NotFound is an error when the client tries to access an unknown resource. +func NotFound(msg string) *MatrixError { + return &MatrixError{"M_NOT_FOUND", msg} +} + +// MissingToken is an error when the client tries to access a resource which +// requires authentication without supplying credentials. +func MissingToken(msg string) *MatrixError { + return &MatrixError{"M_MISSING_TOKEN", msg} +} + +// UnknownToken is an error when the client tries to access a resource which +// requires authentication and supplies a valid, but out-of-date token. +func UnknownToken(msg string) *MatrixError { + return &MatrixError{"M_UNKNOWN_TOKEN", msg} +} + +// LimitExceededError is a rate-limiting error. +type LimitExceededError struct { + MatrixError + RetryAfterMS int64 `json:"retry_after_ms,omitempty"` +} + +// LimitExceeded is an error when the client tries to send events too quickly. +func LimitExceeded(msg string, retryAfterMS int64) *LimitExceededError { + return &LimitExceededError{ + MatrixError: MatrixError{"M_LIMIT_EXCEEDED", msg}, + RetryAfterMS: retryAfterMS, + } +} diff --git a/src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror_test.go b/src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror_test.go new file mode 100644 index 000000000..33e2ede83 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror_test.go @@ -0,0 +1,30 @@ +package jsonerror + +import ( + "encoding/json" + "testing" +) + +func TestLimitExceeded(t *testing.T) { + e := LimitExceeded("too fast", 5000) + jsonBytes, err := json.Marshal(&e) + if err != nil { + t.Fatalf("TestLimitExceeded: Failed to marshal LimitExceeded error. %s", err.Error()) + } + want := `{"errcode":"M_LIMIT_EXCEEDED","error":"too fast","retry_after_ms":5000}` + if string(jsonBytes) != want { + t.Errorf("TestLimitExceeded: want %s, got %s", want, string(jsonBytes)) + } +} + +func TestForbidden(t *testing.T) { + e := Forbidden("you shall not pass") + jsonBytes, err := json.Marshal(&e) + if err != nil { + t.Fatalf("TestForbidden: Failed to marshal Forbidden error. %s", err.Error()) + } + want := `{"errcode":"M_FORBIDDEN","error":"you shall not pass"}` + if string(jsonBytes) != want { + t.Errorf("TestForbidden: want %s, got %s", want, string(jsonBytes)) + } +}