|  |  |  | @ -5,7 +5,8 @@ | 
		
	
		
			
				|  |  |  |  | const _ = require('lodash'); | 
		
	
		
			
				|  |  |  |  | const { rpc } = require('./loki_rpc'); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const DEFAULT_CONNECTIONS = 2; | 
		
	
		
			
				|  |  |  |  | const DEFAULT_CONNECTIONS = 3; | 
		
	
		
			
				|  |  |  |  | const MAX_ACCEPTABLE_FAILURES = 1; | 
		
	
		
			
				|  |  |  |  | const LOKI_LONGPOLL_HEADER = 'X-Loki-Long-Poll'; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | function sleepFor(time) { | 
		
	
	
		
			
				
					|  |  |  | @ -122,9 +123,27 @@ class LokiMessageAPI { | 
		
	
		
			
				|  |  |  |  |       promises.push(this.openSendConnection(params)); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     let results; | 
		
	
		
			
				|  |  |  |  |     // Taken from https://stackoverflow.com/questions/51160260/clean-way-to-wait-for-first-true-returned-by-promise
 | 
		
	
		
			
				|  |  |  |  |     // The promise returned by this function will resolve true when the first promise
 | 
		
	
		
			
				|  |  |  |  |     // in ps resolves true *or* it will resolve false when all of ps resolve false
 | 
		
	
		
			
				|  |  |  |  |     const firstTrue = ps => { | 
		
	
		
			
				|  |  |  |  |       const newPs = ps.map( | 
		
	
		
			
				|  |  |  |  |         p => | 
		
	
		
			
				|  |  |  |  |           new Promise( | 
		
	
		
			
				|  |  |  |  |             // eslint-disable-next-line more/no-then
 | 
		
	
		
			
				|  |  |  |  |             (resolve, reject) => p.then(v => v && resolve(true), reject) | 
		
	
		
			
				|  |  |  |  |           ) | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |       // eslint-disable-next-line more/no-then
 | 
		
	
		
			
				|  |  |  |  |       newPs.push(Promise.all(ps).then(() => false)); | 
		
	
		
			
				|  |  |  |  |       return Promise.race(newPs); | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     let success; | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
		
			
				|  |  |  |  |       results = await Promise.all(promises); | 
		
	
		
			
				|  |  |  |  |       // eslint-disable-next-line more/no-then
 | 
		
	
		
			
				|  |  |  |  |       Promise.all(promises).then(delete this.sendingSwarmNodes[timestamp]); | 
		
	
		
			
				|  |  |  |  |       success = await firstTrue(promises); | 
		
	
		
			
				|  |  |  |  |     } catch (e) { | 
		
	
		
			
				|  |  |  |  |       if (e instanceof textsecure.WrongDifficultyError) { | 
		
	
		
			
				|  |  |  |  |         // Force nonce recalculation
 | 
		
	
	
		
			
				
					|  |  |  | @ -133,18 +152,13 @@ class LokiMessageAPI { | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       throw e; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     delete this.sendingSwarmNodes[timestamp]; | 
		
	
		
			
				|  |  |  |  |     if (results.every(value => value === false)) { | 
		
	
		
			
				|  |  |  |  |     if (!success) { | 
		
	
		
			
				|  |  |  |  |       throw new window.textsecure.EmptySwarmError( | 
		
	
		
			
				|  |  |  |  |         pubKey, | 
		
	
		
			
				|  |  |  |  |         'Ran out of swarm nodes to query' | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (results.every(value => value === true)) { | 
		
	
		
			
				|  |  |  |  |       log.info(`Successful storage message to ${pubKey}`); | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       log.warn(`Partially successful storage message to ${pubKey}`); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     log.info(`Successful storage message to ${pubKey}`); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   async openSendConnection(params) { | 
		
	
	
		
			
				
					|  |  |  | @ -165,7 +179,7 @@ class LokiMessageAPI { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   async sendToNode(address, port, params) { | 
		
	
		
			
				|  |  |  |  |     let successiveFailures = 0; | 
		
	
		
			
				|  |  |  |  |     while (successiveFailures < 3) { | 
		
	
		
			
				|  |  |  |  |     while (successiveFailures < MAX_ACCEPTABLE_FAILURES) { | 
		
	
		
			
				|  |  |  |  |       await sleepFor(successiveFailures * 500); | 
		
	
		
			
				|  |  |  |  |       try { | 
		
	
		
			
				|  |  |  |  |         const result = await rpc(`https://${address}`, port, 'store', params); | 
		
	
	
		
			
				
					|  |  |  | @ -212,7 +226,7 @@ class LokiMessageAPI { | 
		
	
		
			
				|  |  |  |  |       const nodeData = this.ourSwarmNodes[address]; | 
		
	
		
			
				|  |  |  |  |       delete this.ourSwarmNodes[address]; | 
		
	
		
			
				|  |  |  |  |       let successiveFailures = 0; | 
		
	
		
			
				|  |  |  |  |       while (successiveFailures < 3) { | 
		
	
		
			
				|  |  |  |  |       while (successiveFailures < MAX_ACCEPTABLE_FAILURES) { | 
		
	
		
			
				|  |  |  |  |         await sleepFor(successiveFailures * 1000); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         try { | 
		
	
	
		
			
				
					|  |  |  | 
 |