Browse Source

Performance improvements

Supported SSL. Closes #71
Added setZeroTimeout. Now downloading files when tab in background and
improved performance
Multiple file parts download in parallel
TLDeserialization.fetchBytes returns typed array
master
Igor Zhukov 10 years ago
parent
commit
ceec0fce2a
  1. 3
      app/js/lib/bin_utils.js
  2. 54
      app/js/lib/mtproto.js
  3. 2
      app/js/lib/mtproto_wrapper.js
  4. 12
      app/js/lib/ng_utils.js
  5. 35
      app/js/lib/polyfill.js
  6. 6
      app/js/lib/tl_utils.js

3
app/js/lib/bin_utils.js

@ -161,7 +161,8 @@ function convertToArrayBuffer(bytes) { @@ -161,7 +161,8 @@ function convertToArrayBuffer(bytes) {
if (bytes instanceof ArrayBuffer) {
return bytes;
}
if (bytes.buffer !== undefined) {
if (bytes.buffer !== undefined &&
bytes.buffer.byteLength == bytes.length * bytes.BYTES_PER_ELEMENT) {
return bytes.buffer;
}
return bytesToArrayBuffer(bytes);

54
app/js/lib/mtproto.js

@ -10,17 +10,27 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -10,17 +10,27 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
.factory('MtpDcConfigurator', function () {
var dcOptions = Config.Modes.test
? [
{id: 1, host: '173.240.5.253', port: 80},
{id: 2, host: '149.154.167.40', port: 80},
{id: 3, host: '174.140.142.5', port: 80}
{id: 1, url: 'http://173.240.5.253'},
{id: 2, url: 'http://149.154.167.40'},
{id: 3, url: 'http://174.140.142.5'}
]
: (location.protocol == 'https:'
? [
{id: 1, url: 'https://pluto.web.telegram.org'},
{id: 2, url: 'https://venus.web.telegram.org'},
{id: 3, url: 'https://aurora.web.telegram.org'},
{id: 4, url: 'https://vesta.web.telegram.org'},
{id: 5, url: 'https://flora.web.telegram.org'}
]
: [
{id: 1, host: '173.240.5.1', port: 80},
{id: 2, host: '149.154.167.51', port: 80},
{id: 3, host: '174.140.142.6', port: 80},
{id: 4, host: '149.154.167.91', port: 80},
{id: 5, host: '149.154.171.5', port: 80}
];
{id: 1, url: 'http://173.240.5.1'},
{id: 2, url: 'http://149.154.167.51'},
{id: 3, url: 'http://174.140.142.6'},
{id: 4, url: 'http://149.154.167.91'},
{id: 5, url: 'http://149.154.171.5'}
]);
var sslSubdomains = 'pluto,venus,aurora,vesta,flora';
var chosenServers = {};
@ -31,7 +41,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -31,7 +41,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
for (i = 0; i < dcOptions.length; i++) {
dcOption = dcOptions[i];
if (dcOption.id == dcID) {
chosenServer = dcOption.host + ':' + dcOption.port;
chosenServer = dcOption.url;
}
}
chosenServers[dcID] = chosenServer;
@ -197,7 +207,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -197,7 +207,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var requestData = xhrSendBuffer ? resultBuffer : resultArray,
requestPromise;
try {
requestPromise = $http.post('http://' + MtpDcConfigurator.chooseServer(dcID) + '/apiw1', requestData, {
requestPromise = $http.post(MtpDcConfigurator.chooseServer(dcID) + '/apiw1', requestData, {
responseType: 'arraybuffer',
transformRequest: null
});
@ -791,7 +801,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -791,7 +801,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
longPoll: true
}).then(function () {
delete self.longPollPending;
$timeout(self.checkLongPoll.bind(self), 0);
setZeroTimeout(self.checkLongPoll.bind(self));
}, function () {
console.log('Long-poll failed');
});
@ -948,7 +958,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -948,7 +958,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
MtpNetworker.prototype.performSheduledRequest = function() {
// console.trace('sheduled', this.dcID, this.iii);
// console.log(dT(), 'sheduled', this.dcID, this.iii);
if (this.offline) {
console.log(dT(), 'Cancel sheduled');
return false;
@ -1126,7 +1136,9 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1126,7 +1136,9 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
};
MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) {
// console.log(dT(), 'get decrypted start');
return this.getMsgKeyIv(msgKey, false).then(function (keyIv) {
// console.log(dT(), 'after msg key iv');
return CryptoWorker.aesDecrypt(encryptedData, keyIv[0], keyIv[1]);
});
};
@ -1162,7 +1174,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1162,7 +1174,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
responseType: 'arraybuffer',
transformRequest: null
});
requestPromise = $http.post('http://' + MtpDcConfigurator.chooseServer(self.dcID) + '/apiw1', requestData, options);
requestPromise = $http.post(MtpDcConfigurator.chooseServer(self.dcID) + '/apiw1', requestData, options);
} catch (e) {
requestPromise = $q.reject(e);
}
@ -1206,6 +1218,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1206,6 +1218,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data');
return this.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) {
// console.log(dT(), 'after decrypt');
var deserializer = new TLDeserialization(dataWithPadding, {mtproto: true});
var salt = deserializer.fetchIntBytes(64, false, 'salt');
@ -1216,6 +1229,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1216,6 +1229,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var messageBody = deserializer.fetchRawBytes(false, true, 'message_data');
// console.log(dT(), 'before hash');
var hashData = convertToUint8Array(dataWithPadding).subarray(0, deserializer.getOffset());
return CryptoWorker.sha1Hash(hashData).then(function (dataHash) {
@ -1223,6 +1237,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1223,6 +1237,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
console.warn(msgKey, bytesFromArrayBuffer(dataHash));
throw new Error('server msgKey mismatch');
}
// console.log(dT(), 'after hash check');
var buffer = bytesToArrayBuffer(messageBody);
var deserializerOptions = {
@ -1243,7 +1258,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1243,7 +1258,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
}
if (this.offset != offset + result.bytes) {
console.warn(dT(), 'set offset', this.offset, offset, result.bytes);
console.log(dT(), result);
// console.log(dT(), result);
this.offset = offset + result.bytes;
}
// console.log(dT(), 'override message', result);
@ -1262,6 +1277,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1262,6 +1277,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var deserializer = new TLDeserialization(buffer, deserializerOptions);
var response = deserializer.fetchObject('', 'INPUT');
// console.log(dT(), 'after fetch');
return {
response: response,
@ -1294,12 +1310,16 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -1294,12 +1310,16 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
return false;
}
// console.log('shedule req', delay);
// console.log(dT(), 'shedule req', delay);
// console.trace();
$timeout.cancel(this.nextReqPromise);
if (delay > 0) {
this.nextReqPromise = $timeout(this.performSheduledRequest.bind(this), delay || 0);
} else {
setZeroTimeout(this.performSheduledRequest.bind(this))
}
this.nextReqPromise = $timeout(this.performSheduledRequest.bind(this), delay || 0);
this.nextReq = nextReq;
};

2
app/js/lib/mtproto_wrapper.js

@ -464,7 +464,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) @@ -464,7 +464,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
fileDownload: true,
createNetworker: true
});
}, 6).then(function (result) {
}, 2).then(function (result) {
writeFilePromise.then(function () {
if (canceled) {
return $q.when();

12
app/js/lib/ng_utils.js

@ -33,7 +33,7 @@ angular.module('izhukov.utils', []) @@ -33,7 +33,7 @@ angular.module('izhukov.utils', [])
})
.service('FileManager', function ($window, $timeout, $q) {
.service('FileManager', function ($window, $q) {
$window.URL = $window.URL || $window.webkitURL;
$window.BlobBuilder = $window.BlobBuilder || $window.WebKitBlobBuilder || $window.MozBlobBuilder;
@ -98,10 +98,10 @@ angular.module('izhukov.utils', []) @@ -98,10 +98,10 @@ angular.module('izhukov.utils', [])
else {
try {
var blob = blobConstruct([bytesToArrayBuffer(bytes)]);
fileWriter.write(blob);
} catch (e) {
deferred.reject(e);
}
fileWriter.write(blob);
}
return deferred.promise;
@ -150,7 +150,7 @@ angular.module('izhukov.utils', []) @@ -150,7 +150,7 @@ angular.module('izhukov.utils', [])
return false;
}
blobParts.push(blob);
$timeout(function () {
setZeroTimeout(function () {
if (fakeFileWriter.onwriteend) {
fakeFileWriter.onwriteend();
}
@ -493,7 +493,7 @@ angular.module('izhukov.utils', []) @@ -493,7 +493,7 @@ angular.module('izhukov.utils', [])
finalizeTask = function (taskID, result) {
var deferred = awaiting[taskID];
if (deferred !== undefined) {
console.log(dT(), 'CW done');
// console.log(dT(), 'CW done');
deferred.resolve(result);
delete awaiting[taskID];
}
@ -524,7 +524,7 @@ angular.module('izhukov.utils', []) @@ -524,7 +524,7 @@ angular.module('izhukov.utils', [])
}
function performTaskWorker (task, params, embed) {
console.log(dT(), 'CW start', task);
// console.log(dT(), 'CW start', task);
var deferred = $q.defer();
awaiting[taskID] = deferred;
@ -562,7 +562,6 @@ angular.module('izhukov.utils', []) @@ -562,7 +562,6 @@ angular.module('izhukov.utils', [])
},
aesEncrypt: function (bytes, keyBytes, ivBytes) {
if (aesNaClEmbed) {
// aesEncryptSync(bytes, keyBytes, ivBytes);
return performTaskWorker('aes-encrypt', {
bytes: addPadding(convertToArrayBuffer(bytes)),
keyBytes: convertToArrayBuffer(keyBytes),
@ -575,7 +574,6 @@ angular.module('izhukov.utils', []) @@ -575,7 +574,6 @@ angular.module('izhukov.utils', [])
},
aesDecrypt: function (encryptedBytes, keyBytes, ivBytes) {
if (aesNaClEmbed) {
// aesDecryptSync(encryptedBytes, keyBytes, ivBytes);
return performTaskWorker('aes-decrypt', {
encryptedBytes: addPadding(convertToArrayBuffer(encryptedBytes)),
keyBytes: convertToArrayBuffer(keyBytes),

35
app/js/lib/polyfill.js

@ -95,4 +95,37 @@ if (!Function.prototype.bind) { @@ -95,4 +95,37 @@ if (!Function.prototype.bind) {
return fBound;
};
}
}
/* setZeroTimeout polyfill, from http://dbaron.org/log/20100309-faster-timeouts */
(function(global) {
var timeouts = [];
var messageName = 'zero-timeout-message';
function setZeroTimeout(fn) {
timeouts.push(fn);
global.postMessage(messageName, '*');
}
function handleMessage(event) {
if (event.source == global && event.data == messageName) {
event.stopPropagation();
if (timeouts.length > 0) {
var fn = timeouts.shift();
fn();
}
}
}
global.addEventListener('message', handleMessage, true);
var originalSetTimeout = global.setTimeout;
global.setTimeout = function (callback, delay) {
if (!delay || delay <= 5) {
return setZeroTimeout(callback);
}
return originalSetTimeout(callback, delay);
};
global.setZeroTimeout = setZeroTimeout;
})(this);

6
app/js/lib/tl_utils.js

@ -402,10 +402,8 @@ TLDeserialization.prototype.fetchBytes = function (field) { @@ -402,10 +402,8 @@ TLDeserialization.prototype.fetchBytes = function (field) {
(this.byteView[this.offset++] << 16);
}
var bytes = [];
for (var i = 0; i < len; i++) {
bytes.push(this.byteView[this.offset++]);
}
var bytes = this.byteView.subarray(this.offset, this.offset + len);
this.offset += len;
// Padding
while (this.offset % 4) {

Loading…
Cancel
Save