void loader_Prompt(object sender, MessagePromptEventArgs e) { if (this.Prompt != null) { this.Prompt(sender, e); } }
Task <GetMd5Result> GetRemoteMd5(CancellationToken token) { return(Task.Run <GetMd5Result>(() => { REDO_MD5: int nRet = GetServerFileMD5ByTask( this.Channel, this.Stop, this.ServerFilePath, this.Prompt, token, out byte[] server_md5, out string strError); if (nRet != 1) { if (nRet == -1) { if (token.IsCancellationRequested) { goto ERROR1; } if (this.Prompt != null && !(this.Stop != null && this.Stop.IsStopped == true)) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得服务器文件 '" + this.ServerFilePath + "' 的 MD5 时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { goto ERROR1; } else if (e.ResultAction == "yes") { goto REDO_MD5; } else { goto ERROR1; } } else { goto ERROR1; } } strError = "探测服务器端文件 '" + this.ServerFilePath + "' MD5 时出错: " + strError; goto ERROR1; } return new GetMd5Result { Value = 0, MD5 = server_md5 }; ERROR1: return new GetMd5Result { Value = -1, ErrorInfo = strError }; })); }
long DetectFileLength(long lStart, out string strError) { byte[] baContent = null; string strMetadata = ""; string strOutputPath = ""; string strStyle = "content,data"; byte[] timestamp = null; REDO: long lRet = this.Channel.GetRes( this.Stop, this.ServerFilePath, lStart, 0, // nPerLength, strStyle, out baContent, out strMetadata, out strOutputPath, out timestamp, out strError); if (lRet == -1) { if (this.Prompt != null && !(this.Stop != null && this.Stop.IsStopped == true)) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "探测服务器文件 '" + this.ServerFilePath + "' 长度时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { return(-1); } else if (e.ResultAction == "yes") { goto REDO; } else { return(-1); } } else { return(-1); } } return(lRet); }
// 探测下载状态 // return: // -1 出错 // 0 文件没有找到 // 1 文件找到 int DetectDownloadState(string strServerPath, out string strResult, out string strError) { strError = ""; strResult = ""; string strPath = strServerPath + ".~state"; // LibraryServerUtil.STATE_EXTENSION string strStyle = "content,data"; string strMetadata = ""; byte[] baOutputTimestamp = null; string strOutputPath = ""; REDO: // 获得资源。包装版本 -- 返回字符串版本。 // return: // strStyle 一般设置为"content,data,metadata,timestamp,outputpath"; // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // >=0 成功 long lRet = this.Channel.GetRes( this.Stop, strPath, strStyle, out strResult, out strMetadata, out baOutputTimestamp, out strOutputPath, out strError); if (lRet == -1) { if (this.Channel.ErrorCode == localhost.ErrorCode.NotFound) { return(0); } if (this.Prompt != null && !(this.Stop != null && this.Stop.IsStopped == true)) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得服务器文件 '" + strPath + "' 时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { return(-1); } else if (e.ResultAction == "yes") { goto REDO; } else { return(-1); } } else { return(-1); } } return(1); }
// TODO: 遇到出错,要删除已经下载的临时文件; 如果是中断,临时文件要保留 // parameters: // getMd5NewStyle 获得服务器文件 MD5 的时候是否使用新轮询风格? (注:只能对 dp2library 本地文件用新轮询风格) void Download(bool getMd5NewStyle) { string strError = ""; TimeSpan old_timeout = this.Channel.Timeout; this.Channel.Timeout = TimeSpan.FromSeconds(60); try { bool bNotFound = false; string strPath = this.ServerFilePath; string strStyle = "content,data,metadata,timestamp,outputpath,gzip"; byte[] baContent = null; long lStart = _stream.Length; int nPerLength = -1; // byte[] old_timestamp = null; byte[] timestamp = null; long lTotalLength = -1; for (; ;) { #if NO if (_token.IsCancellationRequested) { strError = "中断"; goto ERROR1; } #endif if (_cancel.IsCancellationRequested) { strError = "中断"; goto ERROR1; } if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; goto ERROR1; } // REDO: string strMessage = ""; string strPercent = ""; if (lTotalLength != -1) { double ratio = (double)lStart / (double)lTotalLength; strPercent = String.Format("{0,3:N}", ratio * (double)100) + "%"; } if (this.Stop != null) { strMessage = "正在下载 " + StringUtil.GetLengthText(lStart) + " / " + (lTotalLength == -1 ? "?" : StringUtil.GetLengthText(lTotalLength)) + " " + strPercent + " " + strPath; this.Stop.SetMessage(strMessage); } REDO: string strMetadata = ""; long lRet = this.Channel.GetRes( this.Stop, this.ServerFilePath, lStart, nPerLength, strStyle, out baContent, out strMetadata, out string strOutputPath, out timestamp, out strError); if (lRet == -1) { if (this.Channel.ErrorCode == localhost.ErrorCode.NotFound) { bNotFound = true; goto DETECT_STATE; } if (this.Prompt != null && !(this.Stop != null && this.Stop.IsStopped == true)) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得服务器文件 '" + this.ServerFilePath + "' 时发生错误: " + strError + "\r\nstart=" + lStart + ", length=" + nPerLength + ")"; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { goto ERROR1; } else if (e.ResultAction == "yes") { goto REDO; } else { goto ERROR1; } } else { goto ERROR1; } } bNotFound = false; #if NO if (bHasMetadataStyle == true) { StringUtil.RemoveFromInList("metadata", true, ref strStyle); bHasMetadataStyle = false; } #endif if (lTotalLength != -1 && lTotalLength > lRet) { strError = "下载被前端放弃。因下载中途文件尺寸变小(曾经的尺寸=" + lTotalLength + ",当前尺寸=" + lRet + ")"; goto ERROR1; } lTotalLength = lRet; #if NO if (StringUtil.IsInList("timestamp", strStyle) == true) { if (input_timestamp != null) { if (ByteArray.Compare(input_timestamp, timestamp) != 0) { strError = "下载过程中发现时间戳和input_timestamp参数中的时间戳不一致,下载失败 ..."; return(-1); } } if (old_timestamp != null) { if (ByteArray.Compare(old_timestamp, timestamp) != 0) { strError = "下载过程中发现时间戳变化,下载失败 ..."; return(-1); } } } old_timestamp = timestamp; if (fileTarget == null) { break; } #endif // 写入文件 if (StringUtil.IsInList("attachment", strStyle) == true) { Debug.Assert(false, "attachment style暂时不能使用"); } else { if (_cancel.IsCancellationRequested) { strError = "中断"; goto ERROR1; } Debug.Assert(StringUtil.IsInList("content", strStyle) == true, "不是attachment风格,就应是content风格"); Debug.Assert(baContent != null, "返回的baContent不能为null"); Debug.Assert(baContent.Length <= lRet, "每次返回的包尺寸[" + Convert.ToString(baContent.Length) + "]应当小于result.Value[" + Convert.ToString(lRet) + "]"); if (baContent.Length > 0) { _stream.Write(baContent, 0, baContent.Length); _stream.Flush(); // 2013/5/17 lStart += baContent.Length; var func = this.ProgressChanged; if (func != null) { try { DownloadProgressChangedEventArgs e = new DownloadProgressChangedEventArgs(lStart, lTotalLength); func(this, e); } catch (ObjectDisposedException) { } } } } DETECT_STATE: if (lStart >= lRet || bNotFound == true) { // 探测文件状态。 // 探测下载状态 // return: // -1 出错 // 0 文件没有找到 // 1 文件找到 int nRet = DetectDownloadState(this.ServerFilePath, out string strState, out strError); if (nRet == -1) { strError = "探测状态文件过程出错: " + strError; goto ERROR1; } if (nRet == 0 && bNotFound) { strError = "文件 '" + this.ServerFilePath + "' 没有找到"; goto ERROR1; } if (nRet == 0 || // 状态文件没有找到,说明不是动态下载情形,要结束下载 strState != "creating") { // 需要再次确认一下文件最大尺寸 long lTempLength = DetectFileLength(lTotalLength, out strError); if (lTempLength == -1) { strError = "文件 '" + this.ServerFilePath + "' finish 之前探测文件尺寸发生错误: " + strError; goto ERROR1; } // 如果发现文件尺寸又变大了,则继续循环 if (lTempLength > lTotalLength) { continue; } if (strState != "finish" && nRet != 0) { this.ErrorInfo = "下载文件 '" + this.ServerFilePath + "' 时遭遇(服务器端)状态出错: " + strState; } else if (this.ServerFilePath.StartsWith("!")) { #if NO DisplayMessage("正在获得服务器文件 " + this.ServerFilePath + " 的 MD5 ..."); // 检查 MD5 byte[] server_md5 = null; REDO_MD5: // return: // -1 出错 // 0 文件没有找到 // 1 文件找到 if (getMd5NewStyle && this.ServerFilePath.StartsWith("!") == true) { nRet = GetServerFileMD5ByTask( this.Channel, this.Stop, this.ServerFilePath, this.Prompt, new CancellationToken(), out server_md5, out strError); } else { nRet = GetServerFileMD5_old( this.Channel, this.Stop, this.ServerFilePath, out server_md5, out strError); } if (nRet != 1) { if (nRet == -1) { if (this.Prompt != null && !(this.Stop != null && this.Stop.IsStopped == true)) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得服务器文件 '" + this.ServerFilePath + "' 的 MD5 时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { goto ERROR1; } else if (e.ResultAction == "yes") { goto REDO_MD5; } else { goto ERROR1; } } else { goto ERROR1; } } strError = "探测服务器端文件 '" + this.ServerFilePath + "' MD5 时出错: " + strError; goto ERROR1; } DisplayMessage("正在获得本地文件 " + this.LocalFilePath + " 的 MD5 ..."); _stream.Seek(0, SeekOrigin.Begin); byte[] local_md5 = GetFileMd5(_stream); if (ByteArray.Compare(server_md5, local_md5) != 0) { strError = "服务器端文件 '" + this.ServerFilePath + "' 和刚下载的本地文件 MD5 不匹配"; goto ERROR1; } #endif // 让两个任务并行执行 var task1 = GetRemoteMd5(this._cancel.Token); var task2 = GetLocalMd5(this._cancel.Token); DisplayMessage($"正在对比 MD5 {this.ServerFilePath} <--> {this.LocalFilePath} ..."); Task.WaitAll(new Task[] { task1, task2 }, this._cancel.Token); if (task1.Result.Value != 0) { strError = "探测服务器端文件 '" + this.ServerFilePath + "' MD5 时出错: " + task1.Result.ErrorInfo; goto ERROR1; } var server_md5 = task1.Result.MD5; if (task2.Result.Value != 0) { strError = "探测本地文件 '" + this.LocalFilePath + "' MD5 时出错: " + task2.Result.ErrorInfo; goto ERROR1; } var local_md5 = task2.Result.MD5; if (ByteArray.Compare(server_md5, local_md5) != 0) { strError = "服务器端文件 '" + this.ServerFilePath + "' 和刚下载的本地文件 MD5 不匹配"; goto ERROR1; } } this.State = "finish:" + strState; TriggerClosedEvent(); this._timestamp = timestamp; return; } // 休眠一段时间后重试下载 Thread.Sleep(1000); } } // end of for this.State = "end"; TriggerClosedEvent(); return; ERROR1: this.State = "error"; this.ErrorInfo = strError; TriggerClosedEvent(); } catch (Exception ex) { this.State = "error"; this.ErrorInfo = ExceptionUtil.GetDebugText(ex); TriggerClosedEvent(); } finally { this.Channel.Timeout = old_timeout; if (_stream != null) { _stream.Close(); _stream = null; } if (string.IsNullOrEmpty(this.ErrorInfo)) { RenameTempFile(); } } }
public IEnumerator GetEnumerator() { string strError = ""; long lPerCount = this.BatchSize; // 每批获得多少个 if (lPerCount == 0) { lPerCount = DefaultBatchSize; } long lStart = 0; long lResultCount = 0; long lCount = -1; TimeSpan old_timeout = this.Channel.Timeout; this.Channel.Timeout = new TimeSpan(0, 5, 0); try { for (; ;) { if (this.Stop != null && this.Stop.State != 0) { throw new InterruptException("用户中断"); } int nRedoCount = 0; REDO: EntityInfo[] entities = null; long lRet = 0; if (this.DbType == "item") { lRet = this.Channel.GetEntities( this.Stop, this.BiblioRecPath, lStart, lCount, this.Format == null ? "" : this.Format, // 为了回避 dp2library 2.102 以前版本的一个 bug "zh", out entities, out strError); } else if (this.DbType == "order") { lRet = this.Channel.GetOrders( this.Stop, this.BiblioRecPath, lStart, lCount, this.Format == null ? "" : this.Format, "zh", out entities, out strError); } else if (this.DbType == "issue") { lRet = this.Channel.GetIssues( this.Stop, this.BiblioRecPath, lStart, lCount, this.Format == null ? "" : this.Format, "zh", out entities, out strError); } else if (this.DbType == "comment") { lRet = this.Channel.GetComments( this.Stop, this.BiblioRecPath, lStart, lCount, this.Format == null ? "" : this.Format, "zh", out entities, out strError); } else { throw new Exception("未知的 this.DbType '" + this.DbType + "'"); } if (lRet == -1) { if (this.Stop != null && this.Stop.State != 0) { throw new InterruptException("用户中断"); } if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得书目记录 '" + this.BiblioRecPath + "' 的下级 " + this.DbType + " 记录时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new ChannelException(Channel.ErrorCode, strError); } else if (e.ResultAction == "yes") { goto REDO; } else { // no 也是抛出异常。因为继续下一批代价太大 throw new ChannelException(Channel.ErrorCode, strError); } } else { throw new ChannelException(Channel.ErrorCode, strError); } } // 发现 dp2library GetEntities() API 非常偶然地会在 entities 数组中返回一个 info.OldRecPath 为空的元素。这里试图重试获取 // 2017/6/5 // return: // true 出现了反常的情况 // false 没有发现反常的情况 if (VerifyItems(entities) == true && nRedoCount < 2) { nRedoCount++; goto REDO; } lResultCount = lRet; this.TotalCount = lRet; // 记载下级记录总数 if (lRet == 0) { yield break; } Debug.Assert(entities != null, ""); foreach (EntityInfo info in entities) { if (info.ErrorCode != ErrorCodeValue.NoError) { strError = "路径为 '" + info.OldRecPath + "' 的册记录装载中发生错误: " + info.ErrorInfo; throw new Exception(strError); } yield return(info); } lStart += entities.Length; if (lStart >= lResultCount) { yield break; } if (lCount == -1) { lCount = lPerCount; } if (lStart + lCount > lResultCount) { lCount = lResultCount - lStart; } } } finally { this.Channel.Timeout = old_timeout; } }
public IEnumerator GetEnumerator() { string strError = ""; if ((this.LogType & LogType.AccessLog) != 0 && (this.LogType & LogType.OperLog) != 0) { throw new ArgumentException("OperLogLoader 的 LogType 只能使用一种类型"); } List <string> filter_dates = null; if (this.FilterDates != null) { // 丢弃文件扩展名部分 filter_dates = new List <string>(); foreach (string date in this.FilterDates) { filter_dates.Add(date.Substring(0, 8)); } } long lStart = 0; int nPerCount = -1; long lHitCount = 0; for (; ;) { if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); } REDO: OperLogInfo[] records = null; long lRet = this.Channel.GetOperLogs(this.Stop, "", lStart, -1, nPerCount, "getfilenames", "", out records, out strError); if (lRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获取日志文件名的操作发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new InterruptException(strError); } else if (e.ResultAction == "yes") { if (this.Stop != null) { this.Stop.Continue(); } goto REDO; } else { // 还没有得到文件名,通讯就失败,所以操作无法进行了,只能抛出异常 throw new ChannelException(this.Channel.ErrorCode, strError); // continue; } } else { throw new ChannelException(this.Channel.ErrorCode, strError); } } lHitCount = lRet; foreach (OperLogInfo info in records) { string strDate = info.Xml.Substring(0, 8); if (filter_dates != null && filter_dates.IndexOf(strDate) == -1) { continue; } OperLogDateItem item = new OperLogDateItem(); item.Date = strDate; item.Length = info.AttachmentLength; yield return(item); } if (lStart + records.Length >= lHitCount) { yield break; } lStart += records.Length; } }
public IEnumerator GetEnumerator() { string strError = ""; long lHitCount = -1; long lStart = this.Start; long nPerCount = this.BatchSize == 0 ? -1 : this.BatchSize; // nPerCount = 1; // test for (; ;) { Record[] searchresults = null; REDO: long lRet = this.Channel.GetSearchResult( // this.Stop, this.ResultSetName, // "default", lStart, nPerCount, this.FormatList, // "id,xml,timestamp,metadata", string.IsNullOrEmpty(this.Lang) ? "zh" : this.Lang, out searchresults, out strError); if (lRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得数据库记录时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new ChannelException(Channel.ErrorCode, strError); } else if (e.ResultAction == "yes") { goto REDO; } else { // no 也是抛出异常。因为继续下一批代价太大 throw new ChannelException(Channel.ErrorCode, strError); } } else { throw new ChannelException(Channel.ErrorCode, strError); } } this.TotalCount = lRet; if (lRet == 0) { yield break; } if (searchresults == null) { strError = "searchresults == null"; throw new Exception(strError); } if (searchresults.Length == 0) { strError = "searchresults.Length == 0"; throw new Exception(strError); } lHitCount = lRet; foreach (Record record in searchresults) { yield return(record); } lStart += searchresults.Length; if (lStart >= lHitCount) { yield break; } } }
public IEnumerator GetEnumerator() { string strError = ""; int nRet = 0; if ((this.LogType & dp2Circulation.LogType.AccessLog) != 0 && (this.LogType & dp2Circulation.LogType.OperLog) != 0) throw new ArgumentException("OperLogLoader 的 LogType 只能使用一种类型"); if (string.IsNullOrEmpty(this.CacheDir) == false) PathUtil.CreateDirIfNeed(this.CacheDir); // ProgressEstimate estimate = new ProgressEstimate(); bool bAutoCache = this.AutoCache; if (bAutoCache == true) { long lServerFileSize = 0; long lCacheFileSize = 0; // 象征性获得一个日志文件的尺寸,主要目的是为了触发一次通道登录 // return: // -2 此类型的日志尚未启用 // -1 error // 0 file not found // 1 found nRet = GetFileSize( this.Stop, this.Channel, this.CacheDir, "20121001.log", this.LogType, out lServerFileSize, out lCacheFileSize, out strError); if (nRet == -1) throw new Exception(strError); // 2015/11/25 if (nRet == -2) yield break; // 此类型的日志尚未启用 // 检查日志文件缓存目录的版本是否和当前用户的信息一致 // return: // -1 出错 // 0 一致 // 1 不一致 nRet = DetectCacheVersionFile( this.CacheDir, "version.xml", this.Channel.LibraryCodeList, this.Channel.Url, out strError); if (nRet == -1) throw new Exception(strError); if (nRet == 1) { REDO: // 清空当前缓存目录 nRet = Global.DeleteDataDir( null, // owner, this.CacheDir, out strError); if (nRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "清空当前缓存目录时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") throw new Exception(strError); else if (e.ResultAction == "yes") goto REDO; else { } } else throw new Exception(strError); } #if NO if (nRet == -1) throw new Exception(strError); #endif PathUtil.CreateDirIfNeed(this.CacheDir); // 重新创建目录 // 创建版本文件 nRet = CreateCacheVersionFile( this.CacheDir, "version.xml", this.Channel.LibraryCodeList, this.Channel.Url, out strError); if (nRet == -1) throw new Exception(strError); } } long lTotalSize = 0; List<string> lines = new List<string>(); // 经过处理后排除了不存在的文件名 List<string> ranges = new List<string>(); List<long> sizes = new List<long>(); this.Stop.SetMessage("正在准备获得日志文件尺寸 ..."); foreach (string strLine in this.FileNames) { Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new Exception(strError); // yield break; ? } if (String.IsNullOrEmpty(strLine) == true) continue; string strFilename = strLine.Trim(); // 去掉注释 nRet = strFilename.IndexOf("#"); if (nRet != -1) strFilename = strFilename.Substring(0, nRet).Trim(); if (String.IsNullOrEmpty(strFilename) == true) continue; string strLogFilename = ""; string strRange = ""; nRet = strFilename.IndexOf(":"); if (nRet != -1) { strLogFilename = strFilename.Substring(0, nRet).Trim(); strRange = strFilename.Substring(nRet + 1).Trim(); } else { strLogFilename = strFilename.Trim(); strRange = ""; } if (strLogFilename.Length == 8) strLogFilename += ".log"; REDO_GETSIZE: long lServerFileSize = 0; long lCacheFileSize = 0; // 获得一个日志文件的尺寸 // -2 此类型的日志尚未启用 // -1 error // 0 file not found // 1 found nRet = GetFileSize( this.Stop, this.Channel, this.CacheDir, strLogFilename, this.LogType, out lServerFileSize, out lCacheFileSize, out strError); if (nRet == -1) { // throw new Exception(strError); if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获取日志文件 " + strLogFilename + " 尺寸的操作发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") throw new Exception(strError); else if (e.ResultAction == "yes") { if (this.Stop != null) this.Stop.Continue(); goto REDO_GETSIZE; } else { // ?? continue; } } else throw new Exception(strError); } if (nRet == 0) continue; if (lServerFileSize == 0) continue; // 0字节的文件当作不存在处理 // 2015/11/25 if (lServerFileSize == -1) yield break; // 此类型的日志尚未启用 Debug.Assert(lServerFileSize >= 0, ""); if (bAutoCache == true) { if (lCacheFileSize > 0) lTotalSize += lCacheFileSize; else lTotalSize += lServerFileSize; } else { lTotalSize += lServerFileSize; } // lines.Add(strFilename); lines.Add(strLogFilename); ranges.Add(strRange); // 记忆每个文件的尺寸,后面就不用获取了? sizes.Add(lServerFileSize); } long lDoneSize = 0; if (this.ProgressStart == -1) lDoneSize = lTotalSize; else lDoneSize = this.ProgressStart; lTotalSize += lDoneSize; if (this.Stop != null) { this.Stop.SetProgressRange(0, lTotalSize); } estimate.SetRange(lDoneSize, lTotalSize); estimate.StartEstimate(); for (int i = 0; i < lines.Count; i++) { Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new Exception(strError); // yield break; ? } string strLine = lines[i]; string strRange = ranges[i]; string strLogFilename = strLine; #if NO string strLogFilename = ""; string strRange = ""; nRet = strLine.IndexOf(":"); if (nRet != -1) { strLogFilename = strLine.Substring(0, nRet).Trim(); strRange = strLine.Substring(nRet + 1).Trim(); } else { strLogFilename = strLine.Trim(); strRange = ""; } #endif { OperLogItemLoader loader = new OperLogItemLoader(); loader.Stop = this.Stop; loader.Channel = this.Channel; // loader.owner = this.owner; loader.estimate = this.estimate; loader.FileName = strLogFilename; loader.Level = this.Level; loader.lServerFileSize = sizes[i]; loader.Range = strRange; loader.AutoCache = this.AutoCache; loader.lProgressValue = lDoneSize; loader.lSize = lTotalSize; loader.Filter = this.Filter; loader.LogType = this.LogType; loader.Prompt -= new MessagePromptEventHandler(loader_Prompt); loader.Prompt += new MessagePromptEventHandler(loader_Prompt); foreach (OperLogItem item in loader) { yield return item; } lDoneSize = loader.lProgressValue; lTotalSize = loader.lSize; } } }
void loader_Prompt(object sender, MessagePromptEventArgs e) { // TODO: 不再出现此对话框。不过重试有个次数限制,同一位置失败多次后总要出现对话框才好 if (e.Actions == "yes,no,cancel") { #if NO DialogResult result = MessageBox.Show(this, e.MessageText + "\r\n\r\n是否重试操作?\r\n\r\n(是: 重试; 否: 跳过本次操作,继续后面的操作; 取消: 停止全部操作)", "ReportForm", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) e.ResultAction = "yes"; else if (result == DialogResult.Cancel) e.ResultAction = "cancel"; else e.ResultAction = "no"; #endif DialogResult result = AutoCloseMessageBox.Show(this, e.MessageText + "\r\n\r\n将自动重试操作\r\n\r\n(点右上角关闭按钮可以中断批处理)", 20 * 1000, "BiblioSearchForm"); if (result == DialogResult.Cancel) e.ResultAction = "no"; else e.ResultAction = "yes"; } }
public IEnumerator GetEnumerator() { List<string> format_list = new List<string>(); int nContentIndex = format_list.Count; int nTimestampIndex = -1; int nMetadataIndex = -1; format_list.Add(this.Format); // if ((this.GetBiblioInfoStyle & dp2Circulation.GetBiblioInfoStyle.Timestamp) != 0) if (this.GetBiblioInfoStyle.HasFlag(GetBiblioInfoStyle.Timestamp) == true) // 新用法 { nTimestampIndex = format_list.Count; format_list.Add("timestamp"); } if ((this.GetBiblioInfoStyle & GetBiblioInfoStyle.Metadata) != 0) { nMetadataIndex = format_list.Count; format_list.Add("metadata"); } string[] formats = new string[format_list.Count]; format_list.CopyTo(formats); List<string> batch = new List<string>(); for (int index = 0; index < m_recpaths.Count; index++) { string s = m_recpaths[index]; batch.Add(s); // 每100个一批,或者最后一次 if (batch.Count >= 100 || (index == m_recpaths.Count - 1 && batch.Count > 0)) { REDO: string strCommand = "@path-list:" + StringUtil.MakePathList(batch); string[] results = null; byte[] timestamp = null; string strError = ""; // Channel.Timeout = new TimeSpan(0, 0, 5); 应该让调主设置这个值 long lRet = Channel.GetBiblioInfos( this.Stop, strCommand, "", formats, out results, out timestamp, out strError); if (lRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得书目记录 '"+strCommand+"' ("+StringUtil.MakePathList(format_list)+") 时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") throw new ChannelException(Channel.ErrorCode, strError); else if (e.ResultAction == "yes") goto REDO; else { // no 也是抛出异常。因为继续下一批代价太大 throw new ChannelException(Channel.ErrorCode, strError); } } else throw new ChannelException(Channel.ErrorCode, strError); } if (lRet == 0) { if (lRet == 0 && String.IsNullOrEmpty(strError) == true) { foreach (string path in batch) { BiblioItem item = new BiblioItem(); item.RecPath = path; item.ErrorCode = ErrorCode.NotFound; item.ErrorInfo = "书目记录 '" + path + "' 不存在"; yield return item; } goto CONTINUE; } // 如果results.Length表现正常,其实还可以继续处理 if (results != null && results.Length > 0) { } else { // 2014/1/15 if (Channel.ErrorCode == ErrorCode.NotFound) { foreach (string path in batch) { BiblioItem item = new BiblioItem(); item.RecPath = path; item.ErrorCode = ErrorCode.NotFound; item.ErrorInfo = "书目记录 '" + path + "' 不存在"; yield return item; } goto CONTINUE; } strError = "获得书目记录 '" + StringUtil.MakePathList(batch) + "' 时发生错误: " + strError; throw new Exception(strError); } } if (results == null) { strError = "results == null"; throw new Exception(strError); } for (int i = 0; i < results.Length / formats.Length; i++) { BiblioItem item = new BiblioItem(); item.RecPath = batch[i]; if (nContentIndex != -1) item.Content = results[i * formats.Length + nContentIndex]; if (nTimestampIndex != -1) item.Timestamp = ByteArray.GetTimeStampByteArray(results[i * formats.Length + nTimestampIndex]); if (nMetadataIndex != -1) item.Metadata = results[i * formats.Length + nMetadataIndex]; if (string.IsNullOrEmpty(item.Content) == true) { item.ErrorCode = ErrorCode.NotFound; item.ErrorInfo = "书目记录 '" + item.RecPath + "' 不存在"; } yield return item; } CONTINUE: if (batch.Count > results.Length / formats.Length) { // 有本次没有获取到的记录 batch.RemoveRange(0, results.Length / formats.Length); if (index == m_recpaths.Count - 1) goto REDO; // 当前已经是最后一轮了,需要继续做完 // 否则可以留给下一轮处理 } else batch.Clear(); } } }
public IEnumerator GetEnumerator() { List <string> batch = new List <string>(); for (int index = 0; index < m_recpaths.Count; index++) { string s = m_recpaths[index]; batch.Add(s); // 每100个一批,或者最后一次 if (batch.Count >= 100 || (index == m_recpaths.Count - 1 && batch.Count > 0)) { REDO: #if NO string[] paths = new string[batch.Count]; batch.CopyTo(paths); #endif string[] paths = batch.ToArray(); DigitalPlatform.LibraryClient.localhost.Record[] searchresults = null; string strError = ""; long lRet = Channel.GetBrowseRecords( this.Stop, paths, this.Format, // "id,cols", out searchresults, out strError); if (lRet == -1) { // throw new Exception(strError); if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得浏览记录时发生错误: " + strError + "\r\npaths='" + StringUtil.MakePathList(paths) + "' (" + this.Format + ")"; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new ChannelException(Channel.ErrorCode, strError); } else if (e.ResultAction == "yes") { goto REDO; } else { // no 也是抛出异常。因为继续下一批代价太大 throw new ChannelException(Channel.ErrorCode, strError); } } else { throw new ChannelException(Channel.ErrorCode, strError); } } if (searchresults == null) { strError = "searchresults == null"; throw new Exception(strError); } for (int i = 0; i < searchresults.Length; i++) { DigitalPlatform.LibraryClient.localhost.Record record = searchresults[i]; if (batch[i] != record.Path) { throw new Exception("下标 " + i + " 的 batch 元素 '" + batch[i] + "' 和返回的该下标位置 GetBrowseRecords() 结果路径 '" + record.Path + "' 不匹配"); } Debug.Assert(batch[i] == record.Path, ""); yield return(record); } // CONTINUE: if (batch.Count > searchresults.Length) { // 有本次没有获取到的记录 batch.RemoveRange(0, searchresults.Length); if (index == m_recpaths.Count - 1) { goto REDO; // 当前已经是最后一轮了,需要继续做完 } // 否则可以留给下一轮处理 } else { batch.Clear(); } } } }
public IEnumerator GetEnumerator() { string strError = ""; long lHitCount = -1; long lStart = this.Start; long nBasePerCount = this.BatchSize == 0 ? -1 : this.BatchSize; // nPerCount = 1; // test for (; ;) { if (this.Stop != null && this.Stop.State != 0) { throw new InterruptException($"用户中断"); } Record[] searchresults = null; long nPerCount = nBasePerCount; if (nPerCount != -1 && IsMaxResultCountValid() && nPerCount > this.MaxResultCount) { nPerCount = this.MaxResultCount; } else if (nPerCount == -1 && IsMaxResultCountValid() && this.MaxResultCount > this.BatchSize) { nPerCount = this.MaxResultCount; } // 限制 nPerCount,不要超过余下的记录数 if (nPerCount != -1 && lHitCount != -1 && nPerCount > lHitCount - lStart) { nPerCount = lHitCount - lStart; } REDO: var e1 = new GettingEventArgs { Start = lStart, PerCount = nPerCount, ResultSetName = this.ResultSetName }; this.Getting?.Invoke(this, e1); if (e1.Cancelled == true) { throw new InterruptException($"用户中断"); } long lRet = this.Channel.GetSearchResult( this.Stop, this.ResultSetName, // "default", lStart, nPerCount, this.FormatList, // "id,xml,timestamp,metadata", string.IsNullOrEmpty(this.Lang) ? "zh" : this.Lang, out searchresults, out strError); var e2 = new GettedEventArgs { Count = lRet, ErrorInfo = strError, ErrorCode = Channel.ErrorCode }; this.Getted?.Invoke(this, e2); if (e2.Cancelled == true) { throw new InterruptException($"用户中断"); } if (lRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获得数据库记录时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new ChannelException(Channel.ErrorCode, strError); } else if (e.ResultAction == "yes") { goto REDO; } else { // no 也是抛出异常。因为继续下一批代价太大 throw new ChannelException(Channel.ErrorCode, strError); } } else { throw new ChannelException(Channel.ErrorCode, strError); } } if (lRet == 0) { yield break; } if (searchresults == null) { strError = "searchresults == null"; throw new Exception(strError); } if (searchresults.Length == 0) { strError = "searchresults.Length == 0"; throw new Exception(strError); } if (IsMaxResultCountValid() == false) { lHitCount = lRet; } else { lHitCount = lRet == -1 ? -1 : Math.Min(MaxResultCount, lRet); } long i = 0; foreach (Record record in searchresults) { if (lStart + i >= lHitCount) { yield break; } yield return(record); i++; } lStart += searchresults.Length; if (lStart >= lHitCount) { yield break; } } }
public IEnumerator GetEnumerator() { string strError = ""; int nRet = 0; long lRet = 0; if ((this.LogType & dp2Circulation.LogType.AccessLog) != 0 && (this.LogType & dp2Circulation.LogType.OperLog) != 0) throw new ArgumentException("OperLogItemLoader 的 LogType 只能使用一种类型"); if (this.Stop != null && this.estimate != null) this.Stop.SetMessage("正在装入日志文件 " + this.FileName + " 中的记录。" + "剩余时间 " + ProgressEstimate.Format(estimate.Estimate(lProgressValue)) + " 已经过时间 " + ProgressEstimate.Format(estimate.delta_passed)); string strXml = ""; long lAttachmentTotalLength = 0; byte[] attachment_data = null; long lFileSize = 0; if (lServerFileSize == -1) { long _lServerFileSize = 0; string strStyle = "level-" + Level.ToString(); if ((this.LogType & dp2Circulation.LogType.AccessLog) != 0) strStyle += ",accessLog"; // 获得服务器端日志文件尺寸 lRet = this.Channel.GetOperLog( this.Stop, this.FileName, -1, // lIndex, -1, // lHint, strStyle, "", // strFilter out strXml, out _lServerFileSize, 0, // lAttachmentFragmentStart, 0, // nAttachmentFramengLength, out attachment_data, out lAttachmentTotalLength, out strError); // 2015/11/25 if (lRet == -1) throw new Exception(strError); this.lServerFileSize = _lServerFileSize; if (lRet == 0) yield break; // 2015/11/25 if (_lServerFileSize == -1) yield break; // 此类型的日志尚未启用 } Stream stream = null; bool bCacheFileExist = false; bool bRemoveCacheFile = false; // 是否要自动删除未全部完成的本地缓存文件 bool bAutoCache = this.AutoCache; if (bAutoCache == true) { string strFileName = this.FileName; if ((this.LogType & dp2Circulation.LogType.AccessLog) != 0) strFileName = this.FileName + ".a"; nRet = PrepareCacheFile( this.CacheDir, strFileName, // this.FileName, lServerFileSize, out bCacheFileExist, out stream, out strError); if (nRet == -1) throw new Exception(strError); if (bCacheFileExist == false && stream != null) bRemoveCacheFile = true; } try { if (bCacheFileExist == true) lFileSize = stream.Length; else lFileSize = lServerFileSize; // stop.SetProgressRange(0, lTotalSize); if (String.IsNullOrEmpty(Range) == true) Range = "0-" + (long.MaxValue - 1).ToString(); // "0-9999999999"; RangeList rl = new RangeList(Range); for (int i = 0; i < rl.Count; i++) { RangeItem ri = (RangeItem)rl[i]; // 让 100- 这样的 range 可以使用 if (ri.lLength == -1) ri.lLength = long.MaxValue - ri.lStart; OperLogInfo[] records = null; long lStartRecords = 0; long lHint = -1; long lHintNext = -1; for (long lIndex = ri.lStart; lIndex < ri.lStart + ri.lLength; lIndex++) { Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new Exception(strError); // yield break; ? } if (lIndex == ri.lStart) lHint = -1; else lHint = lHintNext; if (bCacheFileExist == true) { if (lHint == -1) { // return: // -1 error // 0 成功 // 1 到达文件末尾或者超出 nRet = LocationRecord(stream, lIndex, out strError); if (nRet == -1) throw new Exception(strError); } else { // 根据暗示找到 if (lHint == stream.Length) break; if (lHint > stream.Length) { strError = "lHint参数值不正确"; throw new Exception(strError); } if (stream.Position != lHint) stream.Seek(lHint, SeekOrigin.Begin); } nRet = ReadCachedEnventLog( stream, out strXml, out lAttachmentTotalLength, out strError); if (nRet == -1) throw new Exception(strError); lHintNext = stream.Position; } else { if (records == null || lIndex /*- ri.lStart*/ >= lStartRecords + records.Length) { int nCount = -1; if (ri.lLength >= Int32.MaxValue) nCount = -1; // 500; // -1; else nCount = (int)ri.lLength; // Math.Min(500, (int)ri.lLength); string strStyle = "level-" + Level.ToString(); if ((this.LogType & dp2Circulation.LogType.AccessLog) != 0) strStyle += ",accessLog"; REDO: // 获得日志 // return: // -1 error // 0 file not found // 1 succeed // 2 超过范围,本次调用无效 lRet = this.Channel.GetOperLogs( this.Stop, this.FileName, lIndex, lHint, nCount, strStyle, this.Filter, // strFilter out records, out strError); if (lRet == -1) { #if NO DialogResult result = MessageBox.Show(owner, "获取日志信息 ("+this.FileName + " " +lIndex.ToString() + ") 的操作发生错误: " + strError + "\r\n\r\n是否重试操作?\r\n\r\n(是: 重试; 否: 跳过本次操作,继续后面的操作; 放弃: 停止全部操作)", "OperLogItemLoader", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) goto REDO; if (result == DialogResult.Cancel) throw new Exception(strError); else { // TODO: 是否要在listview中装入一条表示出错的行? lHintNext = -1; continue; } #endif if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获取 " + this._logType.ToString() + " 日志信息 (" + this.FileName + " " + lIndex.ToString() + ") 的操作发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") throw new Exception(strError); else if (e.ResultAction == "yes") { if (this.Stop != null) this.Stop.Continue(); goto REDO; } else { lHintNext = -1; continue; } } else throw new Exception(strError); } if (lRet == 0) yield break; if (lRet == 2) break; // records数组表示的起点位置 lStartRecords = lIndex /* - ri.lStart*/; } OperLogInfo info = records[lIndex - lStartRecords]; strXml = info.Xml; lHintNext = info.HintNext; lAttachmentTotalLength = info.AttachmentLength; // 写入本地缓存的日志文件 if (stream != null) { try { WriteCachedEnventLog( stream, strXml, lAttachmentTotalLength); } catch (Exception ex) { strError = "写入本地缓存文件的时候出错: " + ex.Message; throw new Exception(strError); } } } #if NO // 2011/12/30 // 日志记录可能动态地增加了,超过了原先为ProgressBar设置的范围 if (lFizeTotalSize < (int)lHintNext) { lFizeTotalSize = lHintNext; stop.SetProgressRange(0, lFizeTotalSize); } #endif if (lHintNext >= 0) { // 校正 if (lProgressValue + lHintNext > lSize) { lSize = lProgressValue + lHintNext; if (this.Stop != null && this.estimate != null) { this.Stop.SetProgressRange(0, lSize); estimate.SetRange(0, lSize); } } this.Stop.SetProgressValue(lProgressValue + lHintNext); } if (lIndex % 100 == 0) { if (this.Stop != null && this.estimate != null) { estimate.Text = "剩余时间 " + ProgressEstimate.Format(estimate.Estimate(lProgressValue + lHintNext)) + " 已经过时间 " + ProgressEstimate.Format(estimate.delta_passed); this.Stop.SetMessage("正在装入日志文件 " + this.FileName + " 中的记录 " + lIndex.ToString() + " 。" + estimate.Text); } } { OperLogItem item = new OperLogItem(); item.Xml = strXml; item.Index = lIndex; item.Date = this.FileName.Substring(0, 8); yield return item; } } } // 创建本地缓存的日志文件的metadata文件 if (bCacheFileExist == false && stream != null) { string strFileName = this.FileName; if ((this.LogType & dp2Circulation.LogType.AccessLog) != 0) strFileName = this.FileName + ".a"; nRet = CreateCacheMetadataFile( this.CacheDir, strFileName, // this.FileName, lServerFileSize, out strError); if (nRet == -1) throw new Exception(strError); } bRemoveCacheFile = false; // 不删除 } finally { if (stream != null) stream.Close(); if (bRemoveCacheFile == true) { string strFileName = this.FileName; if ((this.LogType & dp2Circulation.LogType.AccessLog) != 0) strFileName = this.FileName + ".a"; string strError1 = ""; nRet = DeleteCacheFile( this.CacheDir, strFileName, // this.FileName, out strError1); if (nRet == -1) { // MessageBox.Show(owner, strError1); if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = strError1; e.Actions = "ok"; this.Prompt(this, e); } } } } lProgressValue += lFileSize; }
void loader_Prompt(object sender, MessagePromptEventArgs e) { // TODO: 不再出现此对话框。不过重试有个次数限制,同一位置失败多次后总要出现对话框才好 if (e.Actions == "yes,no,cancel") { this.Invoke((Action)(() => { DialogResult result = MessageBox.Show(this, e.MessageText + "\r\n\r\n是否重试操作?\r\n\r\n(是: 重试; 否: 跳过本次操作,继续后面的操作; 取消: 停止全部操作)", "ReportForm", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) e.ResultAction = "yes"; else if (result == DialogResult.Cancel) e.ResultAction = "cancel"; else e.ResultAction = "no"; })); } }
// static CancellationToken _token; // 探测 MD5 (用轮询任务法) // return: // -1 出错 // 0 文件没有找到 // 1 文件找到 public static int GetServerFileMD5ByTask( LibraryChannel channel, Stop stop, string strServerPath, MessagePromptEventHandler prompt, CancellationToken token, out byte[] md5, out string strError) { strError = ""; md5 = null; // 对于 dp2Kernel 内的资源只能用以前的非 Task 方式 if (strServerPath.StartsWith("!") == false) { return(GetServerFileMD5_old( channel, stop, strServerPath, out md5, out strError)); } /* * string strStyle = "md5"; * string strMetadata = ""; * byte[] baContent = null; * string strOutputPath = ""; */ TimeSpan old_timeout = channel.Timeout; channel.Timeout = TimeSpan.FromSeconds(10); try { // 检查 dp2library 版本号 REDO_GETVERSION: long lRet = channel.GetVersion(stop, out string version, out string uid, out strError); if (lRet == -1) { if (prompt != null && !(stop != null && stop.IsStopped == true)) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = $"获得 dp2library 服务器 {channel.Url} 版本号时发生错误: {strError}"; e.Actions = "yes,no,cancel"; prompt(null, e); if (e.ResultAction == "yes") { goto REDO_GETVERSION; } } strError = "检查 dp2library 服务器版本号时出错: " + strError; return(-1); } string base_version = "3.23"; if (StringUtil.CompareVersion(version, base_version) < 0) { // strError = "获得服务器文件 MD5 的功能需要 dp2library 服务器版本为 {base_version} 以上"; // return -1; // 改用旧功能 return(GetServerFileMD5_old( channel, stop, strServerPath, out md5, out strError)); } // TODO: 如果此请求出现通讯错误,再次重试请求的时候记得 removeTask 前一次的 task // 启动任务 // return: // strStyle 一般设置为"content,data,metadata,timestamp,outputpath"; // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 lRet = channel.GetRes( stop, strServerPath, 0, 0, "md5,beginTask", out byte[] baContent, out string strMetadata, out string strOutputPath, out md5, out strError); if (lRet == -1) { if (channel.ErrorCode == localhost.ErrorCode.NotFound) { return(0); } // TODO: 遇到通讯出错,需要重试操作 return(-1); } string taskID = Encoding.UTF8.GetString(md5); // 轮询,获得任务结果 while (true) { if (token.IsCancellationRequested) { strError = "前端请求中断"; return(-1); } if (stop != null && stop.IsStopped) { strError = "前端请求中断"; return(-1); } REDO_CHECKTASK: lRet = channel.GetRes( stop, strServerPath, 0, 0, $"md5,getTaskResult,taskID:{taskID}", out baContent, out strMetadata, out strOutputPath, out md5, out strError); // TODO: 如果遇到通讯出错,需要重试操作 if (lRet == -1) { if (prompt != null && !(stop != null && stop.IsStopped == true)) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = $"检查文件 {strServerPath} MD5 任务状态时发生错误: {strError}"; e.Actions = "yes,no,cancel"; prompt(null, e); if (e.ResultAction == "yes") { goto REDO_CHECKTASK; } } return(-1); } if (lRet == 1) { return(1); } Task.Delay(TimeSpan.FromSeconds(1), token).Wait(); } } catch (Exception ex) { strError = "GetServerFileMD5ByTask() 出现异常: " + ex.Message; return(-1); } finally { channel.Timeout = old_timeout; } }
public IEnumerator GetEnumerator() { string strError = ""; int nRet = 0; long lRet = 0; if (this.Date.Length != 8) { throw new ArgumentException("FileName 成员值的长度应该是 8 字符"); } if ((this.LogType & LogType.AccessLog) != 0 && (this.LogType & LogType.OperLog) != 0) { throw new ArgumentException("OperLogItemLoader 的 LogType 只能使用一种类型"); } if (this.Stop != null && this.Estimate != null) { this.Stop.SetMessage("正在装入日志文件 " + this.Date + " 中的记录。" + "剩余时间 " + ProgressEstimate.Format(Estimate.Estimate(lProgressValue)) + " 已经过时间 " + ProgressEstimate.Format(Estimate.delta_passed)); } string strXml = ""; long lAttachmentTotalLength = 0; byte[] attachment_data = null; long lFileSize = 0; if (lServerFileSize == -1) { long _lServerFileSize = 0; string strStyle = "level-" + Level.ToString(); if ((this.LogType & LogType.AccessLog) != 0) { strStyle += ",accessLog"; } // 获得服务器端日志文件尺寸 lRet = this.Channel.GetOperLog( this.Stop, this.Date, -1, // lIndex, -1, // lHint, strStyle, "", // strFilter out strXml, out _lServerFileSize, 0, // lAttachmentFragmentStart, 0, // nAttachmentFramengLength, out attachment_data, out lAttachmentTotalLength, out strError); // 2015/11/25 if (lRet == -1) { throw new ChannelException(this.Channel.ErrorCode, strError); } this.lServerFileSize = _lServerFileSize; if (lRet == 0) { yield break; } // 2015/11/25 if (_lServerFileSize == -1) { yield break; // 此类型的日志尚未启用 } } Stream stream = null; bool bCacheFileExist = false; bool bRemoveCacheFile = false; // 是否要自动删除未全部完成的本地缓存文件 bool bAutoCache = this.AutoCache; if (bAutoCache == true) { string strFileName = this.Date; if ((this.LogType & LogType.AccessLog) != 0) { strFileName = this.Date + ".a"; } nRet = PrepareCacheFile( this.CacheDir, strFileName, // this.FileName, lServerFileSize, out bCacheFileExist, out stream, out strError); if (nRet == -1) { throw new Exception(strError); } if (bCacheFileExist == false && stream != null) { bRemoveCacheFile = true; } } try { if (bCacheFileExist == true) { lFileSize = stream.Length; } else { lFileSize = lServerFileSize; } // stop.SetProgressRange(0, lTotalSize); if (String.IsNullOrEmpty(Range) == true) { Range = "0-" + (long.MaxValue - 1).ToString(); // "0-9999999999"; } RangeList rl = new RangeList(Range); for (int i = 0; i < rl.Count; i++) { RangeItem ri = (RangeItem)rl[i]; // 让 100- 这样的 range 可以使用 if (ri.lLength == -1) { ri.lLength = long.MaxValue - ri.lStart; } OperLogInfo[] records = null; long lStartRecords = 0; long lHint = -1; long lHintNext = -1; for (long lIndex = ri.lStart; lIndex < ri.lStart + ri.lLength; lIndex++) { // Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); // yield break; ? } if (lIndex == ri.lStart) { lHint = -1; } else { lHint = lHintNext; } if (bCacheFileExist == true) { if (lHint == -1) { // return: // -1 error // 0 成功 // 1 到达文件末尾或者超出 nRet = LocationRecord(stream, lIndex, out strError); if (nRet == -1) { throw new Exception(strError); } } else { // 根据暗示找到 if (lHint == stream.Length) { break; } if (lHint > stream.Length) { strError = "lHint参数值不正确"; throw new Exception(strError); } if (stream.Position != lHint) { stream.Seek(lHint, SeekOrigin.Begin); } } nRet = ReadCachedEnventLog( stream, out strXml, out lAttachmentTotalLength, out strError); if (nRet == -1) { throw new Exception(strError); } lHintNext = stream.Position; } else { if (records == null || lIndex /*- ri.lStart*/ >= lStartRecords + records.Length) { int nCount = -1; if (ri.lLength >= Int32.MaxValue) { nCount = -1; // 500; // -1; } else { nCount = (int)ri.lLength; // Math.Min(500, (int)ri.lLength); } string strStyle = "level-" + Level.ToString(); if ((this.LogType & LogType.AccessLog) != 0) { strStyle += ",accessLog"; } // 2017/10/9 if (this.ReplicationLevel == true) { strStyle += ",supervisor"; // 注:当前账户中还应该包含 replicatoin 权限才能真正获得日志记录中的密码字段 } if (string.IsNullOrEmpty(this.ServerVersion) == false && StringUtil.CompareVersion(this.ServerVersion, "3.17") >= 0) { strStyle += ",wait"; } REDO: // 获得日志 // return: // -1 error // 0 file not found // 1 succeed // 2 超过范围,本次调用无效 lRet = this.Channel.GetOperLogs( this.Stop, this.Date + ".log", lIndex, lHint, nCount, strStyle, this.Filter, // strFilter out records, out strError); if (lRet == -1) { #if NO DialogResult result = MessageBox.Show(owner, "获取日志信息 (" + this.FileName + " " + lIndex.ToString() + ") 的操作发生错误: " + strError + "\r\n\r\n是否重试操作?\r\n\r\n(是: 重试; 否: 跳过本次操作,继续后面的操作; 放弃: 停止全部操作)", "OperLogItemLoader", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) { goto REDO; } if (result == DialogResult.Cancel) { throw new Exception(strError); } else { // TODO: 是否要在listview中装入一条表示出错的行? lHintNext = -1; continue; } #endif if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获取 " + this._logType.ToString() + " 日志信息 (" + this.Date + " " + lIndex.ToString() + ") 的操作发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new InterruptException(strError); } else if (e.ResultAction == "yes") { if (this.Stop != null) { this.Stop.Continue(); } goto REDO; } else { lHintNext = -1; continue; } } else { throw new ChannelException(this.Channel.ErrorCode, strError); } } if (lRet == 0) { yield break; } if (lRet == 2) { break; } // records数组表示的起点位置 lStartRecords = lIndex /* - ri.lStart*/; } OperLogInfo info = records[lIndex - lStartRecords]; strXml = info.Xml; lHintNext = info.HintNext; lAttachmentTotalLength = info.AttachmentLength; // 写入本地缓存的日志文件 if (stream != null) { try { WriteCachedEnventLog( stream, strXml, lAttachmentTotalLength); } catch (Exception ex) { strError = "写入本地缓存文件的时候出错: " + ex.Message; throw new Exception(strError); } } } #if NO // 2011/12/30 // 日志记录可能动态地增加了,超过了原先为ProgressBar设置的范围 if (lFizeTotalSize < (int)lHintNext) { lFizeTotalSize = lHintNext; stop.SetProgressRange(0, lFizeTotalSize); } #endif if (lHintNext >= 0) { // 校正 if (lProgressValue + lHintNext >= lSize) // > 2017/12/4 修改为 >= { lSize = lProgressValue + lHintNext; if (this.Stop != null) { this.Stop.SetProgressRange(0, lSize); } if (this.Estimate != null) { Estimate.SetRange(0, lSize); } } this.Stop?.SetProgressValue(lProgressValue + lHintNext); } if (lIndex % 100 == 0) { if (this.Stop != null && this.Estimate != null) { Estimate.Text = "剩余时间 " + ProgressEstimate.Format(Estimate.Estimate(lProgressValue + lHintNext)) + " 已经过时间 " + ProgressEstimate.Format(Estimate.delta_passed); this.Stop.SetMessage("正在装入日志文件 " + this.Date + " 中的记录 " + lIndex.ToString() + " 。" + Estimate.Text); } } { OperLogItem item = new OperLogItem { Xml = strXml, Index = lIndex, Date = this.Date.Substring(0, 8), AttachmentLength = lAttachmentTotalLength }; yield return(item); } } } // 创建本地缓存的日志文件的 metadata 文件 if (bCacheFileExist == false && stream != null) { string strFileName = this.Date; if ((this.LogType & LogType.AccessLog) != 0) { strFileName = this.Date + ".a"; } nRet = CreateCacheMetadataFile( this.CacheDir, strFileName, // this.FileName, lServerFileSize, out strError); if (nRet == -1) { throw new Exception(strError); } } bRemoveCacheFile = false; // 不删除 } finally { if (stream != null) { stream.Close(); } if (bRemoveCacheFile == true) { string strFileName = this.Date; if ((this.LogType & LogType.AccessLog) != 0) { strFileName = this.Date + ".a"; } string strError1 = ""; nRet = DeleteCacheFile( this.CacheDir, strFileName, // this.FileName, out strError1); if (nRet == -1) { // MessageBox.Show(owner, strError1); if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = strError1; e.Actions = "ok"; this.Prompt(this, e); } } } } lProgressValue += lFileSize; }
void loader_Prompt(object sender, MessagePromptEventArgs e) { if (this.Prompt != null) this.Prompt(sender, e); }
public IEnumerator GetEnumerator() { string strError = ""; int nRet = 0; if ((this.LogType & LogType.AccessLog) != 0 && (this.LogType & LogType.OperLog) != 0) { throw new ArgumentException("OperLogLoader 的 LogType 只能使用一种类型"); } if (string.IsNullOrEmpty(this.CacheDir) == false) { TryCreateDir(this.CacheDir); } // ProgressEstimate estimate = new ProgressEstimate(); bool bAutoCache = this.AutoCache; if (bAutoCache == true) { // 象征性获得一个日志文件的尺寸,主要目的是为了触发一次通道登录 // return: // -2 此类型的日志尚未启用 // -1 error // 0 file not found // 1 found nRet = GetFileSize( this.Stop, this.Channel, this.CacheDir, "20121001.log", this.LogType, out long lServerFileSize, out long lCacheFileSize, out strError); if (nRet == -1) { throw new ChannelException(this.Channel.ErrorCode, strError); } // 2015/11/25 if (nRet == -2) { yield break; // 此类型的日志尚未启用 } // 检查日志文件缓存目录的版本是否和当前用户的信息一致 // return: // -1 出错 // 0 一致 // 1 不一致 nRet = DetectCacheVersionFile( this.CacheDir, "version.xml", this.Channel.LibraryCodeList, this.Channel.Url, out strError); if (nRet == -1) { throw new Exception(strError); } if (nRet == 1) { REDO: // 清空当前缓存目录 nRet = DeleteDataDir( this.CacheDir, out strError); if (nRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "清空当前缓存目录时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new InterruptException(strError); } else if (e.ResultAction == "yes") { goto REDO; } else { } } else { throw new Exception(strError); } } #if NO if (nRet == -1) { throw new Exception(strError); } #endif TryCreateDir(this.CacheDir); // 重新创建目录 // 创建版本文件 nRet = CreateCacheVersionFile( this.CacheDir, "version.xml", this.Channel.LibraryCodeList, this.Channel.Url, out strError); if (nRet == -1) { throw new Exception(strError); } } } long lTotalSize = 0; List <string> lines = new List <string>(); // 经过处理后排除了不存在的文件名 List <string> ranges = new List <string>(); // 日期后面的偏移部分 List <long> sizes = new List <long>(); // 服务器日志文件的尺寸 #if NO this.Stop.SetMessage("正在准备获得日志文件尺寸 ..."); foreach (string strLine in this.FileNames) { // Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); // yield break; ? } if (String.IsNullOrEmpty(strLine) == true) { continue; } string strFilename = strLine.Trim(); // 去掉注释 nRet = strFilename.IndexOf("#"); if (nRet != -1) { strFilename = strFilename.Substring(0, nRet).Trim(); } if (String.IsNullOrEmpty(strFilename) == true) { continue; } string strLogFilename = ""; string strRange = ""; nRet = strFilename.IndexOf(":"); if (nRet != -1) { strLogFilename = strFilename.Substring(0, nRet).Trim(); strRange = strFilename.Substring(nRet + 1).Trim(); } else { strLogFilename = strFilename.Trim(); strRange = ""; } if (strLogFilename.Length == 8) { strLogFilename += ".log"; } REDO_GETSIZE: long lServerFileSize = 0; long lCacheFileSize = 0; // 获得一个日志文件的尺寸 // -2 此类型的日志尚未启用 // -1 error // 0 file not found // 1 found nRet = GetFileSize( this.Stop, this.Channel, this.CacheDir, strLogFilename, this.LogType, out lServerFileSize, out lCacheFileSize, out strError); if (nRet == -1) { // throw new Exception(strError); if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获取日志文件 " + strLogFilename + " 尺寸的操作发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new InterruptException(strError); } else if (e.ResultAction == "yes") { if (this.Stop != null) { this.Stop.Continue(); } goto REDO_GETSIZE; } else { // ?? continue; } } else { throw new ChannelException(this.Channel.ErrorCode, strError); } } if (nRet == 0) { continue; } if (lServerFileSize == 0) { continue; // 0字节的文件当作不存在处理 } // 2015/11/25 if (lServerFileSize == -1) { yield break; // 此类型的日志尚未启用 } Debug.Assert(lServerFileSize >= 0, ""); if (bAutoCache == true) { if (lCacheFileSize > 0) { lTotalSize += lCacheFileSize; } else { lTotalSize += lServerFileSize; } } else { lTotalSize += lServerFileSize; } // lines.Add(strFilename); lines.Add(strLogFilename); ranges.Add(strRange); // 记忆每个文件的尺寸,后面就不用获取了? sizes.Add(lServerFileSize); } #endif // 预先处理一下文件名 List <string> filenames = new List <string>(); foreach (string strLine in this.Dates) { if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); } if (String.IsNullOrEmpty(strLine) == true) { continue; } string strFilename = strLine.Trim(); // 去掉注释 nRet = strFilename.IndexOf("#"); if (nRet != -1) { strFilename = strFilename.Substring(0, nRet).Trim(); } if (String.IsNullOrEmpty(strFilename) == true) { continue; } #if NO List <string> parts = StringUtil.ParseTwoPart(strFilename, ":"); string strRange = parts[1]; strFilename = parts[0].Substring(0, 8); if (string.IsNullOrEmpty(strRange) == false) { range_table[strFilename] = strRange; // TODO: 如何防范文件名重复? } #endif filenames.Add(strFilename); Debug.Assert(strFilename.Length >= 8, ""); } // 准备查找表 Hashtable length_table = new Hashtable(); { List <FileSize> size_pairs = GetFilesLength( // filenames ); foreach (FileSize size_pair in size_pairs) { length_table[size_pair.Date] = size_pair; } } foreach (string filename in filenames) { FileSize size_pair = length_table[filename.Substring(0, 8)] as FileSize; if (size_pair == null) { continue; } Debug.Assert(size_pair != null, ""); lines.Add(filename); sizes.Add(size_pair.ServerFileSize); if (size_pair.ServerFileSize == -1) { yield break; // 此类型的日志尚未启用 } Debug.Assert(size_pair.ServerFileSize >= 0, ""); if (bAutoCache == true) { if (size_pair.CacheFileSize > 0) { lTotalSize += size_pair.CacheFileSize; } else { lTotalSize += size_pair.ServerFileSize; } } else { lTotalSize += size_pair.ServerFileSize; } } long lDoneSize = 0; if (this.ProgressStart == -1) { lDoneSize = lTotalSize; } else { lDoneSize = this.ProgressStart; } lTotalSize += lDoneSize; if (this.Stop != null) { this.Stop.SetProgressRange(0, lTotalSize); } if (Estimate != null) { Estimate.SetRange(lDoneSize, lTotalSize); Estimate.StartEstimate(); } for (int i = 0; i < lines.Count; i++) { // Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); // yield break; ? } string strLine = lines[i]; Debug.Assert(strLine.Length >= 8, ""); // string strRange = ranges[i]; // 2017/10/9 List <string> parts = StringUtil.ParseTwoPart(strLine, ":"); string strRange = parts[1]; strLine = parts[0]; string strLogFilename = strLine; #if NO string strLogFilename = ""; string strRange = ""; nRet = strLine.IndexOf(":"); if (nRet != -1) { strLogFilename = strLine.Substring(0, nRet).Trim(); strRange = strLine.Substring(nRet + 1).Trim(); } else { strLogFilename = strLine.Trim(); strRange = ""; } #endif { OperLogItemLoader loader = new OperLogItemLoader { Stop = this.Stop, Channel = this.Channel, // loader.owner = this.owner; Estimate = this.Estimate, Date = strLogFilename, Level = this.Level, ReplicationLevel = this.ReplicationLevel, lServerFileSize = sizes[i], Range = strRange, AutoCache = this.AutoCache, lProgressValue = lDoneSize, lSize = lTotalSize, Filter = this.Filter, LogType = this.LogType, ServerVersion = this.ServerVersion }; if (this.Prompt != null) { loader.Prompt += new MessagePromptEventHandler(loader_Prompt); } try { foreach (OperLogItem item in loader) { yield return(item); } } finally { if (this.Prompt != null) { loader.Prompt -= new MessagePromptEventHandler(loader_Prompt); } } lDoneSize = loader.lProgressValue; lTotalSize = loader.lSize; } } }
public IEnumerator GetEnumerator() { List <string> format_list = new List <string>(); int nContentIndex = format_list.Count; int nTimestampIndex = -1; int nMetadataIndex = -1; format_list.Add(this.Format); // if ((this.GetBiblioInfoStyle & dp2Circulation.GetBiblioInfoStyle.Timestamp) != 0) if (this.GetBiblioInfoStyle.HasFlag(GetBiblioInfoStyle.Timestamp) == true) // 新用法 { nTimestampIndex = format_list.Count; format_list.Add("timestamp"); } if ((this.GetBiblioInfoStyle & GetBiblioInfoStyle.Metadata) != 0) { nMetadataIndex = format_list.Count; format_list.Add("metadata"); } string[] formats = new string[format_list.Count]; format_list.CopyTo(formats); List <string> batch = new List <string>(); for (int index = 0; index < m_recpaths.Count; index++) { string s = m_recpaths[index]; batch.Add(s); // 每100个一批,或者最后一次 if (batch.Count >= 100 || (index == m_recpaths.Count - 1 && batch.Count > 0)) { REDO: string strCommand = "@path-list:" + StringUtil.MakePathList(batch); string[] results = null; byte[] timestamp = null; string strError = ""; // Channel.Timeout = new TimeSpan(0, 0, 5); 应该让调主设置这个值 long lRet = Channel.GetBiblioInfos( this.Stop, strCommand, "", formats, out results, out timestamp, out strError); if (lRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); // e.MessageText = "获得书目记录 '"+strCommand+"' ("+StringUtil.MakePathList(format_list)+") 时发生错误: " + strError; e.MessageText = "获得书目记录时发生错误: " + strError + "\r\ncommand='" + strCommand + "' (" + StringUtil.MakePathList(format_list) + ")"; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new ChannelException(Channel.ErrorCode, strError); } else if (e.ResultAction == "yes") { goto REDO; } else { // no 也是抛出异常。因为继续下一批代价太大 throw new ChannelException(Channel.ErrorCode, strError); } } else { throw new ChannelException(Channel.ErrorCode, strError); } } if (lRet == 0) { if (lRet == 0 && String.IsNullOrEmpty(strError) == true) { foreach (string path in batch) { BiblioItem item = new BiblioItem(); item.RecPath = path; item.ErrorCode = ErrorCode.NotFound; item.ErrorInfo = "书目记录 '" + path + "' 不存在"; yield return(item); } goto CONTINUE; } // 如果results.Length表现正常,其实还可以继续处理 if (results != null && results.Length > 0) { } else { // 2014/1/15 if (Channel.ErrorCode == ErrorCode.NotFound) { foreach (string path in batch) { BiblioItem item = new BiblioItem(); item.RecPath = path; item.ErrorCode = ErrorCode.NotFound; item.ErrorInfo = "书目记录 '" + path + "' 不存在"; yield return(item); } goto CONTINUE; } strError = "获得书目记录 '" + StringUtil.MakePathList(batch) + "' 时发生错误: " + strError; throw new Exception(strError); } } if (results == null) { strError = "results == null"; throw new Exception(strError); } for (int i = 0; i < results.Length / formats.Length; i++) { BiblioItem item = new BiblioItem(); item.RecPath = batch[i]; if (nContentIndex != -1) { item.Content = results[i * formats.Length + nContentIndex]; } if (nTimestampIndex != -1) { item.Timestamp = ByteArray.GetTimeStampByteArray(results[i * formats.Length + nTimestampIndex]); } if (nMetadataIndex != -1) { item.Metadata = results[i * formats.Length + nMetadataIndex]; } if (string.IsNullOrEmpty(item.Content) == true) { item.ErrorCode = ErrorCode.NotFound; item.ErrorInfo = "书目记录 '" + item.RecPath + "' 不存在"; } yield return(item); } CONTINUE: if (batch.Count > results.Length / formats.Length) { // 有本次没有获取到的记录 batch.RemoveRange(0, results.Length / formats.Length); if (index == m_recpaths.Count - 1) { goto REDO; // 当前已经是最后一轮了,需要继续做完 } // 否则可以留给下一轮处理 } else { batch.Clear(); } } } }
public IEnumerator GetEnumerator() { List<string> batch = new List<string>(); for (int index = 0; index < m_barcodes.Count; index++) { string s = m_barcodes[index]; if (string.IsNullOrEmpty(s) == true) throw new Exception("册条码号字符串不允许为空 (index=" + index.ToString() + ")"); batch.Add(s); // 每100个一批,或者最后一次 if (batch.Count >= 100 || (index == m_barcodes.Count - 1 && batch.Count > 0)) { REDO_GETITEMINFO: string strBiblio = ""; string strResult = ""; string strError = ""; long lRet = this.Channel.GetItemInfo( this.Stop, "@barcode-list:" + StringUtil.MakePathList(batch), "get-path-list", out strResult, "", // strBiblioType, out strBiblio, out strError); if (lRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "通过册条码号获得记录路径时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") throw new Exception(strError); else if (e.ResultAction == "yes") { if (this.Stop != null) this.Stop.Continue(); goto REDO_GETITEMINFO; } else { } } else throw new ChannelException(Channel.ErrorCode, strError); } List<string> recpaths = StringUtil.SplitList(strResult); if (batch.Count != recpaths.Count) { strError = "batch.Count != recpaths.Count"; throw new Exception(strError); } Debug.Assert(batch.Count == recpaths.Count, ""); int i = 0; foreach (string recpath in recpaths) { EntityItem item = new EntityItem(); item.Barcode = batch[i]; if (string.IsNullOrEmpty(recpath) == false && recpath[0] == '!') item.ErrorInfo = recpath.Substring(1); else item.RecPath = recpath; i++; yield return item; } batch.Clear(); } } }