Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/prism/proxy/internal/proxyio"
|
||||
"github.com/prism/proxy/internal/store"
|
||||
)
|
||||
|
||||
func (s *Server) exportProxies(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
items, err := s.app.Store.ListProxyNodes(ctx, "manual", nil)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
format := strings.ToLower(c.DefaultQuery("format", "json"))
|
||||
filename := "prism-proxies"
|
||||
switch format {
|
||||
case "text", "txt", "links":
|
||||
c.Header("Content-Type", "text/plain; charset=utf-8")
|
||||
c.Header("Content-Disposition", `attachment; filename="`+filename+`.txt"`)
|
||||
c.String(http.StatusOK, proxyio.ExportLinks(items))
|
||||
default:
|
||||
data, err := proxyio.ExportJSON(items)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.Header("Content-Type", "application/json; charset=utf-8")
|
||||
c.Header("Content-Disposition", `attachment; filename="`+filename+`.json"`)
|
||||
c.Data(http.StatusOK, "application/json; charset=utf-8", data)
|
||||
}
|
||||
}
|
||||
|
||||
type importProxiesReq struct {
|
||||
Mode string `json:"mode"`
|
||||
Text string `json:"text"`
|
||||
Nodes []proxyio.ExportNode `json:"nodes"`
|
||||
}
|
||||
|
||||
func (s *Server) importProxies(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
mode := strings.ToLower(strings.TrimSpace(c.DefaultQuery("mode", "")))
|
||||
|
||||
var nodes []store.ProxyNode
|
||||
var parseErrors []string
|
||||
|
||||
contentType := c.GetHeader("Content-Type")
|
||||
if strings.Contains(contentType, "application/json") {
|
||||
var req importProxiesReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if mode == "" {
|
||||
mode = strings.ToLower(strings.TrimSpace(req.Mode))
|
||||
}
|
||||
if len(req.Nodes) > 0 {
|
||||
var valErrors []string
|
||||
nodes, valErrors = proxyio.ToStoreNodes(req.Nodes)
|
||||
parseErrors = append(parseErrors, valErrors...)
|
||||
} else if strings.TrimSpace(req.Text) != "" {
|
||||
nodes, parseErrors = proxyio.ParseText(req.Text)
|
||||
} else {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "nodes or text required"})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
body, err := io.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if mode == "" {
|
||||
mode = "append"
|
||||
}
|
||||
nodes, parseErrors = proxyio.ParseText(string(body))
|
||||
}
|
||||
|
||||
if mode == "" {
|
||||
mode = "append"
|
||||
}
|
||||
if mode != "append" && mode != "replace" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "mode must be append or replace"})
|
||||
return
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "no valid proxies", "errors": parseErrors})
|
||||
return
|
||||
}
|
||||
|
||||
if mode == "append" {
|
||||
existing, _ := s.app.Store.ListProxyNodes(ctx, "manual", nil)
|
||||
proxyio.AssignUniqueNames(nodes, proxyio.ReservedNames(existing))
|
||||
if err := s.app.Store.AppendManualProxies(ctx, nodes); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
proxyio.AssignUniqueNames(nodes, nil)
|
||||
if err := s.app.Store.ReplaceManualProxies(ctx, nodes); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_ = s.app.Store.AddAuditLog(ctx, "import", "proxies", mode+": "+strconv.Itoa(len(nodes)))
|
||||
_ = s.app.ReloadEngine(ctx)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"ok": true,
|
||||
"imported": len(nodes),
|
||||
"skipped": len(parseErrors),
|
||||
"errors": parseErrors,
|
||||
"mode": mode,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user