110 lines
3.3 KiB
Go
110 lines
3.3 KiB
Go
package admission
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-admin-team/go-admin-core/sdk/api"
|
|
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
|
|
|
"git.ilapage.cn/ila/yovision/Sense/server/app/sense/credential"
|
|
"git.ilapage.cn/ila/yovision/Sense/server/app/sense/media"
|
|
"git.ilapage.cn/ila/yovision/Sense/server/app/sense/onvif"
|
|
)
|
|
|
|
type API struct{ api.Api }
|
|
|
|
func (e *API) runtime(c *gin.Context) (*Service, error) {
|
|
base := Service{}
|
|
if err := e.MakeContext(c).MakeOrm().MakeService(&base.Service).Errors; err != nil {
|
|
return nil, err
|
|
}
|
|
return NewRuntime(base.Service)
|
|
}
|
|
func (e *API) Discover(c *gin.Context) {
|
|
service, err := e.runtime(c)
|
|
if err != nil {
|
|
e.writeError(err)
|
|
return
|
|
}
|
|
result, err := service.Discover(c.Request.Context())
|
|
if err != nil {
|
|
e.writeError(err)
|
|
return
|
|
}
|
|
e.OK(result, "发现完成")
|
|
}
|
|
func (e *API) Probe(c *gin.Context) {
|
|
service, err := e.runtime(c)
|
|
if err != nil {
|
|
e.writeError(err)
|
|
return
|
|
}
|
|
request := ProbeRequest{DeviceID: c.Param("id"), UpdateBy: user.GetUserId(c)}
|
|
if err = bindStrict(c, &request); err != nil {
|
|
e.Error(http.StatusBadRequest, err, "请求内容格式不正确")
|
|
return
|
|
}
|
|
result, err := service.Probe(c.Request.Context(), request)
|
|
if err != nil {
|
|
e.writeError(err)
|
|
return
|
|
}
|
|
// Media route intent is best-effort and credential-free. A MediaMTX
|
|
// failure must never roll back the verified device/Profile transaction.
|
|
_ = media.EnsureDeviceRoutes(c.Request.Context(), service.Orm, request.DeviceID)
|
|
e.OK(result, "探测完成")
|
|
}
|
|
func (e *API) Get(c *gin.Context) {
|
|
service := &Service{}
|
|
if err := e.MakeContext(c).MakeOrm().MakeService(&service.Service).Errors; err != nil {
|
|
e.writeError(err)
|
|
return
|
|
}
|
|
result, err := service.Get(c.Param("id"))
|
|
if err != nil {
|
|
e.writeError(err)
|
|
return
|
|
}
|
|
e.OK(result, "查询成功")
|
|
}
|
|
func (e *API) writeError(err error) {
|
|
switch {
|
|
case errors.Is(err, ErrInvalid):
|
|
e.Error(http.StatusBadRequest, err, err.Error())
|
|
case errors.Is(err, ErrNotFound):
|
|
e.Error(http.StatusNotFound, err, err.Error())
|
|
case errors.Is(err, ErrConflict):
|
|
e.Error(http.StatusConflict, err, err.Error())
|
|
case errors.Is(err, onvif.ErrDiscoveryNotConfigured), errors.Is(err, onvif.ErrDiscoveryInterface), errors.Is(err, onvif.ErrTargetNotAllowed):
|
|
e.Error(http.StatusBadRequest, err, err.Error())
|
|
case errors.Is(err, credential.ErrCredentialNotConfigured):
|
|
e.Error(http.StatusConflict, err, "请先在设备管理中配置摄像头凭据")
|
|
case errors.Is(err, credential.ErrKeyUnavailable):
|
|
e.Error(http.StatusServiceUnavailable, err, "摄像头凭据安全配置不可用")
|
|
default:
|
|
e.Error(http.StatusInternalServerError, err, "视频接入操作失败")
|
|
}
|
|
}
|
|
func bindStrict(c *gin.Context, target any) error {
|
|
if !strings.HasPrefix(strings.ToLower(strings.TrimSpace(c.GetHeader("Content-Type"))), "application/json") {
|
|
return errors.New("content type must be application/json")
|
|
}
|
|
decoder := json.NewDecoder(http.MaxBytesReader(c.Writer, c.Request.Body, 64<<10))
|
|
decoder.DisallowUnknownFields()
|
|
if err := decoder.Decode(target); err != nil {
|
|
return err
|
|
}
|
|
if err := decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
|
|
if err == nil {
|
|
return errors.New("request body must contain one JSON object")
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
}
|