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
This commit is contained in:
parent
44d7747ade
commit
ceec0fce2a
@ -161,7 +161,8 @@ function convertToArrayBuffer(bytes) {
|
|||||||
if (bytes instanceof ArrayBuffer) {
|
if (bytes instanceof ArrayBuffer) {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
if (bytes.buffer !== undefined) {
|
if (bytes.buffer !== undefined &&
|
||||||
|
bytes.buffer.byteLength == bytes.length * bytes.BYTES_PER_ELEMENT) {
|
||||||
return bytes.buffer;
|
return bytes.buffer;
|
||||||
}
|
}
|
||||||
return bytesToArrayBuffer(bytes);
|
return bytesToArrayBuffer(bytes);
|
||||||
|
@ -10,17 +10,27 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
.factory('MtpDcConfigurator', function () {
|
.factory('MtpDcConfigurator', function () {
|
||||||
var dcOptions = Config.Modes.test
|
var dcOptions = Config.Modes.test
|
||||||
? [
|
? [
|
||||||
{id: 1, host: '173.240.5.253', port: 80},
|
{id: 1, url: 'http://173.240.5.253'},
|
||||||
{id: 2, host: '149.154.167.40', port: 80},
|
{id: 2, url: 'http://149.154.167.40'},
|
||||||
{id: 3, host: '174.140.142.5', port: 80}
|
{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: 1, url: 'http://173.240.5.1'},
|
||||||
{id: 2, host: '149.154.167.51', port: 80},
|
{id: 2, url: 'http://149.154.167.51'},
|
||||||
{id: 3, host: '174.140.142.6', port: 80},
|
{id: 3, url: 'http://174.140.142.6'},
|
||||||
{id: 4, host: '149.154.167.91', port: 80},
|
{id: 4, url: 'http://149.154.167.91'},
|
||||||
{id: 5, host: '149.154.171.5', port: 80}
|
{id: 5, url: 'http://149.154.171.5'}
|
||||||
];
|
]);
|
||||||
|
|
||||||
|
var sslSubdomains = 'pluto,venus,aurora,vesta,flora';
|
||||||
|
|
||||||
var chosenServers = {};
|
var chosenServers = {};
|
||||||
|
|
||||||
@ -31,7 +41,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
for (i = 0; i < dcOptions.length; i++) {
|
for (i = 0; i < dcOptions.length; i++) {
|
||||||
dcOption = dcOptions[i];
|
dcOption = dcOptions[i];
|
||||||
if (dcOption.id == dcID) {
|
if (dcOption.id == dcID) {
|
||||||
chosenServer = dcOption.host + ':' + dcOption.port;
|
chosenServer = dcOption.url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chosenServers[dcID] = chosenServer;
|
chosenServers[dcID] = chosenServer;
|
||||||
@ -197,7 +207,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
var requestData = xhrSendBuffer ? resultBuffer : resultArray,
|
var requestData = xhrSendBuffer ? resultBuffer : resultArray,
|
||||||
requestPromise;
|
requestPromise;
|
||||||
try {
|
try {
|
||||||
requestPromise = $http.post('http://' + MtpDcConfigurator.chooseServer(dcID) + '/apiw1', requestData, {
|
requestPromise = $http.post(MtpDcConfigurator.chooseServer(dcID) + '/apiw1', requestData, {
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
transformRequest: null
|
transformRequest: null
|
||||||
});
|
});
|
||||||
@ -791,7 +801,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
longPoll: true
|
longPoll: true
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
delete self.longPollPending;
|
delete self.longPollPending;
|
||||||
$timeout(self.checkLongPoll.bind(self), 0);
|
setZeroTimeout(self.checkLongPoll.bind(self));
|
||||||
}, function () {
|
}, function () {
|
||||||
console.log('Long-poll failed');
|
console.log('Long-poll failed');
|
||||||
});
|
});
|
||||||
@ -948,7 +958,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
|
|
||||||
MtpNetworker.prototype.performSheduledRequest = function() {
|
MtpNetworker.prototype.performSheduledRequest = function() {
|
||||||
// console.trace('sheduled', this.dcID, this.iii);
|
// console.log(dT(), 'sheduled', this.dcID, this.iii);
|
||||||
if (this.offline) {
|
if (this.offline) {
|
||||||
console.log(dT(), 'Cancel sheduled');
|
console.log(dT(), 'Cancel sheduled');
|
||||||
return false;
|
return false;
|
||||||
@ -1126,7 +1136,9 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
};
|
};
|
||||||
|
|
||||||
MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) {
|
MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) {
|
||||||
|
// console.log(dT(), 'get decrypted start');
|
||||||
return this.getMsgKeyIv(msgKey, false).then(function (keyIv) {
|
return this.getMsgKeyIv(msgKey, false).then(function (keyIv) {
|
||||||
|
// console.log(dT(), 'after msg key iv');
|
||||||
return CryptoWorker.aesDecrypt(encryptedData, keyIv[0], keyIv[1]);
|
return CryptoWorker.aesDecrypt(encryptedData, keyIv[0], keyIv[1]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -1162,7 +1174,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
transformRequest: null
|
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) {
|
} catch (e) {
|
||||||
requestPromise = $q.reject(e);
|
requestPromise = $q.reject(e);
|
||||||
}
|
}
|
||||||
@ -1206,6 +1218,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data');
|
encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data');
|
||||||
|
|
||||||
return this.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) {
|
return this.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) {
|
||||||
|
// console.log(dT(), 'after decrypt');
|
||||||
var deserializer = new TLDeserialization(dataWithPadding, {mtproto: true});
|
var deserializer = new TLDeserialization(dataWithPadding, {mtproto: true});
|
||||||
|
|
||||||
var salt = deserializer.fetchIntBytes(64, false, 'salt');
|
var salt = deserializer.fetchIntBytes(64, false, 'salt');
|
||||||
@ -1216,6 +1229,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
var messageBody = deserializer.fetchRawBytes(false, true, 'message_data');
|
var messageBody = deserializer.fetchRawBytes(false, true, 'message_data');
|
||||||
|
|
||||||
|
// console.log(dT(), 'before hash');
|
||||||
var hashData = convertToUint8Array(dataWithPadding).subarray(0, deserializer.getOffset());
|
var hashData = convertToUint8Array(dataWithPadding).subarray(0, deserializer.getOffset());
|
||||||
|
|
||||||
return CryptoWorker.sha1Hash(hashData).then(function (dataHash) {
|
return CryptoWorker.sha1Hash(hashData).then(function (dataHash) {
|
||||||
@ -1223,6 +1237,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
console.warn(msgKey, bytesFromArrayBuffer(dataHash));
|
console.warn(msgKey, bytesFromArrayBuffer(dataHash));
|
||||||
throw new Error('server msgKey mismatch');
|
throw new Error('server msgKey mismatch');
|
||||||
}
|
}
|
||||||
|
// console.log(dT(), 'after hash check');
|
||||||
|
|
||||||
var buffer = bytesToArrayBuffer(messageBody);
|
var buffer = bytesToArrayBuffer(messageBody);
|
||||||
var deserializerOptions = {
|
var deserializerOptions = {
|
||||||
@ -1243,7 +1258,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
}
|
}
|
||||||
if (this.offset != offset + result.bytes) {
|
if (this.offset != offset + result.bytes) {
|
||||||
console.warn(dT(), 'set offset', 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;
|
this.offset = offset + result.bytes;
|
||||||
}
|
}
|
||||||
// console.log(dT(), 'override message', result);
|
// console.log(dT(), 'override message', result);
|
||||||
@ -1262,6 +1277,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
var deserializer = new TLDeserialization(buffer, deserializerOptions);
|
var deserializer = new TLDeserialization(buffer, deserializerOptions);
|
||||||
|
|
||||||
var response = deserializer.fetchObject('', 'INPUT');
|
var response = deserializer.fetchObject('', 'INPUT');
|
||||||
|
// console.log(dT(), 'after fetch');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response: response,
|
response: response,
|
||||||
@ -1294,12 +1310,16 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('shedule req', delay);
|
// console.log(dT(), 'shedule req', delay);
|
||||||
// console.trace();
|
// console.trace();
|
||||||
|
|
||||||
$timeout.cancel(this.nextReqPromise);
|
$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;
|
this.nextReq = nextReq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -464,7 +464,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
|||||||
fileDownload: true,
|
fileDownload: true,
|
||||||
createNetworker: true
|
createNetworker: true
|
||||||
});
|
});
|
||||||
}, 6).then(function (result) {
|
}, 2).then(function (result) {
|
||||||
writeFilePromise.then(function () {
|
writeFilePromise.then(function () {
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
return $q.when();
|
return $q.when();
|
||||||
|
@ -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.URL = $window.URL || $window.webkitURL;
|
||||||
$window.BlobBuilder = $window.BlobBuilder || $window.WebKitBlobBuilder || $window.MozBlobBuilder;
|
$window.BlobBuilder = $window.BlobBuilder || $window.WebKitBlobBuilder || $window.MozBlobBuilder;
|
||||||
@ -98,10 +98,10 @@ angular.module('izhukov.utils', [])
|
|||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
var blob = blobConstruct([bytesToArrayBuffer(bytes)]);
|
var blob = blobConstruct([bytesToArrayBuffer(bytes)]);
|
||||||
|
fileWriter.write(blob);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
deferred.reject(e);
|
deferred.reject(e);
|
||||||
}
|
}
|
||||||
fileWriter.write(blob);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
@ -150,7 +150,7 @@ angular.module('izhukov.utils', [])
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
blobParts.push(blob);
|
blobParts.push(blob);
|
||||||
$timeout(function () {
|
setZeroTimeout(function () {
|
||||||
if (fakeFileWriter.onwriteend) {
|
if (fakeFileWriter.onwriteend) {
|
||||||
fakeFileWriter.onwriteend();
|
fakeFileWriter.onwriteend();
|
||||||
}
|
}
|
||||||
@ -493,7 +493,7 @@ angular.module('izhukov.utils', [])
|
|||||||
finalizeTask = function (taskID, result) {
|
finalizeTask = function (taskID, result) {
|
||||||
var deferred = awaiting[taskID];
|
var deferred = awaiting[taskID];
|
||||||
if (deferred !== undefined) {
|
if (deferred !== undefined) {
|
||||||
console.log(dT(), 'CW done');
|
// console.log(dT(), 'CW done');
|
||||||
deferred.resolve(result);
|
deferred.resolve(result);
|
||||||
delete awaiting[taskID];
|
delete awaiting[taskID];
|
||||||
}
|
}
|
||||||
@ -524,7 +524,7 @@ angular.module('izhukov.utils', [])
|
|||||||
}
|
}
|
||||||
|
|
||||||
function performTaskWorker (task, params, embed) {
|
function performTaskWorker (task, params, embed) {
|
||||||
console.log(dT(), 'CW start', task);
|
// console.log(dT(), 'CW start', task);
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
awaiting[taskID] = deferred;
|
awaiting[taskID] = deferred;
|
||||||
@ -562,7 +562,6 @@ angular.module('izhukov.utils', [])
|
|||||||
},
|
},
|
||||||
aesEncrypt: function (bytes, keyBytes, ivBytes) {
|
aesEncrypt: function (bytes, keyBytes, ivBytes) {
|
||||||
if (aesNaClEmbed) {
|
if (aesNaClEmbed) {
|
||||||
// aesEncryptSync(bytes, keyBytes, ivBytes);
|
|
||||||
return performTaskWorker('aes-encrypt', {
|
return performTaskWorker('aes-encrypt', {
|
||||||
bytes: addPadding(convertToArrayBuffer(bytes)),
|
bytes: addPadding(convertToArrayBuffer(bytes)),
|
||||||
keyBytes: convertToArrayBuffer(keyBytes),
|
keyBytes: convertToArrayBuffer(keyBytes),
|
||||||
@ -575,7 +574,6 @@ angular.module('izhukov.utils', [])
|
|||||||
},
|
},
|
||||||
aesDecrypt: function (encryptedBytes, keyBytes, ivBytes) {
|
aesDecrypt: function (encryptedBytes, keyBytes, ivBytes) {
|
||||||
if (aesNaClEmbed) {
|
if (aesNaClEmbed) {
|
||||||
// aesDecryptSync(encryptedBytes, keyBytes, ivBytes);
|
|
||||||
return performTaskWorker('aes-decrypt', {
|
return performTaskWorker('aes-decrypt', {
|
||||||
encryptedBytes: addPadding(convertToArrayBuffer(encryptedBytes)),
|
encryptedBytes: addPadding(convertToArrayBuffer(encryptedBytes)),
|
||||||
keyBytes: convertToArrayBuffer(keyBytes),
|
keyBytes: convertToArrayBuffer(keyBytes),
|
||||||
|
@ -96,3 +96,36 @@ if (!Function.prototype.bind) {
|
|||||||
return fBound;
|
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);
|
@ -402,10 +402,8 @@ TLDeserialization.prototype.fetchBytes = function (field) {
|
|||||||
(this.byteView[this.offset++] << 16);
|
(this.byteView[this.offset++] << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = [];
|
var bytes = this.byteView.subarray(this.offset, this.offset + len);
|
||||||
for (var i = 0; i < len; i++) {
|
this.offset += len;
|
||||||
bytes.push(this.byteView[this.offset++]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Padding
|
// Padding
|
||||||
while (this.offset % 4) {
|
while (this.offset % 4) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user