diff options
Diffstat (limited to 'vendor/maunium.net/go/mautrix/error.go')
-rw-r--r-- | vendor/maunium.net/go/mautrix/error.go | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/vendor/maunium.net/go/mautrix/error.go b/vendor/maunium.net/go/mautrix/error.go new file mode 100644 index 00000000..9c5e8a0e --- /dev/null +++ b/vendor/maunium.net/go/mautrix/error.go @@ -0,0 +1,154 @@ +// Copyright (c) 2020 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package mautrix + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" +) + +// Common error codes from https://matrix.org/docs/spec/client_server/latest#api-standards +// +// Can be used with errors.Is() to check the response code without casting the error: +// +// err := client.Sync() +// if errors.Is(err, MUnknownToken) { +// // logout +// } +var ( + // Forbidden access, e.g. joining a room without permission, failed login. + MForbidden = RespError{ErrCode: "M_FORBIDDEN"} + // Unrecognized request, e.g. the endpoint does not exist or is not implemented. + MUnrecognized = RespError{ErrCode: "M_UNRECOGNIZED"} + // The access token specified was not recognised. + MUnknownToken = RespError{ErrCode: "M_UNKNOWN_TOKEN"} + // No access token was specified for the request. + MMissingToken = RespError{ErrCode: "M_MISSING_TOKEN"} + // Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. + MBadJSON = RespError{ErrCode: "M_BAD_JSON"} + // Request did not contain valid JSON. + MNotJSON = RespError{ErrCode: "M_NOT_JSON"} + // No resource was found for this request. + MNotFound = RespError{ErrCode: "M_NOT_FOUND"} + // Too many requests have been sent in a short period of time. Wait a while then try again. + MLimitExceeded = RespError{ErrCode: "M_LIMIT_EXCEEDED"} + // The user ID associated with the request has been deactivated. + // Typically for endpoints that prove authentication, such as /login. + MUserDeactivated = RespError{ErrCode: "M_USER_DEACTIVATED"} + // Encountered when trying to register a user ID which has been taken. + MUserInUse = RespError{ErrCode: "M_USER_IN_USE"} + // Encountered when trying to register a user ID which is not valid. + MInvalidUsername = RespError{ErrCode: "M_INVALID_USERNAME"} + // Sent when the room alias given to the createRoom API is already in use. + MRoomInUse = RespError{ErrCode: "M_ROOM_IN_USE"} + // The state change requested cannot be performed, such as attempting to unban a user who is not banned. + MBadState = RespError{ErrCode: "M_BAD_STATE"} + // The request or entity was too large. + MTooLarge = RespError{ErrCode: "M_TOO_LARGE"} + // The resource being requested is reserved by an application service, or the application service making the request has not created the resource. + MExclusive = RespError{ErrCode: "M_EXCLUSIVE"} + // The client's request to create a room used a room version that the server does not support. + MUnsupportedRoomVersion = RespError{ErrCode: "M_UNSUPPORTED_ROOM_VERSION"} + // The client attempted to join a room that has a version the server does not support. + // Inspect the room_version property of the error response for the room's version. + MIncompatibleRoomVersion = RespError{ErrCode: "M_INCOMPATIBLE_ROOM_VERSION"} + // The client specified a parameter that has the wrong value. + MInvalidParam = RespError{ErrCode: "M_INVALID_PARAM"} + + MSC2659URLNotSet = RespError{ErrCode: "FI.MAU.MSC2659_URL_NOT_SET"} + MSC2659BadStatus = RespError{ErrCode: "FI.MAU.MSC2659_BAD_STATUS"} + MSC2659ConnectionTimeout = RespError{ErrCode: "FI.MAU.MSC2659_CONNECTION_TIMEOUT"} + MSC2659ConnectionFailed = RespError{ErrCode: "FI.MAU.MSC2659_CONNECTION_FAILED"} +) + +// HTTPError An HTTP Error response, which may wrap an underlying native Go Error. +type HTTPError struct { + Request *http.Request + Response *http.Response + ResponseBody string + + WrappedError error + RespError *RespError + Message string +} + +func (e HTTPError) Is(err error) bool { + return (e.RespError != nil && errors.Is(e.RespError, err)) || (e.WrappedError != nil && errors.Is(e.WrappedError, err)) +} + +func (e HTTPError) IsStatus(code int) bool { + return e.Response != nil && e.Response.StatusCode == code +} + +func (e HTTPError) Error() string { + if e.WrappedError != nil { + return fmt.Sprintf("%s: %v", e.Message, e.WrappedError) + } else if e.RespError != nil { + return fmt.Sprintf("failed to %s %s: %s (HTTP %d): %s", e.Request.Method, e.Request.URL.Path, + e.RespError.ErrCode, e.Response.StatusCode, e.RespError.Err) + } else { + msg := fmt.Sprintf("failed to %s %s: %s", e.Request.Method, e.Request.URL.Path, e.Response.Status) + if len(e.ResponseBody) > 0 { + msg = fmt.Sprintf("%s\n%s", msg, e.ResponseBody) + } + return msg + } +} + +func (e HTTPError) Unwrap() error { + if e.WrappedError != nil { + return e.WrappedError + } else if e.RespError != nil { + return *e.RespError + } + return nil +} + +// RespError is the standard JSON error response from Homeservers. It also implements the Golang "error" interface. +// See https://spec.matrix.org/v1.2/client-server-api/#api-standards +type RespError struct { + ErrCode string + Err string + ExtraData map[string]interface{} +} + +func (e *RespError) UnmarshalJSON(data []byte) error { + err := json.Unmarshal(data, &e.ExtraData) + if err != nil { + return err + } + e.ErrCode, _ = e.ExtraData["errcode"].(string) + e.Err, _ = e.ExtraData["error"].(string) + return nil +} + +func (e *RespError) MarshalJSON() ([]byte, error) { + if e.ExtraData == nil { + e.ExtraData = make(map[string]interface{}) + } + e.ExtraData["errcode"] = e.ErrCode + e.ExtraData["error"] = e.Err + return json.Marshal(&e.ExtraData) +} + +// Error returns the errcode and error message. +func (e RespError) Error() string { + return e.ErrCode + ": " + e.Err +} + +func (e RespError) Is(err error) bool { + e2, ok := err.(RespError) + if !ok { + return false + } + if e.ErrCode == "M_UNKNOWN" && e2.ErrCode == "M_UNKNOWN" { + return e.Err == e2.Err + } + return e2.ErrCode == e.ErrCode +} |