0ad74d9f7f
* feat(Upload/Common): 重构上传功能以添加通用设置管理 - 新增UploadSettings类用于管理上传通用设置 - 重构上传逻辑,将延迟上传功能移至UploadHelper - 在Dlass设置窗口添加通用设置标签页 - 支持多上传提供者管理及取消操作 - 增强文件上传前的验证和错误处理 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * feat(upload): 添加WebDav文件上传支持 - 新增WebDavUploader工具类实现文件上传功能 - 添加WebDavUploadProvider作为上传提供者 - 在设置界面增加WebDav配置选项 - 添加WebDav.Client NuGet包依赖 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * feat(WebDAV): 实现WebDAV上传队列管理 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * feat(Upload): 重命名Dlass设置项为云存储以支持WebDav保存 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * feat(Dlass):迁移Dlass注册位置 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * refactor(Upload): 优化上传逻辑和界面交互 - 修改Dlass标签页检测逻辑,使用Tag属性替代Header - 限制WebDav上传队列的批量处理大小 - 移除多处上传延迟逻辑,统一在通用设置中配置 - 更新Dlass设置界面提示文本 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * chore:修改窗口命名 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * refactor(upload): 重构上传队列为统一管理架构 重构上传队列系统,引入BaseUploadQueue基类实现通用队列管理逻辑,创建UploadQueueHelper统一管理所有上传队列。将DlassUploadQueue和WebDavUploadQueue重构为继承自BaseUploadQueue的具体实现,简化代码并提高可维护性。修改MainWindow初始化代码以使用新的统一初始化方法。 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * refactor(Upload): 重构上传队列系统,改进错误处理和资源管理 - 将上传队列改为可释放资源,实现IDisposable接口 - 移除硬编码的文件验证逻辑,改为可重写方法 - 改进API客户端,支持取消操作和更好的资源管理 - 优化队列初始化流程,增加错误处理 - 统一上传提供者的队列注册方式 - 改进日志记录和错误信息 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * Update Settings.cs * refactor(UpLoad/Queue): 移除冗余的上传成功/失败日志记录 优化WebDav上传逻辑,增加目录创建重试机制 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * refactor(MW_Settings): 重构全选复选框状态更新逻辑 将直接设置全选复选框状态的逻辑拆分为两步,先计算所有分类复选框状态,再更新全选复选框,提高代码可读性 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> --------- Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> Co-authored-by: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
257 lines
8.7 KiB
C#
257 lines
8.7 KiB
C#
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Ink_Canvas.Helpers
|
|
{
|
|
/// <summary>
|
|
/// Dlass上传队列
|
|
/// </summary>
|
|
public class DlassUploadQueue : BaseUploadQueue
|
|
{
|
|
private const string APP_ID = "app_WkjocWqsrVY7T6zQV2CfiA";
|
|
private const string APP_SECRET = "o7dx5b5ASGUMcM72PCpmRQYAhSijqaOVHoGyBK0IxbA";
|
|
|
|
/// <summary>
|
|
/// 队列文件名
|
|
/// </summary>
|
|
protected override string QueueFileName => "DlassUploadQueue.json";
|
|
|
|
/// <summary>
|
|
/// 上传笔记响应模型
|
|
/// </summary>
|
|
public class UploadNoteResponse
|
|
{
|
|
[JsonProperty("success")]
|
|
public bool Success { get; set; }
|
|
|
|
[JsonProperty("message")]
|
|
public string Message { get; set; }
|
|
|
|
[JsonProperty("note_id")]
|
|
public int? NoteId { get; set; }
|
|
|
|
[JsonProperty("filename")]
|
|
public string Filename { get; set; }
|
|
|
|
[JsonProperty("file_path")]
|
|
public string FilePath { get; set; }
|
|
|
|
[JsonProperty("file_url")]
|
|
public string FileUrl { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 白板信息模型(用于查找白板)
|
|
/// </summary>
|
|
private class WhiteboardInfo
|
|
{
|
|
[JsonProperty("id")]
|
|
public int Id { get; set; }
|
|
|
|
[JsonProperty("name")]
|
|
public string Name { get; set; }
|
|
|
|
[JsonProperty("board_id")]
|
|
public string BoardId { get; set; }
|
|
|
|
[JsonProperty("secret_key")]
|
|
public string SecretKey { get; set; }
|
|
|
|
[JsonProperty("class_name")]
|
|
public string ClassName { get; set; }
|
|
|
|
[JsonProperty("class_id")]
|
|
public int ClassId { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 认证响应模型
|
|
/// </summary>
|
|
private class AuthWithTokenResponse
|
|
{
|
|
[JsonProperty("success")]
|
|
public bool Success { get; set; }
|
|
|
|
[JsonProperty("whiteboards")]
|
|
public List<WhiteboardInfo> Whiteboards { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查上传是否启用
|
|
/// </summary>
|
|
protected override bool IsUploadEnabled()
|
|
{
|
|
return MainWindow.Settings?.Dlass?.IsAutoUploadNotes == true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 内部上传方法,执行实际上传操作
|
|
/// </summary>
|
|
protected override async Task<bool> UploadFileInternalAsync(string filePath, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
// 再次检查文件是否存在(可能在队列等待时被删除)
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 获取白板信息
|
|
var whiteboard = await GetWhiteboardInfo(cancellationToken);
|
|
if (whiteboard == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 获取API基础URL和用户Token
|
|
var apiBaseUrl = MainWindow.Settings?.Dlass?.ApiBaseUrl ?? "https://dlass.tech";
|
|
var userToken = MainWindow.Settings?.Dlass?.UserToken;
|
|
|
|
// 准备上传参数
|
|
var fileName = Path.GetFileNameWithoutExtension(filePath);
|
|
var fileExtension = Path.GetExtension(filePath).ToLower();
|
|
var title = fileName;
|
|
string fileType;
|
|
string tags;
|
|
if (fileExtension == ".zip")
|
|
{
|
|
fileType = "多页面墨迹压缩包";
|
|
tags = "自动上传,多页面,zip,压缩包";
|
|
}
|
|
else if (fileExtension == ".icstk")
|
|
{
|
|
fileType = "墨迹文件";
|
|
tags = "自动上传,墨迹,icstk";
|
|
}
|
|
else if (fileExtension == ".xml")
|
|
{
|
|
fileType = "XML文件";
|
|
tags = "自动上传,xml";
|
|
}
|
|
else
|
|
{
|
|
fileType = "笔记";
|
|
tags = "自动上传,笔记,png";
|
|
}
|
|
var description = $"自动上传的{fileType} - {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
|
|
|
|
// 创建API客户端并上传文件
|
|
var apiClient = new DlassApiClient(APP_ID, APP_SECRET, apiBaseUrl, userToken);
|
|
try
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
var uploadResult = await apiClient.UploadNoteAsync<UploadNoteResponse>(
|
|
"/api/whiteboard/upload_note",
|
|
filePath,
|
|
whiteboard.BoardId,
|
|
whiteboard.SecretKey,
|
|
title,
|
|
description,
|
|
tags,
|
|
cancellationToken);
|
|
|
|
if (uploadResult != null && uploadResult.Success)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
apiClient.Dispose();
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
throw;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取白板信息
|
|
/// </summary>
|
|
private async Task<WhiteboardInfo> GetWhiteboardInfo(CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
var selectedClassName = MainWindow.Settings?.Dlass?.SelectedClassName;
|
|
if (string.IsNullOrEmpty(selectedClassName))
|
|
{
|
|
LogHelper.WriteLogToFile("[DlassUploadQueue] 上传失败:未选择班级", LogHelper.LogType.Error);
|
|
return null;
|
|
}
|
|
|
|
var userToken = MainWindow.Settings?.Dlass?.UserToken;
|
|
if (string.IsNullOrEmpty(userToken))
|
|
{
|
|
LogHelper.WriteLogToFile("[DlassUploadQueue] 上传失败:未设置用户Token", LogHelper.LogType.Error);
|
|
return null;
|
|
}
|
|
|
|
var apiBaseUrl = MainWindow.Settings?.Dlass?.ApiBaseUrl ?? "https://dlass.tech";
|
|
|
|
// 创建API客户端并获取白板信息
|
|
var apiClient = new DlassApiClient(APP_ID, APP_SECRET, apiBaseUrl, userToken);
|
|
try
|
|
{
|
|
var authData = new
|
|
{
|
|
app_id = APP_ID,
|
|
app_secret = APP_SECRET,
|
|
user_token = userToken
|
|
};
|
|
|
|
var authResult = await apiClient.PostAsync<AuthWithTokenResponse>("/api/whiteboard/framework/auth-with-token", authData, requireAuth: false, cancellationToken: cancellationToken);
|
|
|
|
if (authResult == null || !authResult.Success || authResult.Whiteboards == null)
|
|
{
|
|
LogHelper.WriteLogToFile("[DlassUploadQueue] 上传失败:无法获取白板信息", LogHelper.LogType.Error);
|
|
return null;
|
|
}
|
|
|
|
// 查找匹配班级的白板
|
|
var whiteboard = authResult.Whiteboards
|
|
.FirstOrDefault(w => !string.IsNullOrEmpty(w.ClassName) && w.ClassName == selectedClassName);
|
|
|
|
if (whiteboard == null || string.IsNullOrEmpty(whiteboard.BoardId) || string.IsNullOrEmpty(whiteboard.SecretKey))
|
|
{
|
|
LogHelper.WriteLogToFile($"[DlassUploadQueue] 上传失败:未找到班级'{selectedClassName}'对应的白板", LogHelper.LogType.Error);
|
|
return null;
|
|
}
|
|
|
|
return whiteboard;
|
|
}
|
|
finally
|
|
{
|
|
apiClient.Dispose();
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
throw;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
} |