refactor🎨: (阅读代码):putty.ts增加注释

master
yetao 2 weeks ago
parent d6700c67ca
commit 186042f3b3

@ -1,89 +1,204 @@
// 导入 winreg 模块,用于操作 Windows 注册表
import * as Winreg from 'winreg';
// 导入 Logging 模块,用于记录日志
import { Logging } from './logging';
// 导入 toPromise 函数,用于将回调函数转换为 Promise
import { toPromise } from './utils';
// 创建一个 Winreg 实例,用于访问 Windows 注册表中的 PuTTY 会话信息
const winreg = new Winreg({
// 指定要访问的注册表 hive这里是 HKCU当前用户
hive: Winreg.HKCU,
// 指定要访问的注册表键路径,这里是 \Software\SimonTatham\PuTTY\Sessions\
key: `\\Software\\SimonTatham\\PuTTY\\Sessions\\`,
});
// 定义一个类型别名 NumberAsBoolean它表示一个数字其值只能是 0 或 1
export type NumberAsBoolean = 0 | 1;
/**
* PuttySession PuTTY
*/
export interface PuttySession {
//[key: string]: string | number | undefined;
// General settings
// 会话的名称
name: string;
// 远程主机的名称或 IP 地址
hostname: string;
// 连接协议,可以是 'ssh'、'telnet' 等
protocol: string;
// 远程主机的端口号
portnumber: number;
// 用户名,可选
username?: string;
// 是否从环境变量中获取用户名0 或 1
usernamefromenvironment: NumberAsBoolean;
// 是否尝试使用代理0 或 1
tryagent: NumberAsBoolean;
// 公钥文件路径,可选
publickeyfile?: string;
// Proxy settings
// 代理主机,可选
proxyhost?: string;
// 代理端口号
proxyport: number;
// 是否使用本地代理0 或 1
proxylocalhost: NumberAsBoolean;
proxymethod: number; // Key of ['None', 'SOCKS 4', 'SOCKS 5', 'HTTP', 'Telnet', 'Local']
// 代理方法,值为 ['None', 'SOCKS 4', 'SOCKS 5', 'HTTP', 'Telnet', 'Local'] 中的一个 Key of ['None', 'SOCKS 4', 'SOCKS 5', 'HTTP', 'Telnet', 'Local']
proxymethod: number;
}
/**
*
* @param item -
* @returns
*/
function valueFromItem(item: Winreg.RegistryItem) {
switch (item.type) {
case 'REG_DWORD':
// 将十六进制字符串转换为整数
return parseInt(item.value, 16);
case 'REG_SZ':
// 返回字符串值
return item.value;
}
// 如果注册表项的类型未知,则抛出错误
throw new Error(`Unknown RegistryItem type: '${item.type}'`);
}
/**
* PuttySession
*/
const FORMATTED_FIELDS: (keyof PuttySession)[] = [
'name', 'hostname', 'protocol', 'portnumber',
'username', 'usernamefromenvironment', 'tryagent', 'publickeyfile',
'proxyhost', 'proxyport', 'proxylocalhost', 'proxymethod',
// 会话的名称
'name',
// 远程主机的名称或 IP 地址
'hostname',
// 连接协议,可以是 'ssh'、'telnet' 等
'protocol',
// 远程主机的端口号
'portnumber',
// 用户名,可选
'username',
// 是否从环境变量中获取用户名0 或 1
'usernamefromenvironment',
// 是否尝试使用代理0 或 1
'tryagent',
// 公钥文件路径,可选
'publickeyfile',
// 代理主机,可选
'proxyhost',
// 代理端口号
'proxyport',
// 是否使用本地代理0 或 1
'proxylocalhost',
// 代理方法,值为 ['None', 'SOCKS 4', 'SOCKS 5', 'HTTP', 'Telnet', 'Local'] 中的一个
'proxymethod',
];
/**
* PuTTY
* @param session - PuTTY
* @returns 使使
*/
export function formatSession(session: PuttySession): string {
// 创建一个 Partial<PuttySession> 类型的对象 partial用于存储会话的部分信息
const partial: Partial<PuttySession> = {};
for (const field of FORMATTED_FIELDS) partial[field] = session[field] as any;
// 遍历 FORMATTED_FIELDS 数组中的每个字段
for (const field of FORMATTED_FIELDS) {
// 将 session 对象中的每个字段的值赋给 partial 对象中的对应字段
partial[field] = session[field] as any;
}
// 将 partial 对象转换为 JSON 字符串并返回
return JSON.stringify(partial);
}
export async function getSessions() {
/**
* PuTTY
* @returns PuTTY
*/
export async function getSessions(): Promise<PuttySession[]> {
// 记录日志,表明正在从注册表中获取 PuTTY 会话信息
Logging.info`Fetching PuTTY sessions from registry`;
// 使用 winreg 模块的 keys 方法获取所有 PuTTY 会话的注册表项,并将其转换为 Promise
const values = await toPromise<Winreg.Registry[]>(cb => winreg.keys(cb));
// 初始化一个空数组,用于存储解析后的 PuTTY 会话对象
const sessions: PuttySession[] = [];
// 遍历所有注册表项,解析每个会话的信息并添加到 sessions 数组中
await Promise.all(values.map(regSession => (async () => {
// 从注册表项的键名中提取会话名称,并进行 URI 解码
const name = decodeURIComponent(regSession.key.substr(winreg.key.length));
// 使用 values 方法获取当前会话的所有值,并将其转换为 Promise
const props = await toPromise<Winreg.RegistryItem[]>(cb => regSession.values(cb));
// 初始化一个对象,用于存储当前会话的属性
const properties: { [key: string]: string | number } = {};
// 遍历所有属性,将其值添加到 properties 对象中
props.forEach(prop => properties[prop.name.toLowerCase()] = valueFromItem(prop));
sessions.push({ name, ...(properties as any) });
// 将解析后的会话信息添加到 sessions 数组中
sessions.push({ name,...(properties as any) });
})()));
// 记录日志,表明已找到的会话数量
Logging.debug`\tFound ${sessions.length} sessions:`;
// 遍历所有会话,记录日志并输出格式化后的会话信息
sessions.forEach(s => Logging.debug`\t- ${formatSession(s)}`);
// 返回包含所有 PuTTY 会话信息的数组
return sessions;
}
/**
*
* @param sessions -
* @param name -
* @param host - IP
* @param username -
* @param nameOnly - true
* @returns undefined
*/
export async function findSession(sessions: PuttySession[], name?: string, host?: string, username?: string, nameOnly = true): Promise<PuttySession | undefined> {
if (name) {
// 将名称转换为小写,以便不区分大小写地进行搜索
name = name.toLowerCase();
// 在会话数组中查找名称匹配的会话
const session = sessions.find(s => s.name.toLowerCase() === name);
// 如果只根据名称进行匹配,或者找到了匹配的会话,则返回该会话
if (nameOnly || session) return session;
}
// 如果没有提供主机名,则返回未定义
if (!host) return undefined;
// 将主机名转换为小写,以便不区分大小写地进行搜索
host = host.toLowerCase();
// 在会话数组中查找主机名匹配的会话
const hosts = sessions.filter(s => s.hostname && s.hostname.toLowerCase() === host);
// 如果没有提供用户名,则返回第一个匹配的会话或 null
if (!username) return hosts[0] || null;
// 将用户名转换为小写,以便不区分大小写地进行搜索
username = username.toLowerCase();
// 在主机名匹配的会话中查找用户名匹配的会话
return hosts.find(s => !s.username || s.username.toLowerCase() === username);
}
/**
* PuTTY
* @param name -
* @param host - IP
* @param username -
* @param nameOnly - true
* @returns undefined
*/
export async function getSession(name?: string, host?: string, username?: string, nameOnly = true): Promise<PuttySession | undefined> {
// 从注册表中获取所有 PuTTY 会话信息
const sessions = await getSessions();
// 在获取的会话数组中查找匹配的会话
return findSession(sessions, name, host, username, nameOnly);
}
/**
* 使
* @returns getSession
*/
export async function getCachedFinder(): Promise<typeof getSession> {
// 从注册表中获取所有 PuTTY 会话信息
const sessions = await getSessions();
// 返回一个函数,该函数接受与 getSession 相同的参数,并使用预加载的会话数据进行查找
return (...args) => findSession(sessions, ...args);
}

Loading…
Cancel
Save