public static void TestConversion(IConverter converter, string sourceFileName, FileTypes sourceFormat, FileTypes targetFormat, bool assertSuccess)
        {
            string sourceFile = Path.GetFullPath(sourceFileName);

            // Get a temporary target file
            TempFolder tempFolder = new TempFolder();
            string targetFile = tempFolder.getFilePath("target." + targetFormat);

            // Do the conversion
            bool converted = converter.Convert(sourceFile, (int)sourceFormat, targetFile, (int)targetFormat);

            if (assertSuccess)
            {
                // Check that converter returned true
                Assert.IsTrue(converted);
                // Check that converter created the target file and it's not empty
                Assert.AreNotEqual(0, new FileInfo(targetFile).Length);
            }
            else
            {
                // Check that converter returned false
                Assert.IsFalse(converted);
            }

            // Delete the temp folder created
            tempFolder.Release();
        }
        public void Run()
        {
            int bytesRead, bytesSent;
            byte[] buffer = new byte[BufferSize];

            TempFolder tempFolder = null;
            string sourceFilePath = null;
            FileStream sourceFileStream = null;
            string targetFilePath = null;
            FileStream targetFileStream = null;

            bool everythingOk = false;

            try
            {
                // 1) Read the conversion ID

                int conversionId = ReceiveInt();
                log.Info("received conversion id: " + conversionId);


                // 1) Read the source file type

                int sourceFileTypeValue = ReceiveInt();
                FileTypes sourceFileType = (FileTypes)sourceFileTypeValue;
                log.Info("received source file type: " + sourceFileTypeValue + " ("+ sourceFileType +")");
                if (!Enum.IsDefined(typeof(FileTypes), sourceFileType))
                {
                    throw new ProtocolException(StatusCodes.BadFileType);
                }


                // 2) Read the target file type

                int targetFileTypeValue = ReceiveInt();
                FileTypes targetFileType = (FileTypes)targetFileTypeValue;
                log.Info("received target file type: " + targetFileTypeValue + " (" + targetFileType + ")");
                if (!Enum.IsDefined(typeof(FileTypes), targetFileType))
                {
                    throw new ProtocolException(StatusCodes.BadFileType);
                }


                // 3) Read the source file size

                int fileSize = ReceiveInt();
                log.Info("received source file size: " + fileSize);
                if (fileSize <= 0)
                {
                    throw new ProtocolException(StatusCodes.BadFileSize);
                }

                // 4) Read the source file and cache it on disk

                tempFolder = new TempFolder(conversionId);
                log.Info("created temp folder " + tempFolder.ToString());

                sourceFilePath = tempFolder.getFilePath("source." + sourceFileType);
                sourceFileStream = new FileStream(sourceFilePath, FileMode.Create);
                int totalBytesRead = 0;
                log.Info("receiving source file...");
                while (totalBytesRead < fileSize)
                {
                    bytesRead = socket.Receive(buffer, BufferSize, 0);
                    sourceFileStream.Write(buffer, 0, bytesRead);
                    totalBytesRead += bytesRead;
                }
                sourceFileStream.Close();
                log.Info("source file received");


                // 5) Convert the source file
                bool converted = false;
                try
                {
                    targetFilePath = tempFolder.getFilePath("target." + targetFileType);
                    converted = fileConverter.Convert(sourceFilePath, (int)sourceFileType, targetFilePath, (int)targetFileType);
                }
                catch (BrokenSourceException e)
                {
                    throw new ProtocolException(StatusCodes.BrokenSourceFile, e);
                }
                catch (ConversionException e)
                {
                    throw new ProtocolException(StatusCodes.ConversionError, e);
                }
                if (!converted)
                {
                    throw new ProtocolException(StatusCodes.UnsupportedConversion);
                }


                // 6) Send back the ok status code

                SendInt((int)StatusCodes.Ok);
                log.Info("sent status code: 0 (ok!)");


                // 7) Send back the converted file size

                int filesize = 0;
                try
                {
                    filesize = (int)new FileInfo(targetFilePath).Length;
                }
                catch (OverflowException e)
                {
                    throw new ProtocolException(StatusCodes.ConvertedFileTooBig, e);
                }
                SendInt(filesize);
                log.Info("sent target file size: " + filesize);


                // 8) Send back the converted file

                buffer = new byte[BufferSize];
                targetFileStream = new FileStream(targetFilePath, FileMode.Open);
                log.Info("sending target file...");
                while (true)
                {
                    bytesRead = targetFileStream.Read(buffer, 0, BufferSize);
                    if (bytesRead == 0)
                    {
                        break;
                    }
                    else
                    {
                        bytesSent = socket.Send(buffer, bytesRead, 0);
                    }
                }
                log.Info("target file sent");
                targetFileStream.Close();

                // If execution arrives here, everything went well!
                everythingOk = true;
            }
            catch (Exception e)
            {
                log.Error("exception", e);
                StatusCodes statusCode = (e is ProtocolException ? ((ProtocolException)e).statusCode : StatusCodes.InternalServerError);
                string statusCodeDescription = "status code " + (int)statusCode + " (" + statusCode + ")";
                try
                {
                    SendInt((int)statusCode);
                    log.Info("sent " + statusCodeDescription);
                }
                catch (Exception ee)
                {
                    log.Warn("exception while sending " + statusCodeDescription, ee);
                }
            }
            finally
            {
                // Close streams
                if (sourceFileStream != null) sourceFileStream.Close();
                if (targetFileStream != null) targetFileStream.Close();
                
                // Delete temp folder if everything ok, or move it to errors repository
                if (tempFolder != null)
                {
                    tempFolder.Release(!everythingOk);
                }

                EndPoint remoteEndPoint = socket.RemoteEndPoint;
                socket.Shutdown(SocketShutdown.Both);
                // Wait that client closes connection
                //socket.Receive(new byte[1], SocketFlags.Peek);
                socket.Close();
                log.Info("connection closed");
            }
        }
        public static void TestHighConcurrencyConversion(IConverter converter, string sourceFileName, FileTypes sourceFormat, FileTypes targetFormat, int concurrentConversions)
        {
            // Try to convert always the same file
            string sourceFile = Path.GetFullPath(sourceFileName);

            // Count the succeded conversion in this var
            int successes = 0;

            // Create the thread pool
            List<Thread> threads = new List<Thread>();
            for (int i = 0; i < concurrentConversions; i++)
            {
                threads.Add(new Thread(delegate () {
                    // This code will run many times in the same moment on many threads,
                    // so be very careful to not make two Office instances write the same
                    // file, or they will raise exceptions. The most problems I had 
                    // happened exactly because of this. Always make Office instance write
                    // to a clean filepath that points to a still non-existent file.
                    // Don't try anything else, 90% it will raise errors.

                    // The safest way to create a clean lonely filepath is using the 
                    // TempFolder class
                    TempFolder tempFolder = new TempFolder();
                    string targetFile = tempFolder.getFilePath("target." + targetFormat);

                    // Ok, let's do the real conversion
                    try
                    {
                        bool converted = converter.Convert(sourceFile, (int)sourceFormat, targetFile, (int)targetFormat);
                        if (converted) Interlocked.Increment(ref successes);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Conversion failed:\n" + e + "\n");
                    }
                    finally
                    {
                        // Delete the temp target folder
                        tempFolder.Release();
                    }
                }));
            }

            // Launch all the threads in the same time
            foreach (var thread in threads)
            {
                thread.Start();
            }

            // Wait for all threads completion
            foreach (var thread in threads)
            {
                thread.Join();
            }

            // Check test final result
            Assert.AreEqual(concurrentConversions, successes);
        }
        public void Run(object stateInfo)
        {
            if (!socket.Connected) throw new InvalidOperationException("Socket is not connected!");

            int totalTime = Environment.TickCount;

            int bytesRead, bytesSent;
            byte[] buffer = new byte[BufferSize];

            TempFolder tempFolder = null;
            string sourceFilePath = null;
            FileStream sourceFileStream = null;
            string targetFilePath = null;
            FileStream targetFileStream = null;

            bool healthCheck = false;
            bool everythingOk = false;

            try
            {
                // Set socket timeouts
                socket.ReceiveTimeout = SocketTimeout;
                socket.SendTimeout = SocketTimeout;

                // 1) Read the conversion ID
                int conversionId;
                try
                {
                    conversionId = ReceiveInt();
                }
                catch (InvalidOperationException)
                {
                    // If an external service performs a TCP health check on
                    // this on this service, it will shutdown the connection
                    // just after it is accepted by this server. In this catch
                    // I handle just this special case. Don't log anything,
                    // just return successfully.
                    healthCheck = true;
                    everythingOk = true;
                    return;
                }
                log.Info("received conversion id: " + conversionId);


                // 1) Read the source file type

                int sourceFileTypeValue = ReceiveInt();
                FileTypes sourceFileType = (FileTypes)sourceFileTypeValue;
                log.Info("received source file type: " + sourceFileTypeValue + " ("+ sourceFileType +")");
                if (!Enum.IsDefined(typeof(FileTypes), sourceFileType))
                {
                    throw new ProtocolException(StatusCodes.BadFileType);
                }


                // 2) Read the target file type

                int targetFileTypeValue = ReceiveInt();
                FileTypes targetFileType = (FileTypes)targetFileTypeValue;
                log.Info("received target file type: " + targetFileTypeValue + " (" + targetFileType + ")");
                if (!Enum.IsDefined(typeof(FileTypes), targetFileType))
                {
                    throw new ProtocolException(StatusCodes.BadFileType);
                }


                // 3) Read the source file size

                int fileSize = ReceiveInt();
                log.Info("received source file size: " + fileSize);
                if (fileSize <= 0)
                {
                    throw new ProtocolException(StatusCodes.BadFileSize);
                }

                // 4) Read the source file and cache it on disk

                tempFolder = new TempFolder(conversionId);
                log.Info("created temp folder " + tempFolder.ToString());

                sourceFilePath = tempFolder.getFilePath("source." + sourceFileType);
                sourceFileStream = new FileStream(sourceFilePath, FileMode.Create);
                int totalBytesRead = 0;
                log.Info("receiving source file...");
                while (totalBytesRead < fileSize)
                {
                    bytesRead = socket.Receive(buffer, Math.Min(BufferSize, fileSize - totalBytesRead), 0);
                    sourceFileStream.Write(buffer, 0, bytesRead);
                    totalBytesRead += bytesRead;
                }
                sourceFileStream.Close();
                log.Info("source file received");


                // 5) Convert the source file
                log.Info("converting file...");
                int conversionTime = Environment.TickCount;
                bool converted = false;
                try
                {
                    targetFilePath = tempFolder.getFilePath("target." + targetFileType);
                    converted = fileConverter.Convert(sourceFilePath, (int)sourceFileType, targetFilePath, (int)targetFileType);
                }
                catch (BrokenSourceException e)
                {
                    throw new ProtocolException(StatusCodes.BrokenSourceFile, e);
                }
                catch (ConversionException e)
                {
                    throw new ProtocolException(StatusCodes.InternalServerError, e);
                }
                if (!converted)
                {
                    throw new ProtocolException(StatusCodes.UnsupportedConversion);
                }
                conversionTime = Environment.TickCount - conversionTime;
                log.Info("file converted");


                // 6) Send back the ok status code

                SendInt((int)StatusCodes.Ok);
                log.Info("sent status code: 0 (ok!)");


                // 7) Send back the converted file size

                int filesize = 0;
                try
                {
                    filesize = (int)new FileInfo(targetFilePath).Length;
                }
                catch (OverflowException e)
                {
                    throw new ProtocolException(StatusCodes.ConvertedFileTooBig, e);
                }
                SendInt(filesize);
                log.Info("sent target file size: " + filesize);


                // 8) Send back the converted file

                buffer = new byte[BufferSize];
                targetFileStream = new FileStream(targetFilePath, FileMode.Open);
                log.Info("sending target file...");
                while ((bytesRead = targetFileStream.Read(buffer, 0, BufferSize)) > 0)
                {
                    bytesSent = socket.Send(buffer, bytesRead, 0);
                }
                log.Info("target file sent");
                targetFileStream.Close();

                // If execution arrives here, everything went well!
                everythingOk = true;

                // Log timings
                totalTime = Environment.TickCount - totalTime;
                log.Info("timings: total " + totalTime / 1000 + "s, conversion " + conversionTime / 1000 + "s ("+ (int)(((double)conversionTime / totalTime) * 100) +"%)");
            }
            catch (Exception e)
            {
                log.Error("exception", e);
                StatusCodes statusCode = (e is ProtocolException ? ((ProtocolException)e).statusCode : StatusCodes.InternalServerError);
                string statusCodeDescription = "status code " + (int)statusCode + " (" + statusCode + ")";
                try
                {
                    SendInt((int)statusCode);
                    log.Info("sent " + statusCodeDescription);
                }
                catch (Exception ee)
                {
                    log.Warn("exception while sending " + statusCodeDescription, ee);
                }
            }
            finally
            {
                // Close streams
                if (sourceFileStream != null) sourceFileStream.Close();
                if (targetFileStream != null) targetFileStream.Close();
                
                // Delete temp folder if everything ok, or move it to errors repository
                if (tempFolder != null)
                {
                    tempFolder.Release(!everythingOk);
                }

                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
                if (!healthCheck) log.Info("connection closed");
                Interlocked.Decrement(ref serverConnectionsCounter.value);
            }
        }