fix: unexceptional etags handle

This commit is contained in:
Senis John 2023-06-11 20:07:43 +08:00
parent 89f2342a42
commit 42da6c155d
No known key found for this signature in database
GPG Key ID: 845E9E4727C3E1A4
5 changed files with 72 additions and 51 deletions

View File

@ -7,6 +7,12 @@ import (
"github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/infra/conf"
) )
const (
UserNotModified = "users not modified"
NodeNotModified = "node not modified"
RuleNotModified = "rules not modified"
)
// Config API config // Config API config
type Config struct { type Config struct {
APIHost string `mapstructure:"ApiHost"` APIHost string `mapstructure:"ApiHost"`

View File

@ -34,7 +34,7 @@ type APIClient struct {
DeviceLimit int DeviceLimit int
LocalRuleList []api.DetectRule LocalRuleList []api.DetectRule
resp atomic.Value resp atomic.Value
eTag string eTags map[string]string
} }
// New create an api instance // New create an api instance
@ -73,6 +73,7 @@ func New(apiConfig *api.Config) *APIClient {
SpeedLimit: apiConfig.SpeedLimit, SpeedLimit: apiConfig.SpeedLimit,
DeviceLimit: apiConfig.DeviceLimit, DeviceLimit: apiConfig.DeviceLimit,
LocalRuleList: localRuleList, LocalRuleList: localRuleList,
eTags: make(map[string]string),
} }
return apiClient return apiClient
} }
@ -147,9 +148,19 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
path := "/api/v1/server/UniProxy/config" path := "/api/v1/server/UniProxy/config"
res, err := c.client.R(). res, err := c.client.R().
SetHeader("If-None-Match", c.eTags["node"]).
ForceContentType("application/json"). ForceContentType("application/json").
Get(path) Get(path)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 {
return nil, errors.New(api.NodeNotModified)
}
// update etag
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["node"] {
c.eTags["node"] = res.Header().Get("Etag")
}
nodeInfoResp, err := c.parseResponse(res, path, err) nodeInfoResp, err := c.parseResponse(res, path, err)
if err != nil { if err != nil {
return nil, err return nil, err
@ -194,17 +205,17 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
} }
res, err := c.client.R(). res, err := c.client.R().
SetHeader("If-None-Match", c.eTag). SetHeader("If-None-Match", c.eTags["users"]).
ForceContentType("application/json"). ForceContentType("application/json").
Get(path) Get(path)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed // Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 { if res.StatusCode() == 304 {
return nil, errors.New("users no change") return nil, errors.New(api.UserNotModified)
} }
// update etag // update etag
if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTag { if res.Header().Get("Etag") != "" && res.Header().Get("Etag") != c.eTags["users"] {
c.eTag = res.Header().Get("Etag") c.eTags["users"] = res.Header().Get("Etag")
} }
usersResp, err := c.parseResponse(res, path, err) usersResp, err := c.parseResponse(res, path, err)

View File

@ -41,7 +41,7 @@ type APIClient struct {
LastReportOnline map[int]int LastReportOnline map[int]int
access sync.Mutex access sync.Mutex
version string version string
eTag map[string]string eTags map[string]string
} }
// New creat a api instance // New creat a api instance
@ -82,7 +82,7 @@ func New(apiConfig *api.Config) *APIClient {
LocalRuleList: localRuleList, LocalRuleList: localRuleList,
DisableCustomConfig: apiConfig.DisableCustomConfig, DisableCustomConfig: apiConfig.DisableCustomConfig,
LastReportOnline: make(map[int]int), LastReportOnline: make(map[int]int),
eTag: make(map[string]string), eTags: make(map[string]string),
} }
} }
@ -158,16 +158,16 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
path := fmt.Sprintf("/mod_mu/nodes/%d/info", c.NodeID) path := fmt.Sprintf("/mod_mu/nodes/%d/info", c.NodeID)
res, err := c.client.R(). res, err := c.client.R().
SetResult(&Response{}). SetResult(&Response{}).
SetHeader("If-None-Match", c.eTag["NodeInfo"]). SetHeader("If-None-Match", c.eTags["node"]).
ForceContentType("application/json"). ForceContentType("application/json").
Get(path) Get(path)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed // Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 { if res.StatusCode() == 304 {
return nil, errors.New("NodeInfo no change") return nil, errors.New(api.NodeNotModified)
} }
if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTag["NodeInfo"] { if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTags["node"] {
c.eTag["NodeInfo"] = res.Header().Get("ETag") c.eTags["node"] = res.Header().Get("ETag")
} }
response, err := c.parseResponse(res, path, err) response, err := c.parseResponse(res, path, err)
@ -228,17 +228,17 @@ func (c *APIClient) GetUserList() (UserList *[]api.UserInfo, err error) {
path := "/mod_mu/users" path := "/mod_mu/users"
res, err := c.client.R(). res, err := c.client.R().
SetQueryParam("node_id", strconv.Itoa(c.NodeID)). SetQueryParam("node_id", strconv.Itoa(c.NodeID)).
SetHeader("If-None-Match", c.eTag["UserList"]). SetHeader("If-None-Match", c.eTags["users"]).
SetResult(&Response{}). SetResult(&Response{}).
ForceContentType("application/json"). ForceContentType("application/json").
Get(path) Get(path)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed // Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 { if res.StatusCode() == 304 {
return nil, errors.New("users no change") return nil, errors.New(api.UserNotModified)
} }
if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTag["UserList"] { if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTags["users"] {
c.eTag["UserList"] = res.Header().Get("ETag") c.eTags["users"] = res.Header().Get("ETag")
} }
response, err := c.parseResponse(res, path, err) response, err := c.parseResponse(res, path, err)
@ -349,17 +349,17 @@ func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
path := "/mod_mu/func/detect_rules" path := "/mod_mu/func/detect_rules"
res, err := c.client.R(). res, err := c.client.R().
SetResult(&Response{}). SetResult(&Response{}).
SetHeader("If-None-Match", c.eTag["NodeRule"]). SetHeader("If-None-Match", c.eTags["rules"]).
ForceContentType("application/json"). ForceContentType("application/json").
Get(path) Get(path)
// Etag identifier for a specific version of a resource. StatusCode = 304 means no changed // Etag identifier for a specific version of a resource. StatusCode = 304 means no changed
if res.StatusCode() == 304 { if res.StatusCode() == 304 {
return nil, errors.New("detect_rules no change") return nil, errors.New(api.RuleNotModified)
} }
if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTag["NodeRule"] { if res.Header().Get("ETag") != "" && res.Header().Get("ETag") != c.eTags["rules"] {
c.eTag["NodeRule"] = res.Header().Get("ETag") c.eTags["rules"] = res.Header().Get("ETag")
} }
response, err := c.parseResponse(res, path, err) response, err := c.parseResponse(res, path, err)

