Skip to content

Commit

Permalink
feat: 面板代理服务器提供 docker 代理 (#6986)
Browse files Browse the repository at this point in the history
  • Loading branch information
lan-yonghui authored Nov 8, 2024
1 parent cccbaaf commit 204f9f1
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 11 deletions.
17 changes: 17 additions & 0 deletions backend/app/service/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
daemonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
}
}
case "http-proxy", "https-proxy":
delete(daemonMap, "proxies")
if len(req.Value) > 0 {
proxies := map[string]interface{}{
req.Key: req.Value,
}
daemonMap["proxies"] = proxies
}
case "socks5-proxy":
delete(daemonMap, "proxies")
if len(req.Value) > 0 {
proxies := map[string]interface{}{
"http-proxy": req.Value,
"https-proxy": req.Value,
}
daemonMap["proxies"] = proxies
}
}
if len(daemonMap) == 0 {
_ = os.Remove(constant.DaemonJsonPath)
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1392,11 +1392,14 @@ const message = {
proxyHelper: 'After setting up the proxy server, it will be effective in the following scenarios:',
proxyHelper1: 'Downloading and synchronizing installation packages from the app store (Professional)',
proxyHelper2: 'System version upgrades and retrieving update information (Professional)',
proxyHelper4: 'Docker Daemon provides network access proxy (Professional)',
proxyHelper3: 'Verification and synchronization of system licenses',
proxyType: 'Proxy Type',
proxyUrl: 'Proxy Address',
proxyPort: 'Proxy Port',
proxyPasswdKeep: 'Remember Password',
proxyDocker: 'Docker Proxy',
proxyDockerHelper: 'Docker Daemon provides network access proxy',
systemIPWarning: 'The server address is not currently set. Please set it in the control panel first!',
systemIPWarning1: 'The current server address is set to {0}, and quick redirection is not possible!',
defaultNetwork: 'Network Card',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1314,11 +1314,14 @@ const message = {
proxyHelper: '設置代理伺服器後將在以下場景中生效:',
proxyHelper1: '應用商店的安裝包下載和同步專業版功能)',
proxyHelper2: '系統版本升級及獲取更新說明專業版功能)',
proxyHelper4: 'Docker Daemon 提供網絡訪問代理專業版功能)',
proxyHelper3: '系統許可證的驗證和同步',
proxyType: '代理類型',
proxyUrl: '代理地址',
proxyPort: '代理端口',
proxyPasswdKeep: '記住密碼',
proxyDocker: 'Docker 代理',
proxyDockerHelper: '為 Docker Daemon 提供網絡訪問代理',
systemIPWarning: '當前未設置服務器地址請先在面板設置中設置!',
systemIPWarning1: '當前服務器地址設置為 {0},無法快速跳轉!',
defaultNetwork: '默認網卡',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1317,10 +1317,13 @@ const message = {
proxyHelper1: '应用商店的安装包下载和同步专业版功能)',
proxyHelper2: '系统版本升级及获取更新说明专业版功能)',
proxyHelper3: '系统许可证的验证和同步',
proxyHelper4: 'Docker Daemon 提供网络访问代理专业版功能)',
proxyType: '代理类型',
proxyUrl: '代理地址',
proxyPort: '代理端口',
proxyPasswdKeep: '记住密码',
proxyDocker: 'Docker 代理',
proxyDockerHelper: '为 Docker Daemon 提供网络访问代理',
systemIPWarning: '当前未设置服务器地址请先在面板设置中设置!',
systemIPWarning1: '当前服务器地址设置为 {0},无法快速跳转!',
defaultNetwork: '默认网卡',
Expand Down
26 changes: 26 additions & 0 deletions frontend/src/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,3 +589,29 @@ export const getFileType = (extension: string) => {
});
return type;
};

export const escapeProxyURL = (url: string): string => {
const encodeMap: { [key: string]: string } = {
':': '%%3A',
'/': '%%2F',
'?': '%%3F',
'#': '%%23',
'[': '%%5B',
']': '%%5D',
'@': '%%40',
'!': '%%21',
$: '%%24',
'&': '%%26',
"'": '%%27',
'(': '%%28',
')': '%%29',
'*': '%%2A',
'+': '%%2B',
',': '%%2C',
';': '%%3B',
'=': '%%3D',
'%': '%%25',
};

return url.replace(/[\/:?#[\]@!$&'()*+,;=%~]/g, (match) => encodeMap[match] || match);
};
3 changes: 3 additions & 0 deletions frontend/src/views/setting/panel/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ const form = reactive({
proxyUser: '',
proxyPasswd: '',
proxyPasswdKeep: '',
proxyDocker: '',
proHideMenus: ref(i18n.t('setting.unSetting')),
hideMenuList: '',
Expand Down Expand Up @@ -302,6 +303,7 @@ const search = async () => {
form.theme = xpackRes.data.theme || globalStore.themeConfig.theme;
form.themeColor = JSON.parse(xpackRes.data.themeColor);
globalStore.themeConfig.themeColor = xpackRes.data.themeColor;
form.proxyDocker = xpackRes.data.proxyDocker;
}
} else {
form.theme = res.data.theme;
Expand Down Expand Up @@ -355,6 +357,7 @@ const onChangeProxy = () => {
user: form.proxyUser,
passwd: form.proxyPasswd,
passwdKeep: form.proxyPasswdKeep,
proxyDocker: form.proxyDocker,
});
};
const onChangeNetwork = () => {
Expand Down
99 changes: 88 additions & 11 deletions frontend/src/views/setting/panel/proxy/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<ul style="margin-left: -20px">
<li v-if="isProductPro">{{ $t('setting.proxyHelper1') }}</li>
<li v-if="isProductPro">{{ $t('setting.proxyHelper2') }}</li>
<li v-if="isProductPro">{{ $t('setting.proxyHelper4') }}</li>
<li>{{ $t('setting.proxyHelper3') }}</li>
</ul>
</template>
Expand Down Expand Up @@ -59,6 +60,10 @@
:label="$t('setting.proxyPasswdKeep')"
/>
</el-form-item>
<el-form-item v-if="isProductPro">
<el-checkbox v-model="form.proxyDocker" :label="$t('setting.proxyDocker')" />
<span class="input-help">{{ $t('setting.proxyDockerHelper') }}</span>
</el-form-item>
</div>
</el-col>
</el-row>
Expand All @@ -74,6 +79,8 @@
</span>
</template>
</el-drawer>

<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit" />
</div>
</template>

Expand All @@ -87,11 +94,16 @@ import DrawerHeader from '@/components/drawer-header/index.vue';
import { updateProxy } from '@/api/modules/setting';
import { GlobalStore } from '@/store';
import { storeToRefs } from 'pinia';
import { updateXpackSettingByKey } from '@/utils/xpack';
import { updateDaemonJson } from '@/api/modules/container';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { escapeProxyURL } from '@/utils/util';
const globalStore = GlobalStore();
const emit = defineEmits<{ (e: 'search'): void }>();
const { isProductPro } = storeToRefs(globalStore);
const confirmDialogRef = ref();
const formRef = ref<FormInstance>();
const rules = reactive({
proxyType: [Rules.requiredSelect],
Expand All @@ -101,6 +113,7 @@ const rules = reactive({
const loading = ref(false);
const passwordVisible = ref<boolean>(false);
const proxyDockerVisible = ref<boolean>(false);
const form = reactive({
proxyUrl: '',
proxyType: '',
Expand All @@ -110,6 +123,7 @@ const form = reactive({
proxyPasswd: '',
proxyPasswdKeep: '',
proxyPasswdKeepItem: false,
proxyDocker: false,
});
interface DialogProps {
Expand All @@ -119,6 +133,7 @@ interface DialogProps {
user: string;
passwd: string;
passwdKeep: string;
proxyDocker: string;
}
const acceptParams = (params: DialogProps): void => {
if (params.url) {
Expand All @@ -134,6 +149,8 @@ const acceptParams = (params: DialogProps): void => {
form.proxyPortItem = params.port ? Number(params.port) : 7890;
form.proxyUser = params.user;
form.proxyPasswd = params.passwd;
form.proxyDocker = params.proxyDocker !== '';
proxyDockerVisible.value = params.proxyDocker !== '';
passwordVisible.value = true;
form.proxyPasswdKeepItem = params.passwdKeep === 'Enable';
};
Expand All @@ -150,26 +167,86 @@ const submitChangePassword = async (formEl: FormInstance | undefined) => {
proxyUser: isClose ? '' : form.proxyUser,
proxyPasswd: isClose ? '' : form.proxyPasswd,
proxyPasswdKeep: '',
proxyDocker: isClose ? false : form.proxyDocker,
};
if (!isClose) {
params.proxyPasswdKeep = form.proxyPasswdKeepItem ? 'Enable' : 'Disable';
}
if (form.proxyType === 'http' || form.proxyType === 'https') {
params.proxyUrl = form.proxyType + '://' + form.proxyUrl;
}
loading.value = true;
await updateProxy(params)
.then(async () => {
loading.value = false;
emit('search');
passwordVisible.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
if (
isProductPro.value &&
(params.proxyDocker ||
(proxyDockerVisible.value && isClose) ||
(proxyDockerVisible.value && !isClose) ||
(proxyDockerVisible.value && !params.proxyDocker))
) {
let confirmParams = {
header: i18n.global.t('database.confChange'),
operationInfo: i18n.global.t('database.restartNowHelper'),
submitInputInfo: i18n.global.t('database.restartNow'),
};
confirmDialogRef.value!.acceptParams(confirmParams);
} else {
loading.value = true;
await updateProxy(params)
.then(async () => {
loading.value = false;
emit('search');
passwordVisible.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
}
});
};
const onSubmit = async () => {
try {
loading.value = true;
let isClose = form.proxyType === '' || form.proxyType === 'close';
let params = {
proxyType: isClose ? '' : form.proxyType,
proxyUrl: isClose ? '' : form.proxyUrl,
proxyPort: isClose ? '' : form.proxyPortItem + '',
proxyUser: isClose ? '' : form.proxyUser,
proxyPasswd: isClose ? '' : form.proxyPasswd,
proxyPasswdKeep: '',
proxyDocker: isClose ? false : form.proxyDocker,
};
if (!isClose) {
params.proxyPasswdKeep = form.proxyPasswdKeepItem ? 'Enable' : 'Disable';
}
let proxyPort = params.proxyPort ? `:${params.proxyPort}` : '';
let proxyUser = params.proxyUser ? `${escapeProxyURL(params.proxyUser)}` : '';
let proxyPasswd = '';
if (params.proxyUser) {
proxyPasswd = params.proxyPasswd ? `:${escapeProxyURL(params.proxyPasswd)}@` : '@';
}
let proxyUrl = form.proxyType + '://' + proxyUser + proxyPasswd + form.proxyUrl + proxyPort;
if (form.proxyType === 'http' || form.proxyType === 'https') {
params.proxyUrl = form.proxyType + '://' + form.proxyUrl;
}
await updateProxy(params);
if (isClose || params.proxyDocker === false) {
params.proxyUrl = '';
}
await updateXpackSettingByKey('ProxyDocker', proxyUrl);
await updateDaemonJson(`${form.proxyType}-proxy`, proxyUrl);
emit('search');
handleClose();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
};
const handleClose = () => {
passwordVisible.value = false;
};
Expand Down

0 comments on commit 204f9f1

Please sign in to comment.