移除深圳宝安机场跑道数据采集,深圳市场结算使用流浮山 HKO 数据

This commit is contained in:
2569718930@qq.com
2026-05-20 19:38:07 +08:00
parent 0c24a3ed6d
commit 8ba9567f64
3 changed files with 108 additions and 43 deletions
+107 -40
View File
@@ -241,6 +241,8 @@ const TELEGRAM_TOPICS_GROUP_URL = TELEGRAM_GROUP_URL;
const SUBSCRIPTION_HELP_HREF = "/subscription-help";
const PAYMENT_RECOVERY_STORAGE_KEY = "polyweather:lastPaymentRecovery";
const PAYMENT_RECOVERY_TTL_MS = 6 * 60 * 60 * 1000;
const WALLET_REQUEST_TIMEOUT_MS = 60_000;
const WALLET_TRANSACTION_REQUEST_TIMEOUT_MS = 120_000;
let walletConnectProviderCache: EvmProvider | null = null;
let walletConnectProviderChainId: number | null = null;
@@ -574,6 +576,31 @@ function buildBalanceOfCalldata(owner: string) {
return `0x70a08231${toPaddedAddress(owner)}`;
}
async function requestWalletWithTimeout<T>(
provider: EvmProvider,
args: { method: string; params?: unknown[] },
actionLabel = "钱包操作",
timeoutMs = WALLET_REQUEST_TIMEOUT_MS,
): Promise<T> {
let timeoutId: ReturnType<typeof setTimeout> | undefined;
try {
return (await Promise.race([
provider.request(args),
new Promise<never>((_, reject) => {
timeoutId = setTimeout(() => {
reject(
new Error(
`${actionLabel}长时间无响应,请确认钱包弹窗是否被拦截;如使用 Binance Web3 Wallet,请回到钱包确认或重新连接后再试。`,
),
);
}, timeoutMs);
}),
])) as T;
} finally {
if (timeoutId) clearTimeout(timeoutId);
}
}
function formatTokenUnits(amount: bigint, decimals: number) {
const safeDecimals =
Number.isFinite(decimals) && decimals >= 0 ? Math.floor(decimals) : 6;
@@ -1835,17 +1862,23 @@ export function AccountCenter() {
const waitForReceipt = async (
txHash: string,
provider?: EvmProvider,
timeoutMs = 120000,
pollMs = 3000,
) => {
const eth = getEvmProvider();
const eth = provider || getEvmProvider();
if (!eth) throw new Error("No EVM wallet provider found");
const started = Date.now();
while (Date.now() - started < timeoutMs) {
const receipt = (await eth.request({
method: "eth_getTransactionReceipt",
params: [txHash],
})) as { status?: string } | null;
const receipt = await requestWalletWithTimeout<{ status?: string } | null>(
eth,
{
method: "eth_getTransactionReceipt",
params: [txHash],
},
"查询授权交易确认",
15_000,
);
if (receipt && receipt.status) {
if (receipt.status === "0x1") return receipt;
throw new Error(`transaction reverted: ${txHash}`);
@@ -1938,16 +1971,24 @@ export function AccountCenter() {
targetChainId: number,
): Promise<void> => {
const currentChainIdHex = String(
(await eth.request({ method: "eth_chainId" })) || "",
(await requestWalletWithTimeout<string>(
eth,
{ method: "eth_chainId" },
"读取钱包网络",
)) || "",
);
const targetChainHex = `0x${targetChainId.toString(16)}`;
if (currentChainIdHex.toLowerCase() === targetChainHex.toLowerCase())
return;
try {
await eth.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: targetChainHex }],
});
await requestWalletWithTimeout(
eth,
{
method: "wallet_switchEthereumChain",
params: [{ chainId: targetChainHex }],
},
"切换钱包网络",
);
} catch (err: any) {
const code = Number(err?.code);
const msg = String(err?.message || "").toLowerCase();
@@ -1955,9 +1996,11 @@ export function AccountCenter() {
// If the error code indicates the chain is not added (4902), or it's Polygon (137)
if (code === 4902 || targetChainId === 137) {
try {
await eth.request({
method: "wallet_addEthereumChain",
params: [
await requestWalletWithTimeout(
eth,
{
method: "wallet_addEthereumChain",
params: [
{
chainId: "0x89",
chainName: "Polygon Mainnet",
@@ -1965,8 +2008,10 @@ export function AccountCenter() {
rpcUrls: ["https://polygon-rpc.com"],
blockExplorerUrls: ["https://polygonscan.com"],
},
],
});
],
},
"添加 Polygon 网络",
);
return;
} catch (addErr: any) {
err = addErr;
@@ -2010,9 +2055,11 @@ export function AccountCenter() {
Authorization: `Bearer ${accessToken}`,
};
const accounts = (await eth.request({
method: "eth_requestAccounts",
})) as string[];
const accounts = await requestWalletWithTimeout<string[]>(
eth,
{ method: "eth_requestAccounts" },
"连接绑定钱包",
);
const address = String(accounts?.[0] || "").toLowerCase();
if (!address)
throw new Error(isEn ? "Wallet account is empty." : "钱包账户为空");
@@ -2209,9 +2256,11 @@ export function AccountCenter() {
selectedInjectedProviderKey,
);
const eth = providerSelection.provider;
const activeAccounts = (await eth.request({
method: "eth_requestAccounts",
})) as string[];
const activeAccounts = await requestWalletWithTimeout<string[]>(
eth,
{ method: "eth_requestAccounts" },
"连接付款钱包",
);
const activeAddress = String(activeAccounts?.[0] || "").toLowerCase();
if (!activeAddress)
throw new Error(isEn ? "Wallet account is empty." : "钱包账户为空");
@@ -2330,16 +2379,20 @@ export function AccountCenter() {
6,
);
const balanceHex = (await eth.request({
method: "eth_call",
params: [
const balanceHex = await requestWalletWithTimeout<string>(
eth,
{
method: "eth_call",
params: [
{
to: tokenAddress,
data: buildBalanceOfCalldata(payingWallet),
},
"latest",
],
})) as string;
],
},
`读取 ${tokenSymbol} 余额`,
);
const tokenBalance = BigInt(String(balanceHex || "0x0"));
if (tokenBalance < amountUnits) {
const need = formatTokenUnits(amountUnits, tokenDecimals);
@@ -2349,16 +2402,20 @@ export function AccountCenter() {
);
}
const allowanceHex = (await eth.request({
method: "eth_call",
params: [
const allowanceHex = await requestWalletWithTimeout<string>(
eth,
{
method: "eth_call",
params: [
{
to: tokenAddress,
data: buildAllowanceCalldata(payingWallet, txPayload.to),
},
"latest",
],
})) as string;
],
},
`读取 ${tokenSymbol} 授权额度`,
);
const allowance = BigInt(String(allowanceHex || "0x0"));
if (allowance < amountUnits) {
@@ -2368,11 +2425,16 @@ export function AccountCenter() {
to: tokenAddress,
data: buildApproveCalldata(txPayload.to, amountUnits),
};
const approveHash = (await eth.request({
method: "eth_sendTransaction",
params: [approveParams],
})) as string;
await waitForReceipt(String(approveHash || ""));
const approveHash = await requestWalletWithTimeout<string>(
eth,
{
method: "eth_sendTransaction",
params: [approveParams],
},
`发起 ${tokenSymbol} 授权`,
WALLET_TRANSACTION_REQUEST_TIMEOUT_MS,
);
await waitForReceipt(String(approveHash || ""), eth);
approvedInThisRun = true;
setPaymentInfo(`${tokenSymbol} 授权成功,正在发起支付...`);
} else {
@@ -2388,10 +2450,15 @@ export function AccountCenter() {
payParams.value = txPayload.value;
}
const txHash = (await eth.request({
method: "eth_sendTransaction",
params: [payParams],
})) as string;
const txHash = await requestWalletWithTimeout<string>(
eth,
{
method: "eth_sendTransaction",
params: [payParams],
},
"发起支付交易",
WALLET_TRANSACTION_REQUEST_TIMEOUT_MS,
);
const txHashNorm = String(txHash || "").toLowerCase();
setLastTxHash(txHashNorm);
setLastPaymentStartedAt(Date.now());
-1
View File
@@ -27,7 +27,6 @@ AMSC_AWOS_AIRPORTS: Dict[str, Dict[str, str]] = {
"shanghai": {"icao": "ZSPD", "label": "Shanghai Pudong"},
"beijing": {"icao": "ZBAA", "label": "Beijing Capital"},
"guangzhou": {"icao": "ZGGG", "label": "Guangzhou Baiyun"},
"shenzhen": {"icao": "ZGSZ", "label": "Shenzhen Bao'an"},
"chengdu": {"icao": "ZUUU", "label": "Chengdu Shuangliu"},
"chongqing": {"icao": "ZUCK", "label": "Chongqing Jiangbei"},
"wuhan": {"icao": "ZHHH", "label": "Wuhan Tianhe"},
+1 -2
View File
@@ -560,7 +560,7 @@ SETTLEMENT_RUNWAY_PAIRS: Dict[str, Set[Tuple[str, str]]] = {
# All cities with active runway observation data (AMSC AWOS / AMOS).
RUNWAY_OBSERVATION_CITIES = {
"shanghai", "beijing", "guangzhou", "shenzhen",
"shanghai", "beijing", "guangzhou",
"chengdu", "chongqing", "wuhan", "qingdao",
"seoul", "busan",
}
@@ -574,7 +574,6 @@ WIND_REGIME: Dict[str, Dict[str, Tuple[int, int]]] = {
"qingdao": {"sea_breeze": (90, 180), "warm_advection": (200, 300)},
"beijing": {"sea_breeze": (120, 200), "warm_advection": (220, 320)},
"guangzhou": {"sea_breeze": (120, 200), "warm_advection": (200, 300)},
"shenzhen": {"sea_breeze": (120, 200), "warm_advection": (200, 300)},
"chengdu": {"sea_breeze": (0, 0), "warm_advection": (0, 0)},
"chongqing": {"sea_breeze": (0, 0), "warm_advection": (0, 0)},
"wuhan": {"sea_breeze": (0, 0), "warm_advection": (0, 0)},