View File

@ -24,7 +24,7 @@ var (
) )
var ( var (
version = "0.9.0" version = "0.9.1"
codename = "XrayR" codename = "XrayR"
intro = "A Xray backend that supports many panels" intro = "A Xray backend that supports many panels"
) )

View File

@ -185,7 +185,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
var nodeInfoChanged = true var nodeInfoChanged = true
newNodeInfo, err := c.apiClient.GetNodeInfo() newNodeInfo, err := c.apiClient.GetNodeInfo()
if err != nil { if err != nil {
if err.Error() == "NodeInfo no change" { if err.Error() == api.NodeNotModified {
nodeInfoChanged = false nodeInfoChanged = false
newNodeInfo = c.nodeInfo newNodeInfo = c.nodeInfo
} else { } else {
@ -201,7 +201,7 @@ func (c *Controller) nodeInfoMonitor() (err error) {
var usersChanged = true var usersChanged = true
newUserInfo, err := c.apiClient.GetUserList() newUserInfo, err := c.apiClient.GetUserList()
if err != nil { if err != nil {
if err.Error() == "users no change" { if err.Error() == api.UserNotModified {
usersChanged = false usersChanged = false
newUserInfo = c.userList newUserInfo = c.userList
} else { } else {
@ -211,41 +211,45 @@ func (c *Controller) nodeInfoMonitor() (err error) {
} }
// If nodeInfo changed // If nodeInfo changed
if nodeInfoChanged && !reflect.DeepEqual(c.nodeInfo, newNodeInfo) { if nodeInfoChanged {
// Remove old tag if !reflect.DeepEqual(c.nodeInfo, newNodeInfo) {
oldTag := c.Tag // Remove old tag
err := c.removeOldTag(oldTag) oldTag := c.Tag
if err != nil { err := c.removeOldTag(oldTag)
log.Print(err) if err != nil {
return nil log.Print(err)
} return nil
if c.nodeInfo.NodeType == "Shadowsocks-Plugin" { }
err = c.removeOldTag(fmt.Sprintf("dokodemo-door_%s+1", c.Tag)) if c.nodeInfo.NodeType == "Shadowsocks-Plugin" {
} err = c.removeOldTag(fmt.Sprintf("dokodemo-door_%s+1", c.Tag))
if err != nil { }
log.Print(err) if err != nil {
return nil log.Print(err)
} return nil
// Add new tag }
c.nodeInfo = newNodeInfo // Add new tag
c.Tag = c.buildNodeTag() c.nodeInfo = newNodeInfo
err = c.addNewTag(newNodeInfo) c.Tag = c.buildNodeTag()
if err != nil { err = c.addNewTag(newNodeInfo)
log.Print(err) if err != nil {
return nil log.Print(err)
} return nil
nodeInfoChanged = true }
// Remove Old limiter nodeInfoChanged = true
if err = c.DeleteInboundLimiter(oldTag); err != nil { // Remove Old limiter
log.Print(err) if err = c.DeleteInboundLimiter(oldTag); err != nil {
return nil log.Print(err)
return nil
}
} else {
nodeInfoChanged = false
} }
} }
// Check Rule // Check Rule
if !c.config.DisableGetRule { if !c.config.DisableGetRule {
if ruleList, err := c.apiClient.GetNodeRule(); err != nil { if ruleList, err := c.apiClient.GetNodeRule(); err != nil {
if err.Error() != "detect_rules no change" { if err.Error() != api.RuleNotModified {
log.Printf("Get rule list filed: %s", err) log.Printf("Get rule list filed: %s", err)
} }
} else if len(*ruleList) > 0 { } else if len(*ruleList) > 0 {