Browse Source

[subJson] add mux and direct

Co-Authored-By: Alireza Ahmadi <[email protected]>
MHSanaei 1 year ago
parent
commit
8b5fe0b018

+ 13 - 1
sub/sub.go

@@ -92,9 +92,21 @@ func (s *Server) initRouter() (*gin.Engine, error) {
 		SubJsonFragment = ""
 	}
 
+	SubJsonMux, err := s.settingService.GetSubJsonMux()
+	if err != nil {
+		SubJsonMux = ""
+	}
+
+	SubJsonRules, err := s.settingService.GetSubJsonRules()
+	if err != nil {
+		SubJsonRules = ""
+	}
+
 	g := engine.Group("/")
 
-	s.sub = NewSUBController(g, LinksPath, JsonPath, Encrypt, ShowInfo, RemarkModel, SubUpdates, SubJsonFragment)
+	s.sub = NewSUBController(
+		g, LinksPath, JsonPath, Encrypt, ShowInfo, RemarkModel, SubUpdates,
+		SubJsonFragment, SubJsonMux, SubJsonRules)
 
 	return engine, nil
 }

+ 3 - 1
sub/subController.go

@@ -26,6 +26,8 @@ func NewSUBController(
 	rModel string,
 	update string,
 	jsonFragment string,
+	jsonMux string,
+	jsonRules string,
 ) *SUBController {
 	sub := NewSubService(showInfo, rModel)
 	a := &SUBController{
@@ -35,7 +37,7 @@ func NewSUBController(
 		updateInterval: update,
 
 		subService:     sub,
-		subJsonService: NewSubJsonService(jsonFragment, sub),
+		subJsonService: NewSubJsonService(jsonFragment, jsonMux, jsonRules, sub),
 	}
 	a.initRouter(g)
 	return a

+ 21 - 2
sub/subJsonService.go

@@ -21,12 +21,13 @@ type SubJsonService struct {
 	configJson       map[string]interface{}
 	defaultOutbounds []json_util.RawMessage
 	fragment         string
+	mux              string
 
 	inboundService service.InboundService
 	SubService     *SubService
 }
 
-func NewSubJsonService(fragment string, subService *SubService) *SubJsonService {
+func NewSubJsonService(fragment string, mux string, rules string, subService *SubService) *SubJsonService {
 	var configJson map[string]interface{}
 	var defaultOutbounds []json_util.RawMessage
 	json.Unmarshal([]byte(defaultJson), &configJson)
@@ -37,6 +38,17 @@ func NewSubJsonService(fragment string, subService *SubService) *SubJsonService
 		}
 	}
 
+	if rules != "" {
+		var newRules []interface{}
+		routing, _ := configJson["routing"].(map[string]interface{})
+		defaultRules, _ := routing["rules"].([]interface{})
+		json.Unmarshal([]byte(rules), &newRules)
+		defaultRules = append(newRules, defaultRules...)
+		fmt.Printf("routing: %#v\n\nRules: %#v\n\n", routing, defaultRules)
+		routing["rules"] = defaultRules
+		configJson["routing"] = routing
+	}
+
 	if fragment != "" {
 		defaultOutbounds = append(defaultOutbounds, json_util.RawMessage(fragment))
 	}
@@ -45,6 +57,7 @@ func NewSubJsonService(fragment string, subService *SubService) *SubJsonService
 		configJson:       configJson,
 		defaultOutbounds: defaultOutbounds,
 		fragment:         fragment,
+		mux:              mux,
 		SubService:       subService,
 	}
 }
@@ -277,6 +290,9 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_ut
 
 	outbound.Protocol = string(inbound.Protocol)
 	outbound.Tag = "proxy"
