diff options
| author | mhsanaei <ho3ein.sanaei@gmail.com> | 2025-09-20 10:35:50 +0300 |
|---|---|---|
| committer | mhsanaei <ho3ein.sanaei@gmail.com> | 2025-09-20 10:35:50 +0300 |
| commit | 6ced549deaecb42b9bb93ea9efcb4c1bbaabe8a4 (patch) | |
| tree | 28d8d82530476cf607e4d05ca189ae05868711e6 /web/service | |
| parent | f60682a6b7cb749fee403c84e2587c3ad7e7ced0 (diff) | |
docs: add comments for all functions
Diffstat (limited to 'web/service')
| -rw-r--r-- | web/service/inbound.go | 19 | ||||
| -rw-r--r-- | web/service/outbound.go | 2 | ||||
| -rw-r--r-- | web/service/panel.go | 2 | ||||
| -rw-r--r-- | web/service/server.go | 15 | ||||
| -rw-r--r-- | web/service/setting.go | 2 | ||||
| -rw-r--r-- | web/service/tgbot.go | 68 | ||||
| -rw-r--r-- | web/service/user.go | 4 | ||||
| -rw-r--r-- | web/service/warp.go | 2 | ||||
| -rw-r--r-- | web/service/xray.go | 16 | ||||
| -rw-r--r-- | web/service/xray_setting.go | 2 |
10 files changed, 121 insertions, 11 deletions
diff --git a/web/service/inbound.go b/web/service/inbound.go index 414d5945..5c6083ee 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -1,3 +1,5 @@ +// Package service provides business logic services for the 3x-ui web panel, +// including inbound/outbound management, user administration, settings, and Xray integration. package service import ( @@ -17,10 +19,15 @@ import ( "gorm.io/gorm" ) +// InboundService provides business logic for managing Xray inbound configurations. +// It handles CRUD operations for inbounds, client management, traffic monitoring, +// and integration with the Xray API for real-time updates. type InboundService struct { xrayApi xray.XrayAPI } +// GetInbounds retrieves all inbounds for a specific user. +// Returns a slice of inbound models with their associated client statistics. func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) { db := database.GetDB() var inbounds []*model.Inbound @@ -31,6 +38,8 @@ func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) { return inbounds, nil } +// GetAllInbounds retrieves all inbounds from the database. +// Returns a slice of all inbound models with their associated client statistics. func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) { db := database.GetDB() var inbounds []*model.Inbound @@ -163,6 +172,10 @@ func (s *InboundService) checkEmailExistForInbound(inbound *model.Inbound) (stri return "", nil } +// AddInbound creates a new inbound configuration. +// It validates port uniqueness, client email uniqueness, and required fields, +// then saves the inbound to the database and optionally adds it to the running Xray instance. +// Returns the created inbound, whether Xray needs restart, and any error. func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, bool, error) { exist, err := s.checkPortExist(inbound.Listen, inbound.Port, 0) if err != nil { @@ -269,6 +282,9 @@ func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, boo return inbound, needRestart, err } +// DelInbound deletes an inbound configuration by ID. +// It removes the inbound from the database and the running Xray instance if active. +// Returns whether Xray needs restart and any error. func (s *InboundService) DelInbound(id int) (bool, error) { db := database.GetDB() @@ -322,6 +338,9 @@ func (s *InboundService) GetInbound(id int) (*model.Inbound, error) { return inbound, nil } +// UpdateInbound modifies an existing inbound configuration. +// It validates changes, updates the database, and syncs with the running Xray instance. +// Returns the updated inbound, whether Xray needs restart, and any error. func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound, bool, error) { exist, err := s.checkPortExist(inbound.Listen, inbound.Port, inbound.Id) if err != nil { diff --git a/web/service/outbound.go b/web/service/outbound.go index 94a8f0b3..530d12eb 100644 --- a/web/service/outbound.go +++ b/web/service/outbound.go @@ -9,6 +9,8 @@ import ( "gorm.io/gorm" ) +// OutboundService provides business logic for managing Xray outbound configurations. +// It handles outbound traffic monitoring and statistics. type OutboundService struct{} func (s *OutboundService) AddTraffic(traffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) { diff --git a/web/service/panel.go b/web/service/panel.go index 72576299..e4fb0c68 100644 --- a/web/service/panel.go +++ b/web/service/panel.go @@ -8,6 +8,8 @@ import ( "github.com/mhsanaei/3x-ui/v2/logger" ) +// PanelService provides business logic for panel management operations. +// It handles panel restart, updates, and system-level panel controls. type PanelService struct{} func (s *PanelService) RestartPanel(delay time.Duration) error { diff --git a/web/service/server.go b/web/service/server.go index 03199b50..9fe42e2c 100644 --- a/web/service/server.go +++ b/web/service/server.go @@ -35,14 +35,18 @@ import ( "github.com/shirou/gopsutil/v4/net" ) +// ProcessState represents the current state of a system process. type ProcessState string +// Process state constants const ( - Running ProcessState = "running" - Stop ProcessState = "stop" - Error ProcessState = "error" + Running ProcessState = "running" // Process is running normally + Stop ProcessState = "stop" // Process is stopped + Error ProcessState = "error" // Process is in error state ) +// Status represents comprehensive system and application status information. +// It includes CPU, memory, disk, network statistics, and Xray process status. type Status struct { T time.Time `json:"-"` Cpu float64 `json:"cpu"` @@ -89,10 +93,13 @@ type Status struct { } `json:"appStats"` } +// Release represents information about a software release from GitHub. type Release struct { - TagName string `json:"tag_name"` + TagName string `json:"tag_name"` // The tag name of the release } +// ServerService provides business logic for server monitoring and management. +// It handles system status collection, IP detection, and application statistics. type ServerService struct { xrayService XrayService inboundService InboundService diff --git a/web/service/setting.go b/web/service/setting.go index 7046464a..530a6344 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -75,6 +75,8 @@ var defaultValueMap = map[string]string{ "externalTrafficInformURI": "", } +// SettingService provides business logic for application settings management. +// It handles configuration storage, retrieval, and validation for all system settings. type SettingService struct{} func (s *SettingService) GetDefaultJsonConfig() (any, error) { diff --git a/web/service/tgbot.go b/web/service/tgbot.go index 44e4af28..e575bb28 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -65,14 +65,18 @@ var ( var userStates = make(map[int64]string) +// LoginStatus represents the result of a login attempt. type LoginStatus byte +// Login status constants const ( - LoginSuccess LoginStatus = 1 - LoginFail LoginStatus = 0 - EmptyTelegramUserID = int64(0) + LoginSuccess LoginStatus = 1 // Login was successful + LoginFail LoginStatus = 0 // Login failed + EmptyTelegramUserID = int64(0) // Default value for empty Telegram user ID ) +// Tgbot provides business logic for Telegram bot integration. +// It handles bot commands, user interactions, and status reporting via Telegram. type Tgbot struct { inboundService InboundService settingService SettingService @@ -81,18 +85,22 @@ type Tgbot struct { lastStatus *Status } +// NewTgbot creates a new Tgbot instance. func (t *Tgbot) NewTgbot() *Tgbot { return new(Tgbot) } +// I18nBot retrieves a localized message for the bot interface. func (t *Tgbot) I18nBot(name string, params ...string) string { return locale.I18n(locale.Bot, name, params...) } +// GetHashStorage returns the hash storage instance for callback queries. func (t *Tgbot) GetHashStorage() *global.HashStorage { return hashStorage } +// Start initializes and starts the Telegram bot with the provided translation files. func (t *Tgbot) Start(i18nFS embed.FS) error { // Initialize localizer err := locale.InitLocalizer(i18nFS, &t.settingService) @@ -173,6 +181,7 @@ func (t *Tgbot) Start(i18nFS embed.FS) error { return nil } +// NewBot creates a new Telegram bot instance with optional proxy and API server settings. func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*telego.Bot, error) { if proxyUrl == "" && apiServerUrl == "" { return telego.NewBot(token) @@ -209,10 +218,12 @@ func (t *Tgbot) NewBot(token string, proxyUrl string, apiServerUrl string) (*tel return telego.NewBot(token, telego.WithAPIServer(apiServerUrl)) } +// IsRunning checks if the Telegram bot is currently running. func (t *Tgbot) IsRunning() bool { return isRunning } +// SetHostname sets the hostname for the bot. func (t *Tgbot) SetHostname() { host, err := os.Hostname() if err != nil { @@ -223,6 +234,7 @@ func (t *Tgbot) SetHostname() { hostname = host } +// Stop stops the Telegram bot and cleans up resources. func (t *Tgbot) Stop() { if botHandler != nil { botHandler.Stop() @@ -232,6 +244,7 @@ func (t *Tgbot) Stop() { adminIds = nil } +// encodeQuery encodes the query string if it's longer than 64 characters. func (t *Tgbot) encodeQuery(query string) string { // NOTE: we only need to hash for more than 64 chars if len(query) <= 64 { @@ -241,6 +254,7 @@ func (t *Tgbot) encodeQuery(query string) string { return hashStorage.SaveHash(query) } +// decodeQuery decodes a hashed query string back to its original form. func (t *Tgbot) decodeQuery(query string) (string, error) { if !hashStorage.IsMD5(query) { return query, nil @@ -254,6 +268,7 @@ func (t *Tgbot) decodeQuery(query string) (string, error) { return decoded, nil } +// OnReceive starts the message receiving loop for the Telegram bot. func (t *Tgbot) OnReceive() { params := telego.GetUpdatesParams{ Timeout: 10, @@ -430,6 +445,7 @@ func (t *Tgbot) OnReceive() { botHandler.Start() } +// answerCommand processes incoming command messages from Telegram users. func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin bool) { msg, onlyMessage := "", false @@ -505,7 +521,7 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo } } -// Helper function to send the message based on onlyMessage flag. +// sendResponse sends the response message based on the onlyMessage flag. func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool) { if onlyMessage { t.SendMsgToTgbot(chatId, msg) @@ -514,6 +530,7 @@ func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool } } +// randomLowerAndNum generates a random string of lowercase letters and numbers. func (t *Tgbot) randomLowerAndNum(length int) string { charset := "abcdefghijklmnopqrstuvwxyz0123456789" bytes := make([]byte, length) @@ -524,6 +541,7 @@ func (t *Tgbot) randomLowerAndNum(length int) string { return string(bytes) } +// randomShadowSocksPassword generates a random password for Shadowsocks. func (t *Tgbot) randomShadowSocksPassword() string { array := make([]byte, 32) _, err := rand.Read(array) @@ -533,6 +551,7 @@ func (t *Tgbot) randomShadowSocksPassword() string { return base64.StdEncoding.EncodeToString(array) } +// answerCallback processes callback queries from inline keyboards. func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) { chatId := callbackQuery.Message.GetChat().ID @@ -1815,6 +1834,7 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool } } +// BuildInboundClientDataMessage builds a message with client data for the given inbound and protocol. func (t *Tgbot) BuildInboundClientDataMessage(inbound_remark string, protocol model.Protocol) (string, error) { var message string @@ -1864,6 +1884,7 @@ func (t *Tgbot) BuildInboundClientDataMessage(inbound_remark string, protocol mo return message, nil } +// BuildJSONForProtocol builds a JSON string for the given protocol with client data. func (t *Tgbot) BuildJSONForProtocol(protocol model.Protocol) (string, error) { var jsonString string @@ -1942,6 +1963,7 @@ func (t *Tgbot) BuildJSONForProtocol(protocol model.Protocol) (string, error) { return jsonString, nil } +// SubmitAddClient submits the client addition request to the inbound service. func (t *Tgbot) SubmitAddClient() (bool, error) { inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) @@ -1964,6 +1986,7 @@ func (t *Tgbot) SubmitAddClient() (bool, error) { return t.inboundService.AddInboundClient(newInbound) } +// checkAdmin checks if the given Telegram ID is an admin. func checkAdmin(tgId int64) bool { for _, adminId := range adminIds { if adminId == tgId { @@ -1973,6 +1996,7 @@ func checkAdmin(tgId int64) bool { return false } +// SendAnswer sends a response message with an inline keyboard to the specified chat. func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) { numericKeyboard := tu.InlineKeyboard( tu.InlineKeyboardRow( @@ -2028,6 +2052,7 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) { t.SendMsgToTgbot(chatId, msg, ReplyMarkup) } +// SendMsgToTgbot sends a message to the Telegram bot with optional reply markup. func (t *Tgbot) SendMsgToTgbot(chatId int64, msg string, replyMarkup ...telego.ReplyMarkup) { if !isRunning { return @@ -2143,6 +2168,7 @@ func (t *Tgbot) buildSubscriptionURLs(email string) (string, string, error) { return subURL, subJsonURL, nil } +// sendClientSubLinks sends the subscription links for the client to the chat. func (t *Tgbot) sendClientSubLinks(chatId int64, email string) { subURL, subJsonURL, err := t.buildSubscriptionURLs(email) if err != nil { @@ -2338,6 +2364,7 @@ func (t *Tgbot) sendClientQRLinks(chatId int64, email string) { } } +// SendMsgToTgbotAdmins sends a message to all admin Telegram chats. func (t *Tgbot) SendMsgToTgbotAdmins(msg string, replyMarkup ...telego.ReplyMarkup) { if len(replyMarkup) > 0 { for _, adminId := range adminIds { @@ -2350,6 +2377,7 @@ func (t *Tgbot) SendMsgToTgbotAdmins(msg string, replyMarkup ...telego.ReplyMark } } +// SendReport sends a periodic report to admin chats. func (t *Tgbot) SendReport() { runTime, err := t.settingService.GetTgbotRuntime() if err == nil && len(runTime) > 0 { @@ -2371,6 +2399,7 @@ func (t *Tgbot) SendReport() { } } +// SendBackupToAdmins sends a database backup to admin chats. func (t *Tgbot) SendBackupToAdmins() { if !t.IsRunning() { return @@ -2380,6 +2409,7 @@ func (t *Tgbot) SendBackupToAdmins() { } } +// sendExhaustedToAdmins sends notifications about exhausted clients to admins. func (t *Tgbot) sendExhaustedToAdmins() { if !t.IsRunning() { return @@ -2389,6 +2419,7 @@ func (t *Tgbot) sendExhaustedToAdmins() { } } +// getServerUsage retrieves and formats server usage information. func (t *Tgbot) getServerUsage(chatId int64, messageID ...int) string { info := t.prepareServerUsageInfo() @@ -2410,6 +2441,7 @@ func (t *Tgbot) sendServerUsage() string { return info } +// prepareServerUsageInfo prepares the server usage information string. func (t *Tgbot) prepareServerUsageInfo() string { info, ipv4, ipv6 := "", "", "" @@ -2459,6 +2491,7 @@ func (t *Tgbot) prepareServerUsageInfo() string { return info } +// UserLoginNotify sends a notification about user login attempts to admins. func (t *Tgbot) UserLoginNotify(username string, password string, ip string, time string, status LoginStatus) { if !t.IsRunning() { return @@ -2490,6 +2523,7 @@ func (t *Tgbot) UserLoginNotify(username string, password string, ip string, tim t.SendMsgToTgbotAdmins(msg) } +// getInboundUsages retrieves and formats inbound usage information. func (t *Tgbot) getInboundUsages() string { info := "" // get traffic @@ -2515,6 +2549,8 @@ func (t *Tgbot) getInboundUsages() string { } return info } + +// getInbounds creates an inline keyboard with all inbounds. func (t *Tgbot) getInbounds() (*telego.InlineKeyboardMarkup, error) { inbounds, err := t.inboundService.GetAllInbounds() if err != nil { @@ -2546,8 +2582,7 @@ func (t *Tgbot) getInbounds() (*telego.InlineKeyboardMarkup, error) { return keyboard, nil } -// getInboundsFor builds an inline keyboard of inbounds where each button leads to a custom next action -// nextAction should be one of: get_clients_for_sub|get_clients_for_individual|get_clients_for_qr +// getInboundsFor builds an inline keyboard of inbounds for a custom next action. func (t *Tgbot) getInboundsFor(nextAction string) (*telego.InlineKeyboardMarkup, error) { inbounds, err := t.inboundService.GetAllInbounds() if err != nil { @@ -2614,6 +2649,7 @@ func (t *Tgbot) getInboundClientsFor(inboundID int, action string) (*telego.Inli return keyboard, nil } +// getInboundsAddClient creates an inline keyboard for adding clients to inbounds. func (t *Tgbot) getInboundsAddClient() (*telego.InlineKeyboardMarkup, error) { inbounds, err := t.inboundService.GetAllInbounds() if err != nil { @@ -2656,6 +2692,7 @@ func (t *Tgbot) getInboundsAddClient() (*telego.InlineKeyboardMarkup, error) { return keyboard, nil } +// getInboundClients creates an inline keyboard with clients of a specific inbound. func (t *Tgbot) getInboundClients(id int) (*telego.InlineKeyboardMarkup, error) { inbound, err := t.inboundService.GetInbound(id) if err != nil { @@ -2690,6 +2727,7 @@ func (t *Tgbot) getInboundClients(id int) (*telego.InlineKeyboardMarkup, error) return keyboard, nil } +// clientInfoMsg formats client information message based on traffic and flags. func (t *Tgbot) clientInfoMsg( traffic *xray.ClientTraffic, printEnabled bool, @@ -2796,6 +2834,7 @@ func (t *Tgbot) clientInfoMsg( return output } +// getClientUsage retrieves and sends client usage information to the chat. func (t *Tgbot) getClientUsage(chatId int64, tgUserID int64, email ...string) { traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserID) if err != nil { @@ -2838,6 +2877,7 @@ func (t *Tgbot) getClientUsage(chatId int64, tgUserID int64, email ...string) { t.SendAnswer(chatId, output, false) } +// searchClientIps searches and sends client IP addresses for the given email. func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) { ips, err := t.inboundService.GetInboundClientIps(email) if err != nil || len(ips) == 0 { @@ -2865,6 +2905,7 @@ func (t *Tgbot) searchClientIps(chatId int64, email string, messageID ...int) { } } +// clientTelegramUserInfo retrieves and sends Telegram user info for the client. func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ...int) { traffic, client, err := t.inboundService.GetClientByEmail(email) if err != nil { @@ -2917,6 +2958,7 @@ func (t *Tgbot) clientTelegramUserInfo(chatId int64, email string, messageID ... } } +// searchClient searches for a client by email and sends the information. func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { traffic, err := t.inboundService.GetClientTrafficByEmail(email) if err != nil { @@ -2962,6 +3004,7 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { } } +// addClient handles the process of adding a new client to an inbound. func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) { inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) if err != nil { @@ -3058,6 +3101,7 @@ func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) { } +// searchInbound searches for inbounds by remark and sends the results. func (t *Tgbot) searchInbound(chatId int64, remark string) { inbounds, err := t.inboundService.SearchInbounds(remark) if err != nil { @@ -3095,6 +3139,7 @@ func (t *Tgbot) searchInbound(chatId int64, remark string) { } } +// getExhausted retrieves and sends information about exhausted clients. func (t *Tgbot) getExhausted(chatId int64) { trDiff := int64(0) exDiff := int64(0) @@ -3191,6 +3236,7 @@ func (t *Tgbot) getExhausted(chatId int64) { } } +// notifyExhausted sends notifications for exhausted clients. func (t *Tgbot) notifyExhausted() { trDiff := int64(0) exDiff := int64(0) @@ -3262,6 +3308,7 @@ func (t *Tgbot) notifyExhausted() { } } +// int64Contains checks if an int64 slice contains a specific item. func int64Contains(slice []int64, item int64) bool { for _, s := range slice { if s == item { @@ -3271,6 +3318,7 @@ func int64Contains(slice []int64, item int64) bool { return false } +// onlineClients retrieves and sends information about online clients. func (t *Tgbot) onlineClients(chatId int64, messageID ...int) { if !p.IsRunning() { return @@ -3305,6 +3353,7 @@ func (t *Tgbot) onlineClients(chatId int64, messageID ...int) { } } +// sendBackup sends a backup of the database and configuration files. func (t *Tgbot) sendBackup(chatId int64) { output := t.I18nBot("tgbot.messages.backupTime", "Time=="+time.Now().Format("2006-01-02 15:04:05")) t.SendMsgToTgbot(chatId, output) @@ -3344,6 +3393,7 @@ func (t *Tgbot) sendBackup(chatId int64) { } } +// sendBanLogs sends the ban logs to the specified chat. func (t *Tgbot) sendBanLogs(chatId int64, dt bool) { if dt { output := t.I18nBot("tgbot.messages.datetime", "DateTime=="+time.Now().Format("2006-01-02 15:04:05")) @@ -3393,6 +3443,7 @@ func (t *Tgbot) sendBanLogs(chatId int64, dt bool) { } } +// sendCallbackAnswerTgBot answers a callback query with a message. func (t *Tgbot) sendCallbackAnswerTgBot(id string, message string) { params := telego.AnswerCallbackQueryParams{ CallbackQueryID: id, @@ -3403,6 +3454,7 @@ func (t *Tgbot) sendCallbackAnswerTgBot(id string, message string) { } } +// editMessageCallbackTgBot edits the reply markup of a message. func (t *Tgbot) editMessageCallbackTgBot(chatId int64, messageID int, inlineKeyboard *telego.InlineKeyboardMarkup) { params := telego.EditMessageReplyMarkupParams{ ChatID: tu.ID(chatId), @@ -3414,6 +3466,7 @@ func (t *Tgbot) editMessageCallbackTgBot(chatId int64, messageID int, inlineKeyb } } +// editMessageTgBot edits the text and reply markup of a message. func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlineKeyboard ...*telego.InlineKeyboardMarkup) { params := telego.EditMessageTextParams{ ChatID: tu.ID(chatId), @@ -3429,6 +3482,7 @@ func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlin } } +// SendMsgToTgbotDeleteAfter sends a message and deletes it after a specified delay. func (t *Tgbot) SendMsgToTgbotDeleteAfter(chatId int64, msg string, delayInSeconds int, replyMarkup ...telego.ReplyMarkup) { // Determine if replyMarkup was passed; otherwise, set it to nil var replyMarkupParam telego.ReplyMarkup @@ -3455,6 +3509,7 @@ func (t *Tgbot) SendMsgToTgbotDeleteAfter(chatId int64, msg string, delayInSecon }() } +// deleteMessageTgBot deletes a message from the chat. func (t *Tgbot) deleteMessageTgBot(chatId int64, messageID int) { params := telego.DeleteMessageParams{ ChatID: tu.ID(chatId), @@ -3467,6 +3522,7 @@ func (t *Tgbot) deleteMessageTgBot(chatId int64, messageID int) { } } +// isSingleWord checks if the text contains only a single word. func (t *Tgbot) isSingleWord(text string) bool { text = strings.TrimSpace(text) re := regexp.MustCompile(`\s+`) diff --git a/web/service/user.go b/web/service/user.go index 074eb7ef..f42c3cf8 100644 --- a/web/service/user.go +++ b/web/service/user.go @@ -12,10 +12,14 @@ import ( "gorm.io/gorm" ) +// UserService provides business logic for user management and authentication. +// It handles user creation, login, password management, and 2FA operations. type UserService struct { settingService SettingService } +// GetFirstUser retrieves the first user from the database. +// This is typically used for initial setup or when there's only one admin user. func (s *UserService) GetFirstUser() (*model.User, error) { db := database.GetDB() diff --git a/web/service/warp.go b/web/service/warp.go index ef9e573b..6b048ea6 100644 --- a/web/service/warp.go +++ b/web/service/warp.go @@ -12,6 +12,8 @@ import ( "github.com/mhsanaei/3x-ui/v2/util/common" ) +// WarpService provides business logic for Cloudflare WARP integration. +// It manages WARP configuration and connectivity settings. type WarpService struct { SettingService } diff --git a/web/service/xray.go b/web/service/xray.go index 93cbd9f0..43178d2f 100644 --- a/web/service/xray.go +++ b/web/service/xray.go @@ -20,16 +20,20 @@ var ( result string ) +// XrayService provides business logic for Xray process management. +// It handles starting, stopping, restarting Xray, and managing its configuration. type XrayService struct { inboundService InboundService settingService SettingService xrayAPI xray.XrayAPI } +// IsXrayRunning checks if the Xray process is currently running. func (s *XrayService) IsXrayRunning() bool { return p != nil && p.IsRunning() } +// GetXrayErr returns the error from the Xray process, if any. func (s *XrayService) GetXrayErr() error { if p == nil { return nil @@ -46,6 +50,7 @@ func (s *XrayService) GetXrayErr() error { return err } +// GetXrayResult returns the result string from the Xray process. func (s *XrayService) GetXrayResult() string { if result != "" { return result @@ -68,6 +73,7 @@ func (s *XrayService) GetXrayResult() string { return result } +// GetXrayVersion returns the version of the running Xray process. func (s *XrayService) GetXrayVersion() string { if p == nil { return "Unknown" @@ -75,10 +81,13 @@ func (s *XrayService) GetXrayVersion() string { return p.GetVersion() } +// RemoveIndex removes an element at the specified index from a slice. +// Returns a new slice with the element removed. func RemoveIndex(s []any, index int) []any { return append(s[:index], s[index+1:]...) } +// GetXrayConfig retrieves and builds the Xray configuration from settings and inbounds. func (s *XrayService) GetXrayConfig() (*xray.Config, error) { templateConfig, err := s.settingService.GetXrayConfigTemplate() if err != nil { @@ -182,6 +191,7 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) { return xrayConfig, nil } +// GetXrayTraffic fetches the current traffic statistics from the running Xray process. func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic, error) { if !s.IsXrayRunning() { err := errors.New("xray is not running") @@ -200,6 +210,7 @@ func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic, return traffic, clientTraffic, nil } +// RestartXray restarts the Xray process, optionally forcing a restart even if config unchanged. func (s *XrayService) RestartXray(isForce bool) error { lock.Lock() defer lock.Unlock() @@ -229,6 +240,7 @@ func (s *XrayService) RestartXray(isForce bool) error { return nil } +// StopXray stops the running Xray process. func (s *XrayService) StopXray() error { lock.Lock() defer lock.Unlock() @@ -240,15 +252,17 @@ func (s *XrayService) StopXray() error { return errors.New("xray is not running") } +// SetToNeedRestart marks that Xray needs to be restarted. func (s *XrayService) SetToNeedRestart() { isNeedXrayRestart.Store(true) } +// IsNeedRestartAndSetFalse checks if restart is needed and resets the flag to false. func (s *XrayService) IsNeedRestartAndSetFalse() bool { return isNeedXrayRestart.CompareAndSwap(true, false) } -// Check if Xray is not running and wasn't stopped manually, i.e. crashed +// DidXrayCrash checks if Xray crashed by verifying it's not running and wasn't manually stopped. func (s *XrayService) DidXrayCrash() bool { return !s.IsXrayRunning() && !isManuallyStopped.Load() } diff --git a/web/service/xray_setting.go b/web/service/xray_setting.go index 06131ea3..5df8a211 100644 --- a/web/service/xray_setting.go +++ b/web/service/xray_setting.go @@ -8,6 +8,8 @@ import ( "github.com/mhsanaei/3x-ui/v2/xray" ) +// XraySettingService provides business logic for Xray configuration management. +// It handles validation and storage of Xray template configurations. type XraySettingService struct { SettingService } |
