Feat: remote test ping and ping-back

pull/247/head
HFO4 5 years ago
parent f1ef21e195
commit bd643fa2d5

@ -22,7 +22,7 @@ type system struct {
Listen string `validate:"required"` Listen string `validate:"required"`
Debug bool Debug bool
SessionSecret string SessionSecret string
HashIDSalt string `validate:"required"` HashIDSalt string
} }
// slave 作为slave存储端配置 // slave 作为slave存储端配置
@ -72,8 +72,7 @@ type cors struct {
var cfg *ini.File var cfg *ini.File
const defaultConf = ` const defaultConf = `[System]
[System]
Mode = master Mode = master
Listen = :5212 Listen = :5212
SessionSecret = {SessionSecret} SessionSecret = {SessionSecret}

@ -215,6 +215,15 @@ func (handler Driver) Source(
return "", errors.New("无法解析远程服务端地址") return "", errors.New("无法解析远程服务端地址")
} }
// 是否启用了CDN
if handler.Policy.BaseURL != "" {
cdnURL, err := url.Parse(handler.Policy.BaseURL)
if err != nil {
return "", err
}
serverURL = cdnURL
}
var ( var (
signedURI *url.URL signedURI *url.URL
controller = "/api/v3/slave/download" controller = "/api/v3/slave/download"

@ -67,9 +67,11 @@ func HookSlaveUploadValidate(ctx context.Context, fs *FileSystem) error {
policy := ctx.Value(fsctx.UploadPolicyCtx).(serializer.UploadPolicy) policy := ctx.Value(fsctx.UploadPolicyCtx).(serializer.UploadPolicy)
// 验证单文件尺寸 // 验证单文件尺寸
if policy.MaxSize > 0 {
if file.GetSize() > policy.MaxSize { if file.GetSize() > policy.MaxSize {
return ErrFileSizeTooBig return ErrFileSizeTooBig
} }
}
// 验证文件名 // 验证文件名
if !fs.ValidateLegalName(ctx, file.GetFileName()) { if !fs.ValidateLegalName(ctx, file.GetFileName()) {

@ -34,7 +34,7 @@ func (fs *FileSystem) GetThumb(ctx context.Context, id uint) (*response.ContentR
ctx = context.WithValue(ctx, fsctx.ThumbSizeCtx, [2]uint{w, h}) ctx = context.WithValue(ctx, fsctx.ThumbSizeCtx, [2]uint{w, h})
ctx = context.WithValue(ctx, fsctx.FileModelCtx, fs.FileTarget[0]) ctx = context.WithValue(ctx, fsctx.FileModelCtx, fs.FileTarget[0])
res, err := fs.Handler.Thumb(ctx, fs.FileTarget[0].SourceName) res, err := fs.Handler.Thumb(ctx, fs.FileTarget[0].SourceName)
if err == nil { if err == nil && conf.SystemConfig.Mode == "master" {
res.MaxAge = model.GetIntSetting("preview_timeout", 60) res.MaxAge = model.GetIntSetting("preview_timeout", 60)
} }

@ -151,6 +151,17 @@ func AdminTestPath(c *gin.Context) {
} }
} }
// AdminTestSlave 测试从机可用性
func AdminTestSlave(c *gin.Context) {
var service admin.SlaveTestService
if err := c.ShouldBindJSON(&service); err == nil {
res := service.Test()
c.JSON(200, res)
} else {
c.JSON(200, ErrorResponse(err))
}
}
// AdminAddPolicy 新建存储策略 // AdminAddPolicy 新建存储策略
func AdminAddPolicy(c *gin.Context) { func AdminAddPolicy(c *gin.Context) {
var service admin.AddPolicyService var service admin.AddPolicyService

@ -2,6 +2,7 @@ package controllers
import ( import (
model "github.com/HFO4/cloudreve/models" model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/conf"
"github.com/HFO4/cloudreve/pkg/serializer" "github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/pkg/util" "github.com/HFO4/cloudreve/pkg/util"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -41,7 +42,7 @@ func SiteConfig(c *gin.Context) {
func Ping(c *gin.Context) { func Ping(c *gin.Context) {
c.JSON(200, serializer.Response{ c.JSON(200, serializer.Response{
Code: 0, Code: 0,
Msg: "Pong", Data: conf.BackendVersion,
}) })
} }

@ -6,6 +6,7 @@ import (
"github.com/HFO4/cloudreve/pkg/filesystem/driver/local" "github.com/HFO4/cloudreve/pkg/filesystem/driver/local"
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx" "github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
"github.com/HFO4/cloudreve/pkg/serializer" "github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/service/admin"
"github.com/HFO4/cloudreve/service/explorer" "github.com/HFO4/cloudreve/service/explorer"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/url" "net/url"
@ -146,3 +147,14 @@ func SlaveDelete(c *gin.Context) {
c.JSON(200, ErrorResponse(err)) c.JSON(200, ErrorResponse(err))
} }
} }
// SlavePing 从机测试
func SlavePing(c *gin.Context) {
var service admin.SlavePingService
if err := c.ShouldBindJSON(&service); err == nil {
res := service.Test()
c.JSON(200, res)
} else {
c.JSON(200, ErrorResponse(err))
}
}

@ -35,6 +35,8 @@ func InitSlaveRouter() *gin.Engine {
*/ */
{ {
// Ping
v3.POST("ping", controllers.SlavePing)
// 上传 // 上传
v3.POST("upload", controllers.SlaveUpload) v3.POST("upload", controllers.SlaveUpload)
// 下载 // 下载
@ -328,6 +330,8 @@ func InitMasterRouter() *gin.Engine {
policy.POST("list", controllers.AdminListPolicy) policy.POST("list", controllers.AdminListPolicy)
// 测试本地路径可用性 // 测试本地路径可用性
policy.POST("test/path", controllers.AdminTestPath) policy.POST("test/path", controllers.AdminTestPath)
// 测试从机通信
policy.POST("test/slave", controllers.AdminTestSlave)
// 创建存储策略 // 创建存储策略
policy.POST("", controllers.AdminAddPolicy) policy.POST("", controllers.AdminAddPolicy)
} }

@ -1,12 +1,19 @@
package admin package admin
import ( import (
"bytes"
"encoding/json"
"fmt" "fmt"
model "github.com/HFO4/cloudreve/models" model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/auth"
"github.com/HFO4/cloudreve/pkg/conf"
"github.com/HFO4/cloudreve/pkg/request"
"github.com/HFO4/cloudreve/pkg/serializer" "github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/pkg/util" "github.com/HFO4/cloudreve/pkg/util"
"net/url"
"os" "os"
"path/filepath" "path/filepath"
"time"
) )
// PathTestService 本地路径测试服务 // PathTestService 本地路径测试服务
@ -14,11 +21,87 @@ type PathTestService struct {
Path string `json:"path" binding:"required"` Path string `json:"path" binding:"required"`
} }
// SlaveTestService 从机测试服务
type SlaveTestService struct {
Secret string `json:"secret" binding:"required"`
Server string `json:"server" binding:"required"`
}
// SlavePingService 从机相应ping
type SlavePingService struct {
Callback string `json:"callback" binding:"required"`
}
// AddPolicyService 存储策略添加服务 // AddPolicyService 存储策略添加服务
type AddPolicyService struct { type AddPolicyService struct {
Policy model.Policy `json:"policy" binding:"required"` Policy model.Policy `json:"policy" binding:"required"`
} }
// Test 从机响应ping
func (service *SlavePingService) Test() serializer.Response {
master, err := url.Parse(service.Callback)
if err != nil {
return serializer.ParamErr("无法解析主机站点地址,请检查主机 参数设置 - 站点信息 - 站点URL设置"+err.Error(), nil)
}
controller, _ := url.Parse("/api/v3/site/ping")
r := request.HTTPClient{}
res, err := r.Request(
"GET",
master.ResolveReference(controller).String(),
nil,
request.WithTimeout(time.Duration(10)*time.Second),
).DecodeResponse()
if err != nil {
return serializer.ParamErr("从机无法向主机发送回调请求,请检查主机端 参数设置 - 站点信息 - 站点URL设置并确保从机可以连接到此地址"+err.Error(), nil)
}
if res.Data.(string) != conf.BackendVersion {
return serializer.ParamErr("Cloudreve版本不一致主机"+res.Data.(string)+",从机:"+conf.BackendVersion, nil)
}
return serializer.Response{}
}
// Test 测试从机通信
func (service *SlaveTestService) Test() serializer.Response {
slave, err := url.Parse(service.Server)
if err != nil {
return serializer.ParamErr("无法解析从机端地址,"+err.Error(), nil)
}
controller, _ := url.Parse("/api/v3/slave/ping")
// 请求正文
body := map[string]string{
"callback": model.GetSiteURL().String(),
}
bodyByte, _ := json.Marshal(body)
r := request.HTTPClient{}
res, err := r.Request(
"POST",
slave.ResolveReference(controller).String(),
bytes.NewReader(bodyByte),
request.WithTimeout(time.Duration(10)*time.Second),
request.WithCredential(
auth.HMACAuth{SecretKey: []byte(service.Secret)},
int64(model.GetIntSetting("slave_api_timeout", 60)),
),
).DecodeResponse()
if err != nil {
return serializer.ParamErr("无连接到从机,"+err.Error(), nil)
}
if res.Code != 0 {
return serializer.ParamErr("成功接到从机,但是"+res.Msg, nil)
}
return serializer.Response{}
}
// Add 添加存储策略 // Add 添加存储策略
func (service *AddPolicyService) Add() serializer.Response { func (service *AddPolicyService) Add() serializer.Response {
if err := model.DB.Create(&service.Policy).Error; err != nil { if err := model.DB.Create(&service.Policy).Error; err != nil {
@ -54,7 +137,7 @@ func (service *AdminListService) Policies() serializer.Response {
} }
for k, v := range service.Conditions { for k, v := range service.Conditions {
tx = tx.Where("? = ?", k, v) tx = tx.Where(k+" = ?", v)
} }
// 计算总数用于分页 // 计算总数用于分页

Loading…
Cancel
Save