| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- package service
- import (
- "fmt"
- "strings"
- "github.com/mhsanaei/3x-ui/v3/database"
- "github.com/mhsanaei/3x-ui/v3/database/model"
- "gorm.io/gorm"
- )
- type FallbackService struct{}
- // FallbackInput is the payload shape POSTed by the inbound form.
- type FallbackInput struct {
- ChildId int `json:"childId"`
- Name string `json:"name"`
- Alpn string `json:"alpn"`
- Path string `json:"path"`
- Xver int `json:"xver"`
- SortOrder int `json:"sortOrder"`
- }
- // GetByMaster returns every fallback rule attached to the master inbound.
- func (s *FallbackService) GetByMaster(masterId int) ([]model.InboundFallback, error) {
- var rows []model.InboundFallback
- err := database.GetDB().
- Where("master_id = ?", masterId).
- Order("sort_order ASC, id ASC").
- Find(&rows).Error
- if err != nil {
- return nil, err
- }
- return rows, nil
- }
- // GetParentForChild finds the first fallback rule that points at childId.
- // Used by client-link generation: when a child inbound is attached as a
- // fallback, its client links should advertise the master's address+port
- // and TLS instead of the child's loopback listen.
- func (s *FallbackService) GetParentForChild(childId int) (*model.InboundFallback, error) {
- var row model.InboundFallback
- err := database.GetDB().
- Where("child_id = ?", childId).
- Order("sort_order ASC, id ASC").
- First(&row).Error
- if err == gorm.ErrRecordNotFound {
- return nil, nil
- }
- if err != nil {
- return nil, err
- }
- return &row, nil
- }
- // SetByMaster replaces the master's entire fallback list atomically.
- func (s *FallbackService) SetByMaster(masterId int, items []FallbackInput) error {
- db := database.GetDB()
- return db.Transaction(func(tx *gorm.DB) error {
- if err := tx.Where("master_id = ?", masterId).Delete(&model.InboundFallback{}).Error; err != nil {
- return err
- }
- for i, c := range items {
- if c.ChildId <= 0 || c.ChildId == masterId {
- continue
- }
- row := model.InboundFallback{
- MasterId: masterId,
- ChildId: c.ChildId,
- Name: c.Name,
- Alpn: c.Alpn,
- Path: c.Path,
- Xver: c.Xver,
- SortOrder: c.SortOrder,
- }
- if row.SortOrder == 0 {
- row.SortOrder = i
- }
- if err := tx.Create(&row).Error; err != nil {
- return err
- }
- }
- return nil
- })
- }
- // BuildFallbacksJSON resolves the master's fallback rows into Xray's
- // expected settings.fallbacks shape, looking up each child's listen+port
- // to fill the dest field. Returns nil when the master has no rules.
- func (s *FallbackService) BuildFallbacksJSON(tx *gorm.DB, masterId int) ([]map[string]any, error) {
- if tx == nil {
- tx = database.GetDB()
- }
- var rows []model.InboundFallback
- err := tx.Where("master_id = ?", masterId).
- Order("sort_order ASC, id ASC").
- Find(&rows).Error
- if err != nil {
- return nil, err
- }
- if len(rows) == 0 {
- return nil, nil
- }
- childIds := make([]int, 0, len(rows))
- for i := range rows {
- childIds = append(childIds, rows[i].ChildId)
- }
- var children []model.Inbound
- if err := tx.Where("id IN ?", childIds).Find(&children).Error; err != nil {
- return nil, err
- }
- byId := make(map[int]*model.Inbound, len(children))
- for i := range children {
- byId[children[i].Id] = &children[i]
- }
- out := make([]map[string]any, 0, len(rows))
- for _, r := range rows {
- child, ok := byId[r.ChildId]
- if !ok {
- continue
- }
- listen := strings.TrimSpace(child.Listen)
- if listen == "" || listen == "0.0.0.0" || listen == "::" || listen == "::0" {
- listen = "127.0.0.1"
- }
- entry := map[string]any{
- "dest": fmt.Sprintf("%s:%d", listen, child.Port),
- }
- if r.Name != "" {
- entry["name"] = r.Name
- }
- if r.Alpn != "" {
- entry["alpn"] = r.Alpn
- }
- if r.Path != "" {
- entry["path"] = r.Path
- }
- if r.Xver > 0 {
- entry["xver"] = r.Xver
- }
- out = append(out, entry)
- }
- return out, nil
- }
|