1004 lines
52 KiB
C#
1004 lines
52 KiB
C#
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2015
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
|
||
* EU, LV-1021.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.Specialized;
|
||
using System.Configuration;
|
||
using System.Threading;
|
||
using System.IO;
|
||
using System.Net;
|
||
using System.Xml;
|
||
using System.Text;
|
||
using System.Web;
|
||
using FileConverterUtils2;
|
||
using log4net;
|
||
using log4net.Config;
|
||
|
||
namespace FileConverterService2
|
||
{
|
||
public static class StringParser
|
||
{
|
||
public static string[] ParseArguments(string commandLine)
|
||
{
|
||
char[] parmChars = commandLine.ToCharArray();
|
||
bool inQuote = false;
|
||
for (int index = 0; index < parmChars.Length; index++)
|
||
{
|
||
if (parmChars[index] == '"')
|
||
inQuote = !inQuote;
|
||
if (!inQuote && parmChars[index] == ' ')
|
||
parmChars[index] = '\n';
|
||
}
|
||
char[] oDelimiters = new char[] { '\n' };
|
||
return (new string(parmChars)).Split(oDelimiters, StringSplitOptions.RemoveEmptyEntries);
|
||
}
|
||
}
|
||
|
||
public class FileConverter
|
||
{
|
||
private static readonly ILog _log = LogManager.GetLogger(typeof(FileConverter));
|
||
private class IddleProcess
|
||
{
|
||
public System.Diagnostics.Process m_oProcess;
|
||
public string m_sDirToDelete;
|
||
public string m_sDirSource;
|
||
public string m_sDirResult;
|
||
public string m_sFileTo;
|
||
public string m_sChangesAuthor = null;
|
||
public TaskQueueData m_oTaskQueueData;
|
||
}
|
||
private class TransportClass
|
||
{
|
||
public TaskQueueData m_oTaskQueueData;
|
||
public AsyncWebRequestOperation m_oAsyncWebRequestOperation;
|
||
public IAsyncResult m_oAsyncWebRequestOperationResult;
|
||
}
|
||
#if! OPEN_SOURCE
|
||
private static ASCGraphics.CASCWinFonts piWinFonts = null;
|
||
#else
|
||
private static OfficeCore.CWinFontsClass piWinFonts = null;
|
||
#endif
|
||
private int m_nMaxRunThreads;
|
||
|
||
private readonly ManualResetEvent _stopEvt = new ManualResetEvent(false);
|
||
private List<Thread> m_aRunThreads = new List<Thread>();
|
||
|
||
private Thread m_oIddlePriority = null;
|
||
private List<IddleProcess> m_arrIndentFiles = new List<IddleProcess>();
|
||
private Thread m_oGCThread = null;
|
||
|
||
private object m_oKeyToPercentLock = new object();
|
||
private object m_oKeyToPercentValidateLock = new object();
|
||
private Dictionary<string, int> m_mapKeyToPercentValidate = new Dictionary<string, int>();
|
||
private Dictionary<string, int> m_mapKeyToPercent = new Dictionary<string, int>();
|
||
private Timer m_oPercentTimer = null;
|
||
|
||
private static int m_nRunThreadCount = 0;
|
||
|
||
public FileConverter(string serviceName)
|
||
{
|
||
m_nMaxRunThreads = (int)(Environment.ProcessorCount * double.Parse(ConfigurationSettings.AppSettings["maxprocesscount"], new System.Globalization.CultureInfo(0x409)));
|
||
if (0 >= m_nMaxRunThreads)
|
||
m_nMaxRunThreads = 1;
|
||
}
|
||
public void Start()
|
||
{
|
||
if (null == piWinFonts)
|
||
{
|
||
bool bIsUseWinFonts = bool.Parse(ConfigurationSettings.AppSettings["fileconverterservice.usewinfonts"] ?? "true");
|
||
if (bIsUseWinFonts)
|
||
{
|
||
_log.Info("Create WinFonts.");
|
||
#if! OPEN_SOURCE
|
||
piWinFonts = new ASCGraphics.CASCWinFonts();
|
||
|
||
#else
|
||
piWinFonts = new OfficeCore.CWinFontsClass();
|
||
string sFontDir = ConfigurationSettings.AppSettings["utils.common.fontdir"] ?? "";
|
||
if(null != sFontDir && !string.IsNullOrEmpty(sFontDir))
|
||
sFontDir = Path.GetFullPath(Environment.ExpandEnvironmentVariables(sFontDir));
|
||
piWinFonts.Init(sFontDir, true, true);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
Stop();
|
||
_stopEvt.Reset();
|
||
for (int i = 0; i < m_nMaxRunThreads; i++)
|
||
{
|
||
var runThread = new Thread(Run);
|
||
|
||
_log.InfoFormat("Start convertation thread {0} of {1}.", i + 1, m_nMaxRunThreads);
|
||
runThread.Start();
|
||
m_aRunThreads.Add(runThread);
|
||
}
|
||
|
||
m_oGCThread = new Thread(GCThread);
|
||
|
||
_log.Info("Start garbage collector thread.");
|
||
m_oGCThread.Start();
|
||
}
|
||
public void Stop()
|
||
{
|
||
_stopEvt.Set();
|
||
foreach (var runThread in m_aRunThreads)
|
||
{
|
||
try
|
||
{
|
||
if (!runThread.Join(TimeSpan.FromSeconds(30)))
|
||
{
|
||
|
||
runThread.Abort();
|
||
}
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
_log.Error("Exception catched while thread stoping.", e);
|
||
}
|
||
}
|
||
m_aRunThreads.Clear();
|
||
|
||
m_arrIndentFiles.Clear();
|
||
|
||
if (null != m_oGCThread)
|
||
{
|
||
|
||
m_oGCThread.Abort();
|
||
}
|
||
}
|
||
|
||
private void Run()
|
||
{
|
||
FileConverterUtils2.CTaskQueue oTaskQueue = new FileConverterUtils2.CTaskQueue();
|
||
|
||
while (!_stopEvt.WaitOne(0))
|
||
{
|
||
FileConverterUtils2.TaskQueueData oTaskQueueData = oTaskQueue.GetTask();
|
||
|
||
if (null != oTaskQueueData)
|
||
{
|
||
DateTime oGetTaskTime = DateTime.UtcNow;
|
||
|
||
_log.DebugFormat("Start Task(id={0}), Time={1}", oTaskQueueData.m_sKey, oGetTaskTime);
|
||
Interlocked.Increment(ref m_nRunThreadCount);
|
||
ErrorTypes eError = FileConverterUtils2.ErrorTypes.NoError;
|
||
bool bNeedParam = false;
|
||
ITaskResultInterface oTaskResult = TaskResult.NewTaskResult();
|
||
Storage oFileStore = new Storage();
|
||
string sDirToDelete = Utils.GetTempDirectory();
|
||
IddleProcess oNewIddleProcess = new IddleProcess();
|
||
oNewIddleProcess.m_sDirToDelete = sDirToDelete;
|
||
oNewIddleProcess.m_oTaskQueueData = oTaskQueueData;
|
||
try
|
||
{
|
||
string sTempDir = Path.Combine(sDirToDelete, oTaskQueueData.m_sKey);
|
||
Directory.CreateDirectory(sTempDir);
|
||
string sDirSource = Path.Combine(sTempDir, "source");
|
||
Directory.CreateDirectory(sDirSource);
|
||
string sDirResult = Path.Combine(sTempDir, "result");
|
||
Directory.CreateDirectory(sDirResult);
|
||
|
||
oNewIddleProcess.m_sDirSource = sDirSource;
|
||
oNewIddleProcess.m_sDirResult = sDirResult;
|
||
|
||
int nFormatFrom = FileFormats.AVS_OFFICESTUDIO_FILE_UNKNOWN;
|
||
string sFileFrom = "";
|
||
string sFileTo = Path.Combine(sDirResult, oTaskQueueData.m_sToFile);
|
||
if (false == string.IsNullOrEmpty(oTaskQueueData.m_sFromUrl))
|
||
{
|
||
sFileFrom = Path.Combine(sDirSource, oTaskQueueData.m_sKey + "." + oTaskQueueData.m_sFromFormat);
|
||
|
||
eError = DownloadFile(oTaskQueueData.m_sFromUrl, sFileFrom);
|
||
_log.DebugFormat("DownloadFile complete(id={0})", oTaskQueueData.m_sKey);
|
||
|
||
if (FileConverterUtils2.ErrorTypes.NoError == eError)
|
||
{
|
||
nFormatFrom = FileConverterUtils2.FormatChecker.GetFileFormat(sFileFrom);
|
||
switch(nFormatFrom)
|
||
{
|
||
case FileFormats.AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML:
|
||
{
|
||
|
||
if (".html" != Path.GetExtension(sFileFrom))
|
||
{
|
||
string sNewFileFrom = Path.ChangeExtension(sFileFrom, ".html");
|
||
File.Move(sFileFrom, sNewFileFrom);
|
||
sFileFrom = sNewFileFrom;
|
||
oTaskQueueData.m_sFromFormat = "html";
|
||
}
|
||
}
|
||
break;
|
||
case FileFormats.AVS_OFFICESTUDIO_FILE_OTHER_MS_OFFCRYPTO:
|
||
eError = ErrorTypes.ConvertMS_OFFCRYPTO;
|
||
break;
|
||
case FileFormats.AVS_OFFICESTUDIO_FILE_UNKNOWN:
|
||
eError = ErrorTypes.ConvertUnknownFormat;
|
||
break;
|
||
|
||
case FileFormats.AVS_OFFICESTUDIO_FILE_DOCUMENT_TXT:
|
||
{
|
||
if (false == oTaskQueueData.m_nCsvTxtEncoding.HasValue)
|
||
{
|
||
System.Text.Encoding oEncoding = GetEncoding(sFileFrom);
|
||
if (null == oEncoding)
|
||
{
|
||
string sFileFromName = Path.GetFileName(sFileFrom);
|
||
string sJson = Utils.GetSerializedEncodingProperty(sFileFromName, null, null);
|
||
|
||
int nReadWriteBytes;
|
||
byte[] aSettingsPreamble = System.Text.Encoding.UTF8.GetPreamble();
|
||
byte[] aSettingsContent = System.Text.Encoding.UTF8.GetBytes(sJson);
|
||
byte[] aSettingsData = new byte[aSettingsPreamble.Length + aSettingsContent.Length];
|
||
aSettingsPreamble.CopyTo(aSettingsData, 0);
|
||
aSettingsContent.CopyTo(aSettingsData, aSettingsPreamble.Length);
|
||
using (MemoryStream ms = new MemoryStream(aSettingsData))
|
||
oFileStore.WriteFile(Path.Combine(oTaskQueueData.m_sKey, "settings.json"), ms, out nReadWriteBytes);
|
||
using (FileStream fs = new FileStream(sFileFrom, FileMode.Open))
|
||
oFileStore.WriteFile(Path.Combine(oTaskQueueData.m_sKey, sFileFromName), fs, out nReadWriteBytes);
|
||
bNeedParam = true;
|
||
}
|
||
else
|
||
{
|
||
oTaskQueueData.m_nCsvTxtEncoding = oEncoding.CodePage;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case FileFormats.AVS_OFFICESTUDIO_FILE_SPREADSHEET_CSV:
|
||
{
|
||
if (false == oTaskQueueData.m_nCsvTxtEncoding.HasValue ||
|
||
false == oTaskQueueData.m_nCsvDelimiter.HasValue)
|
||
{
|
||
string sFileFromName = Path.GetFileName(sFileFrom);
|
||
|
||
int? encoding;
|
||
int? delimiter;
|
||
GetEncodingAndDelimeter(sFileFrom, out encoding, out delimiter);
|
||
string sJson = Utils.GetSerializedEncodingProperty(sFileFromName, encoding, delimiter);
|
||
|
||
int nReadWriteBytes;
|
||
byte[] aSettingsPreamble = System.Text.Encoding.UTF8.GetPreamble();
|
||
byte[] aSettingsContent = System.Text.Encoding.UTF8.GetBytes(sJson);
|
||
byte[] aSettingsData = new byte[aSettingsPreamble.Length + aSettingsContent.Length];
|
||
aSettingsPreamble.CopyTo(aSettingsData, 0);
|
||
aSettingsContent.CopyTo(aSettingsData, aSettingsPreamble.Length);
|
||
using (MemoryStream ms = new MemoryStream(aSettingsData))
|
||
oFileStore.WriteFile(Path.Combine(oTaskQueueData.m_sKey, "settings.json"), ms, out nReadWriteBytes);
|
||
using (FileStream fs = new FileStream(sFileFrom, FileMode.Open))
|
||
oFileStore.WriteFile(Path.Combine(oTaskQueueData.m_sKey, sFileFromName), fs, out nReadWriteBytes);
|
||
bNeedParam = true;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else if (false == string.IsNullOrEmpty(oTaskQueueData.m_sFromKey))
|
||
{
|
||
|
||
StorageTreeNode oStorageTreeNode = oFileStore.GetTreeNode(oTaskQueueData.m_sFromKey);
|
||
eError = DownloadStorageTreeNodeToFilesystem(sDirSource, oTaskQueueData.m_sFromKey, "", oStorageTreeNode, oFileStore);
|
||
_log.DebugFormat("DownloadStorageTreeNodeToFilesystem complete(id={0})", oTaskQueueData.m_sKey);
|
||
if (oTaskQueueData.m_bFromOrigin.HasValue && true == oTaskQueueData.m_bFromOrigin.Value)
|
||
{
|
||
sFileFrom = Path.Combine(sDirSource, "origin");
|
||
nFormatFrom = FileConverterUtils2.FormatChecker.GetFileFormat(sFileFrom);
|
||
}
|
||
else if (oTaskQueueData.m_bFromSettings.HasValue && true == oTaskQueueData.m_bFromSettings.Value)
|
||
{
|
||
string sSettings = Path.Combine(sDirSource, "settings.json");
|
||
string sFileFromName;
|
||
int? codepage;
|
||
int? delimiter;
|
||
Utils.GetDeserializedEncodingProperty(File.ReadAllText(sSettings, System.Text.Encoding.UTF8), out sFileFromName, out codepage, out delimiter);
|
||
if (null != sFileFromName)
|
||
{
|
||
sFileFrom = Path.Combine(Path.GetDirectoryName(sSettings), sFileFromName);
|
||
nFormatFrom = FileConverterUtils2.FormatChecker.GetFileFormat(sFileFrom);
|
||
}
|
||
else
|
||
eError = ErrorTypes.Unknown;
|
||
}
|
||
else
|
||
{
|
||
|
||
oStorageTreeNode = oFileStore.GetTreeNode(oTaskQueueData.m_sKey);
|
||
eError = DownloadStorageTreeNodeToFilesystem(sDirSource, oTaskQueueData.m_sKey, "", oStorageTreeNode, oFileStore);
|
||
if (ErrorTypes.NoError == eError)
|
||
{
|
||
sFileFrom = Path.Combine(sDirSource, "Editor.bin");
|
||
if (FileFormats.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF == oTaskQueueData.m_nToFormat)
|
||
{
|
||
|
||
string sFileFromWE = Path.GetFileNameWithoutExtension(sFileFrom);
|
||
string[] aFiles = Directory.GetFiles(Path.GetDirectoryName(sFileFrom));
|
||
Array.Sort<string>(aFiles, Utils.CompareStringByLength);
|
||
bool bEmptyFile = true;
|
||
string sTempFile = Path.ChangeExtension(sFileFrom, ".tmp");
|
||
using (BinaryWriter writer = new BinaryWriter(File.Open(sTempFile, FileMode.Create)))
|
||
{
|
||
bool bFirst = true;
|
||
for (int i = 0, length = aFiles.Length; i < length; ++i)
|
||
{
|
||
string sCurFilename = aFiles[i];
|
||
string sCurFileFromWE = Path.GetFileNameWithoutExtension(sCurFilename);
|
||
if (sCurFileFromWE != sFileFromWE && 0 == sCurFileFromWE.IndexOf(sFileFromWE))
|
||
{
|
||
if (bFirst)
|
||
bFirst = false;
|
||
else
|
||
{
|
||
|
||
writer.Write('\n');
|
||
}
|
||
writer.Write(File.ReadAllBytes(sCurFilename));
|
||
bEmptyFile = false;
|
||
}
|
||
}
|
||
}
|
||
if (false == bEmptyFile)
|
||
{
|
||
File.Delete(sFileFrom);
|
||
File.Move(sTempFile, sFileFrom);
|
||
}
|
||
File.Delete(sTempFile);
|
||
}
|
||
else
|
||
nFormatFrom = FileConverterUtils2.FormatChecker.GetFileFormat(sFileFrom);
|
||
}
|
||
}
|
||
if (oTaskQueueData.m_bFromChanges.HasValue && oTaskQueueData.m_bFromChanges.Value)
|
||
{
|
||
List<DocsChange> aChanges;
|
||
(new DocsChanges()).GetChanges(oTaskQueueData.m_sFromKey, out aChanges);
|
||
string sChangesDir = Path.Combine(sDirSource, "changes");
|
||
Directory.CreateDirectory(sChangesDir);
|
||
string sChangesAuthor = null;
|
||
int nIndexFile = 0;
|
||
StreamWriter oStreamWriter = null;
|
||
try
|
||
{
|
||
|
||
for (int i = 0, length = aChanges.Count; i < length; ++i)
|
||
{
|
||
if (null == sChangesAuthor || sChangesAuthor != aChanges[i].userid)
|
||
{
|
||
|
||
if (null != sChangesAuthor)
|
||
{
|
||
oStreamWriter.Write("]");
|
||
oStreamWriter.Dispose();
|
||
oStreamWriter = null;
|
||
}
|
||
sChangesAuthor = aChanges[i].userid;
|
||
|
||
oStreamWriter = new StreamWriter(Path.Combine(sChangesDir, "changes" + (nIndexFile++) + ".json"));
|
||
oStreamWriter.Write("[");
|
||
oStreamWriter.Write(aChanges[i].data);
|
||
}
|
||
else
|
||
{
|
||
oStreamWriter.Write(",");
|
||
oStreamWriter.Write(aChanges[i].data);
|
||
}
|
||
}
|
||
oNewIddleProcess.m_sChangesAuthor = sChangesAuthor;
|
||
|
||
if (null != oStreamWriter)
|
||
{
|
||
oStreamWriter.Write("]");
|
||
oStreamWriter.Dispose();
|
||
oStreamWriter = null;
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
}
|
||
finally
|
||
{
|
||
if (null != oStreamWriter)
|
||
oStreamWriter.Dispose();
|
||
}
|
||
}
|
||
}
|
||
else
|
||
eError = ErrorTypes.Unknown;
|
||
int nToFormat = oTaskQueueData.m_nToFormat;
|
||
if (FileFormats.AVS_OFFICESTUDIO_FILE_CANVAS == nToFormat)
|
||
{
|
||
if (FileFormats.AVS_OFFICESTUDIO_FILE_TEAMLAB_XLSY == nFormatFrom || 0 != (FileFormats.AVS_OFFICESTUDIO_FILE_SPREADSHEET & nFormatFrom))
|
||
nToFormat = FileFormats.AVS_OFFICESTUDIO_FILE_CANVAS_SPREADSHEET;
|
||
else if (FileFormats.AVS_OFFICESTUDIO_FILE_TEAMLAB_PPTY == nFormatFrom || 0 != (FileFormats.AVS_OFFICESTUDIO_FILE_PRESENTATION & nFormatFrom))
|
||
nToFormat = FileFormats.AVS_OFFICESTUDIO_FILE_CANVAS_PRESENTATION;
|
||
else
|
||
nToFormat = FileFormats.AVS_OFFICESTUDIO_FILE_CANVAS_WORD;
|
||
}
|
||
else if (FileFormats.AVS_OFFICESTUDIO_FILE_OTHER_TEAMLAB_INNER == nToFormat)
|
||
{
|
||
if (FileFormats.AVS_OFFICESTUDIO_FILE_CANVAS_SPREADSHEET == nFormatFrom || FileFormats.AVS_OFFICESTUDIO_FILE_TEAMLAB_XLSY == nFormatFrom || 0 != (FileFormats.AVS_OFFICESTUDIO_FILE_SPREADSHEET & nFormatFrom))
|
||
nToFormat = FileFormats.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX;
|
||
else if (FileFormats.AVS_OFFICESTUDIO_FILE_CANVAS_PRESENTATION == nFormatFrom || FileFormats.AVS_OFFICESTUDIO_FILE_TEAMLAB_PPTY == nFormatFrom || 0 != (FileFormats.AVS_OFFICESTUDIO_FILE_PRESENTATION & nFormatFrom))
|
||
nToFormat = FileFormats.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX;
|
||
else
|
||
nToFormat = FileFormats.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX;
|
||
sFileTo = Path.ChangeExtension(sFileTo, "." + FileFormats.ToString(nToFormat));
|
||
}
|
||
oNewIddleProcess.m_sFileTo = sFileTo;
|
||
if (ErrorTypes.NoError == eError && false == bNeedParam)
|
||
{
|
||
|
||
TimeSpan oWaitTimeout = oTaskQueueData.VisibilityTimeout -
|
||
(DateTime.UtcNow - oGetTaskTime);
|
||
|
||
int nWaitTimeout = Convert.ToInt32(oWaitTimeout.TotalMilliseconds * 0.95);
|
||
|
||
TaskResultDataToUpdate oTaskResultData = new TaskResultDataToUpdate();
|
||
oTaskResultData.eStatus = FileStatus.Convert;
|
||
oTaskResultData.nStatusInfo = 0;
|
||
oTaskResult.Update(oTaskQueueData.m_sKey, oTaskResultData);
|
||
TaskQueueDataConvert oTaskQueueDataConvert = new TaskQueueDataConvert(oTaskQueueData.m_sKey, sFileFrom, nFormatFrom, sFileTo, nToFormat);
|
||
if (oTaskQueueData.m_nCsvTxtEncoding.HasValue)
|
||
oTaskQueueDataConvert.m_nCsvTxtEncoding = oTaskQueueData.m_nCsvTxtEncoding.Value;
|
||
if (oTaskQueueData.m_nCsvDelimiter.HasValue)
|
||
oTaskQueueDataConvert.m_nCsvDelimiter = oTaskQueueData.m_nCsvDelimiter;
|
||
if (oTaskQueueData.m_bPaid.HasValue)
|
||
oTaskQueueDataConvert.m_bPaid = oTaskQueueData.m_bPaid.Value;
|
||
if (oTaskQueueData.m_bEmbeddedFonts.HasValue)
|
||
oTaskQueueDataConvert.m_bEmbeddedFonts = oTaskQueueData.m_bEmbeddedFonts.Value;
|
||
if (oTaskQueueData.m_bFromChanges.HasValue)
|
||
oTaskQueueDataConvert.m_bFromChanges = oTaskQueueData.m_bFromChanges.Value;
|
||
#if! OPEN_SOURCE
|
||
string sFontDir = ConfigurationSettings.AppSettings["utils.common.fontdir"];
|
||
#else
|
||
string sFontDir = "";
|
||
#endif
|
||
if (null != sFontDir && !string.IsNullOrEmpty(sFontDir))
|
||
oTaskQueueDataConvert.m_sFontDir = Path.GetFullPath(Environment.ExpandEnvironmentVariables(sFontDir));
|
||
string sThemeDir = ConfigurationSettings.AppSettings["fileconverterservice.converter.presentationthemesdir"];
|
||
if (null != sThemeDir && !string.IsNullOrEmpty(sThemeDir))
|
||
oTaskQueueDataConvert.m_sThemeDir = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), sThemeDir));
|
||
|
||
lock (m_oKeyToPercentValidateLock)
|
||
{
|
||
m_mapKeyToPercentValidate[oTaskQueueData.m_sKey] = 1;
|
||
}
|
||
|
||
string sConvertApp = ConfigurationSettings.AppSettings["fileconverterservice.converter.filepath"] ?? "FileConverter2.exe";
|
||
string sConvertArgs = ConfigurationSettings.AppSettings["fileconverterservice.converter.args"] ?? "";
|
||
|
||
System.Diagnostics.Process convertProc = new System.Diagnostics.Process();
|
||
oNewIddleProcess.m_oProcess = convertProc;
|
||
|
||
convertProc.StartInfo.FileName = sConvertApp;
|
||
string sConfigPath = Path.Combine(sTempDir, "params.xml");
|
||
File.WriteAllText(sConfigPath, TaskQueueDataConvert.SerializeToXml(oTaskQueueDataConvert), System.Text.Encoding.UTF8);
|
||
convertProc.StartInfo.Arguments = sConvertArgs + " " + EscapeCommandLineArguments(sConfigPath);
|
||
|
||
convertProc.StartInfo.CreateNoWindow = true;
|
||
convertProc.StartInfo.UseShellExecute = false;
|
||
|
||
convertProc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(convertProc_OutputDataReceived);
|
||
convertProc.StartInfo.RedirectStandardOutput = true;
|
||
|
||
_log.DebugFormat("Start {0} {1}(id={2})", convertProc.StartInfo.FileName, convertProc.StartInfo.Arguments, oTaskQueueData.m_sKey);
|
||
|
||
convertProc.Start();
|
||
|
||
convertProc.BeginOutputReadLine();
|
||
|
||
bool isProcessExit = convertProc.WaitForExit(nWaitTimeout);
|
||
_log.DebugFormat("Stop WaitForExit({0})(id={1})", nWaitTimeout, oTaskQueueData.m_sKey);
|
||
|
||
if (!isProcessExit)
|
||
{
|
||
_log.DebugFormat("Kill() process (id={1})", oTaskQueueData.m_sKey);
|
||
convertProc.Kill();
|
||
}
|
||
|
||
}
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
eError = ErrorTypes.Convert;
|
||
_log.Error("Exception catched while convertation thread working.", e);
|
||
}
|
||
PostProcess(oNewIddleProcess, eError, bNeedParam);
|
||
|
||
Interlocked.Decrement(ref m_nRunThreadCount);
|
||
}
|
||
else
|
||
{
|
||
Thread.Sleep(TimeSpan.FromSeconds(double.Parse(ConfigurationSettings.AppSettings["sleeptimeout"] ?? "60")));
|
||
}
|
||
}
|
||
}
|
||
|
||
private ErrorTypes DownloadFile(string sUrl, string sFileFrom)
|
||
{
|
||
ErrorTypes eError = ErrorTypes.NoError;
|
||
try
|
||
{
|
||
AsyncWebRequestOperation oAsyncWebRequestOperation = new AsyncWebRequestOperation(Convert.ToInt64(ConfigurationSettings.AppSettings["maxdownloadbytes"] ?? "10485760"));
|
||
byte[] aBuffer;
|
||
if (ErrorTypes.NoError == oAsyncWebRequestOperation.Request(sUrl, "GET", null, null, out aBuffer))
|
||
{
|
||
using(FileStream fs = File.Create(sFileFrom))
|
||
{
|
||
fs.Write(aBuffer, 0, aBuffer.Length);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
eError = ErrorTypes.ConvertDownload;
|
||
_log.ErrorFormat("DownloadFile() from {0} to {1}", sUrl, sFileFrom);
|
||
}
|
||
}
|
||
catch(Exception ex)
|
||
{
|
||
eError = ErrorTypes.ConvertDownload;
|
||
|
||
_log.ErrorFormat("DownloadFile() from {0} to {1}", sUrl, sFileFrom);
|
||
_log.Error("Exception:", ex);
|
||
}
|
||
return eError;
|
||
}
|
||
|
||
private System.Text.Encoding GetEncoding(string sFileFrom)
|
||
{
|
||
const int nBytesToRead = 3;
|
||
byte[] aFirstBytes = new byte[nBytesToRead];
|
||
int nBytesReaded = 0;
|
||
|
||
using (FileStream fs = File.OpenRead(sFileFrom))
|
||
{
|
||
nBytesReaded = fs.Read(aFirstBytes, 0, nBytesToRead);
|
||
}
|
||
|
||
return GetEncodingByContent(aFirstBytes, nBytesReaded);
|
||
}
|
||
|
||
private void GetEncodingAndDelimeter(string sFileFrom, out int? encoding, out int? delimiter)
|
||
{
|
||
encoding = null;
|
||
delimiter = null;
|
||
|
||
const int nBytesToRead = 1000;
|
||
byte[] aFirstBytes = new byte[nBytesToRead];
|
||
int nBytesReaded = 0;
|
||
|
||
using (FileStream fs = File.OpenRead(sFileFrom))
|
||
{
|
||
nBytesReaded = fs.Read(aFirstBytes, 0, nBytesToRead);
|
||
}
|
||
System.Text.Encoding oEncoding = GetEncodingByContent(aFirstBytes, nBytesReaded);
|
||
|
||
if (null != oEncoding)
|
||
encoding = oEncoding.CodePage;
|
||
else
|
||
encoding = System.Text.Encoding.UTF8.CodePage;
|
||
|
||
delimiter = GetDelimeterByContent(aFirstBytes, nBytesReaded);
|
||
}
|
||
|
||
private int? GetDelimeterByContent(byte[] aFirstBytes, int nBytesReaded)
|
||
{
|
||
int? delimiter = null;
|
||
|
||
int nLineLength = nBytesReaded;
|
||
int nDelimiter = (int)CsvDelimiter.None;
|
||
int nDelimitersCount = 6;
|
||
int[] aDelimiters = new int[nDelimitersCount];
|
||
for (int i = 0; i < nDelimitersCount; i++)
|
||
aDelimiters[i] = 0;
|
||
for (int i = 0; i < nBytesReaded; ++i)
|
||
{
|
||
byte cCurChar = aFirstBytes[i];
|
||
if ('\n' == cCurChar)
|
||
{
|
||
nLineLength = i;
|
||
break;
|
||
}
|
||
else if ('\t' == cCurChar)
|
||
aDelimiters[(int)CsvDelimiter.Tab]++;
|
||
else if (';' == cCurChar)
|
||
aDelimiters[(int)CsvDelimiter.Semicolon]++;
|
||
else if (':' == cCurChar)
|
||
aDelimiters[(int)CsvDelimiter.Сolon]++;
|
||
else if (',' == cCurChar)
|
||
aDelimiters[(int)CsvDelimiter.Comma]++;
|
||
else if (' ' == cCurChar)
|
||
aDelimiters[(int)CsvDelimiter.Space]++;
|
||
}
|
||
int nMaxVal = 0;
|
||
int nMaxIndex = 0;
|
||
for (int i = 1; i < nDelimitersCount; i++)
|
||
{
|
||
if (nMaxVal < aDelimiters[i])
|
||
{
|
||
nMaxVal = aDelimiters[i];
|
||
nMaxIndex = i;
|
||
}
|
||
}
|
||
if (nMaxVal > 0)
|
||
nDelimiter = nMaxIndex;
|
||
|
||
if ((int)CsvDelimiter.None != nDelimiter)
|
||
delimiter = nMaxIndex;
|
||
|
||
return delimiter;
|
||
}
|
||
|
||
private static System.Text.Encoding GetEncodingByContent(byte[] aFirstBytes, int nBytesReaded)
|
||
{
|
||
|
||
System.Text.Encoding oEncoding = null;
|
||
if (nBytesReaded >= 2)
|
||
{
|
||
if (aFirstBytes[0] == 0xFF && aFirstBytes[1] == 0xFE)
|
||
oEncoding = System.Text.Encoding.Unicode;
|
||
else if (aFirstBytes[0] == 0xFE && aFirstBytes[1] == 0xFF)
|
||
oEncoding = System.Text.Encoding.BigEndianUnicode;
|
||
}
|
||
if (nBytesReaded >= 3)
|
||
{
|
||
if (aFirstBytes[0] == 0xEF && aFirstBytes[1] == 0xBB && aFirstBytes[2] == 0xBF)
|
||
oEncoding = System.Text.Encoding.UTF8;
|
||
}
|
||
return oEncoding;
|
||
}
|
||
private void GCThread()
|
||
{
|
||
const double dSleepTimeOut = 5;
|
||
int nSleepCount = 0;
|
||
while (!_stopEvt.WaitOne(0))
|
||
{
|
||
try
|
||
{
|
||
if (nSleepCount <=0 && 0 == m_nRunThreadCount)
|
||
{
|
||
ITaskResultInterface oTaskResult = TaskResult.NewTaskResult();
|
||
List<TaskResultData> aTasts = null;
|
||
int nMaxCount = int.Parse(ConfigurationManager.AppSettings["fileconverterservice.gc.removedtaskatonce"] ?? "10");
|
||
ErrorTypes oError = oTaskResult.GetExpired(nMaxCount, out aTasts);
|
||
if (ErrorTypes.NoError == oError && aTasts != null && aTasts.Count > 0)
|
||
{
|
||
Storage oStorage = new Storage();
|
||
DocsChanges oDocsChanges = new DocsChanges();
|
||
|
||
foreach (TaskResultData oTast in aTasts)
|
||
{
|
||
if (ErrorTypes.NoError == oTaskResult.Remove(oTast.sKey))
|
||
{
|
||
oStorage.RemovePath(oTast.sKey);
|
||
oDocsChanges.RemoveChanges(oTast.sKey);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
nSleepCount = (int)(double.Parse(ConfigurationManager.AppSettings["fileconverterservice.gc.runperiod"] ?? "3600") / dSleepTimeOut);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(nSleepCount > 0)
|
||
nSleepCount--;
|
||
|
||
Thread.Sleep(TimeSpan.FromSeconds(dSleepTimeOut));
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_log.Error("Exception catched while garbage collector working.", e);
|
||
}
|
||
}
|
||
}
|
||
private void PercentUpdateCallback(Object stateInfo)
|
||
{
|
||
try
|
||
{
|
||
List<KeyValuePair<string, int>> mapTemp = new List<KeyValuePair<string,int>>();
|
||
lock (m_oKeyToPercentLock)
|
||
{
|
||
foreach (KeyValuePair<string, int> entry in m_mapKeyToPercent)
|
||
mapTemp.Add(entry);
|
||
m_mapKeyToPercent.Clear();
|
||
}
|
||
ITaskResultInterface oTaskResult = TaskResult.NewTaskResult();
|
||
for (int i = 0, length = mapTemp.Count; i < length; ++i)
|
||
{
|
||
KeyValuePair<string, int> elem = mapTemp[i];
|
||
|
||
lock (m_oKeyToPercentValidateLock)
|
||
{
|
||
if (m_mapKeyToPercentValidate.ContainsKey(elem.Key))
|
||
{
|
||
TaskResultDataToUpdate oTaskResultData = new TaskResultDataToUpdate();
|
||
oTaskResultData.nStatusInfo = elem.Value;
|
||
oTaskResult.Update(elem.Key, oTaskResultData);
|
||
}
|
||
}
|
||
}
|
||
lock (m_oKeyToPercentLock)
|
||
{
|
||
if (m_mapKeyToPercent.Count > 0)
|
||
{
|
||
int nPeriod = int.Parse(ConfigurationManager.AppSettings["fileconverterservice.percent.runperiod"] ?? "500");
|
||
m_oPercentTimer.Change(nPeriod, System.Threading.Timeout.Infinite);
|
||
}
|
||
else
|
||
{
|
||
m_oPercentTimer.Dispose();
|
||
m_oPercentTimer = null;
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
m_oPercentTimer = null;
|
||
}
|
||
}
|
||
private static string EscapeCommandLineArguments(string arg)
|
||
{
|
||
return "\"" + arg.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
|
||
}
|
||
private ErrorTypes PostProcess(IddleProcess oIddleProcess, ErrorTypes eError, bool bNeedParam)
|
||
{
|
||
try
|
||
{
|
||
CTaskQueue oTaskQueue = new CTaskQueue();
|
||
ITaskResultInterface oTaskResult = TaskResult.NewTaskResult();
|
||
Storage oStorage = new Storage();
|
||
TaskQueueData oTaskQueueData = oIddleProcess.m_oTaskQueueData;
|
||
if (null != oTaskQueueData)
|
||
{
|
||
if (oIddleProcess.m_oProcess != null)
|
||
{
|
||
|
||
oIddleProcess.m_oProcess.CancelOutputRead();
|
||
}
|
||
|
||
if (ErrorTypes.NoError == eError && null != oIddleProcess.m_oProcess)
|
||
{
|
||
int nExitCode = oIddleProcess.m_oProcess.ExitCode;
|
||
_log.DebugFormat("ExitCode (code={0};id={1})", nExitCode, oTaskQueueData.m_sKey);
|
||
bool bUploadFile = true;
|
||
if (0 != nExitCode)
|
||
{
|
||
bUploadFile = false;
|
||
if (-(int)ErrorTypes.ConvertMS_OFFCRYPTO == nExitCode)
|
||
eError = ErrorTypes.ConvertMS_OFFCRYPTO;
|
||
else if (-(int)ErrorTypes.ConvertCorrupted == nExitCode)
|
||
{
|
||
eError = ErrorTypes.ConvertCorrupted;
|
||
bUploadFile = true;
|
||
}
|
||
else
|
||
eError = ErrorTypes.Convert;
|
||
|
||
SaveErrorFile(oIddleProcess.m_sDirToDelete, oTaskQueueData.m_sKey);
|
||
}
|
||
if (bUploadFile)
|
||
{
|
||
|
||
if (null != oIddleProcess.m_sDirResult)
|
||
{
|
||
ErrorTypes eErrorUpload = UploadDirectoryToStorage(oIddleProcess.m_sDirResult, oTaskQueueData.m_sKey, "", oStorage);
|
||
if (ErrorTypes.NoError != eErrorUpload)
|
||
eError = eErrorUpload;
|
||
}
|
||
_log.DebugFormat("UploadDirectoryToStorage complete(id={0})", oTaskQueueData.m_sKey);
|
||
}
|
||
}
|
||
|
||
lock (m_oKeyToPercentValidateLock)
|
||
{
|
||
m_mapKeyToPercentValidate.Remove(oTaskQueueData.m_sKey);
|
||
}
|
||
|
||
if (false == string.IsNullOrEmpty(oIddleProcess.m_sDirToDelete) && Directory.Exists(oIddleProcess.m_sDirToDelete))
|
||
Directory.Delete(oIddleProcess.m_sDirToDelete, true);
|
||
TaskResultDataToUpdate oTaskResultDataUpdate = new TaskResultDataToUpdate();
|
||
if (null != oIddleProcess.m_oTaskQueueData.m_sFromKey && !string.IsNullOrEmpty(oIddleProcess.m_oTaskQueueData.m_sFromKey))
|
||
oTaskResultDataUpdate.sTitle = Path.GetFileName(oIddleProcess.m_sFileTo);
|
||
if (true == bNeedParam)
|
||
{
|
||
oTaskResultDataUpdate.eStatus = FileStatus.NeedParams;
|
||
oTaskResult.Update(oTaskQueueData.m_sKey, oTaskResultDataUpdate);
|
||
_log.DebugFormat("oTaskResult.Update complete(status={0};id={1})", oTaskResultDataUpdate.eStatus, oTaskQueueData.m_sKey);
|
||
}
|
||
else
|
||
{
|
||
if (ErrorTypes.NoError == eError)
|
||
oTaskResultDataUpdate.eStatus = FileStatus.Ok;
|
||
else
|
||
{
|
||
if (ErrorTypes.ConvertDownload == eError)
|
||
oTaskResultDataUpdate.eStatus = FileStatus.ErrToReload;
|
||
else
|
||
oTaskResultDataUpdate.eStatus = FileStatus.Err;
|
||
}
|
||
oTaskResultDataUpdate.nStatusInfo = (int)eError;
|
||
oTaskResult.Update(oTaskQueueData.m_sKey, oTaskResultDataUpdate);
|
||
_log.DebugFormat("oTaskResult.Update complete(status={0};id={1})", oTaskResultDataUpdate.eStatus, oTaskQueueData.m_sKey);
|
||
}
|
||
if (null != oTaskQueueData.m_sResultCallbackUrl && !string.IsNullOrEmpty(oTaskQueueData.m_sResultCallbackUrl))
|
||
{
|
||
InputCommand cmd = InputCommand.DeserializeFromJson(oTaskQueueData.m_sResultCallbackData);
|
||
cmd.userid = oIddleProcess.m_sChangesAuthor;
|
||
string dataJson = InputCommand.SerializeToJson(cmd);
|
||
byte[] data = System.Text.Encoding.UTF8.GetBytes(dataJson);
|
||
|
||
AsyncWebRequestOperation oAsyncWebRequestOperation = new AsyncWebRequestOperation();
|
||
TransportClass oTransportClass = new TransportClass();
|
||
oTransportClass.m_oTaskQueueData = oTaskQueueData;
|
||
oTransportClass.m_oAsyncWebRequestOperation = oAsyncWebRequestOperation;
|
||
oTransportClass.m_oAsyncWebRequestOperationResult = oAsyncWebRequestOperation.RequestBegin(oTaskQueueData.m_sResultCallbackUrl, "POST", "application/json", data, RequestCallback, oTransportClass);
|
||
_log.DebugFormat("Request to url='{0}' data='{1}' begin(id={2})", oTaskQueueData.m_sResultCallbackUrl, dataJson, oTaskQueueData.m_sKey);
|
||
}
|
||
|
||
oTaskQueue.RemoveTask(oTaskQueueData.m_oDataKey);
|
||
_log.DebugFormat("oTaskResult.RemoveTask complete(id={0})", oTaskQueueData.m_sKey);
|
||
_log.DebugFormat("End Task(id={0})", oTaskQueueData.m_sKey);
|
||
}
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
_log.Error("Exception catched in PostProcess:", e);
|
||
}
|
||
return eError;
|
||
}
|
||
private void RequestCallback(IAsyncResult ar)
|
||
{
|
||
TransportClass oTransportClass = ar.AsyncState as TransportClass;
|
||
try
|
||
{
|
||
byte[] aOutput;
|
||
ErrorTypes eError = oTransportClass.m_oAsyncWebRequestOperation.RequestEnd(oTransportClass.m_oAsyncWebRequestOperationResult, out aOutput);
|
||
if (_log.IsDebugEnabled)
|
||
{
|
||
try
|
||
{
|
||
_log.DebugFormat("RequestCallback Response='{0}'(id={1})", Encoding.UTF8.GetString(aOutput), oTransportClass.m_oTaskQueueData.m_sKey);
|
||
}
|
||
catch
|
||
{
|
||
}
|
||
}
|
||
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_log.Error("Exception catched in RequestCallback:", e);
|
||
}
|
||
}
|
||
private void SaveErrorFile(string sPath, string sKey)
|
||
{
|
||
|
||
string sErrorDir = ConfigurationSettings.AppSettings["fileconverterservice.converter.errorfiles"];
|
||
if (false == string.IsNullOrEmpty(sErrorDir) && false == string.IsNullOrEmpty(sPath))
|
||
UploadDirectoryToStorage(sPath, sErrorDir, "", new Storage());
|
||
}
|
||
private ErrorTypes UploadDirectoryToStorage(string sSourceDir, string sSourceFileStoreDir, string sLocalPath, Storage oFileStore)
|
||
{
|
||
ErrorTypes eResult = ErrorTypes.NoError;
|
||
string[] aFiles = Directory.GetFiles(Path.Combine(sSourceDir, sLocalPath));
|
||
for (int i = 0, length = aFiles.Length; i < length; ++i)
|
||
{
|
||
string sFile = aFiles[i];
|
||
string sFileStorePath = Path.Combine(sSourceFileStoreDir, sLocalPath);
|
||
sFileStorePath = Path.Combine(sFileStorePath, Path.GetFileName(sFile));
|
||
using (FileStream fs = new FileStream(sFile, FileMode.Open))
|
||
{
|
||
int nReadWriteBytes;
|
||
oFileStore.WriteFile(sFileStorePath, fs, out nReadWriteBytes);
|
||
}
|
||
}
|
||
string[] aDirectories = Directory.GetDirectories(Path.Combine(sSourceDir, sLocalPath));
|
||
for (int i = 0, length = aDirectories.Length; i < length; ++i)
|
||
{
|
||
string sDir = aDirectories[i];
|
||
string sDirLocal = Path.Combine(sLocalPath, Path.GetFileName(sDir));
|
||
string sDirStorePath = Path.Combine(sSourceFileStoreDir, sDirLocal);
|
||
oFileStore.CreateDirectory(sDirStorePath);
|
||
ErrorTypes eTypes = UploadDirectoryToStorage(sSourceDir, sSourceFileStoreDir, sDirLocal, oFileStore);
|
||
if (ErrorTypes.NoError != eTypes)
|
||
{
|
||
eResult = eTypes;
|
||
break;
|
||
}
|
||
}
|
||
return eResult;
|
||
}
|
||
ErrorTypes DownloadStorageTreeNodeToFilesystem(string sTargetDir, string sKey, string sLocalDir, StorageTreeNode oNode, Storage oFileStore)
|
||
{
|
||
ErrorTypes eError = ErrorTypes.NoError;
|
||
for (int i = 0, length = oNode.m_aSubNodes.Count; i < length; ++i)
|
||
{
|
||
StorageTreeNode oSubNode = oNode.m_aSubNodes[i];
|
||
string sLocalPath = Path.Combine(sLocalDir, oSubNode.m_sName);
|
||
if (oSubNode.m_bIsDirectory)
|
||
{
|
||
Directory.CreateDirectory(Path.Combine(sTargetDir, sLocalPath));
|
||
eError = DownloadStorageTreeNodeToFilesystem(sTargetDir, sKey, sLocalPath, oSubNode, oFileStore);
|
||
}
|
||
else
|
||
{
|
||
try
|
||
{
|
||
using (FileStream fs = new FileStream(Path.Combine(sTargetDir, sLocalPath), FileMode.Create))
|
||
{
|
||
int nReadWriteBytes;
|
||
oFileStore.ReadFile(Path.Combine(sKey, sLocalPath), fs, out nReadWriteBytes);
|
||
}
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
eError = ErrorTypes.ConvertReadFile;
|
||
_log.Error("Exception catched in DownloadStorageTreeNodeToFilesystem:", e);
|
||
}
|
||
}
|
||
if (ErrorTypes.NoError != eError)
|
||
break;
|
||
}
|
||
return eError;
|
||
}
|
||
void convertProc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
|
||
{
|
||
|
||
if (!String.IsNullOrEmpty(e.Data))
|
||
{
|
||
try
|
||
{
|
||
string[] aArgs = StringParser.ParseArguments(e.Data);
|
||
if (2 <= aArgs.Length)
|
||
{
|
||
int nPercent = System.Convert.ToInt32(aArgs[1].Replace("\"", ""));
|
||
string sKey = aArgs[0].Replace("\"", "");
|
||
lock (m_oKeyToPercentLock)
|
||
{
|
||
m_mapKeyToPercent[sKey] = nPercent;
|
||
if (null == m_oPercentTimer)
|
||
m_oPercentTimer = new Timer(PercentUpdateCallback, null, 0, System.Threading.Timeout.Infinite);
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |