Feature: Automatically start frp client for subordinate
This commit is contained in:
@@ -90,6 +90,7 @@
|
||||
#define TIMER_PREVIEW_ARRIVAL 8 // 屏幕预览到达超时(4 秒未收到则提示"预览不可用")
|
||||
#define TIMER_PREVIEW_LOOP 9 // "播放快照"循环拉取(间隔由 LOOP_INTERVAL_MS 决定)
|
||||
#define TIMER_THUMBNAIL_REFRESH 10 // 主机列表缩略图后台刷新(间隔取自 m_ThumbnailCfg)
|
||||
#define TIMER_FRP_CONFIG_CHECK 11 // 检测外部模块对 [settings] FrpConfig 的写入并热切换 FRPC
|
||||
#define TODO_NOTICE MessageBoxL("This feature has not been implemented!\nPlease contact: 962914132@qq.com", "提示", MB_ICONINFORMATION);
|
||||
#define TINY_DLL_NAME "TinyRun.dll"
|
||||
#define FRPC_DLL_NAME "Frpc.dll"
|
||||
@@ -2186,6 +2187,9 @@ BOOL CMy2015RemoteDlg::OnInitDialog()
|
||||
#endif
|
||||
InitFrpClients();
|
||||
InitFrpcAuto(); // FRP 自动代理(由上级提供配置)
|
||||
// 记录启动时的 FRP 配置作为基线,由 TIMER_FRP_CONFIG_CHECK 周期性检测外部模块写入的变更
|
||||
m_lastSeenFrpConfig = THIS_CFG.GetStr("settings", "FrpConfig", "");
|
||||
SetTimer(TIMER_FRP_CONFIG_CHECK, 10 * 1000, NULL); // 10s 间隔,开销可忽略
|
||||
|
||||
UPDATE_SPLASH(90, "正在启动网络服务...");
|
||||
// 最后启动SOCKET
|
||||
@@ -2804,6 +2808,14 @@ void CMy2015RemoteDlg::StartFrpcAuto(const FrpAutoConfig& cfg)
|
||||
THIS_CFG.SetStr("frp_auto", "privilegeKey", cfg.privilegeKey);
|
||||
THIS_CFG.SetStr("frp_auto", "expireDate", cfg.expireDate);
|
||||
|
||||
// 防御性:若已有运行中的 FRPC 线程,先停掉以避免句柄泄露 + 双实例并存。
|
||||
// 正常调用路径会先 StopFrpcAuto,但 InitFrpcAuto 经 [frp_auto] 旧字段启动 +
|
||||
// 随后外部模块写入 [settings] FrpConfig 的场景可能跳过停步,这里兜底。
|
||||
if (m_hFrpAutoThread != NULL) {
|
||||
Mprintf("[FRP-Auto] StartFrpcAuto: 检测到已有运行中的线程,先停止旧实例\n");
|
||||
StopFrpcAuto();
|
||||
}
|
||||
|
||||
// 启动线程
|
||||
m_frpAutoStatus = STATUS_UNKNOWN;
|
||||
m_hFrpAutoThread = CreateThread(NULL, 0, FrpcAutoThreadProc, this, 0, NULL);
|
||||
@@ -2885,6 +2897,72 @@ void CMy2015RemoteDlg::InitFrpcAuto()
|
||||
}
|
||||
}
|
||||
|
||||
// 清空 [frp_auto] 节中所有用于自动恢复的字段。
|
||||
// 必要性:InitFrpcAuto 在 [settings] FrpConfig 为空或解析失败时会回退读取 [frp_auto]
|
||||
// 兼容旧配置,若此处不清理,上级撤销 FRP 后下级一旦重启就会用过期的 privilegeKey
|
||||
// 重新拉起 FRPC,连不上同时还会让上级以为已释放的端口被悄悄占用。
|
||||
static void ClearFrpAutoSection()
|
||||
{
|
||||
THIS_CFG.SetStr("frp_auto", "server", "");
|
||||
THIS_CFG.SetInt("frp_auto", "serverPort", 0);
|
||||
THIS_CFG.SetInt("frp_auto", "remotePort", 0);
|
||||
THIS_CFG.SetStr("frp_auto", "privilegeKey", "");
|
||||
THIS_CFG.SetStr("frp_auto", "expireDate", "");
|
||||
}
|
||||
|
||||
// 周期性检测 [settings] FrpConfig 是否被外部模块(如授权工具)写入变更。
|
||||
// 检测到变更后:先停旧 FRPC(若有),再按新配置启动(若非空),并在主对话框信息列表中给出友好提示。
|
||||
// 三种情况均无需重启主程序:
|
||||
// - 首次(空 → 有):StartFrpcAuto
|
||||
// - 撤销(有 → 空):StopFrpcAuto + ClearFrpAutoSection(防止重启复活)
|
||||
// - 覆盖(有 → 有,值不同):StopFrpcAuto + StartFrpcAuto(StartFrpcAuto 会重写 [frp_auto])
|
||||
void CMy2015RemoteDlg::CheckUpperFrpConfigChange()
|
||||
{
|
||||
std::string cur = THIS_CFG.GetStr("settings", "FrpConfig", "");
|
||||
if (cur == m_lastSeenFrpConfig) return;
|
||||
|
||||
// 解析(沿用现有 ParseFrpAutoConfig,可正确处理含 '-' 的域名)
|
||||
FrpAutoConfig oldCfg = ParseFrpAutoConfig(m_lastSeenFrpConfig);
|
||||
FrpAutoConfig newCfg = ParseFrpAutoConfig(cur);
|
||||
int oldPort = oldCfg.remotePort;
|
||||
int newPort = newCfg.remotePort;
|
||||
|
||||
CString tip;
|
||||
if (m_lastSeenFrpConfig.empty() && !cur.empty()) {
|
||||
// 首次:从无到有 → 启动
|
||||
if (newCfg.enabled) {
|
||||
StartFrpcAuto(newCfg);
|
||||
tip.FormatL("[FRP] 已启用上级 FRP 反向代理(远程端口 %d),已生效", newPort);
|
||||
} else {
|
||||
// 新配置无效,但 cur 非空 —— 提示但不启动;同时确保 [frp_auto] 不残留旧值
|
||||
ClearFrpAutoSection();
|
||||
tip.FormatL("[FRP] 收到无效的 FRP 配置: %s", cur.c_str());
|
||||
}
|
||||
} else if (!m_lastSeenFrpConfig.empty() && cur.empty()) {
|
||||
// 撤销:从有到无 → 停止并清空 [frp_auto](否则下次启动会从 [frp_auto] 复活 FRPC)
|
||||
StopFrpcAuto();
|
||||
ClearFrpAutoSection();
|
||||
tip = _TR("[FRP] 上级已撤销 FRP 反向代理配置,已停止 FRPC");
|
||||
} else {
|
||||
// 覆盖:值变更 → 先停后起
|
||||
StopFrpcAuto();
|
||||
if (newCfg.enabled) {
|
||||
StartFrpcAuto(newCfg); // 内部会用新值覆盖 [frp_auto]
|
||||
tip.FormatL("[FRP] 上级 FRP 反向代理配置已切换(远程端口 %d → %d),已生效",
|
||||
oldPort, newPort);
|
||||
} else {
|
||||
// 新配置无效(解析失败等),旧的 FRPC 已停,[frp_auto] 必须一并清空
|
||||
ClearFrpAutoSection();
|
||||
tip.FormatL("[FRP] 收到无效的新 FRP 配置: %s,已停止旧 FRPC", cur.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Mprintf("[FRP-Auto] %s\n", (LPCSTR)tip);
|
||||
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg((LPCSTR)tip), NULL);
|
||||
|
||||
m_lastSeenFrpConfig = cur;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CMy2015RemoteDlg::ApplyFrpSettings()
|
||||
@@ -3250,6 +3328,9 @@ void CMy2015RemoteDlg::OnTimer(UINT_PTR nIDEvent)
|
||||
if (nIDEvent == TIMER_STATUSBAR_UPDATE) {
|
||||
UpdateStatusBarStats();
|
||||
}
|
||||
if (nIDEvent == TIMER_FRP_CONFIG_CHECK) {
|
||||
CheckUpperFrpConfigChange();
|
||||
}
|
||||
if (nIDEvent == TIMER_STATUSBAR_INIT) {
|
||||
KillTimer(TIMER_STATUSBAR_INIT); // 只执行一次
|
||||
// 强制重新计算状态栏分区宽度
|
||||
@@ -3544,6 +3625,7 @@ void CMy2015RemoteDlg::Release()
|
||||
#ifdef _WIN64
|
||||
StopLocalFrpsServer(); // 停止本地 FRPS 服务器
|
||||
#endif
|
||||
KillTimer(TIMER_FRP_CONFIG_CHECK); // 必须先于 StopFrpcAuto,避免末班定时器再次起飞 FRPC
|
||||
StopFrpcAuto(); // 停止 FRP 自动代理
|
||||
|
||||
THIS_APP->Destroy();
|
||||
|
||||
@@ -224,6 +224,10 @@ public:
|
||||
Buffer* m_ServerBin[PAYLOAD_MAXTYPE];
|
||||
Buffer* m_TinyRun[PAYLOAD_MAXTYPE] = {};
|
||||
MasterSettings m_settings;
|
||||
// 缓存上次检测到的上级 FRP 配置([settings] FrpConfig),由定时器检测外部模块写入的变更。
|
||||
// 检出变更后会热切换 FRPC(首次=启动 / 覆盖=重启 / 撤销=停止),并在主对话框信息列表中给出友好提示。
|
||||
std::string m_lastSeenFrpConfig;
|
||||
void CheckUpperFrpConfigChange();
|
||||
static BOOL CALLBACK NotifyProc(CONTEXT_OBJECT* ContextObject);
|
||||
static BOOL CALLBACK OfflineProc(CONTEXT_OBJECT* ContextObject);
|
||||
int AuthorizeClient(context* ctx, const std::string& sn, const std::string& passcode, uint64_t hmac, bool* outExpired = nullptr);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "2015RemoteDlg.h"
|
||||
#include "InputDlg.h"
|
||||
#include "IPHistoryDlg.h"
|
||||
#include "FrpsForSubDlg.h"
|
||||
#include "pwd_gen.h"
|
||||
#include <algorithm>
|
||||
|
||||
// CLicenseDlg 对话框
|
||||
@@ -42,8 +44,14 @@ BEGIN_MESSAGE_MAP(CLicenseDlg, CDialogEx)
|
||||
ON_COMMAND(ID_LICENSE_EDIT_REMARK, &CLicenseDlg::OnLicenseEditRemark)
|
||||
ON_COMMAND(ID_LICENSE_VIEW_IPS, &CLicenseDlg::OnLicenseViewIPs)
|
||||
ON_COMMAND(ID_LICENSE_DELETE, &CLicenseDlg::OnLicenseDelete)
|
||||
ON_COMMAND(ID_LICENSE_AUTO_FRP, &CLicenseDlg::OnLicenseAutoFrp)
|
||||
ON_COMMAND(ID_LICENSE_REVOKE_FRP, &CLicenseDlg::OnLicenseRevokeFrp)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
// 前向声明:实现位于本文件后段(Auto FRP 相关工具)
|
||||
static int ParseRemotePortFromFrpConfig(const std::string& frpConfig);
|
||||
static bool FreeFrpPortAllocation(int port, const std::string& expectedOwner);
|
||||
|
||||
// 获取所有授权信息
|
||||
std::vector<LicenseInfo> GetAllLicenses()
|
||||
{
|
||||
@@ -331,6 +339,15 @@ void CLicenseDlg::OnNMRClickLicenseList(NMHDR* pNMHDR, LRESULT* pResult)
|
||||
const auto& lic = m_Licenses[nIndex];
|
||||
menu.AppendMenuL(MF_STRING, ID_LICENSE_RENEWAL, _T("预设续期(&N)..."));
|
||||
menu.AppendMenuL(MF_STRING, ID_LICENSE_EDIT_REMARK, _T("编辑备注(&E)..."));
|
||||
menu.AppendMenuL(MF_STRING, ID_LICENSE_AUTO_FRP, _T("自动FRP(&F)..."));
|
||||
|
||||
// 仅当该授权已分配 FRPC 端口时,才显示"撤销FRP"
|
||||
{
|
||||
std::string existingFrp = LoadLicenseFrpConfig(lic.SerialNumber);
|
||||
if (ParseRemotePortFromFrpConfig(existingFrp) > 0) {
|
||||
menu.AppendMenuL(MF_STRING, ID_LICENSE_REVOKE_FRP, _T("撤销FRP(&U)"));
|
||||
}
|
||||
}
|
||||
|
||||
// 只有当有 IP 记录时才显示查看 IP 历史选项
|
||||
int ipCount = GetIPCountFromList(lic.IP);
|
||||
@@ -651,6 +668,14 @@ bool DeleteLicense(const std::string& deviceID)
|
||||
return false; // 授权不存在
|
||||
}
|
||||
|
||||
// 若该授权占用了 FRP 端口,先释放 frp_ports.ini 中的占用记录,
|
||||
// 否则端口会一直被这个已不存在的 SN "挂账",导致端口池逐步耗尽。
|
||||
std::string frpConfig = cfg.GetStr(deviceID, "FrpConfig", "");
|
||||
int allocatedPort = ParseRemotePortFromFrpConfig(frpConfig);
|
||||
if (allocatedPort > 0) {
|
||||
FreeFrpPortAllocation(allocatedPort, deviceID);
|
||||
}
|
||||
|
||||
// 删除该 section (通过写入 NULL 删除整个 section)
|
||||
BOOL ret = ::WritePrivateProfileStringA(deviceID.c_str(), NULL, NULL, iniPath.c_str());
|
||||
::WritePrivateProfileStringA(NULL, NULL, NULL, iniPath.c_str()); // 刷新缓存
|
||||
@@ -1010,3 +1035,193 @@ bool FindLicenseByIPAndMachine(const std::string& ip, const std::string& machine
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从 FrpConfig 字符串解析 remotePort
|
||||
// 格式: "serverAddr:serverPort-remotePort-expireDate-authValue"
|
||||
// 注意:serverAddr 可能是含 '-' 的域名(如 my-server.com),必须从右往左定位
|
||||
// 与 CMy2015RemoteDlg::ParseFrpAutoConfig 的拆分策略一致。
|
||||
static int ParseRemotePortFromFrpConfig(const std::string& frpConfig)
|
||||
{
|
||||
if (frpConfig.empty()) return 0;
|
||||
// 倒数第 1 个 '-':分隔 expireDate 与 authValue
|
||||
size_t dashAuth = frpConfig.rfind('-');
|
||||
if (dashAuth == std::string::npos || dashAuth == 0) return 0;
|
||||
std::string s2 = frpConfig.substr(0, dashAuth);
|
||||
// 倒数第 2 个 '-':分隔 remotePort 与 expireDate
|
||||
size_t dashExpire = s2.rfind('-');
|
||||
if (dashExpire == std::string::npos || dashExpire == 0) return 0;
|
||||
std::string s3 = s2.substr(0, dashExpire);
|
||||
// 倒数第 3 个 '-':分隔 serverAddr:serverPort 与 remotePort
|
||||
size_t dashPort = s3.rfind('-');
|
||||
if (dashPort == std::string::npos || dashPort == 0) return 0;
|
||||
return atoi(s3.substr(dashPort + 1).c_str());
|
||||
}
|
||||
|
||||
// 释放 frp_ports.ini 中指定端口的占用记录。
|
||||
// 必须传入 expectedOwner —— 仅当端口当前的归属确实是它时才清除,
|
||||
// 避免在 race 或外部改动后误抹掉别的 SN 的占用记录。
|
||||
static bool FreeFrpPortAllocation(int port, const std::string& expectedOwner)
|
||||
{
|
||||
if (port <= 0 || expectedOwner.empty()) return false;
|
||||
config portsCfg(CFrpsForSubDlg::GetFrpPortsPath());
|
||||
char portStr[16];
|
||||
sprintf_s(portStr, "%d", port);
|
||||
std::string currentOwner = portsCfg.GetStr("ports", portStr, "");
|
||||
if (currentOwner != expectedOwner) {
|
||||
// 已被改写或释放,不动它
|
||||
return false;
|
||||
}
|
||||
portsCfg.SetStr("ports", portStr, ""); // 写入空 owner,FindNextAvailablePort 将其视为可用
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLicenseDlg::OnLicenseAutoFrp()
|
||||
{
|
||||
int nItem = m_ListLicense.GetNextItem(-1, LVNI_SELECTED);
|
||||
if (nItem < 0)
|
||||
return;
|
||||
|
||||
size_t nIndex = (size_t)m_ListLicense.GetItemData(nItem);
|
||||
if (nIndex >= m_Licenses.size())
|
||||
return;
|
||||
|
||||
const auto& lic = m_Licenses[nIndex];
|
||||
|
||||
// 1. 前提条件:FRPS 服务器必须已在「下级 FRP 代理设置」中配置并启用
|
||||
if (!CFrpsForSubDlg::IsFrpsConfigured()) {
|
||||
MessageBoxL("请先在 扩展 → 下级 FRP 代理设置 中启用并配置 FRPS 服务器地址、端口与 Token,然后再使用此功能。",
|
||||
"未配置 FRPS", MB_OK | MB_ICONINFORMATION);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 读取该授权当前的 FRP 配置(若已分配端口)
|
||||
std::string existingFrpConfig = LoadLicenseFrpConfig(lic.SerialNumber);
|
||||
int existingPort = ParseRemotePortFromFrpConfig(existingFrpConfig);
|
||||
|
||||
// 已分配端口时,先询问是否覆盖
|
||||
if (existingPort > 0) {
|
||||
CString msg;
|
||||
msg.FormatL("该授权已分配 FRPC 远程端口 %d,是否覆盖并重新设置?",
|
||||
existingPort);
|
||||
if (MessageBox(msg, _TR("覆盖 FRPC 配置"),
|
||||
MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 决定默认端口:已有端口则沿用,否则查找下一个可用端口
|
||||
int defaultPort = existingPort;
|
||||
if (defaultPort <= 0) {
|
||||
defaultPort = CFrpsForSubDlg::FindNextAvailablePort();
|
||||
if (defaultPort <= 0) {
|
||||
MessageBoxL("FRPS 端口范围已满,无法自动分配,请扩大「下级 FRP 代理设置」中的端口范围。",
|
||||
"端口已满", MB_OK | MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 弹出输入对话框,允许用户确认或修改端口
|
||||
CInputDialog dlg(this);
|
||||
CString strTitle;
|
||||
strTitle.FormatL("自动 FRP - %s", lic.SerialNumber.c_str());
|
||||
dlg.Init(strTitle, _L("FRPC 远程端口 (1024-65535):"));
|
||||
CString strDefault;
|
||||
strDefault.Format(_T("%d"), defaultPort);
|
||||
dlg.m_str = strDefault;
|
||||
|
||||
if (dlg.DoModal() != IDOK)
|
||||
return;
|
||||
|
||||
int remotePort = _ttoi(dlg.m_str);
|
||||
if (remotePort < 1024 || remotePort > 65535) {
|
||||
MessageBoxL("FRP 远程端口无效(1024-65535)", "提示", MB_OK | MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 端口冲突检测:若端口已被其它序列号占用则拒绝
|
||||
std::string portOwner = CFrpsForSubDlg::GetPortOwner(remotePort);
|
||||
if (!portOwner.empty() && portOwner != lic.SerialNumber) {
|
||||
CString msg;
|
||||
msg.FormatL("端口 %d 已被序列号 %s 占用,请选择其它端口。",
|
||||
remotePort, portOwner.c_str());
|
||||
MessageBox(msg, _TR("端口冲突"), MB_OK | MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. 先生成 FRP 配置串(失败则直接返回,不动 frp_ports.ini)
|
||||
FrpsConfig frpsConfig = CFrpsForSubDlg::GetFrpsConfig();
|
||||
// expireDate 固定 20371231(由 License 自身的过期控制实际有效性)
|
||||
std::string frpConfig = GenerateFrpConfig(
|
||||
frpsConfig.server, frpsConfig.port, remotePort,
|
||||
frpsConfig.token, "20371231", frpsConfig.authMode);
|
||||
|
||||
if (frpConfig.empty()) {
|
||||
MessageBoxL("生成 FRP 配置失败", "错误", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// 7. 提交端口变更(顺序:新端口 RecordPortAllocation → 释放旧端口 → 写 licenses.ini)。
|
||||
// 顺序保证:任意一步失败都不会出现"旧端口已释放 + 新端口未占用"的真空态。
|
||||
CFrpsForSubDlg::RecordPortAllocation(remotePort, lic.SerialNumber);
|
||||
if (existingPort > 0 && existingPort != remotePort) {
|
||||
FreeFrpPortAllocation(existingPort, lic.SerialNumber); // 仅当旧端口确实归属本 SN 时才释放
|
||||
}
|
||||
{
|
||||
std::string iniPath = GetLicensesPath();
|
||||
config cfg(iniPath);
|
||||
cfg.SetStr(lic.SerialNumber, "FrpConfig", frpConfig);
|
||||
}
|
||||
|
||||
CString msg;
|
||||
msg.FormatL("已为授权 %s 配置 FRPC 远程端口 %d。\n\n下级上线时将自动接收 FRP 配置并启用反向代理。",
|
||||
lic.SerialNumber.c_str(), remotePort);
|
||||
MessageBox(msg, _TR("配置成功"), MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
|
||||
void CLicenseDlg::OnLicenseRevokeFrp()
|
||||
{
|
||||
int nItem = m_ListLicense.GetNextItem(-1, LVNI_SELECTED);
|
||||
if (nItem < 0)
|
||||
return;
|
||||
|
||||
size_t nIndex = (size_t)m_ListLicense.GetItemData(nItem);
|
||||
if (nIndex >= m_Licenses.size())
|
||||
return;
|
||||
|
||||
const auto& lic = m_Licenses[nIndex];
|
||||
|
||||
// 读取当前 FRP 配置;若本就没有,菜单理应不显示,这里再防御一次
|
||||
std::string existingFrpConfig = LoadLicenseFrpConfig(lic.SerialNumber);
|
||||
int existingPort = ParseRemotePortFromFrpConfig(existingFrpConfig);
|
||||
if (existingFrpConfig.empty() && existingPort <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 二次确认(撤销后下级下次上线即丢失反向代理通道)
|
||||
CString confirm;
|
||||
confirm.FormatL("确定撤销授权 %s 的 FRP 配置吗?\n\n远程端口 %d 将被释放,下级下次上线后反向代理失效。",
|
||||
lic.SerialNumber.c_str(), existingPort);
|
||||
if (MessageBox(confirm, _TR("撤销 FRP 配置"),
|
||||
MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先释放 frp_ports.ini 中的端口占用(仅当归属仍为本 SN 时才释放)。
|
||||
// 顺序:先释放端口,再清 FrpConfig —— 即便后一步失败,端口也已可被复用,
|
||||
// 不会留下"FrpConfig 还在但端口已挂账"的悬空状态。
|
||||
if (existingPort > 0) {
|
||||
FreeFrpPortAllocation(existingPort, lic.SerialNumber);
|
||||
}
|
||||
|
||||
// 清除 licenses.ini 中该授权的 FrpConfig 字段
|
||||
{
|
||||
std::string iniPath = GetLicensesPath();
|
||||
config cfg(iniPath);
|
||||
cfg.SetStr(lic.SerialNumber, "FrpConfig", "");
|
||||
}
|
||||
|
||||
CString msg;
|
||||
msg.FormatL("已撤销授权 %s 的 FRP 配置,远程端口 %d 已释放。",
|
||||
lic.SerialNumber.c_str(), existingPort);
|
||||
MessageBox(msg, _TR("撤销成功"), MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
afx_msg void OnLicenseEditRemark();
|
||||
afx_msg void OnLicenseViewIPs();
|
||||
afx_msg void OnLicenseDelete();
|
||||
afx_msg void OnLicenseAutoFrp();
|
||||
afx_msg void OnLicenseRevokeFrp();
|
||||
};
|
||||
|
||||
// 获取所有授权信息
|
||||
|
||||
@@ -1854,3 +1854,37 @@ IOCP
|
||||
入站公网 IP=%s (Proxy Protocol 真实 IP 或 raw TCP 对端)=Inbound public IP=%s (resolved via Proxy Protocol v2 real IP or raw TCP peer)
|
||||
检测到入站连接来自公网 IP:%s\r\n\r\n试用版仅供 LAN 内自用,跨网使用属于违反授权条款。\r\n如需跨网远控,请向发行方申请正式授权。\r\n\r\n详细记录见消息列表与运行日志。=Inbound connection from public IP: %s\r\n\r\nTrial version is restricted to LAN-only usage; cross-network use violates the license terms.\r\nFor cross-network remote control, please obtain a commercial license from the publisher.\r\n\r\nSee the message list and runtime log for full details.
|
||||
检测到可疑连接:内核 RTT 中位数 %d ms,超出阈值 %d ms。\r\n\r\n持续偏高的 RTT 提示该连接可能经由代理 / VPN / 隧道中转。\r\n试用版仅供 LAN 内自用,跨网使用属于违反授权条款。\r\n\r\n如需跨网远控,请向发行方申请正式授权。\r\n详细记录见消息列表与运行日志。=Suspicious connection detected: kernel-measured RTT median %d ms exceeds the threshold of %d ms.\r\n\r\nA persistently elevated RTT suggests the connection is being relayed through a proxy / VPN / tunnel.\r\nTrial version is restricted to LAN-only usage; cross-network use violates the license terms.\r\n\r\nFor cross-network remote control, please obtain a commercial license from the publisher.\r\nSee the message list and runtime log for full details.
|
||||
; Auto FRP / Upper-FRP Hot-Swap - English Translation
|
||||
; Format: Simplified Chinese=English
|
||||
; 用途: commit 88a9a01 (Feature: Automatically start frp client for subordinate) 引入的新文案
|
||||
|
||||
; --- 主对话框:检测到 [settings] FrpConfig 被外部模块写入的热切换提示 ---
|
||||
[FRP] 已启用上级 FRP 反向代理(远程端口 %d),已生效=[FRP] Upstream FRP reverse proxy enabled (remote port %d), now active
|
||||
[FRP] 收到无效的 FRP 配置: %s=[FRP] Received invalid FRP configuration: %s
|
||||
[FRP] 上级已撤销 FRP 反向代理配置,已停止 FRPC=[FRP] Upstream FRP reverse proxy configuration revoked, FRPC stopped
|
||||
[FRP] 上级 FRP 反向代理配置已切换(远程端口 %d → %d),已生效=[FRP] Upstream FRP reverse proxy switched (remote port %d → %d), now active
|
||||
[FRP] 收到无效的新 FRP 配置: %s,已停止旧 FRPC=[FRP] Received invalid new FRP configuration: %s. Old FRPC stopped.
|
||||
|
||||
; --- 授权管理:右键菜单"自动FRP" ---
|
||||
自动FRP(&F)...=Auto FRP(&F)...
|
||||
|
||||
; --- 授权管理 → 自动FRP 对话框相关 ---
|
||||
请先在 扩展 → 下级 FRP 代理设置 中启用并配置 FRPS 服务器地址、端口与 Token,然后再使用此功能。=Please first enable and configure the FRPS server address, port and token in Extensions → FRPS for Subordinates, then use this feature.
|
||||
未配置 FRPS=FRPS Not Configured
|
||||
该授权已分配 FRPC 远程端口 %d,是否覆盖并重新设置?=This license is already assigned FRPC remote port %d. Overwrite and reconfigure?
|
||||
覆盖 FRPC 配置=Overwrite FRPC Configuration
|
||||
FRPS 端口范围已满,无法自动分配,请扩大「下级 FRP 代理设置」中的端口范围。=FRPS port range is full, cannot auto-allocate. Please expand the port range in "FRPS for Subordinates" settings.
|
||||
端口已满=Port Range Full
|
||||
自动 FRP - %s=Auto FRP - %s
|
||||
FRPC 远程端口 (1024-65535):=FRPC Remote Port (1024-65535):
|
||||
端口 %d 已被序列号 %s 占用,请选择其它端口。=Port %d is already occupied by serial number %s. Please choose another port.
|
||||
端口冲突=Port Conflict
|
||||
生成 FRP 配置失败=Failed to generate FRP configuration
|
||||
已为授权 %s 配置 FRPC 远程端口 %d。\n\n下级上线时将自动接收 FRP 配置并启用反向代理。=Configured license %s with FRPC remote port %d.\n\nWhen the subordinate comes online, it will automatically receive the FRP configuration and enable the reverse proxy.
|
||||
配置成功=Configured Successfully
|
||||
; --- 授权管理:右键菜单"撤销FRP" + 对话框 ---
|
||||
撤销FRP(&U)=Revoke FRP(&U)
|
||||
确定撤销授权 %s 的 FRP 配置吗?\n\n远程端口 %d 将被释放,下级下次上线后反向代理失效。=Revoke FRP configuration for license %s?\n\nRemote port %d will be released. The reverse proxy will stop working the next time the subordinate comes online.
|
||||
撤销 FRP 配置=Revoke FRP Configuration
|
||||
已撤销授权 %s 的 FRP 配置,远程端口 %d 已释放。=Revoked FRP configuration for license %s. Remote port %d has been released.
|
||||
撤销成功=Revoked Successfully
|
||||
|
||||
@@ -1845,3 +1845,37 @@ IOCP
|
||||
入站公网 IP=%s (Proxy Protocol 真实 IP 或 raw TCP 对端)=入站公網 IP=%s (Proxy Protocol 真實 IP 或 raw TCP 對端)
|
||||
检测到入站连接来自公网 IP:%s\r\n\r\n试用版仅供 LAN 内自用,跨网使用属于违反授权条款。\r\n如需跨网远控,请向发行方申请正式授权。\r\n\r\n详细记录见消息列表与运行日志。=檢測到入站連線來自公網 IP:%s\r\n\r\n試用版僅供 LAN 內自用,跨網使用屬於違反授權條款。\r\n如需跨網遠控,請向發行方申請正式授權。\r\n\r\n詳細記錄請見訊息列表與執行日誌。
|
||||
检测到可疑连接:内核 RTT 中位数 %d ms,超出阈值 %d ms。\r\n\r\n持续偏高的 RTT 提示该连接可能经由代理 / VPN / 隧道中转。\r\n试用版仅供 LAN 内自用,跨网使用属于违反授权条款。\r\n\r\n如需跨网远控,请向发行方申请正式授权。\r\n详细记录见消息列表与运行日志。=檢測到可疑連線:核心 RTT 中位數 %d ms,超出閾值 %d ms。\r\n\r\n持續偏高的 RTT 提示該連線可能經由代理 / VPN / 隧道中轉。\r\n試用版僅供 LAN 內自用,跨網使用屬於違反授權條款。\r\n\r\n如需跨網遠控,請向發行方申請正式授權。\r\n詳細記錄請見訊息列表與執行日誌。
|
||||
; Auto FRP / Upper-FRP Hot-Swap - Traditional Chinese Translation
|
||||
; Format: Simplified Chinese=Traditional Chinese
|
||||
; 用途: commit 88a9a01 (Feature: Automatically start frp client for subordinate) 引入的新文案
|
||||
|
||||
; --- 主对话框:检测到 [settings] FrpConfig 被外部模块写入的热切换提示 ---
|
||||
[FRP] 已启用上级 FRP 反向代理(远程端口 %d),已生效=[FRP] 已啟用上級 FRP 反向代理(遠端連接埠 %d),已生效
|
||||
[FRP] 收到无效的 FRP 配置: %s=[FRP] 收到無效的 FRP 配置: %s
|
||||
[FRP] 上级已撤销 FRP 反向代理配置,已停止 FRPC=[FRP] 上級已撤銷 FRP 反向代理配置,已停止 FRPC
|
||||
[FRP] 上级 FRP 反向代理配置已切换(远程端口 %d → %d),已生效=[FRP] 上級 FRP 反向代理配置已切換(遠端連接埠 %d → %d),已生效
|
||||
[FRP] 收到无效的新 FRP 配置: %s,已停止旧 FRPC=[FRP] 收到無效的新 FRP 配置: %s,已停止舊 FRPC
|
||||
|
||||
; --- 授权管理:右键菜单"自动FRP" ---
|
||||
自动FRP(&F)...=自動FRP(&F)...
|
||||
|
||||
; --- 授权管理 → 自动FRP 对话框相关 ---
|
||||
请先在 扩展 → 下级 FRP 代理设置 中启用并配置 FRPS 服务器地址、端口与 Token,然后再使用此功能。=請先在 擴充 → 下級 FRP 代理設定 中啟用並設定 FRPS 伺服器位址、連接埠與 Token,然後再使用此功能。
|
||||
未配置 FRPS=未設定 FRPS
|
||||
该授权已分配 FRPC 远程端口 %d,是否覆盖并重新设置?=該授權已分配 FRPC 遠端連接埠 %d,是否覆蓋並重新設定?
|
||||
覆盖 FRPC 配置=覆蓋 FRPC 設定
|
||||
FRPS 端口范围已满,无法自动分配,请扩大「下级 FRP 代理设置」中的端口范围。=FRPS 連接埠範圍已滿,無法自動分配,請擴大「下級 FRP 代理設定」中的連接埠範圍。
|
||||
端口已满=連接埠已滿
|
||||
自动 FRP - %s=自動 FRP - %s
|
||||
FRPC 远程端口 (1024-65535):=FRPC 遠端連接埠 (1024-65535):
|
||||
端口 %d 已被序列号 %s 占用,请选择其它端口。=連接埠 %d 已被序列號 %s 佔用,請選擇其他連接埠。
|
||||
端口冲突=連接埠衝突
|
||||
生成 FRP 配置失败=產生 FRP 配置失敗
|
||||
已为授权 %s 配置 FRPC 远程端口 %d。\n\n下级上线时将自动接收 FRP 配置并启用反向代理。=已為授權 %s 設定 FRPC 遠端連接埠 %d。\n\n下級上線時將自動接收 FRP 配置並啟用反向代理。
|
||||
配置成功=設定成功
|
||||
; --- 授权管理:右键菜单"撤销FRP" + 对话框 ---
|
||||
撤销FRP(&U)=撤銷FRP(&U)
|
||||
确定撤销授权 %s 的 FRP 配置吗?\n\n远程端口 %d 将被释放,下级下次上线后反向代理失效。=確定撤銷授權 %s 的 FRP 配置嗎?\n\n遠端連接埠 %d 將被釋放,下級下次上線後反向代理失效。
|
||||
撤销 FRP 配置=撤銷 FRP 配置
|
||||
已撤销授权 %s 的 FRP 配置,远程端口 %d 已释放。=已撤銷授權 %s 的 FRP 配置,遠端連接埠 %d 已釋放。
|
||||
撤销成功=撤銷成功
|
||||
|
||||
@@ -983,6 +983,8 @@
|
||||
#define ID_33048 33048
|
||||
#define ID_SCREENPREVIEW_LOOP 33049
|
||||
#define ID_PARAM_THUMBNAIL_PREVIEW 33050
|
||||
#define ID_LICENSE_AUTO_FRP 33051
|
||||
#define ID_LICENSE_REVOKE_FRP 33052
|
||||
#define ID_EXIT_FULLSCREEN 40001
|
||||
|
||||
// Next default values for new objects
|
||||
@@ -990,7 +992,7 @@
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 386
|
||||
#define _APS_NEXT_COMMAND_VALUE 33051
|
||||
#define _APS_NEXT_COMMAND_VALUE 33053
|
||||
#define _APS_NEXT_CONTROL_VALUE 2542
|
||||
#define _APS_NEXT_SYMED_VALUE 105
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user