+	if s.mux != "" {
+		outbound.Mux = json_util.RawMessage(s.mux)
+	}
 	outbound.StreamSettings = streamSettings
 	outbound.Settings = OutboundSettings{
 		Vnext: vnextData,
@@ -313,6 +329,9 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_u
 
 	outbound.Protocol = string(inbound.Protocol)
 	outbound.Tag = "proxy"
+	if s.mux != "" {
+		outbound.Mux = json_util.RawMessage(s.mux)
+	}
 	outbound.StreamSettings = streamSettings
 	outbound.Settings = OutboundSettings{
 		Servers: serverData,
@@ -326,7 +345,7 @@ type Outbound struct {
 	Protocol       string                 `json:"protocol"`
 	Tag            string                 `json:"tag"`
 	StreamSettings json_util.RawMessage   `json:"streamSettings"`
-	Mux            map[string]interface{} `json:"mux,omitempty"`
+	Mux            json_util.RawMessage   `json:"mux,omitempty"`
 	ProxySettings  map[string]interface{} `json:"proxySettings,omitempty"`
 	Settings       OutboundSettings       `json:"settings,omitempty"`
 }

+ 5 - 3
web/assets/js/model/setting.js

@@ -35,9 +35,11 @@ class AllSetting {
         this.subUpdates = 0;
         this.subEncrypt = true;
         this.subShowInfo = false;
-        this.subURI = '';
-        this.subJsonURI = '';
-        this.subJsonFragment = '';
+        this.subURI = "";
+        this.subJsonURI = "";
+        this.subJsonFragment = "";
+        this.subJsonMux = "";
+        this.subJsonRules = "";
 
         this.timeLocation = "Asia/Tehran";
 

+ 2 - 0
web/entity/entity.go

@@ -52,6 +52,8 @@ type AllSetting struct {
 	SubJsonPath      string `json:"subJsonPath" form:"subJsonPath"`
 	SubJsonURI       string `json:"subJsonURI" form:"subJsonURI"`
 	SubJsonFragment  string `json:"subJsonFragment" form:"subJsonFragment"`
+	SubJsonMux       string `json:"subJsonMux" form:"subJsonMux"`
+	SubJsonRules     string `json:"subJsonRules" form:"subJsonRules"`
 	Datepicker       string `json:"datepicker" form:"datepicker"`
 }
 

+ 121 - 0
web/html/xui/settings.html

@@ -295,6 +295,8 @@
                                 <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="switch" title='{{ i18n "pages.settings.fragment"}}' desc='{{ i18n "pages.settings.fragmentDesc"}}' v-model="fragment"></setting-list-item>
+                                <setting-list-item type="switch" title='Mux' v-model="enableMux"></setting-list-item>
+                                <setting-list-item type="switch" title='{{ i18n "pages.xray.directCountryConfigs"}}' desc='{{ i18n "pages.xray.directCountryConfigsDesc"}}' v-model="enableDirect"></setting-list-item>
                             </a-list>
                             <a-collapse v-if="fragment">
                                 <a-collapse-panel header='{{ i18n "pages.settings.fragment"}}'>
@@ -318,6 +320,36 @@
                                     <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-panel header='Mux' v-if="enableMux">                                    
+                                    <setting-list-item type="number" title='Concurrency' v-model="muxConcurrency" :min="-1" :max="1024"></setting-list-item>
+                                    <setting-list-item type="number" title='xudp Concurrency' v-model="muxXudpConcurrency" :min="-1" :max="1024"></setting-list-item>
+                                    <a-list-item style="padding: 20px">
+                                        <a-row>
+                                            <a-col :lg="24" :xl="12">
+                                                <a-list-item-meta title='xudp UDP 443'/>
+                                            </a-col>
+                                            <a-col :lg="24" :xl="12">
+                                                <a-select
+                                                    v-model="muxXudpProxyUDP443"
+                                                    style="width: 100%"
+                                                    :dropdown-class-name="themeSwitcher.currentTheme">
+                                                    <a-select-option :value="p" :label="p" v-for="p in ['reject', 'allow', 'skip']">
+                                                        [[ p ]]
+                                                    </a-select-option>
+                                                </a-select>
+                                            </a-col>
+                                        </a-row>
+                                    </a-list-item>
+                                </a-collapse-panel>
+                                <a-collapse-panel header='{{ i18n "pages.xray.directCountryConfigs"}}' v-if="enableDirect">
+                                    <a-list-item style="padding: 20px">
+                                        <a-checkbox-group
+                                        v-model="directCountries"
+                                        name="Countries"
+                                        :options="countryOptions"
+                                      />
+                                    </a-list-item>
+                                </a-collapse-panel>
                             </a-collapse>
                         </a-tab-pane>
                     </a-tabs>
@@ -367,6 +399,40 @@
                     }
                 }
             },
