mirror of
				https://github.com/MHSanaei/3x-ui.git
				synced 2025-11-03 22:02:52 +00:00 
			
		
		
		
	[sub] JSON sub enhancement + minor changes
Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
This commit is contained in:
		
							parent
							
								
									8908e8b16a
								
							
						
					
					
						commit
						5b87b12535
					
				
					 8 changed files with 115 additions and 101 deletions
				
			
		| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  "remarks": "",
 | 
				
			||||||
  "dns": {
 | 
					  "dns": {
 | 
				
			||||||
    "tag": "dns_out",
 | 
					    "tag": "dns_out",
 | 
				
			||||||
    "queryStrategy": "UseIP",
 | 
					    "queryStrategy": "UseIP",
 | 
				
			||||||
| 
						 | 
					@ -78,28 +79,9 @@
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        "type": "field",
 | 
					        "type": "field",
 | 
				
			||||||
        "network": "tcp,udp",
 | 
					        "network": "tcp,udp",
 | 
				
			||||||
        "balancerTag": "all"
 | 
					        "outboundTag": "proxy"
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "balancers": [
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        "tag": "all",
 | 
					 | 
				
			||||||
        "selector": [
 | 
					 | 
				
			||||||
          "proxy"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "strategy": {
 | 
					 | 
				
			||||||
          "type": "leastPing"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "observatory": {
 | 
					 | 
				
			||||||
    "probeInterval": "5m",
 | 
					 | 
				
			||||||
    "probeURL": "https://api.github.com/_private/browser/stats",
 | 
					 | 
				
			||||||
    "subjectSelector": [
 | 
					 | 
				
			||||||
      "proxy"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "EnableConcurrency": true
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "stats": {}
 | 
					  "stats": {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -27,14 +27,15 @@ func NewSUBController(
 | 
				
			||||||
	update string,
 | 
						update string,
 | 
				
			||||||
	jsonFragment string,
 | 
						jsonFragment string,
 | 
				
			||||||
) *SUBController {
 | 
					) *SUBController {
 | 
				
			||||||
 | 
						sub := NewSubService(showInfo, rModel)
 | 
				
			||||||
	a := &SUBController{
 | 
						a := &SUBController{
 | 
				
			||||||
		subPath:        subPath,
 | 
							subPath:        subPath,
 | 
				
			||||||
		subJsonPath:    jsonPath,
 | 
							subJsonPath:    jsonPath,
 | 
				
			||||||
		subEncrypt:     encrypt,
 | 
							subEncrypt:     encrypt,
 | 
				
			||||||
		updateInterval: update,
 | 
							updateInterval: update,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		subService:     NewSubService(showInfo, rModel),
 | 
							subService:     sub,
 | 
				
			||||||
		subJsonService: NewSubJsonService(jsonFragment),
 | 
							subJsonService: NewSubJsonService(jsonFragment, sub),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	a.initRouter(g)
 | 
						a.initRouter(g)
 | 
				
			||||||
	return a
 | 
						return a
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,15 +18,34 @@ import (
 | 
				
			||||||
var defaultJson string
 | 
					var defaultJson string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SubJsonService struct {
 | 
					type SubJsonService struct {
 | 
				
			||||||
	fragmanet string
 | 
						configJson       map[string]interface{}
 | 
				
			||||||
 | 
						defaultOutbounds []json_util.RawMessage
 | 
				
			||||||
 | 
						fragment         string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inboundService service.InboundService
 | 
						inboundService service.InboundService
 | 
				
			||||||
	SubService
 | 
						SubService     *SubService
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewSubJsonService(fragment string, subService *SubService) *SubJsonService {
 | 
				
			||||||
 | 
						var configJson map[string]interface{}
 | 
				
			||||||
 | 
						var defaultOutbounds []json_util.RawMessage
 | 
				
			||||||
 | 
						json.Unmarshal([]byte(defaultJson), &configJson)
 | 
				
			||||||
 | 
						if outboundSlices, ok := configJson["outbounds"].([]interface{}); ok {
 | 
				
			||||||
 | 
							for _, defaultOutbound := range outboundSlices {
 | 
				
			||||||
 | 
								jsonBytes, _ := json.Marshal(defaultOutbound)
 | 
				
			||||||
 | 
								defaultOutbounds = append(defaultOutbounds, jsonBytes)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if fragment != "" {
 | 
				
			||||||
 | 
							defaultOutbounds = append(defaultOutbounds, json_util.RawMessage(fragment))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewSubJsonService(fragment string) *SubJsonService {
 | 
					 | 
				
			||||||
	return &SubJsonService{
 | 
						return &SubJsonService{
 | 
				
			||||||
		fragmanet: fragment,
 | 
							configJson:       configJson,
 | 
				
			||||||
 | 
							defaultOutbounds: defaultOutbounds,
 | 
				
			||||||
 | 
							fragment:         fragment,
 | 
				
			||||||
 | 
							SubService:       subService,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,19 +58,8 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err
 | 
				
			||||||
	var header string
 | 
						var header string
 | 
				
			||||||
	var traffic xray.ClientTraffic
 | 
						var traffic xray.ClientTraffic
 | 
				
			||||||
	var clientTraffics []xray.ClientTraffic
 | 
						var clientTraffics []xray.ClientTraffic
 | 
				
			||||||
	var configJson map[string]interface{}
 | 
						var configArray []json_util.RawMessage
 | 
				
			||||||
	var defaultOutbounds []json_util.RawMessage
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	json.Unmarshal([]byte(defaultJson), &configJson)
 | 
					 | 
				
			||||||
	if outboundSlices, ok := configJson["outbounds"].([]interface{}); ok {
 | 
					 | 
				
			||||||
		for _, defaultOutbound := range outboundSlices {
 | 
					 | 
				
			||||||
			jsonBytes, _ := json.Marshal(defaultOutbound)
 | 
					 | 
				
			||||||
			defaultOutbounds = append(defaultOutbounds, jsonBytes)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	outbounds := []json_util.RawMessage{}
 | 
					 | 
				
			||||||
	startIndex := 0
 | 
					 | 
				
			||||||
	// Prepare Inbounds
 | 
						// Prepare Inbounds
 | 
				
			||||||
	for _, inbound := range inbounds {
 | 
						for _, inbound := range inbounds {
 | 
				
			||||||
		clients, err := s.inboundService.GetClients(inbound)
 | 
							clients, err := s.inboundService.GetClients(inbound)
 | 
				
			||||||
| 
						 | 
					@ -62,7 +70,7 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' {
 | 
							if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' {
 | 
				
			||||||
			listen, port, streamSettings, err := s.getFallbackMaster(inbound.Listen, inbound.StreamSettings)
 | 
								listen, port, streamSettings, err := s.SubService.getFallbackMaster(inbound.Listen, inbound.StreamSettings)
 | 
				
			||||||
			if err == nil {
 | 
								if err == nil {
 | 
				
			||||||
				inbound.Listen = listen
 | 
									inbound.Listen = listen
 | 
				
			||||||
				inbound.Port = port
 | 
									inbound.Port = port
 | 
				
			||||||
| 
						 | 
					@ -70,22 +78,16 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var subClients []model.Client
 | 
					 | 
				
			||||||
		for _, client := range clients {
 | 
							for _, client := range clients {
 | 
				
			||||||
			if client.Enable && client.SubID == subId {
 | 
								if client.Enable && client.SubID == subId {
 | 
				
			||||||
				subClients = append(subClients, client)
 | 
					 | 
				
			||||||
				clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email))
 | 
									clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email))
 | 
				
			||||||
 | 
									newConfigs := s.getConfig(inbound, client, host)
 | 
				
			||||||
 | 
									configArray = append(configArray, newConfigs...)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		outbound := s.getOutbound(inbound, subClients, host, startIndex)
 | 
						if len(configArray) == 0 {
 | 
				
			||||||
		if outbound != nil {
 | 
					 | 
				
			||||||
			outbounds = append(outbounds, outbound...)
 | 
					 | 
				
			||||||
			startIndex += len(outbound)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(outbounds) == 0 {
 | 
					 | 
				
			||||||
		return "", "", nil
 | 
							return "", "", nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,21 +114,15 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if s.fragmanet != "" {
 | 
					 | 
				
			||||||
		outbounds = append(outbounds, json_util.RawMessage(s.fragmanet))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Combile outbounds
 | 
						// Combile outbounds
 | 
				
			||||||
	outbounds = append(outbounds, defaultOutbounds...)
 | 
						finalJson, _ := json.MarshalIndent(configArray, "", "  ")
 | 
				
			||||||
	configJson["outbounds"] = outbounds
 | 
					 | 
				
			||||||
	finalJson, _ := json.MarshalIndent(configJson, "", "  ")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
 | 
						header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
 | 
				
			||||||
	return string(finalJson), header, nil
 | 
						return string(finalJson), header, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SubJsonService) getOutbound(inbound *model.Inbound, clients []model.Client, host string, startIndex int) []json_util.RawMessage {
 | 
					func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client, host string) []json_util.RawMessage {
 | 
				
			||||||
	var newOutbounds []json_util.RawMessage
 | 
						var newJsonArray []json_util.RawMessage
 | 
				
			||||||
	stream := s.streamData(inbound.StreamSettings)
 | 
						stream := s.streamData(inbound.StreamSettings)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	externalProxies, ok := stream["externalProxy"].([]interface{})
 | 
						externalProxies, ok := stream["externalProxy"].([]interface{})
 | 
				
			||||||
| 
						 | 
					@ -136,13 +132,13 @@ func (s *SubJsonService) getOutbound(inbound *model.Inbound, clients []model.Cli
 | 
				
			||||||
				"forceTls": "same",
 | 
									"forceTls": "same",
 | 
				
			||||||
				"dest":     host,
 | 
									"dest":     host,
 | 
				
			||||||
				"port":     float64(inbound.Port),
 | 
									"port":     float64(inbound.Port),
 | 
				
			||||||
 | 
									"remark":   "",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	delete(stream, "externalProxy")
 | 
						delete(stream, "externalProxy")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config_index := startIndex
 | 
					 | 
				
			||||||
	for _, ep := range externalProxies {
 | 
						for _, ep := range externalProxies {
 | 
				
			||||||
		extPrxy := ep.(map[string]interface{})
 | 
							extPrxy := ep.(map[string]interface{})
 | 
				
			||||||
		inbound.Listen = extPrxy["dest"].(string)
 | 
							inbound.Listen = extPrxy["dest"].(string)
 | 
				
			||||||
| 
						 | 
					@ -161,21 +157,28 @@ func (s *SubJsonService) getOutbound(inbound *model.Inbound, clients []model.Cli
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		streamSettings, _ := json.MarshalIndent(newStream, "", "  ")
 | 
							streamSettings, _ := json.MarshalIndent(newStream, "", "  ")
 | 
				
			||||||
		inbound.StreamSettings = string(streamSettings)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, client := range clients {
 | 
							var newOutbounds []json_util.RawMessage
 | 
				
			||||||
			inbound.Tag = fmt.Sprintf("proxy_%d", config_index)
 | 
					
 | 
				
			||||||
		switch inbound.Protocol {
 | 
							switch inbound.Protocol {
 | 
				
			||||||
		case "vmess", "vless":
 | 
							case "vmess", "vless":
 | 
				
			||||||
				newOutbounds = append(newOutbounds, s.genVnext(inbound, client))
 | 
								newOutbounds = append(newOutbounds, s.genVnext(inbound, streamSettings, client))
 | 
				
			||||||
		case "trojan", "shadowsocks":
 | 
							case "trojan", "shadowsocks":
 | 
				
			||||||
				newOutbounds = append(newOutbounds, s.genServer(inbound, client))
 | 
								newOutbounds = append(newOutbounds, s.genServer(inbound, streamSettings, client))
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			config_index += 1
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return newOutbounds
 | 
							newOutbounds = append(newOutbounds, s.defaultOutbounds...)
 | 
				
			||||||
 | 
							newConfigJson := make(map[string]interface{})
 | 
				
			||||||
 | 
							for key, value := range s.configJson {
 | 
				
			||||||
 | 
								newConfigJson[key] = value
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							newConfigJson["outbounds"] = newOutbounds
 | 
				
			||||||
 | 
							newConfigJson["remarks"] = s.SubService.genRemark(inbound, client.Email, extPrxy["remark"].(string))
 | 
				
			||||||
 | 
							newConfig, _ := json.MarshalIndent(newConfigJson, "", "  ")
 | 
				
			||||||
 | 
							newJsonArray = append(newJsonArray, newConfig)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newJsonArray
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SubJsonService) streamData(stream string) map[string]interface{} {
 | 
					func (s *SubJsonService) streamData(stream string) map[string]interface{} {
 | 
				
			||||||
| 
						 | 
					@ -189,7 +192,7 @@ func (s *SubJsonService) streamData(stream string) map[string]interface{} {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	delete(streamSettings, "sockopt")
 | 
						delete(streamSettings, "sockopt")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if s.fragmanet != "" {
 | 
						if s.fragment != "" {
 | 
				
			||||||
		streamSettings["sockopt"] = json_util.RawMessage(`{"dialerProxy": "fragment", "tcpKeepAliveIdle": 100, "tcpNoDelay": true}`)
 | 
							streamSettings["sockopt"] = json_util.RawMessage(`{"dialerProxy": "fragment", "tcpKeepAliveIdle": 100, "tcpNoDelay": true}`)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,8 +203,6 @@ func (s *SubJsonService) streamData(stream string) map[string]interface{} {
 | 
				
			||||||
		streamSettings["tcpSettings"] = s.removeAcceptProxy(streamSettings["tcpSettings"])
 | 
							streamSettings["tcpSettings"] = s.removeAcceptProxy(streamSettings["tcpSettings"])
 | 
				
			||||||
	case "ws":
 | 
						case "ws":
 | 
				
			||||||
		streamSettings["wsSettings"] = s.removeAcceptProxy(streamSettings["wsSettings"])
 | 
							streamSettings["wsSettings"] = s.removeAcceptProxy(streamSettings["wsSettings"])
 | 
				
			||||||
	case "httpupgrade":
 | 
					 | 
				
			||||||
		streamSettings["httpupgradeSettings"] = s.removeAcceptProxy(streamSettings["httpupgradeSettings"])
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return streamSettings
 | 
						return streamSettings
 | 
				
			||||||
| 
						 | 
					@ -217,7 +218,7 @@ func (s *SubJsonService) removeAcceptProxy(setting interface{}) map[string]inter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SubJsonService) tlsData(tData map[string]interface{}) map[string]interface{} {
 | 
					func (s *SubJsonService) tlsData(tData map[string]interface{}) map[string]interface{} {
 | 
				
			||||||
	tlsData := make(map[string]interface{}, 1)
 | 
						tlsData := make(map[string]interface{}, 1)
 | 
				
			||||||
	tlsClientSettings := tData["settings"].(map[string]interface{})
 | 
						tlsClientSettings, _ := tData["settings"].(map[string]interface{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tlsData["serverName"] = tData["serverName"]
 | 
						tlsData["serverName"] = tData["serverName"]
 | 
				
			||||||
	tlsData["alpn"] = tData["alpn"]
 | 
						tlsData["alpn"] = tData["alpn"]
 | 
				
			||||||
| 
						 | 
					@ -232,7 +233,7 @@ func (s *SubJsonService) tlsData(tData map[string]interface{}) map[string]interf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]interface{} {
 | 
					func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]interface{} {
 | 
				
			||||||
	rltyData := make(map[string]interface{}, 1)
 | 
						rltyData := make(map[string]interface{}, 1)
 | 
				
			||||||
	rltyClientSettings := rData["settings"].(map[string]interface{})
 | 
						rltyClientSettings, _ := rData["settings"].(map[string]interface{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rltyData["show"] = false
 | 
						rltyData["show"] = false
 | 
				
			||||||
	rltyData["publicKey"] = rltyClientSettings["publicKey"]
 | 
						rltyData["publicKey"] = rltyClientSettings["publicKey"]
 | 
				
			||||||
| 
						 | 
					@ -256,7 +257,7 @@ func (s *SubJsonService) realityData(rData map[string]interface{}) map[string]in
 | 
				
			||||||
	return rltyData
 | 
						return rltyData
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SubJsonService) genVnext(inbound *model.Inbound, client model.Client) json_util.RawMessage {
 | 
					func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client) json_util.RawMessage {
 | 
				
			||||||
	outbound := Outbound{}
 | 
						outbound := Outbound{}
 | 
				
			||||||
	usersData := make([]UserVnext, 1)
 | 
						usersData := make([]UserVnext, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,8 +276,8 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, client model.Client) j
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outbound.Protocol = string(inbound.Protocol)
 | 
						outbound.Protocol = string(inbound.Protocol)
 | 
				
			||||||
	outbound.Tag = inbound.Tag
 | 
						outbound.Tag = "proxy"
 | 
				
			||||||
	outbound.StreamSettings = json_util.RawMessage(inbound.StreamSettings)
 | 
						outbound.StreamSettings = streamSettings
 | 
				
			||||||
	outbound.Settings = OutboundSettings{
 | 
						outbound.Settings = OutboundSettings{
 | 
				
			||||||
		Vnext: vnextData,
 | 
							Vnext: vnextData,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -285,7 +286,7 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, client model.Client) j
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SubJsonService) genServer(inbound *model.Inbound, client model.Client) json_util.RawMessage {
 | 
					func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client) json_util.RawMessage {
 | 
				
			||||||
	outbound := Outbound{}
 | 
						outbound := Outbound{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	serverData := make([]ServerSetting, 1)
 | 
						serverData := make([]ServerSetting, 1)
 | 
				
			||||||
| 
						 | 
					@ -311,8 +312,8 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, client model.Client)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outbound.Protocol = string(inbound.Protocol)
 | 
						outbound.Protocol = string(inbound.Protocol)
 | 
				
			||||||
	outbound.Tag = inbound.Tag
 | 
						outbound.Tag = "proxy"
 | 
				
			||||||
	outbound.StreamSettings = json_util.RawMessage(inbound.StreamSettings)
 | 
						outbound.StreamSettings = streamSettings
 | 
				
			||||||
	outbound.Settings = OutboundSettings{
 | 
						outbound.Settings = OutboundSettings{
 | 
				
			||||||
		Servers: serverData,
 | 
							Servers: serverData,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,6 +397,7 @@ class StreamSettings extends CommonClass {
 | 
				
			||||||
                quicSettings=new QuicStreamSettings(),
 | 
					                quicSettings=new QuicStreamSettings(),
 | 
				
			||||||
                grpcSettings=new GrpcStreamSettings(),
 | 
					                grpcSettings=new GrpcStreamSettings(),
 | 
				
			||||||
                httpupgradeSettings=new HttpUpgradeStreamSettings(),
 | 
					                httpupgradeSettings=new HttpUpgradeStreamSettings(),
 | 
				
			||||||
 | 
					                sockopt = undefined,
 | 
				
			||||||
                ) {
 | 
					                ) {
 | 
				
			||||||
        super();
 | 
					        super();
 | 
				
			||||||
        this.network = network;
 | 
					        this.network = network;
 | 
				
			||||||
| 
						 | 
					@ -410,6 +411,7 @@ class StreamSettings extends CommonClass {
 | 
				
			||||||
        this.quic = quicSettings;
 | 
					        this.quic = quicSettings;
 | 
				
			||||||
        this.grpc = grpcSettings;
 | 
					        this.grpc = grpcSettings;
 | 
				
			||||||
        this.httpupgrade = httpupgradeSettings;
 | 
					        this.httpupgrade = httpupgradeSettings;
 | 
				
			||||||
 | 
					        this.sockopt = sockopt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    get isTls() {
 | 
					    get isTls() {
 | 
				
			||||||
| 
						 | 
					@ -441,6 +443,7 @@ class StreamSettings extends CommonClass {
 | 
				
			||||||
            QuicStreamSettings.fromJson(json.quicSettings),
 | 
					            QuicStreamSettings.fromJson(json.quicSettings),
 | 
				
			||||||
            GrpcStreamSettings.fromJson(json.grpcSettings),
 | 
					            GrpcStreamSettings.fromJson(json.grpcSettings),
 | 
				
			||||||
            HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
 | 
					            HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
 | 
				
			||||||
 | 
					            SockoptStreamSettings.fromJson(json.sockopt),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
{{define "qrcodeModal"}}
 | 
					{{define "qrcodeModal"}}
 | 
				
			||||||
<a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title"
 | 
					<a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title"
 | 
				
			||||||
 | 
					        :dialog-style="{ top: '20px' }"
 | 
				
			||||||
        :closable="true"
 | 
					        :closable="true"
 | 
				
			||||||
        :class="themeSwitcher.currentTheme"
 | 
					        :class="themeSwitcher.currentTheme"
 | 
				
			||||||
        :footer="null"
 | 
					        :footer="null"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
{{define "inboundModal"}}
 | 
					{{define "inboundModal"}}
 | 
				
			||||||
<a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" @ok="inModal.ok"
 | 
					<a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title"
 | 
				
			||||||
 | 
					        :dialog-style="{ top: '20px' }" @ok="inModal.ok"
 | 
				
			||||||
        :confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false"
 | 
					        :confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false"
 | 
				
			||||||
        :class="themeSwitcher.currentTheme"
 | 
					        :class="themeSwitcher.currentTheme"
 | 
				
			||||||
        :ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
 | 
					        :ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,17 +259,13 @@
 | 
				
			||||||
        </a-layout-content>
 | 
					        </a-layout-content>
 | 
				
			||||||
    </a-layout>
 | 
					    </a-layout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <a-modal id="version-modal" v-model="versionModal.visible" title='{{ i18n "pages.index.xraySwitch" }}'
 | 
					    <a-modal id="version-modal" v-model="versionModal.visible" title='{{ i18n "pages.index.xraySwitch" }}' :closable="true"
 | 
				
			||||||
             :closable="true" @ok="() => versionModal.visible = false"
 | 
					        @ok="() => versionModal.visible = false" :class="themeSwitcher.currentTheme" footer="">
 | 
				
			||||||
             :class="themeSwitcher.currentTheme"
 | 
					 | 
				
			||||||
             footer="">
 | 
					 | 
				
			||||||
        <a-alert type="warning" style="margin-bottom: 12px; width: fit-content"
 | 
					        <a-alert type="warning" style="margin-bottom: 12px; width: fit-content"
 | 
				
			||||||
        message='{{ i18n "pages.index.xraySwitchClickDesk" }}'
 | 
					            message='{{ i18n "pages.index.xraySwitchClickDesk" }}' show-icon></a-alert>
 | 
				
			||||||
        show-icon
 | 
					 | 
				
			||||||
        ></a-alert>
 | 
					 | 
				
			||||||
        <template v-for="version, index in versionModal.versions">
 | 
					        <template v-for="version, index in versionModal.versions">
 | 
				
			||||||
            <a-tag :color="index % 2 == 0 ? 'purple' : 'green'"
 | 
					            <a-tag :color="index % 2 == 0 ? 'purple' : 'green'" style="margin-right: 12px; margin-bottom: 12px"
 | 
				
			||||||
                   style="margin-right: 10px" @click="switchV2rayVersion(version)">
 | 
					                @click="switchV2rayVersion(version)">
 | 
				
			||||||
                [[ version ]]
 | 
					                [[ version ]]
 | 
				
			||||||
            </a-tag>
 | 
					            </a-tag>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -295,11 +295,30 @@
 | 
				
			||||||
                                <setting-list-item type="text" title='{{ i18n "pages.settings.subPath"}}' desc='{{ i18n "pages.settings.subPathDesc"}}' v-model="allSetting.subJsonPath"></setting-list-item>
 | 
					                                <setting-list-item type="text" title='{{ i18n "pages.settings.subPath"}}' desc='{{ i18n "pages.settings.subPathDesc"}}' v-model="allSetting.subJsonPath"></setting-list-item>
 | 
				
			||||||
                                <setting-list-item type="text" title='{{ i18n "pages.settings.subURI"}}' desc='{{ i18n "pages.settings.subURIDesc"}}' v-model="allSetting.subJsonURI" placeholder="(http|https)://domain[:port]/path/"></setting-list-item>
 | 
					                                <setting-list-item type="text" title='{{ i18n "pages.settings.subURI"}}' desc='{{ i18n "pages.settings.subURIDesc"}}' v-model="allSetting.subJsonURI" placeholder="(http|https)://domain[:port]/path/"></setting-list-item>
 | 
				
			||||||
                                <setting-list-item type="switch" title='{{ i18n "pages.settings.fragment"}}' desc='{{ i18n "pages.settings.fragmentDesc"}}' v-model="fragment"></setting-list-item>
 | 
					                                <setting-list-item type="switch" title='{{ i18n "pages.settings.fragment"}}' desc='{{ i18n "pages.settings.fragmentDesc"}}' v-model="fragment"></setting-list-item>
 | 
				
			||||||
                                <template v-if="fragment">
 | 
					 | 
				
			||||||
                                    <setting-list-item type="text" title='length' v-model="fragmentLength" placeholder="100-200"></setting-list-item>
 | 
					 | 
				
			||||||
                                    <setting-list-item type="text" title='Interval' v-model="fragmentInterval" placeholder="10-20"></setting-list-item>
 | 
					 | 
				
			||||||
                                </template>
 | 
					 | 
				
			||||||
                            </a-list>
 | 
					                            </a-list>
 | 
				
			||||||
 | 
					                            <a-collapse v-if="fragment">
 | 
				
			||||||
 | 
					                                <a-collapse-panel header='{{ i18n "pages.settings.fragment"}}'>
 | 
				
			||||||
 | 
					                                    <a-list-item style="padding: 20px">
 | 
				
			||||||
 | 
					                                        <a-row>
 | 
				
			||||||
 | 
					                                            <a-col :lg="24" :xl="12">
 | 
				
			||||||
 | 
					                                                <a-list-item-meta title='Packets'/>
 | 
				
			||||||
 | 
					                                            </a-col>
 | 
				
			||||||
 | 
					                                            <a-col :lg="24" :xl="12">
 | 
				
			||||||
 | 
					                                                <a-select
 | 
				
			||||||
 | 
					                                                    v-model="fragmentPackets"
 | 
				
			||||||
 | 
					                                                    style="width: 100%"
 | 
				
			||||||
 | 
					                                                    :dropdown-class-name="themeSwitcher.currentTheme">
 | 
				
			||||||
 | 
					                                                    <a-select-option :value="p" :label="p" v-for="p in ['1-1', '1-3', 'tlshello']">
 | 
				
			||||||
 | 
					                                                        [[ p ]]
 | 
				
			||||||
 | 
					                                                    </a-select-option>
 | 
				
			||||||
 | 
					                                                </a-select>
 | 
				
			||||||
 | 
					                                            </a-col>
 | 
				
			||||||
 | 
					                                        </a-row>
 | 
				
			||||||
 | 
					                                    </a-list-item>
 | 
				
			||||||
 | 
					                                    <setting-list-item type="text" title='Length' v-model="fragmentLength" placeholder="100-200"></setting-list-item>
 | 
				
			||||||
 | 
					                                    <setting-list-item type="text" title='Interval' v-model="fragmentInterval" placeholder="10-20"></setting-list-item>
 | 
				
			||||||
 | 
					                                </a-collapse-panel>
 | 
				
			||||||
 | 
					                            </a-collapse>
 | 
				
			||||||
                        </a-tab-pane>
 | 
					                        </a-tab-pane>
 | 
				
			||||||
                    </a-tabs>
 | 
					                    </a-tabs>
 | 
				
			||||||
                </a-space>
 | 
					                </a-space>
 | 
				
			||||||
| 
						 | 
					@ -483,6 +502,16 @@
 | 
				
			||||||
                    this.allSetting.subJsonFragment = v ? JSON.stringify(this.defaultFragment) : "";
 | 
					                    this.allSetting.subJsonFragment = v ? JSON.stringify(this.defaultFragment) : "";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            fragmentPackets: {
 | 
				
			||||||
 | 
					                get: function() { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.packets : ""; },
 | 
				
			||||||
 | 
					                set: function(v) {
 | 
				
			||||||
 | 
					                    if (v != ""){
 | 
				
			||||||
 | 
					                        newFragment = JSON.parse(this.allSetting.subJsonFragment);
 | 
				
			||||||
 | 
					                        newFragment.settings.fragment.packets = v;
 | 
				
			||||||
 | 
					                        this.allSetting.subJsonFragment = JSON.stringify(newFragment);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            fragmentLength: {
 | 
					            fragmentLength: {
 | 
				
			||||||
                get: function() { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.length : ""; },
 | 
					                get: function() { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.length : ""; },
 | 
				
			||||||
                set: function(v) {
 | 
					                set: function(v) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue