v3.2:上下行带宽限速 + 品牌更新 + 产品修复
亮点 - v3.2 带宽限速(upload_rate/download_rate,字节/秒,0=不限速;管理端立即生效) - middleware/bandwidth.go 时间窗对齐 sleep 算法 + 单元测试(400KB@100KB/s 4.00s 精度) - 下载:serveFile 包裹 storage.ReadCloser(统一覆盖 local/webdav/s3 代理下载) - 上传:UploadBandwidthMiddleware 包裹 Request.Body(shareFile/chunk/presign proxy) - S3 预签名直传不可服务端限速——UI/文档明示 - 后台 SettingsView 增加 MB/s 友好输入;i18n zh-CN/en-US 双语 - v3.2 文档:新增 docs/api/13-bandwidth.md 专题;10-config 指针;00-overview changelog 与限流表带宽行;openapi.yaml 三处 schema + description 更新 - README.md / web/README.md / server/README.md / deploy/README.md 全部覆盖 品牌(v3.1 收尾) - 文件快递柜 → 文件快传(前端/后端默认值/文档/产物/运行 KV) - 「复制取件码」按钮删除;取件码块点击即复制(保持原尺寸) - 「复制链接」→「复制链接和提取码」(一并复制链接和提取码) 产品修复(v3.1.1) - 文本分享 Content-Type text/plain + urlencoded body:前端显式声明 urlencoded 头根治; 后端 bindJSONOrForm 兜底兼容 text/plain + JSON/urlencoded 嗅探 - Docker 部署文档校对到 v3.1 现状(热切换 + 端口/卷/健康检查)
This commit is contained in:
@@ -795,6 +795,7 @@ var configKeys = []string{
|
||||
"uploadMinute", "uploadCount", "errorMinute", "errorCount",
|
||||
"loginCount", "loginMinute",
|
||||
"opacity", "background", "showAdminAddr", "robotsText", "site_domain", // v3.1:站点对外域名
|
||||
"upload_rate", "download_rate", // v3.2:上下行带宽字节/秒(0=不限速)
|
||||
"adminSessionExpire", "storage_path", "local_storage_path",
|
||||
"file_storage",
|
||||
// v3 存储引擎与引擎参数(热切换;凭据为敏感键,get 掩码/update 空跳过)
|
||||
@@ -814,6 +815,7 @@ var intConfigKeys = []string{
|
||||
"loginCount", "loginMinute", "max_save_seconds", "uploadSize",
|
||||
"adminSessionExpire",
|
||||
"max_save_count", "max_file_size", "notify_enabled",
|
||||
"upload_rate", "download_rate", // v3.2
|
||||
}
|
||||
|
||||
// validateConfigValue 按 settings.KVSchema 校验单个配置值:
|
||||
|
||||
@@ -46,7 +46,7 @@ func Register(r *gin.Engine, d *Deps) {
|
||||
share := r.Group("/share")
|
||||
{
|
||||
share.POST("/text", d.shareText)
|
||||
share.POST("/file", d.shareFile)
|
||||
share.POST("/file", middleware.UploadBandwidthMiddleware(d.Cfg.UploadRate), d.shareFile)
|
||||
// metadata:每次访问即计数(RequireRateLimit=进入检查+完成计数)
|
||||
share.GET("/metadata", d.Limiter.RequireRateLimit(middleware.LimitMeta), d.shareMetadata)
|
||||
share.POST("/metadata", d.Limiter.RequireRateLimit(middleware.LimitMeta), d.shareMetadataPost)
|
||||
@@ -61,8 +61,8 @@ func Register(r *gin.Engine, d *Deps) {
|
||||
chunk.POST("/upload/init", d.chunkInit)
|
||||
// 主路径(参考语义):/chunk/upload/{uploadID}/{index};
|
||||
// 扁平兼容:/chunk/upload + 表单/query 传 upload_id/chunk_index
|
||||
chunk.POST("/upload/:uploadID/:chunkIndex", d.chunkUpload)
|
||||
chunk.POST("/upload", d.chunkUploadFlat)
|
||||
chunk.POST("/upload/:uploadID/:chunkIndex", middleware.UploadBandwidthMiddleware(d.Cfg.UploadRate), d.chunkUpload)
|
||||
chunk.POST("/upload", middleware.UploadBandwidthMiddleware(d.Cfg.UploadRate), d.chunkUploadFlat)
|
||||
chunk.GET("/upload/status/:uploadID", d.chunkStatus)
|
||||
chunk.POST("/upload/complete/:uploadID", d.chunkComplete)
|
||||
chunk.DELETE("/upload/:uploadID", d.chunkCancel)
|
||||
@@ -72,7 +72,7 @@ func Register(r *gin.Engine, d *Deps) {
|
||||
presign := r.Group("/presign")
|
||||
{
|
||||
presign.POST("/upload/init", d.presignInit)
|
||||
presign.PUT("/upload/proxy/:uploadID", d.presignProxy)
|
||||
presign.PUT("/upload/proxy/:uploadID", middleware.UploadBandwidthMiddleware(d.Cfg.UploadRate), d.presignProxy)
|
||||
presign.POST("/upload/confirm/:uploadID", d.presignConfirm)
|
||||
presign.GET("/upload/status/:uploadID", d.presignStatus)
|
||||
presign.DELETE("/upload/:uploadID", d.presignCancel)
|
||||
@@ -135,6 +135,9 @@ func (d *Deps) publicConfig(c *gin.Context) {
|
||||
// v3:当前存储引擎名(仅名称,任何引擎参数/凭据不下发)
|
||||
"storage_engine": d.Store.CurrentName(),
|
||||
"site_domain": d.Cfg.SiteDomain(),
|
||||
// v3.2:上下行带宽字节/秒(公开下发,0=不限速,方便管理端展示当前值)
|
||||
"upload_rate": d.Cfg.UploadRate(),
|
||||
"download_rate": d.Cfg.DownloadRate(),
|
||||
// 需求 ③:系统通知(开关 + 内容,前台右上角悬浮窗)
|
||||
// L7:读取侧再做一次白名单净化,覆盖历史存量与直改库的数据
|
||||
"notify_enabled": boolToInt(cfg.NotifyEnabled()),
|
||||
|
||||
@@ -597,7 +597,9 @@ func (d *Deps) serveFile(c *gin.Context, fc *model.FileCodes) {
|
||||
}
|
||||
auditUploadEntry(c, fc.Code, name, total, 0)
|
||||
c.Status(status)
|
||||
n, _ := io.Copy(c.Writer, dl)
|
||||
// v3.2:下载带宽限速(storage.ReadCloser → 限速 reader → c.Writer)
|
||||
dlReader := middleware.WrapReadCloser(dl, d.Cfg.DownloadRate())
|
||||
n, _ := io.Copy(c.Writer, dlReader)
|
||||
middleware.AuditSet(c, func(e *audit.Entry) {
|
||||
if e.TransferredBytes == 0 {
|
||||
e.TransferredBytes = n
|
||||
|
||||
Reference in New Issue
Block a user