1
+ import { InteractionManager } from 'react-native'
2
+ import Semaphore from 'semaphore-async-await'
3
+ import net from 'react-native-tcp'
4
+ import events from 'events'
1
5
import {
2
6
Cipher ,
3
7
createCipheriv ,
@@ -6,9 +10,6 @@ import {
6
10
Decipher ,
7
11
publicEncrypt
8
12
} from 'react-native-crypto'
9
- import { InteractionManager } from 'react-native'
10
- import net from 'react-native-tcp'
11
- import events from 'events'
12
13
import {
13
14
concatPacketData ,
14
15
makeBaseCompressedPacket ,
@@ -67,8 +68,9 @@ export class ServerConnection extends events.EventEmitter {
67
68
data : Buffer ,
68
69
cb ?: ( ( err ?: Error | undefined ) => void ) | undefined
69
70
) : Promise < boolean > {
71
+ const compressionThreshold = this . compressionThreshold
70
72
const packet = this . compressionEnabled
71
- ? makeBaseCompressedPacket ( this . compressionThreshold , packetId , data )
73
+ ? await makeBaseCompressedPacket ( compressionThreshold , packetId , data )
72
74
: makeBasePacket ( packetId , data )
73
75
const toWrite = this . aesCipher ? this . aesCipher . update ( packet ) : packet
74
76
return this . socket . write ( toWrite , cb )
@@ -126,23 +128,24 @@ const initiateConnection = async (opts: ConnectionOptions) => {
126
128
if ( ! resolved ) reject ( err )
127
129
else conn . emit ( 'error' , err )
128
130
} )
131
+ const lock = new Semaphore ( 1 )
129
132
socket . on ( 'data' , newData => {
130
133
// Handle timeout after 20 seconds of no data.
131
134
if ( conn . disconnectTimer ) clearTimeout ( conn . disconnectTimer )
132
135
conn . disconnectTimer = setTimeout ( ( ) => conn . close ( ) , 20000 )
133
136
// Run after interactions to improve user experience.
134
- InteractionManager . runAfterInteractions ( ( ) => {
137
+ InteractionManager . runAfterInteractions ( async ( ) => {
138
+ await lock . acquire ( )
135
139
try {
136
140
// Note: the entire packet is encrypted, including the length fields and the packet's data.
137
141
// https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/src/transforms/encryption.js
138
142
let finalData = newData
139
143
if ( conn . aesDecipher ) finalData = conn . aesDecipher . update ( newData )
140
144
// Buffer data for read.
141
145
conn . bufferedData = Buffer . concat ( [ conn . bufferedData , finalData ] )
142
- // ;(async () => { This would need a mutex.
143
146
while ( true ) {
144
147
const packet = conn . compressionEnabled
145
- ? parseCompressedPacket ( conn . bufferedData )
148
+ ? await parseCompressedPacket ( conn . bufferedData )
146
149
: parsePacket ( conn . bufferedData )
147
150
if ( packet ) {
148
151
// Remove packet from buffered data.
@@ -233,6 +236,7 @@ const initiateConnection = async (opts: ConnectionOptions) => {
233
236
} catch ( err ) {
234
237
conn . emit ( 'error' , err )
235
238
}
239
+ lock . release ( )
236
240
} ) . then ( ( ) => { } , console . error )
237
241
} )
238
242
} )
0 commit comments