+            defaultMux: {
+                enabled: true,
+                concurrency: 8,
+                xudpConcurrency: 16,
+                xudpProxyUDP443: "reject"
+            },
+            defaultRules: [
+                {
+                    type: "field",
+                    outboundTag: "direct",
+                    domain: [
+                        "geosite:category-ir",
+                        "geosite:cn"
+                    ],
+                    "enabled": true
+                },
+                {
+                    type: "field",
+                    outboundTag: "direct",
+                    ip: [
+                        "geoip:private",
+                        "geoip:ir",
+                        "geoip:cn"
+                    ],
+                    enabled: true
+                },
+            ],
+            countryOptions: [
+                { label: 'Private IP/Domain', value: 'private' },
+                { label: '🇮🇷 Iran', value: 'ir' },
+                { label: '🇨🇳 China', value: 'cn' },
+                { label: '🇷🇺 Russia', value: 'ru' },
+                { label: '🇻🇳 Vietnam', value: 'vn' },
+            ],
             get remarkModel() {
                 rm = this.allSetting.remarkModel;
                 return rm.length>1 ? rm.substring(1).split('') : [];
@@ -530,6 +596,61 @@
                     }
                 }
             },
+            enableMux: {
+                get: function() { return this.allSetting?.subJsonMux != ""; },
+                set: function (v) {
+                    this.allSetting.subJsonMux = v ? JSON.stringify(this.defaultMux) : "";
+                }
+            },
+            muxConcurrency: {
+                get: function() { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).concurrency : -1; },
+                set: function(v) {
+                    newMux = JSON.parse(this.allSetting.subJsonMux);
+                    newMux.concurrency = v;
+                    this.allSetting.subJsonMux = JSON.stringify(newMux);
+                }
+            },
+            muxXudpConcurrency: {
+                get: function() { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpConcurrency : -1; },
+                set: function(v) {
+                    newMux = JSON.parse(this.allSetting.subJsonMux);
+                    newMux.xudpConcurrency = v;
+                    this.allSetting.subJsonMux = JSON.stringify(newMux);
+                }
+            },
+            muxXudpProxyUDP443: {
+                get: function() { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpProxyUDP443 : "reject"; },
+                set: function(v) {
+                    newMux = JSON.parse(this.allSetting.subJsonMux);
+                    newMux.xudpProxyUDP443 = v;
+                    this.allSetting.subJsonMux = JSON.stringify(newMux);
+                }
+            },
+            enableDirect: {
+                get: function() { return this.allSetting?.subJsonRules != ""; },
+                set: function (v) {
+                    this.allSetting.subJsonRules = v ? JSON.stringify(this.defaultRules) : "";
+                }
+            },
+            directCountries: {
+                get: function() {
+                    if (!this.enableDirect) return [];
+                    rules = JSON.parse(this.allSetting.subJsonRules);
+                    return Array.isArray(rules) ? rules[1].ip.map(d => d.replace("geoip:","")) : [];
+                },
+                set: function (v) {
+                    rules = JSON.parse(this.allSetting.subJsonRules);
+                    if (!Array.isArray(rules)) return;
+                    rules[0].domain = [];
+                    rules[1].ip = [];
+                    v.forEach(d => {
+                        category = ["cn","private"].includes(d) ? "" : "category-";
+                        rules[0].domain.push("geosite:"+category+d);
+                        rules[1].ip.push("geoip:"+d);
+                    });
+                    this.allSetting.subJsonRules = JSON.stringify(rules);
+                }
+            },
             confAlerts: {
                 get: function() {
                     if (!this.allSetting) return [];

+ 10 - 0
web/service/setting.go

@@ -61,6 +61,8 @@ var defaultValueMap = map[string]string{
 	"subJsonPath":        "/json/",
 	"subJsonURI":         "",
 	"subJsonFragment":    "",
+	"subJsonMux":         "",
+	"subJsonRules":       "",
 	"datepicker":         "gregorian",
 	"warp":               "",
 }
@@ -437,6 +439,14 @@ func (s *SettingService) GetSubJsonFragment() (string, error) {
 	return s.getString("subJsonFragment")
 }
 
+func (s *SettingService) GetSubJsonMux() (string, error) {
+	return s.getString("subJsonMux")
+}
+
+func (s *SettingService) GetSubJsonRules() (string, error) {
+	return s.getString("subJsonRules")
+}
+
 func (s *SettingService) GetDatepicker() (string, error) {
 	return s.getString("datepicker")
 }