@@ -47,6 +47,7 @@ type AdditionalDisplayData = {
47
47
formattedText : string
48
48
textNameRight : string
49
49
icon ?: string
50
+ offline ?: boolean
50
51
}
51
52
52
53
export interface AuthenticatedAccount {
@@ -138,6 +139,9 @@ export const updateAuthenticatedAccountData = (callback: (data: AuthenticatedAcc
138
139
// todo move to base
139
140
const normalizeIp = ( ip : string ) => ip . replace ( / h t t p s ? : \/ \/ / , '' ) . replace ( / \/ ( : | $ ) / , '' )
140
141
142
+ const FETCH_DELAY = 100 // ms between each request
143
+ const MAX_CONCURRENT_REQUESTS = 10
144
+
141
145
const Inner = ( { hidden, customServersList } : { hidden ?: boolean , customServersList ?: string [ ] } ) => {
142
146
const [ proxies , setProxies ] = useState < readonly string [ ] > ( localStorage [ 'proxies' ] ? JSON . parse ( localStorage [ 'proxies' ] ) : getInitialProxies ( ) )
143
147
const [ selectedProxy , setSelectedProxy ] = useState ( proxyQs ?? localStorage . getItem ( 'selectedProxy' ) ?? proxies ?. [ 0 ] ?? '' )
@@ -198,30 +202,69 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL
198
202
199
203
useUtilsEffect ( ( { signal } ) => {
200
204
const update = async ( ) => {
201
- for ( const server of serversListSorted ) {
202
- const isInLocalNetwork = server . ip . startsWith ( '192.168.' ) || server . ip . startsWith ( '10.' ) || server . ip . startsWith ( '172.' ) || server . ip . startsWith ( '127.' ) || server . ip . startsWith ( 'localhost' )
203
- if ( isInLocalNetwork || signal . aborted ) continue
204
- // eslint-disable-next-line no-await-in-loop
205
- await fetch ( `https://api.mcstatus.io/v2/status/java/${ server . ip } ` , {
206
- // TODO: bounty for this who fix it
207
- // signal
208
- } ) . then ( async r => r . json ( ) ) . then ( ( data : ServerResponse ) => {
209
- const versionClean = data . version ?. name_raw . replace ( / ^ [ ^ \d . ] + / , '' )
210
- if ( ! versionClean ) return
211
- setAdditionalData ( old => {
212
- return ( {
213
- ...old ,
214
- [ server . ip ] : {
215
- formattedText : data . motd ?. raw ?? '' ,
216
- textNameRight : `${ versionClean } ${ data . players ?. online ?? '??' } /${ data . players ?. max ?? '??' } ` ,
217
- icon : data . icon ,
218
- }
219
- } )
220
- } )
205
+ const queue = serversListSorted
206
+ . map ( server => {
207
+ const isInLocalNetwork = server . ip . startsWith ( '192.168.' ) ||
208
+ server . ip . startsWith ( '10.' ) ||
209
+ server . ip . startsWith ( '172.' ) ||
210
+ server . ip . startsWith ( '127.' ) ||
211
+ server . ip . startsWith ( 'localhost' ) ||
212
+ server . ip . startsWith ( ':' )
213
+
214
+ const VALID_IP_OR_DOMAIN = server . ip . includes ( '.' )
215
+ if ( isInLocalNetwork || signal . aborted || ! VALID_IP_OR_DOMAIN ) return null
216
+
217
+ return server
218
+ } )
219
+ . filter ( x => x !== null )
220
+
221
+ const activeRequests = new Set < Promise < void > > ( )
222
+
223
+ let lastRequestStart = 0
224
+ for ( const server of queue ) {
225
+ // Wait if at concurrency limit
226
+ if ( activeRequests . size >= MAX_CONCURRENT_REQUESTS ) {
227
+ // eslint-disable-next-line no-await-in-loop
228
+ await Promise . race ( activeRequests )
229
+ }
230
+
231
+ // Create and track new request
232
+ // eslint-disable-next-line @typescript-eslint/no-loop-func
233
+ const request = new Promise < void > ( resolve => {
234
+ setTimeout ( async ( ) => {
235
+ try {
236
+ lastRequestStart = Date . now ( )
237
+ if ( signal . aborted ) return
238
+ const response = await fetch ( `https://api.mcstatus.io/v2/status/java/${ server . ip } ` , { signal } )
239
+ const data : ServerResponse = await response . json ( )
240
+ const versionClean = data . version ?. name_raw . replace ( / ^ [ ^ \d . ] + / , '' )
241
+
242
+ setAdditionalData ( old => ( {
243
+ ...old ,
244
+ [ server . ip ] : {
245
+ formattedText : data . motd ?. raw ?? '' ,
246
+ textNameRight : data . online ?
247
+ `${ versionClean } ${ data . players ?. online ?? '??' } /${ data . players ?. max ?? '??' } ` :
248
+ '' ,
249
+ icon : data . icon ,
250
+ offline : ! data . online
251
+ }
252
+ } ) )
253
+ } finally {
254
+ activeRequests . delete ( request )
255
+ resolve ( )
256
+ }
257
+ } , lastRequestStart ? Math . max ( 0 , FETCH_DELAY - ( Date . now ( ) - lastRequestStart ) ) : 0 )
221
258
} )
259
+
260
+ activeRequests . add ( request )
222
261
}
262
+
263
+ // Wait for remaining requests
264
+ await Promise . all ( activeRequests )
223
265
}
224
- void update ( ) . catch ( ( err ) => { } )
266
+
267
+ void update ( )
225
268
} , [ serversListSorted ] )
226
269
227
270
const isEditScreenModal = useIsModalActive ( 'editServer' )
@@ -394,10 +437,10 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL
394
437
name : server . index . toString ( ) ,
395
438
title : server . name || server . ip ,
396
439
detail : ( server . versionOverride ?? '' ) + ' ' + ( server . usernameOverride ?? '' ) ,
397
- // lastPlayed: server.lastJoined,
398
440
formattedTextOverride : additional ?. formattedText ,
399
441
worldNameRight : additional ?. textNameRight ?? '' ,
400
442
iconSrc : additional ?. icon ,
443
+ offline : additional ?. offline
401
444
}
402
445
} ) }
403
446
initialProxies = { {
0 commit comments