DESIGN REFACTOR (#600)

### New features
- New face + dark mode
  - [Change font to vazirmatn](057f3190de)
  - [use customized andtv](f956009fd2)
  - [popConfirm for del and reset client](66c98e8392)
  - [Separate page for xray config](9e1cd6315f)
  - Separate face for mobile view
- [Show online users](bf892e9965) [#559](https://github.com/alireza0/x-ui/issues/559)
- [Auto renew](96408967ae)

### Bug fixes
- [[tgbot] Retry loop on start](211c05ec29)
- [fix docker-compose version](1dcec91ce4)
- [fix redirect after restart](81d25a032c)
This commit is contained in:
Alireza Ahmadi
2023-11-09 23:31:17 +01:00
committed by GitHub
parent d4a23f8a23
commit 7c74c534f0
64 changed files with 2986 additions and 2220 deletions

View File

@@ -249,7 +249,18 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
tag := oldInbound.Tag
err = s.updateClientTraffics(oldInbound, inbound)
db := database.GetDB()
tx := db.Begin()
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
err = s.updateClientTraffics(tx, oldInbound, inbound)
if err != nil {
return inbound, false, err
}
@@ -290,11 +301,10 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
}
s.xrayApi.Close()
db := database.GetDB()
return inbound, needRestart, db.Save(oldInbound).Error
return inbound, needRestart, tx.Save(oldInbound).Error
}
func (s *InboundService) updateClientTraffics(oldInbound *model.Inbound, newInbound *model.Inbound) error {
func (s *InboundService) updateClientTraffics(tx *gorm.DB, oldInbound *model.Inbound, newInbound *model.Inbound) error {
oldClients, err := s.GetClients(oldInbound)
if err != nil {
return err
@@ -304,17 +314,6 @@ func (s *InboundService) updateClientTraffics(oldInbound *model.Inbound, newInbo
return err
}
db := database.GetDB()
tx := db.Begin()
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
var emailExists bool
for _, oldClient := range oldClients {
@@ -581,7 +580,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
if len(clients[0].Email) > 0 {
if len(oldEmail) > 0 {
err = s.UpdateClientStat(oldEmail, &clients[0])
err = s.UpdateClientStat(tx, oldEmail, &clients[0])
if err != nil {
return false, err
}
@@ -648,6 +647,13 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff
return err, false
}
needRestart0, count, err := s.autoRenewClients(tx)
if err != nil {
logger.Warning("Error in renew clients:", err)
} else if count > 0 {
logger.Debugf("%v clients renewed", count)
}
needRestart1, count, err := s.disableInvalidClients(tx)
if err != nil {
logger.Warning("Error in disabling invalid clients:", err)
@@ -661,7 +667,7 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff
} else if count > 0 {
logger.Debugf("%v inbounds disabled", count)
}
return nil, (needRestart1 || needRestart2)
return nil, (needRestart0 || needRestart1 || needRestart2)
}
func (s *InboundService) addInboundTraffic(tx *gorm.DB, traffics []*xray.Traffic) error {
@@ -688,9 +694,15 @@ func (s *InboundService) addInboundTraffic(tx *gorm.DB, traffics []*xray.Traffic
func (s *InboundService) addClientTraffic(tx *gorm.DB, traffics []*xray.ClientTraffic) (err error) {
if len(traffics) == 0 {
// Empty onlineUsers
if p != nil {
p.SetOnlineClients(nil)
}
return nil
}
var onlineClients []string
emails := make([]string, 0, len(traffics))
for _, traffic := range traffics {
emails = append(emails, traffic.Email)
@@ -716,11 +728,19 @@ func (s *InboundService) addClientTraffic(tx *gorm.DB, traffics []*xray.ClientTr
if dbClientTraffics[dbTraffic_index].Email == traffics[traffic_index].Email {
dbClientTraffics[dbTraffic_index].Up += traffics[traffic_index].Up
dbClientTraffics[dbTraffic_index].Down += traffics[traffic_index].Down
// Add user in onlineUsers array on traffic
if traffics[traffic_index].Up+traffics[traffic_index].Down > 0 {
onlineClients = append(onlineClients, traffics[traffic_index].Email)
}
break
}
}
}
// Set onlineUsers
p.SetOnlineClients(onlineClients)
err = tx.Save(dbClientTraffics).Error
if err != nil {
logger.Warning("AddClientTraffic update data ", err)
@@ -781,6 +801,102 @@ func (s *InboundService) adjustTraffics(tx *gorm.DB, dbClientTraffics []*xray.Cl
return dbClientTraffics, nil
}
func (s *InboundService) autoRenewClients(tx *gorm.DB) (bool, int64, error) {
// check for time expired
var traffics []*xray.ClientTraffic
now := time.Now().Unix() * 1000
var err, err1 error
err = tx.Model(xray.ClientTraffic{}).Where("reset > 0 and expiry_time > 0 and expiry_time <= ?", now).Find(&traffics).Error
if err != nil {
return false, 0, err
}
// return if there is no client to renew
if len(traffics) == 0 {
return false, 0, nil
}
var inbound_ids []int
var inbounds []*model.Inbound
needRestart := false
var clientsToAdd []struct {
protocol string
tag string
client map[string]interface{}
}
for _, traffic := range traffics {
inbound_ids = append(inbound_ids, traffic.InboundId)
}
err = tx.Model(model.Inbound{}).Where("id IN ?", inbound_ids).Find(&inbounds).Error
if err != nil {
return false, 0, err
}
for inbound_index := range inbounds {
settings := map[string]interface{}{}
json.Unmarshal([]byte(inbounds[inbound_index].Settings), &settings)
clients := settings["clients"].([]interface{})
for client_index := range clients {
c := clients[client_index].(map[string]interface{})
for traffic_index, traffic := range traffics {
if traffic.Email == c["email"].(string) {
newExpiryTime := traffic.ExpiryTime
for newExpiryTime < now {
newExpiryTime += (int64(traffic.Reset) * 86400000)
}
c["expiryTime"] = newExpiryTime
traffics[traffic_index].ExpiryTime = newExpiryTime
traffics[traffic_index].Down = 0
traffics[traffic_index].Up = 0
if !traffic.Enable {
traffics[traffic_index].Enable = true
clientsToAdd = append(clientsToAdd,
struct {
protocol string
tag string
client map[string]interface{}
}{
protocol: string(inbounds[inbound_index].Protocol),
tag: inbounds[inbound_index].Tag,
client: c,
})
}
clients[client_index] = interface{}(c)
break
}
}
}
settings["clients"] = clients
newSettings, err := json.MarshalIndent(settings, "", " ")
if err != nil {
return false, 0, err
}
inbounds[inbound_index].Settings = string(newSettings)
}
err = tx.Save(inbounds).Error
if err != nil {
return false, 0, err
}
err = tx.Save(traffics).Error
if err != nil {
return false, 0, err
}
if p != nil {
err1 = s.xrayApi.Init(p.GetAPIPort())
if err1 != nil {
return true, int64(len(traffics)), nil
}
for _, clientToAdd := range clientsToAdd {
err1 = s.xrayApi.AddUser(clientToAdd.protocol, clientToAdd.tag, clientToAdd.client)
if err1 != nil {
needRestart = true
}
}
s.xrayApi.Close()
}
return needRestart, int64(len(traffics)), nil
}
func (s *InboundService) disableInvalidInbounds(tx *gorm.DB) (bool, int64, error) {
now := time.Now().Unix() * 1000
needRestart := false
@@ -874,6 +990,7 @@ func (s *InboundService) AddClientStat(tx *gorm.DB, inboundId int, client *model
clientTraffic.Enable = true
clientTraffic.Up = 0
clientTraffic.Down = 0
clientTraffic.Reset = client.Reset
result := tx.Create(&clientTraffic)
err := result.Error
if err != nil {
@@ -882,16 +999,15 @@ func (s *InboundService) AddClientStat(tx *gorm.DB, inboundId int, client *model
return nil
}
func (s *InboundService) UpdateClientStat(email string, client *model.Client) error {
db := database.GetDB()
result := db.Model(xray.ClientTraffic{}).
func (s *InboundService) UpdateClientStat(tx *gorm.DB, email string, client *model.Client) error {
result := tx.Model(xray.ClientTraffic{}).
Where("email = ?", email).
Updates(map[string]interface{}{
"enable": true,
"email": client.Email,
"total": client.TotalGB,
"expiry_time": client.ExpiryTime})
"expiry_time": client.ExpiryTime,
"reset": client.Reset})
err := result.Error
if err != nil {
return err
@@ -1011,7 +1127,7 @@ func (s *InboundService) DelDepletedClients(id int) (err error) {
}
}()
whereText := "inbound_id "
whereText := "reset = 0 and inbound_id "
if id < 0 {
whereText += "> ?"
} else {
@@ -1248,3 +1364,7 @@ func (s *InboundService) MigrateDB() {
s.MigrationRequirements()
s.MigrationRemoveOrphanedTraffics()
}
func (s *InboundService) GetOnlineClinets() []string {
return p.GetOnlineClients()
}