feat(runtime): Optimize port selection for runtime environments (#8086)

This commit is contained in:
zhengkunwang 2025-03-06 18:04:57 +08:00 committed by GitHub
parent 07f2a34373
commit dd66622be1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 88 additions and 220 deletions

View file

@ -1,165 +0,0 @@
package qqwry
import (
"encoding/binary"
"net"
"strings"
"github.com/1Panel-dev/1Panel/agent/cmd/server/qqwry"
"golang.org/x/text/encoding/simplifiedchinese"
)
const (
indexLen = 7
redirectMode1 = 0x01
redirectMode2 = 0x02
)
var IpCommonDictionary []byte
type QQwry struct {
Data []byte
Offset int64
}
func NewQQwry() (*QQwry, error) {
IpCommonDictionary := qqwry.QQwryByte
return &QQwry{Data: IpCommonDictionary}, nil
}
// readData 从文件中读取数据
func (q *QQwry) readData(num int, offset ...int64) (rs []byte) {
if len(offset) > 0 {
q.setOffset(offset[0])
}
nums := int64(num)
end := q.Offset + nums
dataNum := int64(len(q.Data))
if q.Offset > dataNum {
return nil
}
if end > dataNum {
end = dataNum
}
rs = q.Data[q.Offset:end]
q.Offset = end
return
}
// setOffset 设置偏移量
func (q *QQwry) setOffset(offset int64) {
q.Offset = offset
}
// Find ip地址查询对应归属地信息
func (q *QQwry) Find(ip string) (res ResultQQwry) {
res = ResultQQwry{}
res.IP = ip
if strings.Count(ip, ".") != 3 {
return res
}
offset := q.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4()))
if offset <= 0 {
return
}
var area []byte
mode := q.readMode(offset + 4)
if mode == redirectMode1 {
countryOffset := q.readUInt24()
mode = q.readMode(countryOffset)
if mode == redirectMode2 {
c := q.readUInt24()
area = q.readString(c)
} else {
area = q.readString(countryOffset)
}
} else if mode == redirectMode2 {
countryOffset := q.readUInt24()
area = q.readString(countryOffset)
} else {
area = q.readString(offset + 4)
}
enc := simplifiedchinese.GBK.NewDecoder()
res.Area, _ = enc.String(string(area))
return
}
type ResultQQwry struct {
IP string `json:"ip"`
Area string `json:"area"`
}
// readMode 获取偏移值类型
func (q *QQwry) readMode(offset uint32) byte {
mode := q.readData(1, int64(offset))
return mode[0]
}
// readString 获取字符串
func (q *QQwry) readString(offset uint32) []byte {
q.setOffset(int64(offset))
data := make([]byte, 0, 30)
for {
buf := q.readData(1)
if buf[0] == 0 {
break
}
data = append(data, buf[0])
}
return data
}
// searchIndex 查找索引位置
func (q *QQwry) searchIndex(ip uint32) uint32 {
header := q.readData(8, 0)
start := binary.LittleEndian.Uint32(header[:4])
end := binary.LittleEndian.Uint32(header[4:])
for {
mid := q.getMiddleOffset(start, end)
buf := q.readData(indexLen, int64(mid))
_ip := binary.LittleEndian.Uint32(buf[:4])
if end-start == indexLen {
offset := byteToUInt32(buf[4:])
buf = q.readData(indexLen)
if ip < binary.LittleEndian.Uint32(buf[:4]) {
return offset
}
return 0
}
if _ip > ip {
end = mid
} else if _ip < ip {
start = mid
} else if _ip == ip {
return byteToUInt32(buf[4:])
}
}
}
// readUInt24
func (q *QQwry) readUInt24() uint32 {
buf := q.readData(3)
return byteToUInt32(buf)
}
// getMiddleOffset
func (q *QQwry) getMiddleOffset(start uint32, end uint32) uint32 {
records := ((end - start) / indexLen) >> 1
return start + records*indexLen
}
// byteToUInt32 将 byte 转换为uint32
func byteToUInt32(data []byte) uint32 {
i := uint32(data[0]) & 0xff
i |= (uint32(data[1]) << 8) & 0xff00
i |= (uint32(data[2]) << 16) & 0xff0000
return i
}

View file

@ -14,22 +14,20 @@
<TableSetting title="task-log-refresh" @search="search()" />
</template>
<template #main>
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="370">
<el-table-column :label="$t('logs.taskName')" prop="name" />
<el-table-column :label="$t('commons.table.type')" prop="type" />
<el-table-column :label="$t('commons.table.status')" prop="status">
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="320">
<el-table-column :label="$t('logs.taskName')" prop="name" min-width="180px"></el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status" max-width="100px">
<template #default="{ row }">
<Status :status="row.status" :msg="row.errorMsg" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.button.log')" prop="log">
<el-table-column :label="$t('commons.button.log')" prop="log" max-width="100px">
<template #default="{ row }">
<el-button @click="openTaskLog(row)" link type="primary">
{{ $t('website.check') }}
</el-button>
</template>
</el-table-column>
<el-table-column
prop="createdAt"
:label="$t('commons.table.date')"
@ -39,6 +37,7 @@
</ComplexTable>
</template>
</LayoutContent>
<TaskLog ref="taskLogRef" width="70%" />
</template>
</DrawerPro>

