mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-10 18:05:48 +02:00
feat(wip): node selector supports sse
This commit is contained in:
parent
ed0dca6820
commit
bc70567dc1
31 changed files with 176 additions and 166 deletions
112
api/api.go
112
api/api.go
|
@ -1,15 +1,10 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CurrentUser(c *gin.Context) *model.User {
|
||||
|
@ -23,105 +18,10 @@ func ErrHandler(c *gin.Context, err error) {
|
|||
})
|
||||
}
|
||||
|
||||
type ValidError struct {
|
||||
Key string
|
||||
Message string
|
||||
}
|
||||
|
||||
func BindAndValid(c *gin.Context, target interface{}) bool {
|
||||
err := c.ShouldBindJSON(target)
|
||||
if err != nil {
|
||||
logger.Error("bind err", err)
|
||||
|
||||
var verrs validator.ValidationErrors
|
||||
ok := errors.As(err, &verrs)
|
||||
|
||||
if !ok {
|
||||
c.JSON(http.StatusNotAcceptable, gin.H{
|
||||
"message": "Requested with wrong parameters",
|
||||
"code": http.StatusNotAcceptable,
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(target).Elem()
|
||||
errorsMap := make(map[string]interface{})
|
||||
for _, value := range verrs {
|
||||
var path []string
|
||||
|
||||
namespace := strings.Split(value.StructNamespace(), ".")
|
||||
// logger.Debug(t.Name(), namespace)
|
||||
if t.Name() != "" && len(namespace) > 1 {
|
||||
namespace = namespace[1:]
|
||||
}
|
||||
|
||||
getJsonPath(t, namespace, &path)
|
||||
insertError(errorsMap, path, value.Tag())
|
||||
}
|
||||
|
||||
c.JSON(http.StatusNotAcceptable, gin.H{
|
||||
"errors": errorsMap,
|
||||
"message": "Requested with wrong parameters",
|
||||
"code": http.StatusNotAcceptable,
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// findField recursively finds the field in a nested struct
|
||||
func getJsonPath(t reflect.Type, fields []string, path *[]string) {
|
||||
field := fields[0]
|
||||
// used in case of array
|
||||
var index string
|
||||
if field[len(field)-1] == ']' {
|
||||
re := regexp.MustCompile(`(\w+)\[(\d+)\]`)
|
||||
matches := re.FindStringSubmatch(field)
|
||||
|
||||
if len(matches) > 2 {
|
||||
field = matches[1]
|
||||
index = matches[2]
|
||||
}
|
||||
}
|
||||
|
||||
f, ok := t.FieldByName(field)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
*path = append(*path, f.Tag.Get("json"))
|
||||
|
||||
if index != "" {
|
||||
*path = append(*path, index)
|
||||
}
|
||||
|
||||
if len(fields) > 1 {
|
||||
subFields := fields[1:]
|
||||
getJsonPath(f.Type, subFields, path)
|
||||
}
|
||||
}
|
||||
|
||||
// insertError inserts an error into the errors map
|
||||
func insertError(errorsMap map[string]interface{}, path []string, errorTag string) {
|
||||
if len(path) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
jsonTag := path[0]
|
||||
if len(path) == 1 {
|
||||
// Last element in the path, set the error
|
||||
errorsMap[jsonTag] = errorTag
|
||||
return
|
||||
}
|
||||
|
||||
// Create a new map if necessary
|
||||
if _, ok := errorsMap[jsonTag]; !ok {
|
||||
errorsMap[jsonTag] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// Recursively insert into the nested map
|
||||
subMap, _ := errorsMap[jsonTag].(map[string]interface{})
|
||||
insertError(subMap, path[1:], errorTag)
|
||||
func SetSSEHeaders(c *gin.Context) {
|
||||
c.Header("Content-Type", "text/event-stream")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Header("Connection", "keep-alive")
|
||||
// https://stackoverflow.com/questions/27898622/server-sent-events-stopped-work-after-enabling-ssl-on-proxy/27960243#27960243
|
||||
c.Header("X-Accel-Buffering", "no")
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ type certJson struct {
|
|||
func AddCert(c *gin.Context) {
|
||||
var json certJson
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ func ModifyCert(c *gin.Context) {
|
|||
|
||||
var json certJson
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ func RemoveCert(c *gin.Context) {
|
|||
func SyncCertificate(c *gin.Context) {
|
||||
var json cert.SyncCertificatePayload
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ type DnsCredentialManageJson struct {
|
|||
|
||||
func AddDnsCredential(c *gin.Context) {
|
||||
var json DnsCredentialManageJson
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ func EditDnsCredential(c *gin.Context) {
|
|||
id := cast.ToUint64(c.Param("id"))
|
||||
|
||||
var json DnsCredentialManageJson
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package cluster
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
||||
"github.com/0xJacky/Nginx-UI/internal/cluster"
|
||||
|
@ -11,7 +14,9 @@ import (
|
|||
"github.com/spf13/cast"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"gorm.io/gorm"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetEnvironment(c *gin.Context) {
|
||||
|
@ -44,6 +49,85 @@ func GetEnvironmentList(c *gin.Context) {
|
|||
}).PagingList()
|
||||
}
|
||||
|
||||
func GetAllEnabledEnvironment(c *gin.Context) {
|
||||
api.SetSSEHeaders(c)
|
||||
notify := c.Writer.CloseNotify()
|
||||
|
||||
interval := 10
|
||||
|
||||
type respEnvironment struct {
|
||||
*model.Environment
|
||||
Status bool `json:"status"`
|
||||
}
|
||||
|
||||
f := func() (any, bool) {
|
||||
return cosy.Core[model.Environment](c).
|
||||
SetFussy("name").
|
||||
SetTransformer(func(m *model.Environment) any {
|
||||
resp := respEnvironment{
|
||||
Environment: m,
|
||||
Status: analytic.GetNode(m).Status,
|
||||
}
|
||||
return resp
|
||||
}).ListAllData()
|
||||
}
|
||||
|
||||
getHash := func(data any) string {
|
||||
bytes, _ := json.Marshal(data)
|
||||
hash := sha256.New()
|
||||
hash.Write(bytes)
|
||||
hashSum := hash.Sum(nil)
|
||||
return hex.EncodeToString(hashSum)
|
||||
}
|
||||
|
||||
dataHash := ""
|
||||
|
||||
{
|
||||
data, ok := f()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
c.SSEvent("message", data)
|
||||
dataHash = getHash(data)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Duration(interval) * time.Second):
|
||||
data, ok := f()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// if data is not changed, send heartbeat
|
||||
if dataHash == getHash(data) {
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
c.SSEvent("heartbeat", "")
|
||||
return false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
dataHash = getHash(data)
|
||||
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
c.SSEvent("message", data)
|
||||
return false
|
||||
})
|
||||
case <-time.After(30 * time.Second):
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
c.SSEvent("heartbeat", "")
|
||||
return false
|
||||
})
|
||||
case <-notify:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AddEnvironment(c *gin.Context) {
|
||||
cosy.Core[model.Environment](c).SetValidRules(gin.H{
|
||||
"name": "required",
|
||||
|
|
|
@ -5,6 +5,7 @@ import "github.com/gin-gonic/gin"
|
|||
func InitRouter(r *gin.RouterGroup) {
|
||||
// Environment
|
||||
r.GET("environments", GetEnvironmentList)
|
||||
r.GET("environments/enabled", GetAllEnabledEnvironment)
|
||||
r.POST("environments/load_from_settings", LoadEnvironmentFromSettings)
|
||||
envGroup := r.Group("environments")
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -24,7 +25,7 @@ func AddConfig(c *gin.Context) {
|
|||
SyncNodeIds []uint64 `json:"sync_node_ids"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/internal/helper"
|
||||
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
@ -14,7 +15,7 @@ func Mkdir(c *gin.Context) {
|
|||
BasePath string `json:"base_path"`
|
||||
FolderName string `json:"folder_name"`
|
||||
}
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
fullPath := nginx.GetConfPath(json.BasePath, json.FolderName)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -26,7 +27,7 @@ func EditConfig(c *gin.Context) {
|
|||
SyncOverwrite bool `json:"sync_overwrite"`
|
||||
SyncNodeIds []uint64 `json:"sync_node_ids"`
|
||||
}
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -21,8 +23,7 @@ func Rename(c *gin.Context) {
|
|||
NewName string `json:"new_name"`
|
||||
SyncNodeIds []uint64 `json:"sync_node_ids" gorm:"serializer:json"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,13 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func BuildNginxConfig(c *gin.Context) {
|
||||
var ngxConf nginx.NgxConfig
|
||||
if !api.BindAndValid(c, &ngxConf) {
|
||||
if !cosy.BindAndValid(c, &ngxConf) {
|
||||
return
|
||||
}
|
||||
content, err := ngxConf.BuildConfig()
|
||||
|
@ -27,7 +28,7 @@ func TokenizeNginxConfig(c *gin.Context) {
|
|||
Content string `json:"content" binding:"required"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,7 @@ func FormatNginxConfig(c *gin.Context) {
|
|||
Content string `json:"content" binding:"required"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
content, err := nginx.FmtCode(json.Content)
|
||||
|
|
|
@ -3,7 +3,6 @@ package nginx
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/internal/cache"
|
||||
"github.com/0xJacky/Nginx-UI/internal/helper"
|
||||
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
||||
|
@ -13,6 +12,7 @@ import (
|
|||
"github.com/hpcloud/tail"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -44,7 +44,7 @@ func GetNginxLogPage(c *gin.Context) {
|
|||
}
|
||||
|
||||
var control controlStruct
|
||||
if !api.BindAndValid(c, &control) {
|
||||
if !cosy.BindAndValid(c, &control) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/internal/notification"
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -9,11 +10,7 @@ import (
|
|||
)
|
||||
|
||||
func Live(c *gin.Context) {
|
||||
c.Header("Content-Type", "text/event-stream")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Header("Connection", "keep-alive")
|
||||
// https://stackoverflow.com/questions/27898622/server-sent-events-stopped-work-after-enabling-ssl-on-proxy/27960243#27960243
|
||||
c.Header("X-Accel-Buffering", "no")
|
||||
api.SetSSEHeaders(c)
|
||||
|
||||
evtChan := make(chan *model.Notification)
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ package openai
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/internal/chatbot"
|
||||
"github.com/0xJacky/Nginx-UI/internal/transport"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -26,7 +26,7 @@ func MakeChatCompletionRequest(c *gin.Context) {
|
|||
Messages []openai.ChatCompletionMessage `json:"messages"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -15,7 +16,7 @@ func StoreChatGPTRecord(c *gin.Context) {
|
|||
Messages []openai.ChatCompletionMessage `json:"messages"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package settings
|
||||
|
||||
import (
|
||||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ func GetBanLoginIP(c *gin.Context) {
|
|||
b.ExpiredAt.Gte(time.Now().Unix()),
|
||||
b.Attempts.Gte(settings.AuthSettings.MaxAttempts)).Find()
|
||||
if err != nil {
|
||||
api.ErrHandler(c, err)
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, banIps)
|
||||
|
@ -29,7 +29,7 @@ func RemoveBannedIP(c *gin.Context) {
|
|||
var json struct {
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ func RemoveBannedIP(c *gin.Context) {
|
|||
_, err := b.Where(b.IP.Eq(json.IP)).Delete()
|
||||
|
||||
if err != nil {
|
||||
api.ErrHandler(c, err)
|
||||
cosy.ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
cSettings "github.com/uozi-tech/cosy/settings"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -68,7 +69,7 @@ func SaveSettings(c *gin.Context) {
|
|||
Logrotate settings.Logrotate `json:"logrotate"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -13,7 +14,7 @@ func DomainEditByAdvancedMode(c *gin.Context) {
|
|||
Advanced bool `json:"advanced"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -19,7 +20,7 @@ func AddDomainToAutoCert(c *gin.Context) {
|
|||
KeyType certcrypto.KeyType `json:"key_type"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/api"
|
||||
"github.com/0xJacky/Nginx-UI/internal/site"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -16,7 +17,7 @@ func DuplicateSite(c *gin.Context) {
|
|||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ func SaveSite(c *gin.Context) {
|
|||
Overwrite bool `json:"overwrite"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -13,7 +14,7 @@ func AdvancedEdit(c *gin.Context) {
|
|||
Advanced bool `json:"advanced"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/internal/helper"
|
||||
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -17,7 +18,7 @@ func Duplicate(c *gin.Context) {
|
|||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -174,7 +175,7 @@ func SaveStream(c *gin.Context) {
|
|||
Overwrite bool `json:"overwrite"`
|
||||
}
|
||||
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/uozi-tech/cosy"
|
||||
cSettings "github.com/uozi-tech/cosy/settings"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"net/http"
|
||||
|
@ -39,7 +40,7 @@ func InstallNginxUI(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
var json InstallJson
|
||||
ok := api.BindAndValid(c, &json)
|
||||
ok := cosy.BindAndValid(c, &json)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
"github.com/google/uuid"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -71,7 +72,7 @@ func Start2FASecureSessionByOTP(c *gin.Context) {
|
|||
OTP string `json:"otp"`
|
||||
RecoveryCode string `json:"recovery_code"`
|
||||
}
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
u := api.CurrentUser(c)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"github.com/uozi-tech/cosy/logger"
|
||||
"math/rand/v2"
|
||||
"net/http"
|
||||
|
@ -61,7 +62,7 @@ func Login(c *gin.Context) {
|
|||
}
|
||||
|
||||
var json LoginUser
|
||||
ok := api.BindAndValid(c, &json)
|
||||
ok := cosy.BindAndValid(c, &json)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -22,7 +23,7 @@ type CasdoorLoginUser struct {
|
|||
func CasdoorCallback(c *gin.Context) {
|
||||
var loginUser CasdoorLoginUser
|
||||
|
||||
ok := api.BindAndValid(c, &loginUser)
|
||||
ok := cosy.BindAndValid(c, &loginUser)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
"github.com/pquerna/otp"
|
||||
"github.com/pquerna/otp/totp"
|
||||
"github.com/uozi-tech/cosy"
|
||||
"image/jpeg"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -81,7 +82,7 @@ func EnrollTOTP(c *gin.Context) {
|
|||
Secret string `json:"secret" binding:"required"`
|
||||
Passcode string `json:"passcode" binding:"required"`
|
||||
}
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -117,7 +118,7 @@ func ResetOTP(c *gin.Context) {
|
|||
var json struct {
|
||||
RecoveryCode string `json:"recovery_code"`
|
||||
}
|
||||
if !api.BindAndValid(c, &json) {
|
||||
if !cosy.BindAndValid(c, &json) {
|
||||
return
|
||||
}
|
||||
recoverCode, err := hex.DecodeString(json.RecoveryCode)
|
||||
|
|
|
@ -38,7 +38,7 @@ type UserJson struct {
|
|||
|
||||
func AddUser(c *gin.Context) {
|
||||
var json UserJson
|
||||
ok := api.BindAndValid(c, &json)
|
||||
ok := cosy.BindAndValid(c, &json)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func EditUser(c *gin.Context) {
|
|||
}
|
||||
|
||||
var json UserJson
|
||||
ok := api.BindAndValid(c, &json)
|
||||
ok := cosy.BindAndValid(c, &json)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type { Environment } from '@/api/environment'
|
||||
import type { Ref } from 'vue'
|
||||
import environment from '@/api/environment'
|
||||
import { useUserStore } from '@/pinia'
|
||||
import { SSE, type SSEvent } from 'sse.js'
|
||||
|
||||
const props = defineProps<{
|
||||
hiddenLocal?: boolean
|
||||
|
@ -9,26 +10,35 @@ const props = defineProps<{
|
|||
|
||||
const target = defineModel<number[]>('target')
|
||||
const map = defineModel<Record<number, string>>('map')
|
||||
const { token } = storeToRefs(useUserStore())
|
||||
|
||||
const data = ref([]) as Ref<Environment[]>
|
||||
const data_map = ref({}) as Ref<Record<number, Environment>>
|
||||
|
||||
onMounted(async () => {
|
||||
let hasMore = true
|
||||
let page = 1
|
||||
while (hasMore) {
|
||||
await environment.get_list({ page, enabled: true }).then(r => {
|
||||
data.value.push(...r.data)
|
||||
r.data?.forEach(node => {
|
||||
data_map.value[node.id] = node
|
||||
})
|
||||
hasMore = r.data.length === r.pagination?.per_page
|
||||
page++
|
||||
}).catch(() => {
|
||||
hasMore = false
|
||||
})
|
||||
const sse = shallowRef(newSSE())
|
||||
|
||||
function reconnect() {
|
||||
setTimeout(() => {
|
||||
sse.value = newSSE()
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
function newSSE() {
|
||||
const s = new SSE('/api/environments/enabled', {
|
||||
headers: {
|
||||
Authorization: token.value,
|
||||
},
|
||||
})
|
||||
|
||||
s.onmessage = (e: SSEvent) => {
|
||||
data.value = JSON.parse(e.data)
|
||||
}
|
||||
})
|
||||
|
||||
// reconnect
|
||||
s.onerror = reconnect
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
const value = computed({
|
||||
get() {
|
||||
|
|
|
@ -35,7 +35,7 @@ function batchUpgrade() {
|
|||
:api="environment"
|
||||
:columns="envColumns"
|
||||
>
|
||||
<template #extra>
|
||||
<template #beforeAdd>
|
||||
<a @click="loadFromSettings">{{ $gettext('Load from settings') }}</a>
|
||||
</template>
|
||||
</StdCurd>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue