From e679437c9c8805155cb6b439522cc34962565530 Mon Sep 17 00:00:00 2001 From: leeyeh Date: Fri, 11 May 2018 12:31:42 +0800 Subject: [PATCH] feat: update Error messages Error messages are for humans. Previously we use error name as the message. This commit replaces some confusing error messages with more detailed explanations. BREAKING CHANGE: Some error messages is changed. This is breaking if string comparison are used against error.message. We suggest to use error.code or error.name for error handling. PLEASE NOTE: In future, changes to error.message will not be considered breaking. --- realtime.d.ts | 22 +++++- src/connection.js | 7 +- src/conversations/temporary-conversation.js | 4 +- src/error.js | 80 +++++++++++++++++++-- test/conversation.js | 6 +- test/messages.js | 1 + 6 files changed, 109 insertions(+), 11 deletions(-) diff --git a/realtime.d.ts b/realtime.d.ts index 365aaf856..80bfa7072 100644 --- a/realtime.d.ts +++ b/realtime.d.ts @@ -353,6 +353,7 @@ declare namespace LeanCloudRealtime { CLOSE_NORMAL, CLOSE_ABNORMAL, APP_NOT_AVAILABLE, + SIGNATURE_FAILED, INVALID_LOGIN, SESSION_REQUIRED, READ_TIMEOUT, @@ -361,8 +362,10 @@ declare namespace LeanCloudRealtime { INVALID_ORIGIN, SESSION_CONFLICT, SESSION_TOKEN_EXPIRED, + APP_QUOTA_EXCEEDED, + MESSAGE_SENT_QUOTA_EXCEEDED, INTERNAL_ERROR, - SEND_MESSAGE_TIMEOUT, + CONVERSATION_API_FAILED, CONVERSATION_SIGNATURE_FAILED, CONVERSATION_NOT_FOUND, CONVERSATION_FULL, @@ -370,9 +373,24 @@ declare namespace LeanCloudRealtime { CONVERSATION_UPDATE_FAILED, CONVERSATION_READ_ONLY, CONVERSATION_NOT_ALLOWED, - CONVERSATION_EXPIRED, + CONVERSATION_UPDATE_REJECTED, + CONVERSATION_QUERY_FAILED, + CONVERSATION_LOG_FAILED, + CONVERSATION_LOG_REJECTED, + SYSTEM_CONVERSATION_REQUIRED, + NORMAL_CONVERSATION_REQUIRED, + CONVERSATION_BLACKLISTED, + TRANSIENT_CONVERSATION_REQUIRED, + CONVERSATION_MEMBERSHIP_REQUIRED, + CONVERSATION_API_QUOTA_EXCEEDED, + TEMPORARY_CONVERSATION_EXPIRED, INVALID_MESSAGING_TARGET, MESSAGE_REJECTED_BY_APP, + MESSAGE_OWNERSHIP_REQUIRED, + MESSAGE_NOT_FOUND, + MESSAGE_UPDATE_REJECTED_BY_APP, + MESSAGE_EDIT_DISABLED, + MESSAGE_RECALL_DISABLED, } export enum Event { diff --git a/src/connection.js b/src/connection.js index a6063d033..f9896122c 100644 --- a/src/connection.js +++ b/src/connection.js @@ -82,7 +82,12 @@ export default class Connection extends WebSocketPlus { timeout: setTimeout(() => { if (this._commands[serialId]) { if (debug.enabled) debug('✗ %O timeout', trim(command)); - reject(new Error('Command Timeout.')); + reject( + createError({ + error: `Command Timeout [cmd:${command.cmd} op:${command.op}]`, + name: 'COMMAND_TIMEOUT', + }) + ); delete this._commands[serialId]; } }, COMMAND_TIMEOUT), diff --git a/src/conversations/temporary-conversation.js b/src/conversations/temporary-conversation.js index f65725377..4f2d0ce1a 100644 --- a/src/conversations/temporary-conversation.js +++ b/src/conversations/temporary-conversation.js @@ -4,7 +4,7 @@ import { decodeDate, getTime } from '../utils'; const transformNotFoundError = error => error.code === ErrorCode.CONVERSATION_NOT_FOUND - ? createError({ code: ErrorCode.CONVERSATION_EXPIRED }) + ? createError({ code: ErrorCode.TEMPORARY_CONVERSATION_EXPIRED }) : error; /** @@ -48,7 +48,7 @@ class TemporaryConversation extends ConversationBase { async _send(...args) { if (this.expired) - throw createError({ code: ErrorCode.CONVERSATION_EXPIRED }); + throw createError({ code: ErrorCode.TEMPORARY_CONVERSATION_EXPIRED }); try { return await super._send(...args); } catch (error) { diff --git a/src/error.js b/src/error.js index 436acf565..0aebe149b 100644 --- a/src/error.js +++ b/src/error.js @@ -9,6 +9,10 @@ export const error = Object.freeze({ name: 'APP_NOT_AVAILABLE', message: 'App not exists or realtime message service is disabled.', }, + 4102: { + name: 'SIGNATURE_FAILED', + message: 'Login signature mismatch.', + }, 4103: { name: 'INVALID_LOGIN', message: 'Malformed clientId.', @@ -36,15 +40,25 @@ export const error = Object.freeze({ 4112: { name: 'SESSION_TOKEN_EXPIRED', }, + 4113: { + name: 'APP_QUOTA_EXCEEDED', + message: 'The daily active users limit exceeded.', + }, + 4116: { + name: 'MESSAGE_SENT_QUOTA_EXCEEDED', + message: 'Command sent too fast.', + }, 4200: { name: 'INTERNAL_ERROR', message: 'Internal error, please contact LeanCloud for support.', }, - 4201: { - name: 'SEND_MESSAGE_TIMEOUT', + 4301: { + name: 'CONVERSATION_API_FAILED', + message: 'Upstream Conversatoin API failed, see error.detail for details.', }, 4302: { name: 'CONVERSATION_SIGNATURE_FAILED', + message: 'Conversation action signature mismatch.', }, 4303: { name: 'CONVERSATION_NOT_FOUND', @@ -54,6 +68,7 @@ export const error = Object.freeze({ }, 4305: { name: 'CONVERSATION_REJECTED_BY_APP', + message: 'Conversation action rejected by hook.', }, 4306: { name: 'CONVERSATION_UPDATE_FAILED', @@ -64,15 +79,69 @@ export const error = Object.freeze({ 4308: { name: 'CONVERSATION_NOT_ALLOWED', }, + 4309: { + name: 'CONVERSATION_UPDATE_REJECTED', + message: 'Conversation update rejected because the client is not a member.', + }, + 4310: { + name: 'CONVERSATION_QUERY_FAILED', + message: 'Conversation query failed because it is too expansive.', + }, + 4311: { + name: 'CONVERSATION_LOG_FAILED', + }, + 4312: { + name: 'CONVERSATION_LOG_REJECTED', + message: + 'Message query rejected because the client is not a member of the conversation.', + }, + 4313: { + name: 'SYSTEM_CONVERSATION_REQUIRED', + }, + 4314: { + name: 'NORMAL_CONVERSATION_REQUIRED', + }, + 4315: { + name: 'CONVERSATION_BLACKLISTED', + message: 'Blacklisted in the conversation.', + }, + 4316: { + name: 'TRANSIENT_CONVERSATION_REQUIRED', + }, 4317: { - name: 'CONVERSATION_EXPIRED', + name: 'CONVERSATION_MEMBERSHIP_REQUIRED', + }, + 4318: { + name: 'CONVERSATION_API_QUOTA_EXCEEDED', + message: 'LeanCloud API quota exceeded. You may upgrade your plan.', + }, + 4323: { + name: 'TEMPORARY_CONVERSATION_EXPIRED', message: 'Temporary conversation expired or does not exist.', }, 4401: { name: 'INVALID_MESSAGING_TARGET', + message: 'Conversation does not exist or client is not a member.', }, 4402: { name: 'MESSAGE_REJECTED_BY_APP', + message: 'Message rejected by hook.', + }, + 4403: { + name: 'MESSAGE_OWNERSHIP_REQUIRED', + }, + 4404: { + name: 'MESSAGE_NOT_FOUND', + }, + 4405: { + name: 'MESSAGE_UPDATE_REJECTED_BY_APP', + message: 'Message update rejected by hook.', + }, + 4406: { + name: 'MESSAGE_EDIT_DISABLED', + }, + 4407: { + name: 'MESSAGE_RECALL_DISABLED', }, }); @@ -94,8 +163,10 @@ export const createError = ({ error: errorMessage, }) => { let message = reason || detail || errorMessage; + let name = reason; if (!message && error[code]) { - message = error[code].message || error[code].name; + ({ name } = error[code]); + message = error[code].message || name; } if (!message) { message = `Unknow Error: ${code}`; @@ -105,5 +176,6 @@ export const createError = ({ code, appCode, detail, + name, }); }; diff --git a/test/conversation.js b/test/conversation.js index 15f715fca..b9894dd6f 100644 --- a/test/conversation.js +++ b/test/conversation.js @@ -754,14 +754,16 @@ describe('Conversation', () => { conv.expired.should.eql(true); await conv.send(new TextMessage('')).should.be.rejectedWith(Error, { message: 'Temporary conversation expired or does not exist.', - code: ErrorCode.CONVERSATION_EXPIRED, + code: ErrorCode.TEMPORARY_CONVERSATION_EXPIRED, + name: 'TEMPORARY_CONVERSATION_EXPIRED', }); // server expiration check conv.expiredAt = Date.now() + 1000000; conv.expired.should.eql(false); return conv.send(new TextMessage('')).should.be.rejectedWith(Error, { message: 'Temporary conversation expired or does not exist.', - code: ErrorCode.CONVERSATION_EXPIRED, + code: ErrorCode.TEMPORARY_CONVERSATION_EXPIRED, + name: 'TEMPORARY_CONVERSATION_EXPIRED', }); }); it('serialize and parse', async () => { diff --git a/test/messages.js b/test/messages.js index fb3ca9cb0..52134828a 100644 --- a/test/messages.js +++ b/test/messages.js @@ -323,6 +323,7 @@ describe('Messages', () => { .then(conversation => conversation.send(message)) .should.be.rejectedWith(Error, { message: 'INVALID_MESSAGING_TARGET', + name: 'INVALID_MESSAGING_TARGET', code: ErrorCode.INVALID_MESSAGING_TARGET, }) .then(() => {