00001 #include "NativeFeatureIncludes.h"
00002 #if _RAKNET_SUPPORT_DirectoryDeltaTransfer==1
00003
00004 #include "DirectoryDeltaTransfer.h"
00005 #include "FileList.h"
00006 #include "StringCompressor.h"
00007 #include "RakPeerInterface.h"
00008 #include "FileListTransfer.h"
00009 #include "FileListTransferCBInterface.h"
00010 #include "BitStream.h"
00011 #include "MessageIdentifiers.h"
00012 #include "FileOperations.h"
00013 #include "IncrementalReadInterface.h"
00014
00015 #ifdef _MSC_VER
00016 #pragma warning( push )
00017 #endif
00018
00019 class DDTCallback : public FileListTransferCBInterface
00020 {
00021 public:
00022 unsigned subdirLen;
00023 char outputSubdir[512];
00024 FileListTransferCBInterface *onFileCallback;
00025
00026 DDTCallback() {}
00027 virtual ~DDTCallback() {}
00028
00029 virtual bool OnFile(OnFileStruct *onFileStruct)
00030 {
00031 char fullPathToDir[1024];
00032
00033 if (onFileStruct->fileName && onFileStruct->fileData && subdirLen < strlen(onFileStruct->fileName))
00034 {
00035 strcpy(fullPathToDir, outputSubdir);
00036 strcat(fullPathToDir, onFileStruct->fileName+subdirLen);
00037 WriteFileWithDirectories(fullPathToDir, (char*)onFileStruct->fileData, (unsigned int ) onFileStruct->byteLengthOfThisFile);
00038 }
00039 else
00040 fullPathToDir[0]=0;
00041
00042 return onFileCallback->OnFile(onFileStruct);
00043 }
00044
00045 virtual void OnFileProgress(FileProgressStruct *fps)
00046 {
00047 char fullPathToDir[1024];
00048
00049 if (fps->onFileStruct->fileName && subdirLen < strlen(fps->onFileStruct->fileName))
00050 {
00051 strcpy(fullPathToDir, outputSubdir);
00052 strcat(fullPathToDir, fps->onFileStruct->fileName+subdirLen);
00053 }
00054 else
00055 fullPathToDir[0]=0;
00056
00057 onFileCallback->OnFileProgress(fps);
00058 }
00059 virtual bool OnDownloadComplete(void)
00060 {
00061 return onFileCallback->OnDownloadComplete();
00062 }
00063 };
00064
00065 DirectoryDeltaTransfer::DirectoryDeltaTransfer()
00066 {
00067 applicationDirectory[0]=0;
00068 fileListTransfer=0;
00069 availableUploads = RakNet::OP_NEW<FileList>( __FILE__, __LINE__ );
00070 priority=HIGH_PRIORITY;
00071 orderingChannel=0;
00072 incrementalReadInterface=0;
00073 compressOutgoingSends=false;
00074 }
00075 DirectoryDeltaTransfer::~DirectoryDeltaTransfer()
00076 {
00077 RakNet::OP_DELETE(availableUploads, __FILE__, __LINE__);
00078 }
00079 void DirectoryDeltaTransfer::SetFileListTransferPlugin(FileListTransfer *flt)
00080 {
00081 fileListTransfer=flt;
00082 if (flt)
00083 availableUploads->SetCallback(flt->GetCallback());
00084 else
00085 availableUploads->SetCallback(0);
00086 }
00087 void DirectoryDeltaTransfer::SetApplicationDirectory(const char *pathToApplication)
00088 {
00089 if (pathToApplication==0 || pathToApplication[0]==0)
00090 applicationDirectory[0]=0;
00091 else
00092 {
00093 strncpy(applicationDirectory, pathToApplication, 510);
00094 if (applicationDirectory[strlen(applicationDirectory)-1]!='/' && applicationDirectory[strlen(applicationDirectory)-1]!='\\')
00095 strcat(applicationDirectory, "/");
00096 applicationDirectory[511]=0;
00097 }
00098 }
00099 void DirectoryDeltaTransfer::SetUploadSendParameters(PacketPriority _priority, char _orderingChannel)
00100 {
00101 priority=_priority;
00102 orderingChannel=_orderingChannel;
00103 }
00104 void DirectoryDeltaTransfer::AddUploadsFromSubdirectory(const char *subdir)
00105 {
00106 availableUploads->AddFilesFromDirectory(applicationDirectory, subdir, true, false, true, FileListNodeContext(0,0));
00107 }
00108 unsigned short DirectoryDeltaTransfer::DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb)
00109 {
00110
00111
00112 RakAssert(host!=UNASSIGNED_SYSTEM_ADDRESS);
00113
00114 DDTCallback *transferCallback;
00115 FileList localFiles;
00116 localFiles.SetCallback(cb);
00117
00118 localFiles.AddFilesFromDirectory(prependAppDirToOutputSubdir ? applicationDirectory : 0, outputSubdir, true, false, true, FileListNodeContext(0,0));
00119
00120
00121 transferCallback = RakNet::OP_NEW<DDTCallback>( __FILE__, __LINE__ );
00122 if (subdir && subdir[0])
00123 {
00124 transferCallback->subdirLen=(unsigned int)strlen(subdir);
00125 if (subdir[transferCallback->subdirLen-1]!='/' && subdir[transferCallback->subdirLen-1]!='\\')
00126 transferCallback->subdirLen++;
00127 }
00128 else
00129 transferCallback->subdirLen=0;
00130 if (prependAppDirToOutputSubdir)
00131 strcpy(transferCallback->outputSubdir, applicationDirectory);
00132 else
00133 transferCallback->outputSubdir[0]=0;
00134 if (outputSubdir)
00135 strcat(transferCallback->outputSubdir, outputSubdir);
00136 if (transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='/' && transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='\\')
00137 strcat(transferCallback->outputSubdir, "/");
00138 transferCallback->onFileCallback=onFileCallback;
00139
00140
00141 unsigned short setId = fileListTransfer->SetupReceive(transferCallback, true, host);
00142
00143
00144 RakNet::BitStream outBitstream;
00145 outBitstream.Write((MessageID)ID_DDT_DOWNLOAD_REQUEST);
00146 outBitstream.Write(setId);
00147 stringCompressor->EncodeString(subdir, 256, &outBitstream);
00148 stringCompressor->EncodeString(outputSubdir, 256, &outBitstream);
00149 localFiles.Serialize(&outBitstream);
00150 SendUnified(&outBitstream, _priority, RELIABLE_ORDERED, _orderingChannel, host, false);
00151
00152 return setId;
00153 }
00154 void DirectoryDeltaTransfer::ClearUploads(void)
00155 {
00156 availableUploads->Clear();
00157 }
00158 void DirectoryDeltaTransfer::OnDownloadRequest(Packet *packet)
00159 {
00160 char subdir[256];
00161 char remoteSubdir[256];
00162 RakNet::BitStream inBitstream(packet->data, packet->length, false);
00163 FileList remoteFileHash;
00164 FileList delta;
00165 unsigned short setId;
00166 inBitstream.IgnoreBits(8);
00167 inBitstream.Read(setId);
00168 stringCompressor->DecodeString(subdir, 256, &inBitstream);
00169 stringCompressor->DecodeString(remoteSubdir, 256, &inBitstream);
00170 if (remoteFileHash.Deserialize(&inBitstream)==false)
00171 {
00172 #ifdef _DEBUG
00173 RakAssert(0);
00174 #endif
00175 return;
00176 }
00177
00178 availableUploads->GetDeltaToCurrent(&remoteFileHash, &delta, subdir, remoteSubdir);
00179 if (incrementalReadInterface==0)
00180 delta.PopulateDataFromDisk(applicationDirectory, true, false, true);
00181 else
00182 delta.FlagFilesAsReferences();
00183
00184
00185 fileListTransfer->Send(&delta, rakPeerInterface, packet->systemAddress, setId, priority, orderingChannel, compressOutgoingSends, incrementalReadInterface, chunkSize);
00186 }
00187 PluginReceiveResult DirectoryDeltaTransfer::OnReceive(Packet *packet)
00188 {
00189 switch (packet->data[0])
00190 {
00191 case ID_DDT_DOWNLOAD_REQUEST:
00192 OnDownloadRequest(packet);
00193 return RR_STOP_PROCESSING_AND_DEALLOCATE;
00194 }
00195
00196 return RR_CONTINUE_PROCESSING;
00197 }
00198
00199 unsigned DirectoryDeltaTransfer::GetNumberOfFilesForUpload(void) const
00200 {
00201 return availableUploads->fileList.Size();
00202 }
00203 void DirectoryDeltaTransfer::SetCompressOutgoingSends(bool compress)
00204 {
00205 compressOutgoingSends=compress;
00206 }
00207
00208 void DirectoryDeltaTransfer::SetDownloadRequestIncrementalReadInterface(IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize)
00209 {
00210 incrementalReadInterface=_incrementalReadInterface;
00211 chunkSize=_chunkSize;
00212 }
00213
00214 #ifdef _MSC_VER
00215 #pragma warning( pop )
00216 #endif
00217
00218 #endif // _RAKNET_SUPPORT_*