Some fixes and improvements (#1077)

* [refactor] api controller

* [update] use status code for jsonMsg and 401 to unauthorize

* [update] handle response status code via axios

* [lint] all .go files
This commit is contained in:
Hamidreza
2024-03-10 20:30:44 +03:30
committed by GitHub
parent e3c2b42048
commit b6ccb2e076
40 changed files with 135 additions and 142 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
.cache
.sync*
*.tar.gz
*.log
access.log
error.log
tmp

View File

@@ -6,6 +6,7 @@ import (
"io/fs"
"os"
"path"
"x-ui/config"
"x-ui/database/model"
"x-ui/xray"

View File

@@ -2,6 +2,7 @@ package model
import (
"fmt"
"x-ui/util/json_util"
"x-ui/xray"
)

View File

@@ -8,12 +8,14 @@ import (
"github.com/op/go-logging"
)
var logger *logging.Logger
var logBuffer []struct {
var (
logger *logging.Logger
logBuffer []struct {
time string
level logging.Level
log string
}
}
)
func init() {
InitLogger(logging.INFO)

View File

@@ -8,6 +8,7 @@ import (
"os/signal"
"syscall"
_ "unsafe"
"x-ui/config"
"x-ui/database"
"x-ui/logger"

View File

@@ -7,6 +7,7 @@ import (
"net"
"net/http"
"strconv"
"x-ui/config"
"x-ui/logger"
"x-ui/util/common"
@@ -99,7 +100,7 @@ func (s *Server) initRouter() (*gin.Engine, error) {
}
func (s *Server) Start() (err error) {
//This is an anonymous function, no function name
// This is an anonymous function, no function name
defer func() {
if err != nil {
s.Stop()

View File

@@ -25,8 +25,8 @@ func NewSUBController(
showInfo bool,
rModel string,
update string,
jsonFragment string) *SUBController {
jsonFragment string,
) *SUBController {
a := &SUBController{
subPath: subPath,
subJsonPath: jsonPath,

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"strings"
"x-ui/database/model"
"x-ui/logger"
"x-ui/util/json_util"

View File

@@ -6,6 +6,7 @@ import (
"net/url"
"strings"
"time"
"x-ui/database"
"x-ui/database/model"
"x-ui/logger"

View File

@@ -3,6 +3,7 @@ package common
import (
"errors"
"fmt"
"x-ui/logger"
)

View File

@@ -5,12 +5,14 @@ import (
"time"
)
var numSeq [10]rune
var lowerSeq [26]rune
var upperSeq [26]rune
var numLowerSeq [36]rune
var numUpperSeq [36]rune
var allSeq [62]rune
var (
numSeq [10]rune
lowerSeq [26]rune
upperSeq [26]rune
numLowerSeq [36]rune
numUpperSeq [36]rune
allSeq [62]rune
)
func init() {
rand.Seed(time.Now().UnixNano())

View File

@@ -14,3 +14,17 @@ axios.interceptors.request.use(
},
(error) => Promise.reject(error),
);
axios.interceptors.response.use(
(response) => response,
(error) => {
if (error.response) {
const statusCode = error.response.status;
// Check the status code
if (statusCode === 401) { // Unauthorized
return window.location.reload();
}
}
return Promise.reject(error);
}
);

View File

@@ -22,81 +22,35 @@ func (a *APIController) initRouter(g *gin.RouterGroup) {
g = g.Group("/xui/API/inbounds")
g.Use(a.checkLogin)
g.GET("/", a.inbounds)
g.GET("/get/:id", a.inbound)
g.GET("/getClientTraffics/:email", a.getClientTraffics)
g.POST("/add", a.addInbound)
g.POST("/del/:id", a.delInbound)
g.POST("/update/:id", a.updateInbound)
g.POST("/addClient", a.addInboundClient)
g.POST("/:id/delClient/:clientId", a.delInboundClient)
g.POST("/updateClient/:clientId", a.updateInboundClient)
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
g.POST("/resetAllTraffics", a.resetAllTraffics)
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
g.POST("/delDepletedClients/:id", a.delDepletedClients)
g.GET("/createbackup", a.createBackup)
g.POST("/onlines", a.onlines)
a.inboundController = NewInboundController(g)
}
func (a *APIController) inbounds(c *gin.Context) {
a.inboundController.getInbounds(c)
}
inboundRoutes := []struct {
Method string
Path string
Handler gin.HandlerFunc
}{
{"GET", "/createbackup", a.createBackup},
{"GET", "/", a.inboundController.getInbounds},
{"GET", "/get/:id", a.inboundController.getInbound},
{"GET", "/getClientTraffics/:email", a.inboundController.getClientTraffics},
{"POST", "/add", a.inboundController.addInbound},
{"POST", "/del/:id", a.inboundController.delInbound},
{"POST", "/update/:id", a.inboundController.updateInbound},
{"POST", "/addClient", a.inboundController.addInboundClient},
{"POST", "/:id/delClient/:clientId", a.inboundController.delInboundClient},
{"POST", "/updateClient/:clientId", a.inboundController.updateInboundClient},
{"POST", "/:id/resetClientTraffic/:email", a.inboundController.resetClientTraffic},
{"POST", "/resetAllTraffics", a.inboundController.resetAllTraffics},
{"POST", "/resetAllClientTraffics/:id", a.inboundController.resetAllClientTraffics},
{"POST", "/delDepletedClients/:id", a.inboundController.delDepletedClients},
{"POST", "/onlines", a.inboundController.onlines},
}
func (a *APIController) inbound(c *gin.Context) {
a.inboundController.getInbound(c)
}
func (a *APIController) getClientTraffics(c *gin.Context) {
a.inboundController.getClientTraffics(c)
}
func (a *APIController) addInbound(c *gin.Context) {
a.inboundController.addInbound(c)
}
func (a *APIController) delInbound(c *gin.Context) {
a.inboundController.delInbound(c)
}
func (a *APIController) updateInbound(c *gin.Context) {
a.inboundController.updateInbound(c)
}
func (a *APIController) addInboundClient(c *gin.Context) {
a.inboundController.addInboundClient(c)
}
func (a *APIController) delInboundClient(c *gin.Context) {
a.inboundController.delInboundClient(c)
}
func (a *APIController) updateInboundClient(c *gin.Context) {
a.inboundController.updateInboundClient(c)
}
func (a *APIController) resetClientTraffic(c *gin.Context) {
a.inboundController.resetClientTraffic(c)
}
func (a *APIController) resetAllTraffics(c *gin.Context) {
a.inboundController.resetAllTraffics(c)
}
func (a *APIController) resetAllClientTraffics(c *gin.Context) {
a.inboundController.resetAllClientTraffics(c)
}
func (a *APIController) delDepletedClients(c *gin.Context) {
a.inboundController.delDepletedClients(c)
for _, route := range inboundRoutes {
g.Handle(route.Method, route.Path, route.Handler)
}
}
func (a *APIController) createBackup(c *gin.Context) {
a.Tgbot.SendBackupToAdmins()
}
func (a *APIController) onlines(c *gin.Context) {
a.inboundController.onlines(c)
}

View File

@@ -2,6 +2,7 @@ package controller
import (
"net/http"
"x-ui/logger"
"x-ui/web/locale"
"x-ui/web/session"
@@ -9,13 +10,12 @@ import (
"github.com/gin-gonic/gin"
)
type BaseController struct {
}
type BaseController struct{}
func (a *BaseController) checkLogin(c *gin.Context) {
if !session.IsLogin(c) {
if isAjax(c) {
pureJsonMsg(c, false, I18nWeb(c, "pages.login.loginAgain"))
pureJsonMsg(c, http.StatusUnauthorized, false, I18nWeb(c, "pages.login.loginAgain"))
} else {
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
}

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"strconv"
"x-ui/database/model"
"x-ui/web/service"
"x-ui/web/session"
@@ -63,6 +64,7 @@ func (a *InboundController) getInbound(c *gin.Context) {
}
jsonObj(c, inbound, nil)
}
func (a *InboundController) getClientTraffics(c *gin.Context) {
email := c.Param("email")
clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)

View File

@@ -3,6 +3,7 @@ package controller
import (
"net/http"
"time"
"x-ui/logger"
"x-ui/web/service"
"x-ui/web/session"
@@ -47,15 +48,15 @@ func (a *IndexController) login(c *gin.Context) {
var form LoginForm
err := c.ShouldBind(&form)
if err != nil {
pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.invalidFormData"))
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.invalidFormData"))
return
}
if form.Username == "" {
pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.emptyUsername"))
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.emptyUsername"))
return
}
if form.Password == "" {
pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.emptyPassword"))
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.emptyPassword"))
return
}
@@ -64,7 +65,7 @@ func (a *IndexController) login(c *gin.Context) {
if user == nil {
logger.Infof("wrong username or password: \"%s\" \"%s\"", form.Username, form.Password)
a.tgbot.UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
pureJsonMsg(c, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
pureJsonMsg(c, http.StatusOK, false, I18nWeb(c, "pages.login.toasts.wrongUsernameOrPassword"))
return
} else {
logger.Infof("%s login success ,Ip Address: %s\n", form.Username, getRemoteIp(c))

View File

@@ -5,6 +5,7 @@ import (
"net/http"
"regexp"
"time"
"x-ui/web/global"
"x-ui/web/service"

View File

@@ -3,6 +3,7 @@ package controller
import (
"errors"
"time"
"x-ui/web/entity"
"x-ui/web/service"
"x-ui/web/session"

View File

@@ -4,6 +4,7 @@ import (
"net"
"net/http"
"strings"
"x-ui/config"
"x-ui/logger"
"x-ui/web/entity"
@@ -48,18 +49,11 @@ func jsonMsgObj(c *gin.Context, msg string, obj interface{}, err error) {
c.JSON(http.StatusOK, m)
}
func pureJsonMsg(c *gin.Context, success bool, msg string) {
if success {
c.JSON(http.StatusOK, entity.Msg{
Success: true,
func pureJsonMsg(c *gin.Context, statusCode int, success bool, msg string) {
c.JSON(statusCode, entity.Msg{
Success: success,
Msg: msg,
})
} else {
c.JSON(http.StatusOK, entity.Msg{
Success: false,
Msg: msg,
})
}
}
func html(c *gin.Context, name string, title string, data gin.H) {

View File

@@ -5,6 +5,7 @@ import (
"net"
"strings"
"time"
"x-ui/util/common"
)

View File

@@ -7,8 +7,10 @@ import (
"github.com/robfig/cron/v3"
)
var webServer WebServer
var subServer SubServer
var (
webServer WebServer
subServer SubServer
)
type WebServer interface {
GetCron() *cron.Cron

View File

@@ -3,6 +3,7 @@ package job
import (
"strconv"
"time"
"x-ui/web/service"
"github.com/shirou/gopsutil/v3/cpu"

View File

@@ -31,5 +31,4 @@ func (j *XrayTrafficJob) Run() {
if needRestart {
j.xrayService.SetToNeedRestart()
}
}

View File

@@ -4,6 +4,7 @@ import (
"embed"
"io/fs"
"strings"
"x-ui/logger"
"github.com/gin-gonic/gin"
@@ -12,9 +13,11 @@ import (
"golang.org/x/text/language"
)
var i18nBundle *i18n.Bundle
var LocalizerWeb *i18n.Localizer
var LocalizerBot *i18n.Localizer
var (
i18nBundle *i18n.Bundle
LocalizerWeb *i18n.Localizer
LocalizerBot *i18n.Localizer
)
type I18nType string
@@ -79,7 +82,6 @@ func I18n(i18nType I18nType, key string, params ...string) string {
MessageID: key,
TemplateData: templateData,
})
if err != nil {
logger.Errorf("Failed to localize message: %v", err)
return ""
@@ -135,7 +137,6 @@ func parseTranslationFiles(i18nFS embed.FS, i18nBundle *i18n.Bundle) error {
_, err = i18nBundle.ParseMessageFileBytes(data, path)
return err
})
if err != nil {
return err
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"strings"
"time"
"x-ui/database"
"x-ui/database/model"
"x-ui/logger"
@@ -90,7 +91,6 @@ func (s *InboundService) getAllEmails() ([]string, error) {
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
`).Scan(&emails).Error
if err != nil {
return nil, err
}
@@ -1044,13 +1044,15 @@ func (s *InboundService) UpdateClientStat(tx *gorm.DB, email string, client *mod
"email": client.Email,
"total": client.TotalGB,
"expiry_time": client.ExpiryTime,
"reset": client.Reset})
"reset": client.Reset,
})
err := result.Error
if err != nil {
return err
}
return nil
}
func (s *InboundService) DelClientStat(tx *gorm.DB, email string) error {
return tx.Where("email = ?", email).Delete(xray.ClientTraffic{}).Error
}
@@ -1131,7 +1133,6 @@ func (s *InboundService) ResetAllClientTraffics(id int) error {
Updates(map[string]interface{}{"enable": true, "up": 0, "down": 0})
err := result.Error
if err != nil {
return err
}
@@ -1146,7 +1147,6 @@ func (s *InboundService) ResetAllTraffics() error {
Updates(map[string]interface{}{"up": 0, "down": 0})
err := result.Error
if err != nil {
return err
}

View File

@@ -4,11 +4,11 @@ import (
"os"
"syscall"
"time"
"x-ui/logger"
)
type PanelService struct {
}
type PanelService struct{}
func (s *PanelService) RestartPanel(delay time.Duration) error {
p, err := os.FindProcess(syscall.Getpid())

View File

@@ -15,6 +15,7 @@ import (
"strconv"
"strings"
"time"
"x-ui/config"
"x-ui/database"
"x-ui/logger"
@@ -250,7 +251,6 @@ func (s *ServerService) GetXrayVersions() ([]string, error) {
}
func (s *ServerService) StopXrayService() (string error) {
err := s.xrayService.StopXray()
if err != nil {
logger.Error("stop xray failed:", err)
@@ -261,7 +261,6 @@ func (s *ServerService) StopXrayService() (string error) {
}
func (s *ServerService) RestartXrayService() (string error) {
s.xrayService.StopXray()
defer func() {
err := s.xrayService.RestartXray(true)
@@ -365,7 +364,6 @@ func (s *ServerService) UpdateXray(version string) error {
}
return nil
}
func (s *ServerService) GetLogs(count string, level string, syslog string) []string {

View File

@@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"time"
"x-ui/database"
"x-ui/database/model"
"x-ui/logger"
@@ -61,8 +62,7 @@ var defaultValueMap = map[string]string{
"warp": "",
}
type SettingService struct {
}
type SettingService struct{}
func (s *SettingService) GetAllSetting() (*entity.AllSetting, error) {
db := database.GetDB()
@@ -406,6 +406,7 @@ func (s *SettingService) GetSubJsonFragment() (string, error) {
func (s *SettingService) GetWarp() (string, error) {
return s.getString("warp")
}
func (s *SettingService) SetWarp(data string) error {
return s.setString("warp", data)
}

View File

@@ -8,6 +8,7 @@ import (
"strconv"
"strings"
"time"
"x-ui/config"
"x-ui/database"
"x-ui/database/model"
@@ -19,10 +20,12 @@ import (
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
var bot *tgbotapi.BotAPI
var adminIds []int64
var isRunning bool
var hostname string
var (
bot *tgbotapi.BotAPI
adminIds []int64
isRunning bool
hostname string
)
type LoginStatus byte

View File

@@ -2,6 +2,7 @@ package service
import (
"errors"
"x-ui/database"
"x-ui/database/model"
"x-ui/logger"
@@ -9,8 +10,7 @@ import (
"gorm.io/gorm"
)
type UserService struct {
}
type UserService struct{}
func (s *UserService) GetFirstUser() (*model.User, error) {
db := database.GetDB()

View File

@@ -4,16 +4,19 @@ import (
"encoding/json"
"errors"
"sync"
"x-ui/logger"
"x-ui/xray"
"go.uber.org/atomic"
)
var p *xray.Process
var lock sync.Mutex
var isNeedXrayRestart atomic.Bool
var result string
var (
p *xray.Process
lock sync.Mutex
isNeedXrayRestart atomic.Bool
result string
)
type XrayService struct {
inboundService InboundService
@@ -87,7 +90,6 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
// check users active or not
clientStats := inbound.ClientStats
for _, clientTraffic := range clientStats {
indexDecrease := 0
for index, client := range clients {
c := client.(map[string]interface{})
@@ -96,10 +98,8 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
clients = RemoveIndex(clients, index-indexDecrease)
indexDecrease++
}
}
}
}
// clear client config for additional parameters

View File

@@ -8,6 +8,7 @@ import (
"net/http"
"os"
"time"
"x-ui/util/common"
"x-ui/xray"
)

View File

@@ -2,6 +2,7 @@ package session
import (
"encoding/gob"
"x-ui/database/model"
sessions "github.com/Calidity/gin-sessions"

View File

@@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"time"
"x-ui/config"
"x-ui/logger"
"x-ui/util/common"
@@ -283,7 +284,7 @@ func (s *Server) startTask() {
}
func (s *Server) Start() (err error) {
//This is an anonymous function, no function name
// This is an anonymous function, no function name
defer func() {
if err != nil {
s.Stop()

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"regexp"
"time"
"x-ui/logger"
"x-ui/util/common"
@@ -159,8 +160,8 @@ func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
if x.grpcClient == nil {
return nil, nil, common.NewError("xray api is not initialized")
}
var trafficRegex = regexp.MustCompile("(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
var ClientTrafficRegex = regexp.MustCompile("(user)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
trafficRegex := regexp.MustCompile("(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
ClientTrafficRegex := regexp.MustCompile("(user)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
client := *x.StatsServiceClient
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)

View File

@@ -2,6 +2,7 @@ package xray
import (
"bytes"
"x-ui/util/json_util"
)

View File

@@ -2,6 +2,7 @@ package xray
import (
"bytes"
"x-ui/util/json_util"
)

View File

@@ -3,6 +3,7 @@ package xray
import (
"regexp"
"strings"
"x-ui/logger"
)

View File

@@ -11,6 +11,7 @@ import (
"runtime"
"syscall"
"time"
"x-ui/config"
"x-ui/util/common"
)