mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-03-01 01:20:49 +03:00
[feature] add grpc multiMode
This commit is contained in:
parent
8879541999
commit
607c5d3598
2
go.sum
2
go.sum
@ -9,8 +9,6 @@ github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P
|
|||||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.8.7 h1:d3sry5vGgVq/OpgozRUNP6xBsSo0mtNdwliApw+SAMQ=
|
|
||||||
github.com/bytedance/sonic v1.8.7/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
|
||||||
github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q=
|
github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q=
|
||||||
github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package logger
|
package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/op/go-logging"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/op/go-logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger *logging.Logger
|
var logger *logging.Logger
|
||||||
|
@ -440,18 +440,26 @@ class QuicStreamSettings extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GrpcStreamSettings extends XrayCommonClass {
|
class GrpcStreamSettings extends XrayCommonClass {
|
||||||
constructor(serviceName="") {
|
constructor(
|
||||||
|
serviceName="",
|
||||||
|
multiMode=false
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this.serviceName = serviceName;
|
this.serviceName = serviceName;
|
||||||
|
this.multiMode = multiMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
return new GrpcStreamSettings(json.serviceName);
|
return new GrpcStreamSettings(
|
||||||
|
json.serviceName,
|
||||||
|
json.multiMode
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson() {
|
toJson() {
|
||||||
return {
|
return {
|
||||||
serviceName: this.serviceName,
|
serviceName: this.serviceName,
|
||||||
|
multiMode: this.multiMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1246,50 +1254,6 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (this.protocol !== Protocols.VMESS) {
|
if (this.protocol !== Protocols.VMESS) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
let network = this.stream.network;
|
|
||||||
let type = 'none';
|
|
||||||
let host = '';
|
|
||||||
let path = '';
|
|
||||||
if (network === 'tcp') {
|
|
||||||
let tcp = this.stream.tcp;
|
|
||||||
type = tcp.type;
|
|
||||||
if (type === 'http') {
|
|
||||||
let request = tcp.request;
|
|
||||||
path = request.path.join(',');
|
|
||||||
let index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
|
||||||
if (index >= 0) {
|
|
||||||
host = request.headers[index].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (network === 'kcp') {
|
|
||||||
let kcp = this.stream.kcp;
|
|
||||||
type = kcp.type;
|
|
||||||
path = kcp.seed;
|
|
||||||
} else if (network === 'ws') {
|
|
||||||
let ws = this.stream.ws;
|
|
||||||
path = ws.path;
|
|
||||||
let index = ws.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
|
||||||
if (index >= 0) {
|
|
||||||
host = ws.headers[index].value;
|
|
||||||
}
|
|
||||||
} else if (network === 'http') {
|
|
||||||
network = 'h2';
|
|
||||||
path = this.stream.http.path;
|
|
||||||
host = this.stream.http.host.join(',');
|
|
||||||
} else if (network === 'quic') {
|
|
||||||
type = this.stream.quic.type;
|
|
||||||
host = this.stream.quic.security;
|
|
||||||
path = this.stream.quic.key;
|
|
||||||
} else if (network === 'grpc') {
|
|
||||||
path = this.stream.grpc.serviceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.stream.security === 'tls') {
|
|
||||||
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
|
||||||
address = this.stream.tls.server;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let obj = {
|
let obj = {
|
||||||
v: '2',
|
v: '2',
|
||||||
ps: remark,
|
ps: remark,
|
||||||
@ -1297,16 +1261,66 @@ class Inbound extends XrayCommonClass {
|
|||||||
port: this.port,
|
port: this.port,
|
||||||
id: this.settings.vmesses[clientIndex].id,
|
id: this.settings.vmesses[clientIndex].id,
|
||||||
aid: this.settings.vmesses[clientIndex].alterId,
|
aid: this.settings.vmesses[clientIndex].alterId,
|
||||||
net: network,
|
net: this.stream.network,
|
||||||
type: type,
|
type: 'none',
|
||||||
host: host,
|
|
||||||
path: path,
|
|
||||||
tls: this.stream.security,
|
tls: this.stream.security,
|
||||||
sni: this.stream.tls.settings.serverName,
|
|
||||||
fp: this.stream.tls.settings.fingerprint,
|
|
||||||
alpn: this.stream.tls.alpn.join(','),
|
|
||||||
allowInsecure: this.stream.tls.settings.allowInsecure,
|
|
||||||
};
|
};
|
||||||
|
let network = this.stream.network;
|
||||||
|
if (network === 'tcp') {
|
||||||
|
let tcp = this.stream.tcp;
|
||||||
|
obj.type = tcp.type;
|
||||||
|
if (tcp.type === 'http') {
|
||||||
|
let request = tcp.request;
|
||||||
|
obj.path = request.path.join(',');
|
||||||
|
let index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
||||||
|
if (index >= 0) {
|
||||||
|
obj.host = request.headers[index].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (network === 'kcp') {
|
||||||
|
let kcp = this.stream.kcp;
|
||||||
|
obj.type = kcp.type;
|
||||||
|
obj.path = kcp.seed;
|
||||||
|
} else if (network === 'ws') {
|
||||||
|
let ws = this.stream.ws;
|
||||||
|
obj.path = ws.path;
|
||||||
|
let index = ws.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
||||||
|
if (index >= 0) {
|
||||||
|
obj.host = ws.headers[index].value;
|
||||||
|
}
|
||||||
|
} else if (network === 'http') {
|
||||||
|
obj.net = 'h2';
|
||||||
|
obj.path = this.stream.http.path;
|
||||||
|
obj.host = this.stream.http.host.join(',');
|
||||||
|
} else if (network === 'quic') {
|
||||||
|
obj.type = this.stream.quic.type;
|
||||||
|
obj.host = this.stream.quic.security;
|
||||||
|
obj.path = this.stream.quic.key;
|
||||||
|
} else if (network === 'grpc') {
|
||||||
|
obj.path = this.stream.grpc.serviceName;
|
||||||
|
if (this.stream.grpc.multiMode){
|
||||||
|
obj.type = 'multi'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stream.security === 'tls') {
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
|
obj.add = this.stream.tls.server;
|
||||||
|
}
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.settings.serverName)){
|
||||||
|
obj.sni = this.stream.tls.settings.serverName;
|
||||||
|
}
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerprint)){
|
||||||
|
obj.fp = this.stream.tls.settings.fingerprint;
|
||||||
|
}
|
||||||
|
if (this.stream.tls.alpn.length>0){
|
||||||
|
obj.alpn = this.stream.tls.alpn.join(',');
|
||||||
|
}
|
||||||
|
if (this.stream.tls.settings.allowInsecure){
|
||||||
|
obj.allowInsecure = this.stream.tls.settings.allowInsecure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 'vmess://' + base64(JSON.stringify(obj, null, 2));
|
return 'vmess://' + base64(JSON.stringify(obj, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,6 +1373,9 @@ class Inbound extends XrayCommonClass {
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
const grpc = this.stream.grpc;
|
const grpc = this.stream.grpc;
|
||||||
params.set("serviceName", grpc.serviceName);
|
params.set("serviceName", grpc.serviceName);
|
||||||
|
if(grpc.multiMode){
|
||||||
|
params.set("mode", "multi");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1476,6 +1493,9 @@ class Inbound extends XrayCommonClass {
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
const grpc = this.stream.grpc;
|
const grpc = this.stream.grpc;
|
||||||
params.set("serviceName", grpc.serviceName);
|
params.set("serviceName", grpc.serviceName);
|
||||||
|
if(grpc.multiMode){
|
||||||
|
params.set("mode", "multi");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@ package global
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/robfig/cron/v3"
|
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var webServer WebServer
|
var webServer WebServer
|
||||||
|
@ -3,5 +3,8 @@
|
|||||||
<a-form-item label="ServiceName">
|
<a-form-item label="ServiceName">
|
||||||
<a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input>
|
<a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="Multi Mode">
|
||||||
|
<a-switch v-model="inbound.stream.grpc.multiMode"></a-switch>
|
||||||
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
{{end}}
|
{{end}}
|
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
<template v-if="inbound.isGrpc">
|
<template v-if="inbound.isGrpc">
|
||||||
<tr><td>grpc serviceName</td><td><a-tag color="green">[[ inbound.serviceName ]]</a-tag></td></tr>
|
<tr><td>grpc serviceName</td><td><a-tag color="green">[[ inbound.serviceName ]]</a-tag></td></tr>
|
||||||
|
<tr><td>grpc multiMode</td><td><a-tag color="green">[[ inbound.stream.grpc.multiMode ]]</a-tag></td></tr>
|
||||||
</template>
|
</template>
|
||||||
</table>
|
</table>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
@ -102,80 +102,89 @@ func (s *SubService) getLink(inbound *model.Inbound, email string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
||||||
address := s.address
|
|
||||||
if inbound.Protocol != model.VMess {
|
if inbound.Protocol != model.VMess {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
obj := map[string]interface{}{
|
||||||
|
"v": "2",
|
||||||
|
"ps": email,
|
||||||
|
"add": s.address,
|
||||||
|
"port": inbound.Port,
|
||||||
|
"type": "none",
|
||||||
|
}
|
||||||
var stream map[string]interface{}
|
var stream map[string]interface{}
|
||||||
json.Unmarshal([]byte(inbound.StreamSettings), &stream)
|
json.Unmarshal([]byte(inbound.StreamSettings), &stream)
|
||||||
network, _ := stream["network"].(string)
|
network, _ := stream["network"].(string)
|
||||||
typeStr := "none"
|
obj["net"] = network
|
||||||
host := ""
|
|
||||||
path := ""
|
|
||||||
sni := ""
|
|
||||||
fp := ""
|
|
||||||
var alpn []string
|
|
||||||
allowInsecure := false
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
tcp, _ := stream["tcpSettings"].(map[string]interface{})
|
tcp, _ := stream["tcpSettings"].(map[string]interface{})
|
||||||
header, _ := tcp["header"].(map[string]interface{})
|
header, _ := tcp["header"].(map[string]interface{})
|
||||||
typeStr, _ = header["type"].(string)
|
typeStr, _ := header["type"].(string)
|
||||||
|
obj["type"] = typeStr
|
||||||
if typeStr == "http" {
|
if typeStr == "http" {
|
||||||
request := header["request"].(map[string]interface{})
|
request := header["request"].(map[string]interface{})
|
||||||
requestPath, _ := request["path"].([]interface{})
|
requestPath, _ := request["path"].([]interface{})
|
||||||
path = requestPath[0].(string)
|
obj["path"] = requestPath[0].(string)
|
||||||
headers, _ := request["headers"].(map[string]interface{})
|
headers, _ := request["headers"].(map[string]interface{})
|
||||||
host = searchHost(headers)
|
obj["host"] = searchHost(headers)
|
||||||
}
|
}
|
||||||
case "kcp":
|
case "kcp":
|
||||||
kcp, _ := stream["kcpSettings"].(map[string]interface{})
|
kcp, _ := stream["kcpSettings"].(map[string]interface{})
|
||||||
header, _ := kcp["header"].(map[string]interface{})
|
header, _ := kcp["header"].(map[string]interface{})
|
||||||
typeStr, _ = header["type"].(string)
|
obj["type"], _ = header["type"].(string)
|
||||||
path, _ = kcp["seed"].(string)
|
obj["path"], _ = kcp["seed"].(string)
|
||||||
case "ws":
|
case "ws":
|
||||||
ws, _ := stream["wsSettings"].(map[string]interface{})
|
ws, _ := stream["wsSettings"].(map[string]interface{})
|
||||||
path = ws["path"].(string)
|
obj["path"] = ws["path"].(string)
|
||||||
headers, _ := ws["headers"].(map[string]interface{})
|
headers, _ := ws["headers"].(map[string]interface{})
|
||||||
host = searchHost(headers)
|
obj["host"] = searchHost(headers)
|
||||||
case "http":
|
case "http":
|
||||||
network = "h2"
|
obj["net"] = "h2"
|
||||||
http, _ := stream["httpSettings"].(map[string]interface{})
|
http, _ := stream["httpSettings"].(map[string]interface{})
|
||||||
path, _ = http["path"].(string)
|
obj["path"], _ = http["path"].(string)
|
||||||
host = searchHost(http)
|
obj["host"] = searchHost(http)
|
||||||
case "quic":
|
case "quic":
|
||||||
quic, _ := stream["quicSettings"].(map[string]interface{})
|
quic, _ := stream["quicSettings"].(map[string]interface{})
|
||||||
header := quic["header"].(map[string]interface{})
|
header := quic["header"].(map[string]interface{})
|
||||||
typeStr, _ = header["type"].(string)
|
obj["type"], _ = header["type"].(string)
|
||||||
host, _ = quic["security"].(string)
|
obj["host"], _ = quic["security"].(string)
|
||||||
path, _ = quic["key"].(string)
|
obj["path"], _ = quic["key"].(string)
|
||||||
case "grpc":
|
case "grpc":
|
||||||
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
||||||
path = grpc["serviceName"].(string)
|
obj["path"] = grpc["serviceName"].(string)
|
||||||
|
if grpc["multiMode"].(bool) {
|
||||||
|
obj["type"] = "multi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
security, _ := stream["security"].(string)
|
security, _ := stream["security"].(string)
|
||||||
|
obj["tls"] = security
|
||||||
if security == "tls" {
|
if security == "tls" {
|
||||||
tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
|
tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
|
||||||
alpns, _ := tlsSetting["alpn"].([]interface{})
|
alpns, _ := tlsSetting["alpn"].([]interface{})
|
||||||
|
if len(alpns) > 0 {
|
||||||
|
var alpn []string
|
||||||
for _, a := range alpns {
|
for _, a := range alpns {
|
||||||
alpn = append(alpn, a.(string))
|
alpn = append(alpn, a.(string))
|
||||||
}
|
}
|
||||||
|
obj["alpn"] = strings.Join(alpn, ",")
|
||||||
|
}
|
||||||
tlsSettings, _ := searchKey(tlsSetting, "settings")
|
tlsSettings, _ := searchKey(tlsSetting, "settings")
|
||||||
if tlsSetting != nil {
|
if tlsSetting != nil {
|
||||||
if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
|
if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
|
||||||
sni, _ = sniValue.(string)
|
obj["sni"], _ = sniValue.(string)
|
||||||
}
|
}
|
||||||
if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
|
if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
|
||||||
fp, _ = fpValue.(string)
|
obj["fp"], _ = fpValue.(string)
|
||||||
}
|
}
|
||||||
if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
|
if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
|
||||||
allowInsecure, _ = insecure.(bool)
|
obj["allowInsecure"], _ = insecure.(bool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverName, _ := tlsSetting["serverName"].(string)
|
serverName, _ := tlsSetting["serverName"].(string)
|
||||||
if serverName != "" {
|
if serverName != "" {
|
||||||
address = serverName
|
obj["add"] = serverName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,24 +196,9 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
obj["id"] = clients[clientIndex].ID
|
||||||
|
obj["aid"] = clients[clientIndex].AlterIds
|
||||||
|
|
||||||
obj := map[string]interface{}{
|
|
||||||
"v": "2",
|
|
||||||
"ps": email,
|
|
||||||
"add": address,
|
|
||||||
"port": inbound.Port,
|
|
||||||
"id": clients[clientIndex].ID,
|
|
||||||
"aid": clients[clientIndex].AlterIds,
|
|
||||||
"net": network,
|
|
||||||
"type": typeStr,
|
|
||||||
"host": host,
|
|
||||||
"path": path,
|
|
||||||
"tls": security,
|
|
||||||
"sni": sni,
|
|
||||||
"fp": fp,
|
|
||||||
"alpn": strings.Join(alpn, ","),
|
|
||||||
"allowInsecure": allowInsecure,
|
|
||||||
}
|
|
||||||
jsonStr, _ := json.MarshalIndent(obj, "", " ")
|
jsonStr, _ := json.MarshalIndent(obj, "", " ")
|
||||||
return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
|
return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
|
||||||
}
|
}
|
||||||
@ -266,6 +260,9 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
||||||
params["serviceName"] = grpc["serviceName"].(string)
|
params["serviceName"] = grpc["serviceName"].(string)
|
||||||
|
if grpc["multiMode"].(bool) {
|
||||||
|
params["mode"] = "multi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
security, _ := stream["security"].(string)
|
security, _ := stream["security"].(string)
|
||||||
@ -444,6 +441,9 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
||||||
params["serviceName"] = grpc["serviceName"].(string)
|
params["serviceName"] = grpc["serviceName"].(string)
|
||||||
|
if grpc["multiMode"].(bool) {
|
||||||
|
params["mode"] = "multi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
security, _ := stream["security"].(string)
|
security, _ := stream["security"].(string)
|
||||||
|
Loading…
Reference in New Issue
Block a user