feat: 后端: 在建立 SSH 连接时应用代理配置

This commit is contained in:
Baobhan Sith
2025-04-15 07:31:25 +08:00
parent 0e863456a2
commit 4f2f8b9f07
19 changed files with 1444 additions and 197 deletions
@@ -8,7 +8,8 @@ export interface ConnectionInfo {
host: string;
port: number;
username: string;
auth_method: 'password' | 'key'; // 允许 key 类型
auth_method: 'password' | 'key';
proxy_id?: number | null; // 新增:关联的代理 ID (可选)
created_at: number;
updated_at: number;
last_connected_at: number | null;
@@ -58,11 +59,12 @@ export const useConnectionsStore = defineStore('connections', {
port: number;
username: string;
auth_method: 'password' | 'key';
password?: string; // 密码变为可选
private_key?: string; // 私钥是可选的 (仅在 auth_method 为 key 时需要)
passphrase?: string; // 私钥密码是可选的
password?: string;
private_key?: string;
passphrase?: string;
proxy_id?: number | null; // 新增:允许传入 proxy_id
}) {
this.isLoading = true; // 可以为添加操作单独设置加载状态,或共用 isLoading
this.isLoading = true;
this.error = null;
try {
const response = await axios.post<{ message: string; connection: ConnectionInfo }>('/api/v1/connections', newConnectionData);
@@ -82,7 +84,8 @@ export const useConnectionsStore = defineStore('connections', {
},
// 更新连接 Action
async updateConnection(connectionId: number, updatedData: Partial<Omit<ConnectionInfo, 'id' | 'created_at' | 'updated_at' | 'last_connected_at'> & { password?: string; private_key?: string; passphrase?: string }>) {
// 更新参数类型以包含 proxy_id
async updateConnection(connectionId: number, updatedData: Partial<Omit<ConnectionInfo, 'id' | 'created_at' | 'updated_at' | 'last_connected_at'> & { password?: string; private_key?: string; passphrase?: string; proxy_id?: number | null }>) {
this.isLoading = true;
this.error = null;
try {
@@ -0,0 +1,129 @@
import { defineStore } from 'pinia';
import axios from 'axios';
// 定义代理信息接口 (前端使用,不含密码)
export interface ProxyInfo {
id: number;
name: string;
type: 'SOCKS5' | 'HTTP';
host: string;
port: number;
username?: string | null;
created_at: number;
updated_at: number;
}
// 定义 Store State 的接口
interface ProxiesState {
proxies: ProxyInfo[];
isLoading: boolean;
error: string | null;
}
// 定义 Pinia Store
export const useProxiesStore = defineStore('proxies', {
state: (): ProxiesState => ({
proxies: [],
isLoading: false,
error: null,
}),
actions: {
// 获取代理列表 Action
async fetchProxies() {
this.isLoading = true;
this.error = null;
try {
const response = await axios.get<ProxyInfo[]>('/api/v1/proxies');
this.proxies = response.data;
} catch (err: any) {
console.error('获取代理列表失败:', err);
this.error = err.response?.data?.message || err.message || '获取代理列表时发生未知错误。';
if (err.response?.status === 401) {
console.warn('未授权,需要登录才能获取代理列表。');
// TODO: 处理未授权情况
}
} finally {
this.isLoading = false;
}
},
// 添加新代理 Action
async addProxy(newProxyData: {
name: string;
type: 'SOCKS5' | 'HTTP';
host: string;
port: number;
username?: string | null;
password?: string | null; // 包含原始密码
}) {
this.isLoading = true;
this.error = null;
try {
const response = await axios.post<{ message: string; proxy: ProxyInfo }>('/api/v1/proxies', newProxyData);
this.proxies.unshift(response.data.proxy); // 将新代理添加到列表开头
return true; // 成功
} catch (err: any) {
console.error('添加代理失败:', err);
this.error = err.response?.data?.message || err.message || '添加代理时发生未知错误。';
if (err.response?.status === 401) {
console.warn('未授权,需要登录才能添加代理。');
}
if (err.response?.status === 409) {
console.warn('添加代理冲突:', err.response?.data?.message);
}
return false; // 失败
} finally {
this.isLoading = false;
}
},
// 更新代理 Action
async updateProxy(proxyId: number, updatedData: Partial<ProxyInfo & { password?: string | null }>) {
this.isLoading = true;
this.error = null;
try {
const response = await axios.put<{ message: string; proxy: ProxyInfo }>(`/api/v1/proxies/${proxyId}`, updatedData);
const index = this.proxies.findIndex(p => p.id === proxyId);
if (index !== -1) {
// 使用返回的更新后的信息替换旧信息
this.proxies[index] = { ...this.proxies[index], ...response.data.proxy };
} else {
await this.fetchProxies(); // 如果本地找不到,重新获取列表
}
return true; // 成功
} catch (err: any) {
console.error(`更新代理 ${proxyId} 失败:`, err);
this.error = err.response?.data?.message || err.message || '更新代理时发生未知错误。';
if (err.response?.status === 401) {
console.warn('未授权,需要登录才能更新代理。');
}
if (err.response?.status === 409) {
console.warn('更新代理冲突:', err.response?.data?.message);
}
return false; // 失败
} finally {
this.isLoading = false;
}
},
// 删除代理 Action
async deleteProxy(proxyId: number) {
this.isLoading = true;
this.error = null;
try {
await axios.delete(`/api/v1/proxies/${proxyId}`);
this.proxies = this.proxies.filter(p => p.id !== proxyId); // 从列表中移除
return true; // 成功
} catch (err: any) {
console.error(`删除代理 ${proxyId} 失败:`, err);
this.error = err.response?.data?.message || err.message || '删除代理时发生未知错误。';
if (err.response?.status === 401) {
console.warn('未授权,需要登录才能删除代理。');
}
return false; // 失败
} finally {
this.isLoading = false;
}
},
},
});