diff options
Diffstat (limited to 'src/services')
| -rw-r--r-- | src/services/api/api.service.js | 17 | ||||
| -rw-r--r-- | src/services/chat_service/chat_service.js | 69 | ||||
| -rw-r--r-- | src/services/chat_utils/chat_utils.js | 21 | ||||
| -rw-r--r-- | src/services/entity_normalizer/entity_normalizer.service.js | 3 |
4 files changed, 100 insertions, 10 deletions
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 1a3495d4..22b5e8ba 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -129,7 +129,11 @@ const promisedRequest = ({ method, url, params, payload, credentials, headers = return reject(new StatusCodeError(response.status, json, { url, options }, response)) } return resolve(json) - })) + }) + .catch((error) => { + return reject(new StatusCodeError(response.status, error, { url, options }, response)) + }) + ) }) } @@ -1210,7 +1214,7 @@ const chatMessages = ({ id, credentials, maxId, sinceId, limit = 20 }) => { }) } -const sendChatMessage = ({ id, content, mediaId = null, credentials }) => { +const sendChatMessage = ({ id, content, mediaId = null, idempotencyKey, credentials }) => { const payload = { 'content': content } @@ -1219,11 +1223,18 @@ const sendChatMessage = ({ id, content, mediaId = null, credentials }) => { payload['media_id'] = mediaId } + const headers = {} + + if (idempotencyKey) { + headers['idempotency-key'] = idempotencyKey + } + return promisedRequest({ url: PLEROMA_CHAT_MESSAGES_URL(id), method: 'POST', payload: payload, - credentials + credentials, + headers }) } diff --git a/src/services/chat_service/chat_service.js b/src/services/chat_service/chat_service.js index 95c69482..b0905dc1 100644 --- a/src/services/chat_service/chat_service.js +++ b/src/services/chat_service/chat_service.js @@ -3,6 +3,7 @@ import _ from 'lodash' const empty = (chatId) => { return { idIndex: {}, + idempotencyKeyIndex: {}, messages: [], newMessageCount: 0, lastSeenTimestamp: 0, @@ -13,8 +14,18 @@ const empty = (chatId) => { } const clear = (storage) => { - storage.idIndex = {} - storage.messages.splice(0, storage.messages.length) + const failedMessageIds = [] + + for (const message of storage.messages) { + if (message.error) { + failedMessageIds.push(message.id) + } else { + delete storage.idIndex[message.id] + delete storage.idempotencyKeyIndex[message.id] + } + } + + storage.messages = storage.messages.filter(m => failedMessageIds.includes(m.id)) storage.newMessageCount = 0 storage.lastSeenTimestamp = 0 storage.minId = undefined @@ -37,6 +48,25 @@ const deleteMessage = (storage, messageId) => { } } +const handleMessageError = (storage, fakeId, isRetry) => { + if (!storage) { return } + const fakeMessage = storage.idIndex[fakeId] + if (fakeMessage) { + fakeMessage.error = true + fakeMessage.pending = false + if (!isRetry) { + // Ensure the failed message doesn't stay at the bottom of the list. + const lastPersistedMessage = _.orderBy(storage.messages, ['pending', 'id'], ['asc', 'desc'])[0] + if (lastPersistedMessage) { + const oldId = fakeMessage.id + fakeMessage.id = `${lastPersistedMessage.id}-${new Date().getTime()}` + storage.idIndex[fakeMessage.id] = fakeMessage + delete storage.idIndex[oldId] + } + } + } +} + const add = (storage, { messages: newMessages, updateMaxId = true }) => { if (!storage) { return } for (let i = 0; i < newMessages.length; i++) { @@ -45,7 +75,25 @@ const add = (storage, { messages: newMessages, updateMaxId = true }) => { // sanity check if (message.chat_id !== storage.chatId) { return } - if (!storage.minId || message.id < storage.minId) { + if (message.fakeId) { + const fakeMessage = storage.idIndex[message.fakeId] + if (fakeMessage) { + // In case the same id exists (chat update before POST response) + // make sure to remove the older duplicate message. + if (storage.idIndex[message.id]) { + delete storage.idIndex[message.id] + storage.messages = storage.messages.filter(msg => msg.id !== message.id) + } + Object.assign(fakeMessage, message, { error: false }) + delete fakeMessage['fakeId'] + storage.idIndex[fakeMessage.id] = fakeMessage + delete storage.idIndex[message.fakeId] + + return + } + } + + if (!storage.minId || (!message.pending && message.id < storage.minId)) { storage.minId = message.id } @@ -55,16 +103,22 @@ const add = (storage, { messages: newMessages, updateMaxId = true }) => { } } - if (!storage.idIndex[message.id]) { + if (!storage.idIndex[message.id] && !isConfirmation(storage, message)) { if (storage.lastSeenTimestamp < message.created_at) { storage.newMessageCount++ } - storage.messages.push(message) storage.idIndex[message.id] = message + storage.messages.push(storage.idIndex[message.id]) + storage.idempotencyKeyIndex[message.idempotency_key] = true } } } +const isConfirmation = (storage, message) => { + if (!message.idempotency_key) return + return storage.idempotencyKeyIndex[message.idempotency_key] +} + const resetNewMessageCount = (storage) => { if (!storage) { return } storage.newMessageCount = 0 @@ -76,7 +130,7 @@ const getView = (storage) => { if (!storage) { return [] } const result = [] - const messages = _.sortBy(storage.messages, ['id', 'desc']) + const messages = _.orderBy(storage.messages, ['pending', 'id'], ['asc', 'asc']) const firstMessage = messages[0] let previousMessage = messages[messages.length - 1] let currentMessageChainId @@ -148,7 +202,8 @@ const ChatService = { getView, deleteMessage, resetNewMessageCount, - clear + clear, + handleMessageError } export default ChatService diff --git a/src/services/chat_utils/chat_utils.js b/src/services/chat_utils/chat_utils.js index 86fe1af9..de6e0625 100644 --- a/src/services/chat_utils/chat_utils.js +++ b/src/services/chat_utils/chat_utils.js @@ -18,3 +18,24 @@ export const maybeShowChatNotification = (store, chat) => { showDesktopNotification(store.rootState, opts) } + +export const buildFakeMessage = ({ content, chatId, attachments, userId, idempotencyKey }) => { + const fakeMessage = { + content, + chat_id: chatId, + created_at: new Date(), + id: `${new Date().getTime()}`, + attachments: attachments, + account_id: userId, + idempotency_key: idempotencyKey, + emojis: [], + pending: true, + isNormalized: true + } + + if (attachments[0]) { + fakeMessage.attachment = attachments[0] + } + + return fakeMessage +} diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 1884478a..9d09b8d0 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -429,6 +429,9 @@ export const parseChatMessage = (message) => { } else { output.attachments = [] } + output.pending = !!message.pending + output.error = false + output.idempotency_key = message.idempotency_key output.isNormalized = true return output } |
