diff --git a/Gruntfile.js b/Gruntfile.js index ec914d56..ea0ec37f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -59,6 +59,7 @@ module.exports = function(grunt) { 'libtextsecure/message_receiver.js', 'libtextsecure/outgoing_message.js', 'libtextsecure/sendmessage.js', + 'libtextsecure/sync_request.js', 'libtextsecure/contacts_parser.js', ], dest: 'js/libtextsecure.js', diff --git a/js/background.js b/js/background.js index f4d5510e..8aa6e0dd 100644 --- a/js/background.js +++ b/js/background.js @@ -103,21 +103,20 @@ messageReceiver.addEventListener('sent', onSentMessage); messageReceiver.addEventListener('error', onError); - messageReceiver.addEventListener('contactsync', onContactSyncComplete); - window.textsecure.messaging = new textsecure.MessageSender(SERVER_URL, USERNAME, PASSWORD, ATTACHMENT_SERVER_URL); if (firstRun === true && textsecure.storage.user.getDeviceId() != '1') { - textsecure.messaging.sendRequestContactSyncMessage().then(function() { - textsecure.messaging.sendRequestGroupSyncMessage(); + var syncRequest = new textsecure.SyncRequest(textsecure.messaging, messageReceiver); + syncRequest.addEventListener('success', function() { + console.log('sync successful'); + window.dispatchEvent(new Event('textsecure:contactsync')); + }); + syncRequest.addEventListener('timeout', function() { + console.log('sync timed out'); + window.dispatchEvent(new Event('textsecure:contactsync')); }); } } - function onContactSyncComplete() { - console.log('Contact sync complete'); - window.dispatchEvent(new Event('textsecure:contactsync')); - } - function onContactReceived(ev) { var contactDetails = ev.contactDetails; ConversationController.create({ diff --git a/js/libtextsecure.js b/js/libtextsecure.js index c9451fe1..79fe86a6 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -37677,6 +37677,125 @@ textsecure.MessageSender.prototype = { constructor: textsecure.MessageSender }; +/* + * vim: ts=4:sw=4:expandtab + */ + + +;(function () { + 'use strict'; + window.textsecure = window.textsecure || {}; + + function SyncRequest(sender, receiver) { + this.receiver = receiver; + + this.oncontact = this.onContactSyncComplete.bind(this); + receiver.addEventListener('contactsync', this.oncontact); + + this.ongroup = this.onGroupSyncComplete.bind(this); + receiver.addEventListener('groupsync', this.ongroup); + + sender.sendRequestContactSyncMessage().then(function() { + sender.sendRequestGroupSyncMessage(); + }); + this.timeout = setTimout(this.onTimeout.bind(this), 60000); + } + + SyncRequest.prototype = { + constructor: SyncRequest, + onContactSyncComplete: function() { + this.contactSync = true; + this.update(); + }, + onGroupSyncComplete: function() { + this.groupSync = true; + this.update(); + }, + update: function() { + if (this.contactSync && this.groupSync) { + this.dispatchEvent(new Event('success')); + this.cleanup(); + } + }, + onTimeout: function() { + this.dispatchEvent(new Event('timeout')); + this.cleanup(); + }, + cleanup: function() { + clearTimeout(this.timeout); + this.receiver.removeEventListener('contactsync', this.oncontact); + this.receiver.removeEventListener('groupSync', this.ongroup); + delete this.listeners; + }, + + /* Implements EventTarget */ /// TODO: Dedupe this same code in MessageReceiver + dispatchEvent: function(ev) { + if (!(ev instanceof Event)) { + throw new Error('Expects an event'); + } + if (this.listeners === null || typeof this.listeners !== 'object') { + this.listeners = {}; + } + var listeners = this.listeners[ev.type]; + if (typeof listeners === 'object') { + for (var i=0; i < listeners.length; ++i) { + if (typeof listeners[i] === 'function') { + listeners[i].call(null, ev); + } + } + } + }, + addEventListener: function(eventName, callback) { + if (typeof eventName !== 'string') { + throw new Error('First argument expects a string'); + } + if (typeof callback !== 'function') { + throw new Error('Second argument expects a function'); + } + if (this.listeners === null || typeof this.listeners !== 'object') { + this.listeners = {}; + } + var listeners = this.listeners[eventName]; + if (typeof listeners !== 'object') { + listeners = []; + } + listeners.push(callback); + this.listeners[eventName] = listeners; + }, + removeEventListener: function(eventName, callback) { + if (typeof eventName !== 'string') { + throw new Error('First argument expects a string'); + } + if (typeof callback !== 'function') { + throw new Error('Second argument expects a function'); + } + if (this.listeners === null || typeof this.listeners !== 'object') { + this.listeners = {}; + } + var listeners = this.listeners[eventName]; + for (var i=0; i < listeners.length; ++ i) { + if (listeners[i] === callback) { + listeners.splice(i, 1); + return; + } + } + this.listeners[eventName] = listeners; + } + }; + + textsecure.SyncRequest = function(sender, receiver) { + var syncRequest = new SyncRequest(sender, receiver); + this.addEventListener = syncRequest.addEventListener.bind(syncRequest); + this.removeEventListener = syncRequest.removeEventListener.bind(syncRequest); + }; + + textsecure.SyncRequest.prototype = { + constructor: textsecure.SyncRequest + }; + + +}()); + /* * vim: ts=4:sw=4:expandtab */ diff --git a/js/options.js b/js/options.js index dd7c6dd5..b43401a1 100644 --- a/js/options.js +++ b/js/options.js @@ -38,10 +38,8 @@ var launch = function() { bg.openInbox(); bg.removeEventListener('textsecure:contactsync', launch); - clearTimeout(timeout); window.close(); }; - var timeout = setTimeout(launch, 60000); bg.addEventListener('textsecure:contactsync', launch); view.showSync(); }).catch(function(e) { diff --git a/libtextsecure/sync_request.js b/libtextsecure/sync_request.js new file mode 100644 index 00000000..240eadac --- /dev/null +++ b/libtextsecure/sync_request.js @@ -0,0 +1,118 @@ +/* + * vim: ts=4:sw=4:expandtab + */ + + +;(function () { + 'use strict'; + window.textsecure = window.textsecure || {}; + + function SyncRequest(sender, receiver) { + this.receiver = receiver; + + this.oncontact = this.onContactSyncComplete.bind(this); + receiver.addEventListener('contactsync', this.oncontact); + + this.ongroup = this.onGroupSyncComplete.bind(this); + receiver.addEventListener('groupsync', this.ongroup); + + sender.sendRequestContactSyncMessage().then(function() { + sender.sendRequestGroupSyncMessage(); + }); + this.timeout = setTimout(this.onTimeout.bind(this), 60000); + } + + SyncRequest.prototype = { + constructor: SyncRequest, + onContactSyncComplete: function() { + this.contactSync = true; + this.update(); + }, + onGroupSyncComplete: function() { + this.groupSync = true; + this.update(); + }, + update: function() { + if (this.contactSync && this.groupSync) { + this.dispatchEvent(new Event('success')); + this.cleanup(); + } + }, + onTimeout: function() { + this.dispatchEvent(new Event('timeout')); + this.cleanup(); + }, + cleanup: function() { + clearTimeout(this.timeout); + this.receiver.removeEventListener('contactsync', this.oncontact); + this.receiver.removeEventListener('groupSync', this.ongroup); + delete this.listeners; + }, + + /* Implements EventTarget */ /// TODO: Dedupe this same code in MessageReceiver + dispatchEvent: function(ev) { + if (!(ev instanceof Event)) { + throw new Error('Expects an event'); + } + if (this.listeners === null || typeof this.listeners !== 'object') { + this.listeners = {}; + } + var listeners = this.listeners[ev.type]; + if (typeof listeners === 'object') { + for (var i=0; i < listeners.length; ++i) { + if (typeof listeners[i] === 'function') { + listeners[i].call(null, ev); + } + } + } + }, + addEventListener: function(eventName, callback) { + if (typeof eventName !== 'string') { + throw new Error('First argument expects a string'); + } + if (typeof callback !== 'function') { + throw new Error('Second argument expects a function'); + } + if (this.listeners === null || typeof this.listeners !== 'object') { + this.listeners = {}; + } + var listeners = this.listeners[eventName]; + if (typeof listeners !== 'object') { + listeners = []; + } + listeners.push(callback); + this.listeners[eventName] = listeners; + }, + removeEventListener: function(eventName, callback) { + if (typeof eventName !== 'string') { + throw new Error('First argument expects a string'); + } + if (typeof callback !== 'function') { + throw new Error('Second argument expects a function'); + } + if (this.listeners === null || typeof this.listeners !== 'object') { + this.listeners = {}; + } + var listeners = this.listeners[eventName]; + for (var i=0; i < listeners.length; ++ i) { + if (listeners[i] === callback) { + listeners.splice(i, 1); + return; + } + } + this.listeners[eventName] = listeners; + } + }; + + textsecure.SyncRequest = function(sender, receiver) { + var syncRequest = new SyncRequest(sender, receiver); + this.addEventListener = syncRequest.addEventListener.bind(syncRequest); + this.removeEventListener = syncRequest.removeEventListener.bind(syncRequest); + }; + + textsecure.SyncRequest.prototype = { + constructor: textsecure.SyncRequest + }; + + +}());