/* global _, Backbone, i18n, MessageController, moment, Whisper */ // eslint-disable-next-line func-names (function() { 'use strict'; window.Whisper = window.Whisper || {}; async function destroyExpiredMessages() { try { window.log.info('destroyExpiredMessages: Loading messages...'); const messages = await window.Signal.Data.getExpiredMessages({ MessageCollection: Whisper.MessageCollection, }); await Promise.all( messages.map(async fromDB => { const message = MessageController.register(fromDB.id, fromDB); window.log.info('Message expired', { sentAt: message.get('sent_at'), }); // We delete after the trigger to allow the conversation time to process // the expiration before the message is removed from the database. await window.Signal.Data.removeMessage(message.id, { Message: Whisper.Message, }); Whisper.events.trigger('messageExpired', { conversationKey: message.attributes.conversationId, messageId: message.id, }); const conversation = message.getConversation(); if (conversation) { conversation.trigger('expired', message); } }) ); } catch (error) { window.log.error( 'destroyExpiredMessages: Error deleting expired messages', error && error.stack ? error.stack : error ); } window.log.info('destroyExpiredMessages: complete'); checkExpiringMessages(); } let timeout; async function checkExpiringMessages() { // Look up the next expiring message and set a timer to destroy it const messages = await window.Signal.Data.getNextExpiringMessage({ MessageCollection: Whisper.MessageCollection, }); const next = messages.at(0); if (!next) { return; } const expiresAt = next.get('expires_at'); Whisper.ExpiringMessagesListener.nextExpiration = expiresAt; window.log.info('next message expires', new Date(expiresAt).toISOString()); let wait = expiresAt - Date.now(); // In the past if (wait < 0) { wait = 0; } // Too far in the future, since it's limited to a 32-bit value if (wait > 2147483647) { wait = 2147483647; } clearTimeout(timeout); timeout = setTimeout(destroyExpiredMessages, wait); } const throttledCheckExpiringMessages = _.throttle( checkExpiringMessages, 1000 ); Whisper.ExpiringMessagesListener = { nextExpiration: null, init(events) { checkExpiringMessages(); events.on('timetravel', throttledCheckExpiringMessages); }, update: throttledCheckExpiringMessages, }; const TimerOption = Backbone.Model.extend({ getName() { return ( i18n(['timerOption', this.get('time'), this.get('unit')].join('_')) || moment.duration(this.get('time'), this.get('unit')).humanize() ); }, getAbbreviated() { return i18n( ['timerOption', this.get('time'), this.get('unit'), 'abbreviated'].join( '_' ) ); }, }); Whisper.ExpirationTimerOptions = new (Backbone.Collection.extend({ model: TimerOption, getName(seconds = 0) { const o = this.findWhere({ seconds }); if (o) { return o.getName(); } return [seconds, 'seconds'].join(' '); }, getAbbreviated(seconds = 0) { const o = this.findWhere({ seconds }); if (o) { return o.getAbbreviated(); } return [seconds, 's'].join(''); }, }))( [ [0, 'seconds'], [5, 'seconds'], [10, 'seconds'], [30, 'seconds'], [1, 'minute'], [5, 'minutes'], [30, 'minutes'], [1, 'hour'], [6, 'hours'], [12, 'hours'], [1, 'day'], [1, 'week'], ].map(o => { const duration = moment.duration(o[0], o[1]); // 5, 'seconds' return { time: o[0], unit: o[1], seconds: duration.asSeconds(), }; }) ); })();