Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
5.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=======================================================================================//
  4. #include "sv_sessioninfopublisher.h"
  5. #include "sv_replaycontext.h"
  6. #include "sv_recordingsessionblock.h"
  7. #include "sv_recordingsession.h"
  8. // memdbgon must be the last include file in a .cpp file!!!
  9. #include "tier0/memdbgon.h"
  10. //----------------------------------------------------------------------------------------
  11. CSessionInfoPublisher::CSessionInfoPublisher( CServerRecordingSession *pSession )
  12. : m_pSession( pSession ),
  13. m_flSessionInfoPublishTime( 0.0f ),
  14. m_itLastCompletedBlockWrittenToBuffer( ~0 ),
  15. m_pFilePublisher( NULL ),
  16. m_bShouldPublish( false )
  17. {
  18. }
  19. CSessionInfoPublisher::~CSessionInfoPublisher()
  20. {
  21. }
  22. void CSessionInfoPublisher::Publish()
  23. {
  24. m_bShouldPublish = true;
  25. }
  26. bool CSessionInfoPublisher::IsDone() const
  27. {
  28. return !m_bShouldPublish && m_pFilePublisher == NULL;
  29. }
  30. void CSessionInfoPublisher::OnStopRecord( bool bAborting )
  31. {
  32. }
  33. void CSessionInfoPublisher::AbortPublish()
  34. {
  35. m_bShouldPublish = false;
  36. if ( m_pFilePublisher && !m_pFilePublisher->IsDone() )
  37. {
  38. m_pFilePublisher->AbortAndCleanup();
  39. }
  40. }
  41. void CSessionInfoPublisher::RefreshSessionInfoBlockData( CUtlBuffer &buf )
  42. {
  43. const CBaseRecordingSession::BlockContainer_t &vecBlocks = m_pSession->GetBlocks();
  44. // Start from head if this is the first time we're writing, otherwise start
  45. // from block after the last one written.
  46. const int itStart = m_itLastCompletedBlockWrittenToBuffer == vecBlocks.InvalidIndex() ?
  47. 0 : m_itLastCompletedBlockWrittenToBuffer + 1;
  48. for( int i = itStart; i < vecBlocks.Count(); ++i )
  49. {
  50. const CServerRecordingSessionBlock *pBlock = SV_CastBlock( vecBlocks[ i ] );
  51. // NOTE: This will SeekPut() on buf, based on the block's reconstruction index.
  52. pBlock->WriteSessionInfoDataToBuffer( buf );
  53. // Cache the last block written whose state isn't going to change
  54. if ( pBlock->m_nRemoteStatus == CBaseRecordingSessionBlock::STATUS_READYFORDOWNLOAD &&
  55. i > m_itLastCompletedBlockWrittenToBuffer )
  56. {
  57. m_itLastCompletedBlockWrittenToBuffer = i;
  58. }
  59. IF_REPLAY_DBG( Warning( "Writing block w/ recon index %i to session info buffer\n", pBlock->m_iReconstruction ) );
  60. }
  61. }
  62. void CSessionInfoPublisher::Think()
  63. {
  64. // Existing publisher?
  65. if ( m_pFilePublisher )
  66. {
  67. // Finished?
  68. if ( m_pFilePublisher->IsDone() )
  69. {
  70. // Free/clear
  71. delete m_pFilePublisher;
  72. m_pFilePublisher = NULL;
  73. }
  74. else
  75. {
  76. // Let the publisher think
  77. m_pFilePublisher->Think();
  78. }
  79. }
  80. // Publish needed?
  81. if ( !m_bShouldPublish )
  82. return;
  83. // Already publishing?
  84. if ( m_pFilePublisher )
  85. return;
  86. DBG( "Publishing session info...\n" );
  87. // Write outstanding blocks to the buffer
  88. RefreshSessionInfoBlockData( m_bufSessionInfo );
  89. // We now know the uncompressed payload size
  90. const int nPayloadSize = m_bufSessionInfo.TellPut();
  91. // Create as much of the header as possible now - the rest will be written in AdjustHeader()
  92. // once the publisher knows the md5 digest and the compression result.
  93. Assert( m_pSession->m_strName.Length() < MAX_SESSIONNAME_LENGTH ); // The only way this name is going to get very long is if
  94. V_strcpy_safe( m_SessionInfoHeader.m_szSessionName, m_pSession->m_strName.Get() );
  95. m_SessionInfoHeader.m_nNumBlocks = m_pSession->GetNumBlocks();
  96. m_SessionInfoHeader.m_bRecording = m_pSession->m_bRecording;
  97. m_SessionInfoHeader.m_uPayloadSizeUC = nPayloadSize;
  98. // Format a path & filename that points to the tmp dir, with <session name>.dmx on the end
  99. CFmtStr fmtTmpSessionInfoFile( "%s%s.%s", SV_GetTmpDir(), m_pSession->m_strName.Get(), GENERIC_FILE_EXTENSION );
  100. // Publish the file now (asynchronous)
  101. PublishFileParams_t params;
  102. params.m_pOutFilename = fmtTmpSessionInfoFile.Access(),
  103. params.m_pSrcData = (uint8 *)m_bufSessionInfo.Base();
  104. params.m_nSrcSize = nPayloadSize;
  105. params.m_pCallbackHandler = this;
  106. params.m_nCompressorType = COMPRESSORTYPE_LZSS;
  107. params.m_bHash = true;
  108. params.m_bFreeSrcData = false;
  109. params.m_bDeleteFile = false;
  110. params.m_pHeaderData = &m_SessionInfoHeader;
  111. params.m_nHeaderSize = sizeof( SessionInfoHeader_t );
  112. params.m_pUserData = NULL;
  113. m_pFilePublisher = SV_PublishFile( params );
  114. // Reset flag
  115. m_bShouldPublish = false;
  116. }
  117. void CSessionInfoPublisher::OnPublishComplete( const IFilePublisher *pPublisher, void *pUserData )
  118. {
  119. Assert( !pUserData );
  120. // Handle publish failure
  121. if ( pPublisher->GetStatus() != IFilePublisher::PUBLISHSTATUS_OK )
  122. {
  123. g_pServerReplayContext->OnPublishFailed();
  124. }
  125. }
  126. void CSessionInfoPublisher::OnPublishAborted( const IFilePublisher *pPublisher )
  127. {
  128. Assert( pPublisher == m_pFilePublisher );
  129. g_pServerReplayContext->OnPublishFailed();
  130. }
  131. void CSessionInfoPublisher::AdjustHeader( const IFilePublisher *pPublisher, void *pHeaderData )
  132. {
  133. SessionInfoHeader_t *pHeader = static_cast< SessionInfoHeader_t * >( pHeaderData );
  134. // Set compressor type - will return COMPRESSORTYPE_INVALID if compression failed.
  135. pHeader->m_nCompressorType = pPublisher->GetCompressorType();
  136. pHeader->m_uPayloadSize = pPublisher->GetCompressedSize();
  137. // Get MD5 digest
  138. pPublisher->GetHash( pHeader->m_aHash );
  139. }
  140. void CSessionInfoPublisher::PublishAllSynchronous()
  141. {
  142. while ( !IsDone() )
  143. {
  144. Think();
  145. }
  146. }
  147. //----------------------------------------------------------------------------------------