diff options
| author | Ali Golzar <57574919+aliglzr@users.noreply.github.com> | 2025-05-21 13:04:38 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-21 13:04:38 +0300 |
| commit | 3850e2f070bb3c1227b78dcd1e8a34a89a9e9906 (patch) | |
| tree | 3a29b65f47f382494b669b29f7c8695f66527df4 /web/service/inbound.go | |
| parent | 1b1cbfff422e6de58a6f524336b19ec809eb45f0 (diff) | |
feat: Add MySQL database support (#3024)MySQL-databases
* feat: Add MySQL database support
- Add MySQL database support with environment-based configuration
- Fix MySQL compatibility issue with 'key' column name
- Maintain SQLite as default database
- Add proper validation for MySQL configuration
- Test and verify compatibility with existing database
- Replaced raw SQL queries using JSON_EACH functions with standard GORM queries
- Modified functions to handle JSON parsing in Go code instead of database since JSON_EACH is not available on MySQL or MariaDB:
- getAllEmails()
- GetClientTrafficByID()
- getFallbackMaster()
- MigrationRemoveOrphanedTraffics()
The system now supports both MySQL and SQLite databases, with SQLite remaining as the default option. MySQL connection is only used when explicitly configured through environment variables.
* refactor: prefix env variables of database with XUI_ to support direct environment usage without .env file
All database configuration environment variables now start with the XUI_ prefix to avoid conflicts and allow configuration via system-level environment variables, not just the .env file.
Diffstat (limited to 'web/service/inbound.go')
| -rw-r--r-- | web/service/inbound.go | 108 |
1 files changed, 84 insertions, 24 deletions
diff --git a/web/service/inbound.go b/web/service/inbound.go index f2646dbb..17a65b65 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -87,15 +87,24 @@ func (s *InboundService) GetClients(inbound *model.Inbound) ([]model.Client, err func (s *InboundService) getAllEmails() ([]string, error) { db := database.GetDB() - var emails []string - err := db.Raw(` - SELECT JSON_EXTRACT(client.value, '$.email') - FROM inbounds, - JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client - `).Scan(&emails).Error + var inbounds []*model.Inbound + err := db.Model(model.Inbound{}).Find(&inbounds).Error if err != nil { return nil, err } + + var emails []string + for _, inbound := range inbounds { + clients, err := s.GetClients(inbound) + if err != nil { + continue + } + for _, client := range clients { + if client.Email != "" { + emails = append(emails, client.Email) + } + } + } return emails, nil } @@ -1120,14 +1129,46 @@ func (s *InboundService) GetInboundTags() (string, error) { func (s *InboundService) MigrationRemoveOrphanedTraffics() { db := database.GetDB() - db.Exec(` - DELETE FROM client_traffics - WHERE email NOT IN ( - SELECT JSON_EXTRACT(client.value, '$.email') - FROM inbounds, - JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client - ) - `) + + // Get all inbounds + var inbounds []*model.Inbound + err := db.Model(model.Inbound{}).Find(&inbounds).Error + if err != nil { + logger.Error("Failed to get inbounds:", err) + return + } + + // Collect all valid emails from inbounds + validEmails := make(map[string]bool) + for _, inbound := range inbounds { + clients, err := s.GetClients(inbound) + if err != nil { + continue + } + for _, client := range clients { + if client.Email != "" { + validEmails[client.Email] = true + } + } + } + + // Get all client traffics + var traffics []xray.ClientTraffic + err = db.Model(xray.ClientTraffic{}).Find(&traffics).Error + if err != nil { + logger.Error("Failed to get client traffics:", err) + return + } + + // Delete traffics with emails not in validEmails + for _, traffic := range traffics { + if !validEmails[traffic.Email] { + err = db.Delete(&traffic).Error + if err != nil { + logger.Error("Failed to delete orphaned traffic:", err) + } + } + } } func (s *InboundService) AddClientStat(tx *gorm.DB, inboundId int, client *model.Client) error { @@ -1789,19 +1830,38 @@ func (s *InboundService) GetClientTrafficByID(id string) ([]xray.ClientTraffic, db := database.GetDB() var traffics []xray.ClientTraffic - err := db.Model(xray.ClientTraffic{}).Where(`email IN( - SELECT JSON_EXTRACT(client.value, '$.email') as email - FROM inbounds, - JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client - WHERE - JSON_EXTRACT(client.value, '$.id') in (?) - )`, id).Find(&traffics).Error - + // First get all inbounds + var inbounds []*model.Inbound + err := db.Model(model.Inbound{}).Find(&inbounds).Error if err != nil { - logger.Debug(err) return nil, err } - return traffics, err + + // Collect all emails that match the ID + var targetEmails []string + for _, inbound := range inbounds { + clients, err := s.GetClients(inbound) + if err != nil { + continue + } + for _, client := range clients { + if client.ID == id && client.Email != "" { + targetEmails = append(targetEmails, client.Email) + } + } + } + // Get traffics for the collected emails + if len(targetEmails) > 0 { + err = db.Model(xray.ClientTraffic{}). + Where("email IN ?", targetEmails). + Find(&traffics).Error + if err != nil { + logger.Debug(err) + return nil, err + } + } + + return traffics, nil } func (s *InboundService) SearchClientTraffic(query string) (traffic *xray.ClientTraffic, err error) { |
