import { app } from 'electron' ; import { LogFileParsingState , LogSenderParsingMetadata } from 'root/app/log-parser/model' ; import { sendMessageToHomeWindow } from 'root/app/messages' ; import { Request } from 'root/app/request' ; import { stateStore } from 'root/app/state_store' ; import { error } from 'root/lib/logger' ; import { NetworkStatusMessage } from 'root/lib/messages' ; import { asMap , asString } from 'root/lib/type_utils' ; import { isMac , sleep } from 'root/lib/utils' ; import { ParseResults } from 'root/models/indicators' ; let logSenderParsingMetadata = { fastTimeout : 1000 , slowTimeout : 5000 , batchSize : 50 , sendingRates : { } , sendOnlyTheLast : { '2' : 1 , } , forceUpload : false , } ; function clearIndicatorInBuffer ( indicator ) { for ( const buffer of internalBuffer ) { buffer . events = buffer . events . filter ( ( event ) => event . indicator !== indicator ) ; } } function filterOnlyLastEvents ( events ) { const res = [ ] ; for ( const event of events ) { if ( logSenderParsingMetadata . sendOnlyTheLast . hasOwnProperty ( event . indicator ) ) { clearIndicatorInBuffer ( event . indicator ) ; const notLastIndex = res . findIndex ( ( _ ) => _ . indicator === event . indicator ) ; if ( notLastIndex > - 1 ) { res . splice ( notLastIndex , 1 ) ; } } res . push ( event ) ; } return res ; } export function sendEventsToServer ( events , parsingMetadata , state , fileId ? , forceUpload ? ) { logSenderParsingMetadata = parsingMetadata ; logSenderParsingMetadata . forceUpload = forceUpload ; if ( events . length === 0 ) { return ; } internalBuffer . push ( { events : filterOnlyLastEvents ( events ) , state , fileId } ) ; setTimeout ( sendNextBatch , logSenderParsingMetadata . fastTimeout ) ; } async function uploadpackfile ( results , version ) { try { const res = await Request . gzip < ParseResults [ ] > ( `/mtg/donew2.php?cmd=cm_uploadpackfile&version=${ version }${ isMac ( ) ? 'm' : 'w' }` , results ) ; const resMap = asMap ( res ) ; if ( resMap === undefined ) { return false ; } return asString ( resMap . status , '' ) . toUpperCase ( ) ; } catch ( e ) { return false ; } } const internalBuffer = [ ] ; interface EventsWithCursor { events : ParseResults [ ] ; state : LogFileParsingState ; fileId ? : string ; } let isCurrentlySending = false ; let currentNumberOfEvents = 0 ; async function sendNextBatch ( ) { if ( isCurrentlySending ) { return ; } isCurrentlySending = true ; currentNumberOfEvents = 0 ; const events = [ ] ; for ( const part of internalBuffer ) { if ( events . length === 0 || events . length + part . events . length <= logSenderParsingMetadata . batchSize ) { for ( const event of part . events ) { let sendingRate = logSenderParsingMetadata . sendingRates [ event . indicator ] as number | undefined ; if ( sendingRate === undefined ) { sendingRate = 1 ; } if ( Math . random ( ) <= sendingRate ) { events . push ( event ) ; } } currentNumberOfEvents ++ ; } else { break ; } } if ( events . length === 0 ) { isCurrentlySending = false ; return ; } let hasErrored = false ; try { const ok = await uploadpackfile ( events , app . getVersion ( ) ) ; if ( ok === 'RESTART' ) { sendMessageToHomeWindow ( 'restart-me' , undefined ) ; } if ( ok === false ) { sendMessageToHomeWindow ( 'network-status' , { active : false , message : NetworkStatusMessage . Disconnected } ) ; throw new Error ( "Couldn't send to server" ) ; } const sentBufferParts = internalBuffer . splice ( 0 , currentNumberOfEvents ) ; if ( sentBufferParts . length > 0 ) { const filteredSentBufferParts = sentBufferParts . filter ( ( _ ) => _ . fileId !== undefined ) ; if ( filteredSentBufferParts . length > 0 ) { const cursor = filteredSentBufferParts [ filteredSentBufferParts . length - 1 ] ; if ( cursor . fileId !== undefined ) { stateStore . saveState ( { fileId : cursor . fileId , state : cursor . state } ) ; } } } sendMessageToHomeWindow ( 'network-status' , { active : true , message : isStillSendingEvents ( ) ? NetworkStatusMessage . SendingEvents : NetworkStatusMessage . Connected , eventsleft : internalBuffer . length , } ) ; } catch ( e ) { hasErrored = true ; error ( String ( e ) , e , { } , true ) ; sendMessageToHomeWindow ( 'show-status' , { message : 'Connection Error' , color : '#cc2d2d' } ) ; } finally { const timeout = internalBuffer . length > 0 && ! hasErrored ? logSenderParsingMetadata . fastTimeout : logSenderParsingMetadata . slowTimeout ; await sleep ( timeout ) ; isCurrentlySending = false ; sendNextBatch ( ) . catch ( ( _ ) => { } ) ; } } export const isStillSendingEvents = ( ) => internalBuffer . length > 0 ;