/// <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>
        /// Process the client put request
        /// </summary>
        /// <param name="stream">The stream to the client requesting the put</param>
        private void ProcessPut(NetworkStream stream)
        {
            byte[] buffer = new byte[16];
            stream.Read(buffer, 0, 16);
            ulong bytesToBeRead = UnityCacheUtilities.GetAsciiBytesAsUInt64(buffer);

            // Read ID
            Guid id = UnityCacheUtilities.ReadGuid(stream);

            // Read HASH
            string hash = UnityCacheUtilities.ReadHash(stream);

            logger.Info("PUT: {0} {1}", id, hash);

            FileStream fileStream = this.fileManager.GetTemporaryFile(id, hash);

            buffer = new byte[this.streamBlockSize];

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

            fileStream.Close();

            this.fileManager.CompleteFile(id, hash);

            // Notify listeners a get was processed
            if (this.OnPutProcessed != null)
            {
                this.OnPutProcessed(this, new EventArgs());
            }
        }
        /// <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());
            }
        }
示例#5
0
        public void EndToEndTest()
        {
            signal = new ManualResetEvent(false);
            UnityCacheServer server = new UnityCacheServer();

            using (UnityCacheClient client = new UnityCacheClient("localhost"))
            {
                server.OnPutProcessed += server_OnPutProcessed;

                try
                {
                    // Start the server
                    Assert.AreEqual <ServerStatus>(server.Status, ServerStatus.Stopped);
                    server.Start();
                    Assert.AreEqual <ServerStatus>(server.Status, ServerStatus.Running);

                    client.Connect();

                    Guid   id = Guid.NewGuid();
                    MD5    md5Hash;
                    string hash;

                    using (md5Hash = MD5.Create())
                    {
                        hash = UnityCacheUtilities.ByteArrayToString(md5Hash.ComputeHash(Encoding.UTF8.GetBytes(DateTime.Now.ToString())));
                    }

                    Console.WriteLine("Requesting ID: {0}, Hash {1}", id, hash);
                    UnityCacheClientGetResult result;

                    // Perform a get
                    for (int x = 0; x < 100; x++)
                    {
                        // Verify that sending the same command over and over works correctly
                        result = client.Get(id, hash);
                        Assert.AreEqual <CacheResult>(result.Result, CacheResult.CacheMiss);
                    }

                    // Perform a put
                    int    dataLen = 1024 * 10 + DateTime.Now.Second % 2;       // Test that even/odd file lengths work correctly randomly
                    byte[] data    = new byte[dataLen];
                    Random r       = new Random();
                    for (int x = 0; x < data.Length; x++)
                    {
                        data[x] = (byte)r.Next();
                    }
                    client.Put(id, hash, data);

                    // Wait for the server to process the request since there isn't an ACK
                    signal.WaitOne();

                    // Fetch the file we just put
                    result = client.Get(id, hash);

                    Assert.AreEqual <CacheResult>(result.Result, CacheResult.CacheHit);
                    Assert.AreEqual(result.Data.Length, dataLen);

                    for (int x = 0; x < data.Length; x++)
                    {
                        Assert.AreEqual <byte>(data[x], result.Data[x], "Data does not match at position {0}", x);
                    }
                }
                finally
                {
                    if (server.Status == ServerStatus.Running)
                    {
                        server.Stop();
                    }
                }
            }
        }