View file

@ -2382,6 +2382,7 @@ const message = {
rainyun: 'Rain Yun',
volcengine: 'Volcengine',
runtimePortHelper: 'The current runtime environment has multiple ports. Please select a proxy port.',
runtimePortWarn: 'The current runtime environment has no ports, unable to proxy',
},
php: {
short_open_tag: 'Short tag support',
@ -3236,6 +3237,8 @@ const message = {
postNode: 'Sync to sub-node',
postNodeHelper: 'Sub-nodes will inherit and use the above configuration by default',
nodes: 'Nodes',
selectNode: 'Select Node',
selectNodeError: 'Please select a node',
},
alert: {
isAlert: 'Alert',

View file

@ -2240,6 +2240,7 @@ const message = {
rainyun: '雨雲',
volcengine: 'volcengine',
runtimePortHelper: '現在の実行環境には複数のポートがありますプロキシポートを選択してください',
runtimePortWarn: '現在の実行環境にはポートがありませんプロキシできません',
},
php: {
short_open_tag: '短いタグサポート',
@ -3045,6 +3046,8 @@ const message = {
postNode: 'サブノードへ同期',
postNodeHelper: 'サブノードはデフォルトで上記の設定を継承して使用します',
nodes: 'ノードを選択',
selectNode: 'ノードを選択',
selectNodeError: 'ノードを選択してください',
},
alert: {
isAlert: 'アラート',

View file

@ -2204,6 +2204,7 @@ const message = {
rainyun: 'Rainyun',
volcengine: 'volcengine',
runtimePortHelper: '현재 실행 환경에 여러 포트가 있습니다. 프록시 포트를 선택하세요.',
runtimePortWarn: '현재 실행 환경에 포트가 없습니다. 프록시할 없습니다',
},
php: {
short_open_tag: '짧은 태그 지원',
@ -2995,6 +2996,8 @@ const message = {
postNode: '서브 노드로 동기화',
postNodeHelper: '서브 노드는 기본적으로 설정을 상속하고 사용합니다',
nodes: '노드 선택',
selectNode: '노드 선택',
selectNodeError: '노드를 선택하세요',
},
alert: {
isAlert: '알림',

View file

@ -2295,6 +2295,7 @@ const message = {
rainyun: 'Rainyun',
volcengine: 'Volcengine',
runtimePortHelper: 'Persekitaran runtime semasa mempunyai beberapa port. Sila pilih port proksi.',
runtimePortWarn: 'Persekitaran runtime semasa tidak mempunyai port, tidak dapat proksi',
},
php: {
short_open_tag: 'Sokongan tag pendek',
@ -3115,6 +3116,8 @@ const message = {
postNode: 'Segerakkan ke sub-node',
postNodeHelper: 'Sub-node akan mewarisi dan menggunakan konfigurasi di atas secara lalai',
nodes: 'Pilih Node',
selectNode: 'Pilih Node',
selectNodeError: 'Sila pilih node',
},
alert: {
isAlert: 'Amaran',

View file

@ -2290,6 +2290,7 @@ const message = {
rainyun: 'Rainyun',
volcengine: 'Volcengine',
runtimePortHelper: 'O ambiente de runtime atual possui várias portas. Por favor, selecione uma porta de proxy.',
runtimePortWarn: 'O ambiente de execução atual não possui portos, não é possível proxiar',
},
php: {
short_open_tag: 'Suporte para short tags',
@ -3119,6 +3120,8 @@ const message = {
postNode: 'Sincronizar para subnó',
postNodeHelper: 'Subnós herdarão e usarão a configuração acima por padrão',
nodes: 'Selecionar Nós',
selectNode: 'Selecionar Node',
selectNodeError: 'Por favor, selecione um ',
},
alert: {
isAlert: 'Alerta',

View file

@ -2292,6 +2292,7 @@ const message = {
rainyun: 'Rainyun',
volcengine: 'Volcengine',
runtimePortHelper: 'O ambiente de runtime atual possui várias portas. Por favor, selecione uma porta de proxy.',
runtimePortWarn: 'В текущей среде выполнения нет портов, невозможно проксировать',
},
php: {
short_open_tag: 'Поддержка коротких тегов',
@ -3109,6 +3110,8 @@ const message = {
postNode: 'Синхронизировать с подузлом',
postNodeHelper: 'Подузлы будут наследовать и использовать указанную конфигурацию по умолчанию',
nodes: 'Выбрать узлы',
selectNode: 'Выбрать узел',
selectNodeError: 'Пожалуйста, выберите узел',
},
alert: {
isAlert: 'Оповещение',

View file

@ -2209,6 +2209,7 @@ const message = {
rainyun: '雨雲',
volcengine: 'Volcengine',
runtimePortHelper: '當前運行環境存在多個端口請選擇一個代理端口',
runtimePortWarn: '當前運行環境沒有端口無法代理',
},
php: {
short_open_tag: '短標簽支持',
@ -2998,6 +2999,8 @@ const message = {
postNode: '同步至子節點',
postNodeHelper: '子節點預設繼承並使用上述配置',
nodes: '節點',
selectNode: '選擇節點',
selectNodeError: '請選擇節點',
},
alert: {
isAlert: '是否告警',

View file

@ -2199,6 +2199,7 @@ const message = {
rainyun: '雨云',
volcengine: '火山引擎',
runtimePortHelper: '当前运行环境存在多个端口请选择一个代理端口',
runtimePortWarn: '当前运行环境没有端口无法代理',
},
php: {
short_open_tag: '短标签支持',
@ -2979,6 +2980,8 @@ const message = {
postNode: '同步至子节点',
postNodeHelper: '子节点默认继承并使用上述配置',
nodes: '节点',
selectNode: '选择节点',
selectNodeError: '请选择节点',
},
alert: {
isAlert: '是否告警',

View file

@ -17,14 +17,13 @@
</template>
<template #main>
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="370">
<el-table-column :label="$t('logs.taskName')" prop="name" />
<el-table-column :label="$t('commons.table.type')" prop="type" />
<el-table-column :label="$t('commons.table.status')" prop="status">
<el-table-column :label="$t('logs.taskName')" prop="name" min-width="180px"></el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status" max-width="100px">
<template #default="{ row }">
<Status :status="row.status" :msg="row.errorMsg" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.button.log')" prop="log">
<el-table-column :label="$t('commons.button.log')" prop="log" max-width="100px">
<template #default="{ row }">
<el-button @click="openTaskLog(row)" link type="primary">
{{ $t('website.check') }}

View file

@ -0,0 +1,25 @@
<template>
<div v-if="row.port != ''">
<span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link @click="jump(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
import { Promotion } from '@element-plus/icons-vue';
defineProps({
row: {
type: Object,
required: true,
},
jump: {
type: Function,
required: true,
},
});
</script>

View file

@ -43,14 +43,7 @@
<el-table-column :label="$t('app.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }">
<span v-if="row.port != ''">
<span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
</span>
<PortJump :row="row" :jump="goDashboard" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status">
@ -104,12 +97,12 @@ import i18n from '@/lang';
import RouterMenu from '../index.vue';
import router from '@/routers/router';
import ComposeLogs from '@/components/log/compose/index.vue';
import { Promotion } from '@element-plus/icons-vue';
import PortJumpDialog from '@/components/port-jump/index.vue';
import AppResources from '@/views/website/runtime/php/check/index.vue';
import { ElMessageBox } from 'element-plus';
import { GlobalStore } from '@/store';
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
import PortJump from '@/views/website/runtime/components/port-jump.vue';
import { disabledButton } from '@/utils/runtime';
let timer: NodeJS.Timer | null = null;

View file

@ -43,12 +43,7 @@
<el-table-column :label="$t('app.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }">
<span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
<PortJump :row="row" :jump="goDashboard" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status">
@ -102,11 +97,11 @@ import i18n from '@/lang';
import RouterMenu from '../index.vue';
import router from '@/routers/router';
import ComposeLogs from '@/components/log/compose/index.vue';
import { Promotion } from '@element-plus/icons-vue';
import PortJumpDialog from '@/components/port-jump/index.vue';
import AppResources from '@/views/website/runtime/php/check/index.vue';
import { ElMessageBox } from 'element-plus';
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
import PortJump from '@/views/website/runtime/components/port-jump.vue';
import { disabledButton } from '@/utils/runtime';
let timer: NodeJS.Timer | null = null;

View file

@ -43,12 +43,7 @@
<el-table-column :label="$t('app.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }">
<span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
<PortJump :row="row" :jump="goDashboard" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status">
@ -102,11 +97,11 @@ import i18n from '@/lang';
import RouterMenu from '../index.vue';
import router from '@/routers/router';
import ComposeLogs from '@/components/log/compose/index.vue';
import { Promotion } from '@element-plus/icons-vue';
import PortJumpDialog from '@/components/port-jump/index.vue';
import AppResources from '@/views/website/runtime/php/check/index.vue';
import { ElMessageBox } from 'element-plus';
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
import PortJump from '@/views/website/runtime/components/port-jump.vue';
import { disabledButton } from '@/utils/runtime';
let timer: NodeJS.Timer | null = null;

View file

@ -43,12 +43,7 @@
<el-table-column :label="$t('app.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }">
<span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
<PortJump :row="row" :jump="goDashboard" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status">
@ -104,11 +99,11 @@ import RouterMenu from '../index.vue';
import Modules from '@/views/website/runtime/node/module/index.vue';
import router from '@/routers/router';
import ComposeLogs from '@/components/log/compose/index.vue';
import { Promotion } from '@element-plus/icons-vue';
import PortJumpDialog from '@/components/port-jump/index.vue';
import AppResources from '@/views/website/runtime/php/check/index.vue';
import { ElMessageBox } from 'element-plus';
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
import PortJump from '@/views/website/runtime/components/port-jump.vue';
import { disabledButton } from '@/utils/runtime';
let timer: NodeJS.Timer | null = null;

View file

@ -43,12 +43,7 @@
<el-table-column :label="$t('app.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }">
<span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
<PortJump :row="row" :jump="goDashboard" />
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status">
@ -102,11 +97,11 @@ import i18n from '@/lang';
import RouterMenu from '../index.vue';
import router from '@/routers/router';
import ComposeLogs from '@/components/log/compose/index.vue';
import { Promotion } from '@element-plus/icons-vue';
import PortJumpDialog from '@/components/port-jump/index.vue';
import AppResources from '@/views/website/runtime/php/check/index.vue';
import { ElMessageBox } from 'element-plus';
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
import PortJump from '@/views/website/runtime/components/port-jump.vue';
import { disabledButton } from '@/utils/runtime';
let timer: NodeJS.Timer | null = null;

View file

@ -240,7 +240,7 @@
<el-form-item
:label="$t('setting.proxyPort')"
prop="port"
v-if="website.runtimeType !== 'php' && runtimePorts.length > 0"
v-if="website.runtimeType !== 'php' && runtimePorts.length > 1"
>
<el-select v-model="website.port">
<el-option
@ -252,6 +252,17 @@
</el-select>
<span class="input-help">{{ $t('website.runtimePortHelper') }}</span>
</el-form-item>
<el-text
v-if="
runtimes.length > 0 &&
website.type === 'runtime' &&
website.runtimeType !== 'php' &&
website.port == 0
"
type="danger"
>
{{ $t('website.runtimePortWarn') }}
</el-text>
</div>
<el-form-item prop="advanced" v-if="website.type === 'deployment' && website.appType === 'new'">
<el-checkbox v-model="website.appinstall.advanced" :label="$t('app.advanced')" size="large" />
@ -542,7 +553,7 @@ import { ElForm, FormInstance } from 'element-plus';
import { reactive, ref } from 'vue';
import Params from '@/views/app-store/detail/params/index.vue';
import Check from '../check/index.vue';
import { MsgSuccess } from '@/utils/message';
import { MsgError, MsgSuccess } from '@/utils/message';
import { getGroupList } from '@/api/modules/group';
import { Group } from '@/api/interface/group';
import { SearchRuntimes } from '@/api/modules/runtime';
@ -787,20 +798,20 @@ const changeRuntimeType = () => {
};
const changeRuntime = (runID: number) => {
website.value.port = 0;
runtimes.value.forEach((item) => {
if (item.id === runID) {
runtimeResource.value = item.resource;
runtimePorts.value = item.port.split(',').map((port: string) => parseInt(port.trim(), 10));
if (runtimePorts.value.length > 1) {
if (runtimePorts.value.length > 0) {
website.value.port = runtimePorts.value[0];
} else {
website.value.port = 0;
}
}
});
};
const getRuntimes = async () => {
website.value.port = 0;
try {
const res = await SearchRuntimes(runtimeReq.value);
runtimes.value = res.data.items || [];
@ -809,10 +820,8 @@ const getRuntimes = async () => {
website.value.runtimeID = first.id;
runtimeResource.value = first.resource;
runtimePorts.value = first.port.split(',').map((port: string) => parseInt(port.trim(), 10));
if (runtimePorts.value.length > 1) {
if (runtimePorts.value.length > 0) {
website.value.port = runtimePorts.value[0];
} else {
website.value.port = 0;
}
}
} catch (error) {}
@ -883,6 +892,10 @@ const submit = async (formEl: FormInstance | undefined) => {
if (!valid) {
return;
}
if (website.value.type === 'runtime' && website.value.runtimeType !== 'php' && website.value.port == 0) {
MsgError(i18n.global.t('website.runtimePortWarn'));
return;
}
loading.value = true;
preCheck({})
.then((res) => {