Files
panel-vpn/internal/handlers/protocols.go
T

169 lines
4.6 KiB
Go

package handlers
import (
"log"
"net/http"
"github.com/google/uuid"
"github.com/gorilla/mux"
"github.com/orohi/vpn-panel/internal/db"
"github.com/orohi/vpn-panel/internal/models"
"github.com/orohi/vpn-panel/internal/nodeclient"
)
func (s *Server) syncNodeConfig(n *models.Node) error {
cfg, err := db.NodeProtocolConfigPayload(s.DB, n.ID)
if err != nil {
return err
}
return nodeclient.PushConfig(n, cfg)
}
func (s *Server) protocols(w http.ResponseWriter, r *http.Request) {
protocols, err := db.ListProtocolsDetailed(s.DB)
if err != nil {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
nodes, _ := db.ListNodes(s.DB)
s.render(w, "protocols.html", pageData{
"Title": "Протоколы",
"UserName": s.Auth.CurrentName(r),
"Protocols": protocols,
"Nodes": nodes,
"Active": "protocols",
"Flash": r.URL.Query().Get("ok"),
"Error": r.URL.Query().Get("err"),
})
}
func (s *Server) toggleProtocol(w http.ResponseWriter, r *http.Request) {
idStr := mux.Vars(r)["id"]
id, err := uuid.Parse(idStr)
if err != nil {
http.Error(w, "invalid id", http.StatusBadRequest)
return
}
if err := db.ToggleProtocol(s.DB, id); err != nil {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/admin/protocols", http.StatusSeeOther)
}
func (s *Server) nodeProtocolAction(w http.ResponseWriter, r *http.Request) {
nodeID, err := uuid.Parse(mux.Vars(r)["id"])
if err != nil {
http.Error(w, "invalid node id", http.StatusBadRequest)
return
}
protocolID, err := uuid.Parse(mux.Vars(r)["protocolID"])
if err != nil {
http.Error(w, "invalid protocol id", http.StatusBadRequest)
return
}
action := r.FormValue("action")
if action == "" {
_ = r.ParseForm()
action = r.FormValue("action")
}
n, err := db.GetNode(s.DB, nodeID)
if err != nil || n == nil {
http.NotFound(w, r)
return
}
p, err := db.GetProtocol(s.DB, protocolID)
if err != nil || p == nil {
http.NotFound(w, r)
return
}
list, err := db.ListNodeProtocols(s.DB, nodeID)
if err != nil {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
var current models.NodeProtocol
for _, item := range list {
if item.ProtocolID == protocolID {
current = item
break
}
}
installed, enabled := current.Installed, current.Enabled
switch action {
case "install":
installed, enabled = true, true
case "uninstall":
installed, enabled = false, false
case "enable":
installed, enabled = true, true
case "disable":
enabled = false
if !installed {
installed = false
}
default:
http.Redirect(w, r, "/admin/nodes/"+nodeID.String()+"?err=bad_action", http.StatusSeeOther)
return
}
if err := db.SetNodeProtocolFlags(s.DB, nodeID, protocolID, installed, enabled); err != nil {
log.Printf("set node protocol: %v", err)
http.Redirect(w, r, "/admin/nodes/"+nodeID.String()+"?err=proto_save", http.StatusSeeOther)
return
}
// If panel catalog was off and we install/enable — turn protocol on in catalog.
if (action == "install" || action == "enable") && !p.Enabled {
_ = db.SetProtocolEnabled(s.DB, protocolID, true)
}
if action == "uninstall" {
// If nowhere else has it installed, turn catalog off.
detailed, _ := db.ListProtocolsDetailed(s.DB)
for _, item := range detailed {
if item.ID == protocolID && len(item.InstalledOn) == 0 {
_ = db.SetProtocolEnabled(s.DB, protocolID, false)
}
}
}
if n.Status == models.NodeStatusOnline {
if err := s.syncNodeConfig(n); err != nil {
http.Redirect(w, r, "/admin/nodes/"+nodeID.String()+"?err=sync_failed", http.StatusSeeOther)
return
}
}
http.Redirect(w, r, "/admin/nodes/"+nodeID.String()+"?ok=protocol_"+action, http.StatusSeeOther)
}
func (s *Server) nodeSyncProtocols(w http.ResponseWriter, r *http.Request) {
nodeID, err := uuid.Parse(mux.Vars(r)["id"])
if err != nil {
http.Error(w, "invalid id", http.StatusBadRequest)
return
}
n, err := db.GetNode(s.DB, nodeID)
if err != nil || n == nil {
http.NotFound(w, r)
return
}
hr, err := nodeclient.Health(n)
if err != nil {
_ = db.UpdateNodeStatus(s.DB, nodeID, models.NodeStatusOffline, err.Error())
http.Redirect(w, r, "/admin/nodes/"+nodeID.String()+"?err=offline", http.StatusSeeOther)
return
}
_ = db.MarkNodeSeen(s.DB, nodeID, hr.Version, models.NodeStatusOnline)
// Push panel → node (desired state). Do not wipe local DB from empty agent.
if err := s.syncNodeConfig(n); err != nil {
http.Redirect(w, r, "/admin/nodes/"+nodeID.String()+"?err=sync_failed", http.StatusSeeOther)
return
}
http.Redirect(w, r, "/admin/nodes/"+nodeID.String()+"?ok=synced", http.StatusSeeOther)
}