/// <summary>
        /// Performs a get synchronously
        /// </summary>
        /// <param name="id">The ID of the file to get</param>
        /// <param name="hash">The hash of the files contents</param>
        /// <returns>The result of the get operation</returns>
        public UnityCacheClientGetResult Get(Guid id, string hash)
        {
            UnityCacheClientGetResult result = new UnityCacheClientGetResult();

            result.Id   = id;
            result.Hash = hash;

            byte[] command = Encoding.ASCII.GetBytes("g");
            this.stream.WriteByte(command[0]);

            UnityCacheUtilities.SendIdAndHashOnStream(this.stream, id, hash);

            this.stream.Read(command, 0, command.Length);
            string strResult = Encoding.ASCII.GetString(command);

            if (strResult == "-")
            {
                result.Result = CacheResult.CacheMiss;

                // Read and toss the hash since we don't need it
                UnityCacheUtilities.ReadGuid(this.stream);
                UnityCacheUtilities.ReadHash(this.stream);
            }
            else if (strResult == "+")
            {
                result.Result = CacheResult.CacheHit;

                // Read the length of the file
                byte[] buffer = new byte[16];
                this.stream.Read(buffer, 0, 16);
                ulong bytesToBeRead = UnityCacheUtilities.GetAsciiBytesAsUInt64(buffer);

                // Read the ID and hash.  Toss this, we don't need it
                UnityCacheUtilities.ReadGuid(this.stream);
                UnityCacheUtilities.ReadHash(this.stream);

                // Read the reply from the server
                buffer      = new byte[bytesToBeRead];
                result.Data = buffer;
                int offset = 0;

                while (bytesToBeRead > 0)
                {
                    int   len           = (bytesToBeRead > (ulong)this.streamBlockSize) ? this.streamBlockSize : (int)bytesToBeRead;
                    ulong bytesReturned = (ulong)this.stream.Read(buffer, offset, len);
                    bytesToBeRead -= (ulong)bytesReturned;
                    offset        += (int)bytesReturned;
                }
            }

            return(result);
        }
        /// <summary>
        /// Puts a file to the server
        /// </summary>
        /// <param name="id">The id of the file</param>
        /// <param name="hash">The hash of the file</param>
        /// <param name="data">The data contained in the file</param>
        public void Put(Guid id, string hash, byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data", "Argument cannot be null");
            }

            byte[] command = Encoding.ASCII.GetBytes("p");
            this.stream.WriteByte(command[0]);

            // Send the length as ASCII
            ulong  dataLength = (ulong)data.Length;
            string lengthStr  = dataLength.ToString("X16", CultureInfo.InvariantCulture);

            byte[] lenBytes = Encoding.ASCII.GetBytes(lengthStr);
            this.stream.Write(lenBytes, 0, lenBytes.Length);

            UnityCacheUtilities.SendIdAndHashOnStream(this.stream, id, hash);

            this.stream.Write(data, 0, data.Length);
        }
        /// <summary>
        /// Processes the get command
        /// </summary>
        /// <param name="stream">The stream to the client</param>
        private void ProcessGet(NetworkStream stream)
        {
            // Read ID
            Guid   id   = UnityCacheUtilities.ReadGuid(stream);
            string hash = UnityCacheUtilities.ReadHash(stream);

            if (!CacheFile.IsFileCached(this.fileManager.Root, id, hash))
            {
                logger.Info("GET: Cache miss. {0} {1}", id, hash);

                // File is not cached
                // Send command it's not cached
                byte[] code = new byte[1];
                code[0] = 45;
                stream.Write(code, 0, 1);

                // Send id and hash
                UnityCacheUtilities.SendIdAndHashOnStream(stream, id, hash);
            }
            else
            {
                logger.Info("GET: Cache hit. {0} {1}", id, hash);

                using (MemoryStream memoryStream = new MemoryStream(49))
                {
                    // File is cached, send the response
                    byte[] code = new byte[1];
                    code[0] = 43;
                    memoryStream.Write(code, 0, 1);

                    // Send the file size in bytes
                    ulong  bytesToBeWritten = CacheFile.GetFileSizeBytes(this.fileManager.Root, id, hash);  // Dumb off by 1 hack
                    byte[] fileSizeBytes    = UnityCacheUtilities.GetUlongAsAsciiBytes(bytesToBeWritten);
                    memoryStream.Write(fileSizeBytes, 0, fileSizeBytes.Length);

                    // Send id and hash
                    UnityCacheUtilities.SendIdAndHashOnStream(memoryStream, id, hash);

                    // Send the file bytes
                    FileStream fileStream = this.fileManager.GetReadFileStream(id, hash);
                    byte[]     buffer     = new byte[this.streamBlockSize];

                    // Workaround to get enough bytes into a single packet so the Unity client doesn't choke
                    byte[] header = memoryStream.GetBuffer();
                    stream.Write(header, 0, header.Length);

                    while (bytesToBeWritten > 0)
                    {
                        int byteCount = (bytesToBeWritten > (ulong)this.streamBlockSize) ? this.streamBlockSize : (int)bytesToBeWritten;
                        fileStream.Read(buffer, 0, byteCount);
                        bytesToBeWritten -= (ulong)byteCount;
                        stream.Write(buffer, 0, byteCount);
                    }

                    fileStream.Close();
                }
            }

            // Notify listeners a get was processed
            if (this.OnGetProcessed != null)
            {
                this.OnGetProcessed(this, new EventArgs());
            }
        }