mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-06 02:17:14 +00:00
feat(amneziawg): swap the app's integration points to the embedded manager
Hard cutover, part 2: every real call site that used to drive internal/amneziawg's kernel-module Manager now drives internal/amneziawgnet's instead -- - internal/web/job/amneziawg_job.go: the reconcile cron job. Traffic/ online-status accounting is dropped entirely (not ported) -- once a peer's traffic is relayed through Xray's own SOCKS5 inbound, it's an ordinary Xray user and XrayTrafficJob's existing generic stats polling already handles it, with zero AmneziaWG-specific code. - internal/web/runtime/local.go: the immediate-apply CRUD path (AddInbound/DelInbound/updateAmneziaWGInbound). - internal/web/web.go: panel shutdown's StopAll. internal/amneziawgnet.Manager gains Remove(id) to match the kernel-module Manager's shape at these call sites (Reconcile alone doesn't cover a single-inbound removal outside a full reconcile pass). internal/web/service/inbound_amneziawg.go's applyLocalAmneziaWG needed no change: it already goes through runtime.Runtime.UpdateInbound, which now resolves to the updated local.go path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -203,6 +203,23 @@ func (m *Manager) Reconcile(desired []Desired) {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove tears down inbound id's embedded interface, if any -- mirrors
|
||||
// internal/amneziawg.Manager.Remove, for a caller that needs to drop a
|
||||
// single inbound outside a full Reconcile pass (e.g. the immediate-apply
|
||||
// CRUD path in internal/web/runtime/local.go).
|
||||
func (m *Manager) Remove(id int) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
cur, exists := m.ifaces[id]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
cur.udpRelay.Close()
|
||||
cur.dev.Close()
|
||||
delete(m.ifaces, id)
|
||||
logger.Infof("amneziawgnet: stopped embedded interface for removed inbound %d", id)
|
||||
}
|
||||
|
||||
// StopAll tears down every managed interface. Called on panel shutdown.
|
||||
func (m *Manager) StopAll() {
|
||||
m.mu.Lock()
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
package job
|
||||
|
||||
import (
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawgnet"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
)
|
||||
|
||||
// AmneziaWGJob reconciles the running AmneziaWG interfaces against the
|
||||
// enabled AmneziaWG inbounds in the database, restarts/reloads any that
|
||||
// drifted, and folds the per-peer traffic scraped from `awg show dump` into
|
||||
// the usual client and inbound traffic accounting. Mirrors MtprotoJob.
|
||||
// AmneziaWGJob reconciles the running embedded AmneziaWG interfaces
|
||||
// (internal/amneziawgnet -- amneziawg-go over a gVisor netstack, no kernel
|
||||
// module) against the enabled AmneziaWG inbounds in the database,
|
||||
// rebuilding/reconfiguring any that drifted. Unlike the retired
|
||||
// kernel-module Manager this job used to drive, there is no traffic/
|
||||
// online-status accounting here at all: once a peer's decapsulated traffic
|
||||
// is relayed into Xray's own SOCKS5 inbound (see
|
||||
// internal/web/service/xray.go's injectAmneziawgnetSocks, and
|
||||
// internal/amneziawgnet.Manager's automatic forwarder/relay wiring), it's
|
||||
// an ordinary Xray user, and XrayTrafficJob's existing, protocol-blind
|
||||
// stats/online-status polling already picks it up for free.
|
||||
type AmneziaWGJob struct {
|
||||
inboundService service.InboundService
|
||||
// warnedMissing tracks whether the "awg/awg-quick not found" warning has
|
||||
// already been logged, so a host without the AmneziaWG kernel module
|
||||
// (RHEL, Arch, a container, or a failed install.sh PPA step) logs it
|
||||
// once instead of every @every-10s tick forever.
|
||||
warnedMissing bool
|
||||
}
|
||||
|
||||
// NewAmneziaWGJob creates a new AmneziaWG reconcile/traffic job instance.
|
||||
// NewAmneziaWGJob creates a new AmneziaWG reconcile job instance.
|
||||
func NewAmneziaWGJob() *AmneziaWGJob {
|
||||
return new(AmneziaWGJob)
|
||||
}
|
||||
|
||||
// Run reconciles desired AmneziaWG inbounds with running interfaces and
|
||||
// records per-peer traffic deltas and online status.
|
||||
// Run reconciles desired AmneziaWG inbounds with running embedded interfaces.
|
||||
func (j *AmneziaWGJob) Run() {
|
||||
desired, err := j.inboundService.DesiredAmneziaWGInstances()
|
||||
if err != nil {
|
||||
@@ -35,59 +34,9 @@ func (j *AmneziaWGJob) Run() {
|
||||
return
|
||||
}
|
||||
|
||||
// Only relevant once an admin actually has an AmneziaWG inbound: no
|
||||
// point warning about a missing binary the panel never needed to touch.
|
||||
if len(desired) > 0 && !amneziawg.IsAwgInstalled() {
|
||||
if !j.warnedMissing {
|
||||
j.warnedMissing = true
|
||||
logger.Warningf("amneziawg job: %d AmneziaWG inbound(s) configured but awg/awg-quick not found on PATH; skipping reconcile until installed", len(desired))
|
||||
}
|
||||
return
|
||||
}
|
||||
j.warnedMissing = false
|
||||
|
||||
activeTags := make([]string, 0, len(desired))
|
||||
wanted := make([]amneziawgnet.Desired, 0, len(desired))
|
||||
for _, inst := range desired {
|
||||
activeTags = append(activeTags, inst.Tag)
|
||||
wanted = append(wanted, amneziawgnet.Desired{Instance: inst})
|
||||
}
|
||||
|
||||
mgr := amneziawg.GetManager()
|
||||
mgr.Reconcile(desired)
|
||||
|
||||
deltas, onlineEmails := mgr.CollectTraffic()
|
||||
|
||||
clientTraffics := make([]*xray.ClientTraffic, 0, len(deltas))
|
||||
inboundUp := make(map[string]int64)
|
||||
inboundDown := make(map[string]int64)
|
||||
for _, d := range deltas {
|
||||
clientTraffics = append(clientTraffics, &xray.ClientTraffic{
|
||||
Email: d.Email,
|
||||
Up: d.Up,
|
||||
Down: d.Down,
|
||||
})
|
||||
inboundUp[d.Tag] += d.Up
|
||||
inboundDown[d.Tag] += d.Down
|
||||
}
|
||||
|
||||
traffics := make([]*xray.Traffic, 0, len(inboundUp))
|
||||
for tag, up := range inboundUp {
|
||||
traffics = append(traffics, &xray.Traffic{
|
||||
IsInbound: true,
|
||||
Tag: tag,
|
||||
Up: up,
|
||||
Down: inboundDown[tag],
|
||||
})
|
||||
}
|
||||
|
||||
if len(traffics) > 0 || len(clientTraffics) > 0 {
|
||||
if _, _, err := j.inboundService.AddTraffic(traffics, clientTraffics); err != nil {
|
||||
logger.Warning("amneziawg job: add traffic failed:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Live speed: AmneziaWG never runs inside xray-core, so XrayTrafficJob's
|
||||
// own 5s broadcast never mentions these tags. See sidecar_traffic.go.
|
||||
broadcastSidecarTraffic(string(model.AmneziaWG), traffics, clientTraffics)
|
||||
|
||||
j.inboundService.RefreshLocalOnlineClients(onlineEmails, activeTags)
|
||||
amneziawgnet.GetManager().Reconcile(wanted)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawgnet"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/mtproto"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -59,7 +60,7 @@ func (l *Local) AddInbound(_ context.Context, ib *model.Inbound) error {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return amneziawg.GetManager().Ensure(inst)
|
||||
return amneziawgnet.GetManager().Ensure(amneziawgnet.Desired{Instance: inst})
|
||||
}
|
||||
body, err := json.MarshalIndent(ib.GenXrayInboundConfig(), "", " ")
|
||||
if err != nil {
|
||||
@@ -76,7 +77,7 @@ func (l *Local) DelInbound(_ context.Context, ib *model.Inbound) error {
|
||||
return nil
|
||||
}
|
||||
if ib.Protocol == model.AmneziaWG {
|
||||
amneziawg.GetManager().Remove(ib.Id)
|
||||
amneziawgnet.GetManager().Remove(ib.Id)
|
||||
return nil
|
||||
}
|
||||
return l.withAPI(func(api *xray.XrayAPI) error {
|
||||
@@ -130,11 +131,12 @@ func (l *Local) updateMtprotoInbound(ctx context.Context, oldIb, newIb *model.In
|
||||
// updateAmneziaWGInbound mirrors updateMtprotoInbound: it skips the
|
||||
// Remove+Ensure sequence a plain Del+Add would force so that, on an
|
||||
// AmneziaWG-to-AmneziaWG edit, Manager.Ensure's own fingerprint comparison
|
||||
// can pick a peers-only `syncconf` instead of always bouncing the interface
|
||||
// (see internal/amneziawg.Manager.ensureLocked).
|
||||
// can reconfigure the running embedded Device in place via IpcSet instead
|
||||
// of always rebuilding it (see internal/amneziawgnet.Manager.ensureLocked --
|
||||
// only an address/MTU change forces a rebuild there, not a peer edit).
|
||||
func (l *Local) updateAmneziaWGInbound(ctx context.Context, oldIb, newIb *model.Inbound) error {
|
||||
if oldIb.Protocol == model.AmneziaWG && newIb.Protocol != model.AmneziaWG {
|
||||
amneziawg.GetManager().Remove(oldIb.Id)
|
||||
amneziawgnet.GetManager().Remove(oldIb.Id)
|
||||
if !newIb.Enable {
|
||||
return nil
|
||||
}
|
||||
@@ -144,15 +146,15 @@ func (l *Local) updateAmneziaWGInbound(ctx context.Context, oldIb, newIb *model.
|
||||
_ = l.DelInbound(ctx, oldIb)
|
||||
}
|
||||
if !newIb.Enable {
|
||||
amneziawg.GetManager().Remove(newIb.Id)
|
||||
amneziawgnet.GetManager().Remove(newIb.Id)
|
||||
return nil
|
||||
}
|
||||
inst, ok := amneziawg.InstanceFromInbound(newIb)
|
||||
if !ok {
|
||||
amneziawg.GetManager().Remove(newIb.Id)
|
||||
amneziawgnet.GetManager().Remove(newIb.Id)
|
||||
return nil
|
||||
}
|
||||
return amneziawg.GetManager().Ensure(inst)
|
||||
return amneziawgnet.GetManager().Ensure(amneziawgnet.Desired{Instance: inst})
|
||||
}
|
||||
|
||||
func (l *Local) AddUser(_ context.Context, ib *model.Inbound, userMap map[string]any) error {
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawgnet"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/eventbus"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
@@ -689,7 +689,7 @@ func (s *Server) stop(stopXray bool, stopTgBot bool) error {
|
||||
if stopXray {
|
||||
_ = s.xrayService.StopXray()
|
||||
mtproto.GetManager().StopAll()
|
||||
amneziawg.GetManager().StopAll()
|
||||
amneziawgnet.GetManager().StopAll()
|
||||
}
|
||||
if s.cron != nil {
|
||||
s.cron.Stop()
|
||||
|
||||
Reference in New Issue
Block a user