Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/sub
diff options
context:
space:
mode:
authorAli Golzar <57574919+aliglzr@users.noreply.github.com>2025-05-21 13:04:38 +0300
committerGitHub <noreply@github.com>2025-05-21 13:04:38 +0300
commit3850e2f070bb3c1227b78dcd1e8a34a89a9e9906 (patch)
tree3a29b65f47f382494b669b29f7c8695f66527df4 /sub
parent1b1cbfff422e6de58a6f524336b19ec809eb45f0 (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 'sub')
-rw-r--r--sub/subService.go74
1 files changed, 58 insertions, 16 deletions
diff --git a/sub/subService.go b/sub/subService.go
index 9f26c0e0..1c74d103 100644
--- a/sub/subService.go
+++ b/sub/subService.go
@@ -107,18 +107,30 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, string, error
func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) {
db := database.GetDB()
var inbounds []*model.Inbound
- err := db.Model(model.Inbound{}).Preload("ClientStats").Where(`id in (
- SELECT DISTINCT inbounds.id
- FROM inbounds,
- JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
- WHERE
- protocol in ('vmess','vless','trojan','shadowsocks')
- AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ?
- )`, subId, true).Find(&inbounds).Error
+ err := db.Model(model.Inbound{}).
+ Preload("ClientStats").
+ Where("protocol IN ? AND enable = ?", []string{"vmess", "vless", "trojan", "shadowsocks"}, true).
+ Find(&inbounds).Error
if err != nil {
return nil, err
}
- return inbounds, nil
+
+ // Filter inbounds that have clients with matching subId
+ var filteredInbounds []*model.Inbound
+ for _, inbound := range inbounds {
+ clients, err := s.inboundService.GetClients(inbound)
+ if err != nil {
+ continue
+ }
+ for _, client := range clients {
+ if client.SubID == subId {
+ filteredInbounds = append(filteredInbounds, inbound)
+ break
+ }
+ }
+ }
+
+ return filteredInbounds, nil
}
func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email string) xray.ClientTraffic {
@@ -132,25 +144,55 @@ func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email stri
func (s *SubService) getFallbackMaster(dest string, streamSettings string) (string, int, string, error) {
db := database.GetDB()
- var inbound *model.Inbound
- err := db.Model(model.Inbound{}).
- Where("JSON_TYPE(settings, '$.fallbacks') = 'array'").
- Where("EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)", dest).
- Find(&inbound).Error
+ var inbounds []*model.Inbound
+ err := db.Model(model.Inbound{}).Find(&inbounds).Error
if err != nil {
return "", 0, "", err
}
+ // Find inbound with matching fallback dest
+ var masterInbound *model.Inbound
+ for _, inbound := range inbounds {
+ var settings map[string]any
+ err := json.Unmarshal([]byte(inbound.Settings), &settings)
+ if err != nil {
+ continue
+ }
+
+ fallbacks, ok := settings["fallbacks"].([]any)
+ if !ok {
+ continue
+ }
+
+ for _, fallback := range fallbacks {
+ f, ok := fallback.(map[string]any)
+ if !ok {
+ continue
+ }
+ if fallbackDest, ok := f["dest"].(string); ok && fallbackDest == dest {
+ masterInbound = inbound
+ break
+ }
+ }
+ if masterInbound != nil {
+ break
+ }
+ }
+
+ if masterInbound == nil {
+ return "", 0, "", fmt.Errorf("no inbound found with fallback dest: %s", dest)
+ }
+
var stream map[string]any
json.Unmarshal([]byte(streamSettings), &stream)
var masterStream map[string]any
- json.Unmarshal([]byte(inbound.StreamSettings), &masterStream)
+ json.Unmarshal([]byte(masterInbound.StreamSettings), &masterStream)
stream["security"] = masterStream["security"]
stream["tlsSettings"] = masterStream["tlsSettings"]
stream["externalProxy"] = masterStream["externalProxy"]
modifiedStream, _ := json.MarshalIndent(stream, "", " ")
- return inbound.Listen, inbound.Port, string(modifiedStream), nil
+ return masterInbound.Listen, masterInbound.Port, string(modifiedStream), nil
}
func (s *SubService) getLink(inbound *model.Inbound, email string) string {