移除深圳宝安机场跑道数据采集,深圳市场结算使用流浮山 HKO 数据
This commit is contained in:
@@ -241,6 +241,8 @@ const TELEGRAM_TOPICS_GROUP_URL = TELEGRAM_GROUP_URL;
|
|||||||
const SUBSCRIPTION_HELP_HREF = "/subscription-help";
|
const SUBSCRIPTION_HELP_HREF = "/subscription-help";
|
||||||
const PAYMENT_RECOVERY_STORAGE_KEY = "polyweather:lastPaymentRecovery";
|
const PAYMENT_RECOVERY_STORAGE_KEY = "polyweather:lastPaymentRecovery";
|
||||||
const PAYMENT_RECOVERY_TTL_MS = 6 * 60 * 60 * 1000;
|
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 walletConnectProviderCache: EvmProvider | null = null;
|
||||||
let walletConnectProviderChainId: number | null = null;
|
let walletConnectProviderChainId: number | null = null;
|
||||||
@@ -574,6 +576,31 @@ function buildBalanceOfCalldata(owner: string) {
|
|||||||
return `0x70a08231${toPaddedAddress(owner)}`;
|
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) {
|
function formatTokenUnits(amount: bigint, decimals: number) {
|
||||||
const safeDecimals =
|
const safeDecimals =
|
||||||
Number.isFinite(decimals) && decimals >= 0 ? Math.floor(decimals) : 6;
|
Number.isFinite(decimals) && decimals >= 0 ? Math.floor(decimals) : 6;
|
||||||
@@ -1835,17 +1862,23 @@ export function AccountCenter() {
|
|||||||
|
|
||||||
const waitForReceipt = async (
|
const waitForReceipt = async (
|
||||||
txHash: string,
|
txHash: string,
|
||||||
|
provider?: EvmProvider,
|
||||||
timeoutMs = 120000,
|
timeoutMs = 120000,
|
||||||
pollMs = 3000,
|
pollMs = 3000,
|
||||||
) => {
|
) => {
|
||||||
const eth = getEvmProvider();
|
const eth = provider || getEvmProvider();
|
||||||
if (!eth) throw new Error("No EVM wallet provider found");
|
if (!eth) throw new Error("No EVM wallet provider found");
|
||||||
const started = Date.now();
|
const started = Date.now();
|
||||||
while (Date.now() - started < timeoutMs) {
|
while (Date.now() - started < timeoutMs) {
|
||||||
const receipt = (await eth.request({
|
const receipt = await requestWalletWithTimeout<{ status?: string } | null>(
|
||||||
method: "eth_getTransactionReceipt",
|
eth,
|
||||||
params: [txHash],
|
{
|
||||||
})) as { status?: string } | null;
|
method: "eth_getTransactionReceipt",
|
||||||
|
params: [txHash],
|
||||||
|
},
|
||||||
|
"查询授权交易确认",
|
||||||
|
15_000,
|
||||||
|
);
|
||||||
if (receipt && receipt.status) {
|
if (receipt && receipt.status) {
|
||||||
if (receipt.status === "0x1") return receipt;
|
if (receipt.status === "0x1") return receipt;
|
||||||
throw new Error(`transaction reverted: ${txHash}`);
|
throw new Error(`transaction reverted: ${txHash}`);
|
||||||
@@ -1938,16 +1971,24 @@ export function AccountCenter() {
|
|||||||
targetChainId: number,
|
targetChainId: number,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const currentChainIdHex = String(
|
const currentChainIdHex = String(
|
||||||
(await eth.request({ method: "eth_chainId" })) || "",
|
(await requestWalletWithTimeout<string>(
|
||||||
|
eth,
|
||||||
|
{ method: "eth_chainId" },
|
||||||
|
"读取钱包网络",
|
||||||
|
)) || "",
|
||||||
);
|
);
|
||||||
const targetChainHex = `0x${targetChainId.toString(16)}`;
|
const targetChainHex = `0x${targetChainId.toString(16)}`;
|
||||||
if (currentChainIdHex.toLowerCase() === targetChainHex.toLowerCase())
|
if (currentChainIdHex.toLowerCase() === targetChainHex.toLowerCase())
|
||||||
return;
|
return;
|
||||||
try {
|
try {
|
||||||
await eth.request({
|
await requestWalletWithTimeout(
|
||||||
method: "wallet_switchEthereumChain",
|
eth,
|
||||||
params: [{ chainId: targetChainHex }],
|
{
|
||||||
});
|
method: "wallet_switchEthereumChain",
|
||||||
|
params: [{ chainId: targetChainHex }],
|
||||||
|
},
|
||||||
|
"切换钱包网络",
|
||||||
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const code = Number(err?.code);
|
const code = Number(err?.code);
|
||||||
const msg = String(err?.message || "").toLowerCase();
|
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 the error code indicates the chain is not added (4902), or it's Polygon (137)
|
||||||
if (code === 4902 || targetChainId === 137) {
|
if (code === 4902 || targetChainId === 137) {
|
||||||
try {
|
try {
|
||||||
await eth.request({
|
await requestWalletWithTimeout(
|
||||||
method: "wallet_addEthereumChain",
|
eth,
|
||||||
params: [
|
{
|
||||||
|
method: "wallet_addEthereumChain",
|
||||||
|
params: [
|
||||||
{
|
{
|
||||||
chainId: "0x89",
|
chainId: "0x89",
|
||||||
chainName: "Polygon Mainnet",
|
chainName: "Polygon Mainnet",
|
||||||
@@ -1965,8 +2008,10 @@ export function AccountCenter() {
|
|||||||
rpcUrls: ["https://polygon-rpc.com"],
|
rpcUrls: ["https://polygon-rpc.com"],
|
||||||
blockExplorerUrls: ["https://polygonscan.com"],
|
blockExplorerUrls: ["https://polygonscan.com"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
},
|
||||||
|
"添加 Polygon 网络",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
} catch (addErr: any) {
|
} catch (addErr: any) {
|
||||||
err = addErr;
|
err = addErr;
|
||||||
@@ -2010,9 +2055,11 @@ export function AccountCenter() {
|
|||||||
Authorization: `Bearer ${accessToken}`,
|
Authorization: `Bearer ${accessToken}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const accounts = (await eth.request({
|
const accounts = await requestWalletWithTimeout<string[]>(
|
||||||
method: "eth_requestAccounts",
|
eth,
|
||||||
})) as string[];
|
{ method: "eth_requestAccounts" },
|
||||||
|
"连接绑定钱包",
|
||||||
|
);
|
||||||
const address = String(accounts?.[0] || "").toLowerCase();
|
const address = String(accounts?.[0] || "").toLowerCase();
|
||||||
if (!address)
|
if (!address)
|
||||||
throw new Error(isEn ? "Wallet account is empty." : "钱包账户为空");
|
throw new Error(isEn ? "Wallet account is empty." : "钱包账户为空");
|
||||||
@@ -2209,9 +2256,11 @@ export function AccountCenter() {
|
|||||||
selectedInjectedProviderKey,
|
selectedInjectedProviderKey,
|
||||||
);
|
);
|
||||||
const eth = providerSelection.provider;
|
const eth = providerSelection.provider;
|
||||||
const activeAccounts = (await eth.request({
|
const activeAccounts = await requestWalletWithTimeout<string[]>(
|
||||||
method: "eth_requestAccounts",
|
eth,
|
||||||
})) as string[];
|
{ method: "eth_requestAccounts" },
|
||||||
|
"连接付款钱包",
|
||||||
|
);
|
||||||
const activeAddress = String(activeAccounts?.[0] || "").toLowerCase();
|
const activeAddress = String(activeAccounts?.[0] || "").toLowerCase();
|
||||||
if (!activeAddress)
|
if (!activeAddress)
|
||||||
throw new Error(isEn ? "Wallet account is empty." : "钱包账户为空");
|
throw new Error(isEn ? "Wallet account is empty." : "钱包账户为空");
|
||||||
@@ -2330,16 +2379,20 @@ export function AccountCenter() {
|
|||||||
6,
|
6,
|
||||||
);
|
);
|
||||||
|
|
||||||
const balanceHex = (await eth.request({
|
const balanceHex = await requestWalletWithTimeout<string>(
|
||||||
method: "eth_call",
|
eth,
|
||||||
params: [
|
{
|
||||||
|
method: "eth_call",
|
||||||
|
params: [
|
||||||
{
|
{
|
||||||
to: tokenAddress,
|
to: tokenAddress,
|
||||||
data: buildBalanceOfCalldata(payingWallet),
|
data: buildBalanceOfCalldata(payingWallet),
|
||||||
},
|
},
|
||||||
"latest",
|
"latest",
|
||||||
],
|
],
|
||||||
})) as string;
|
},
|
||||||
|
`读取 ${tokenSymbol} 余额`,
|
||||||
|
);
|
||||||
const tokenBalance = BigInt(String(balanceHex || "0x0"));
|
const tokenBalance = BigInt(String(balanceHex || "0x0"));
|
||||||
if (tokenBalance < amountUnits) {
|
if (tokenBalance < amountUnits) {
|
||||||
const need = formatTokenUnits(amountUnits, tokenDecimals);
|
const need = formatTokenUnits(amountUnits, tokenDecimals);
|
||||||
@@ -2349,16 +2402,20 @@ export function AccountCenter() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const allowanceHex = (await eth.request({
|
const allowanceHex = await requestWalletWithTimeout<string>(
|
||||||
method: "eth_call",
|
eth,
|
||||||
params: [
|
{
|
||||||
|
method: "eth_call",
|
||||||
|
params: [
|
||||||
{
|
{
|
||||||
to: tokenAddress,
|
to: tokenAddress,
|
||||||
data: buildAllowanceCalldata(payingWallet, txPayload.to),
|
data: buildAllowanceCalldata(payingWallet, txPayload.to),
|
||||||
},
|
},
|
||||||
"latest",
|
"latest",
|
||||||
],
|
],
|
||||||
})) as string;
|
},
|
||||||
|
`读取 ${tokenSymbol} 授权额度`,
|
||||||
|
);
|
||||||
const allowance = BigInt(String(allowanceHex || "0x0"));
|
const allowance = BigInt(String(allowanceHex || "0x0"));
|
||||||
|
|
||||||
if (allowance < amountUnits) {
|
if (allowance < amountUnits) {
|
||||||
@@ -2368,11 +2425,16 @@ export function AccountCenter() {
|
|||||||
to: tokenAddress,
|
to: tokenAddress,
|
||||||
data: buildApproveCalldata(txPayload.to, amountUnits),
|
data: buildApproveCalldata(txPayload.to, amountUnits),
|
||||||
};
|
};
|
||||||
const approveHash = (await eth.request({
|
const approveHash = await requestWalletWithTimeout<string>(
|
||||||
method: "eth_sendTransaction",
|
eth,
|
||||||
params: [approveParams],
|
{
|
||||||
})) as string;
|
method: "eth_sendTransaction",
|
||||||
await waitForReceipt(String(approveHash || ""));
|
params: [approveParams],
|
||||||
|
},
|
||||||
|
`发起 ${tokenSymbol} 授权`,
|
||||||
|
WALLET_TRANSACTION_REQUEST_TIMEOUT_MS,
|
||||||
|
);
|
||||||
|
await waitForReceipt(String(approveHash || ""), eth);
|
||||||
approvedInThisRun = true;
|
approvedInThisRun = true;
|
||||||
setPaymentInfo(`${tokenSymbol} 授权成功,正在发起支付...`);
|
setPaymentInfo(`${tokenSymbol} 授权成功,正在发起支付...`);
|
||||||
} else {
|
} else {
|
||||||
@@ -2388,10 +2450,15 @@ export function AccountCenter() {
|
|||||||
payParams.value = txPayload.value;
|
payParams.value = txPayload.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const txHash = (await eth.request({
|
const txHash = await requestWalletWithTimeout<string>(
|
||||||
method: "eth_sendTransaction",
|
eth,
|
||||||
params: [payParams],
|
{
|
||||||
})) as string;
|
method: "eth_sendTransaction",
|
||||||
|
params: [payParams],
|
||||||
|
},
|
||||||
|
"发起支付交易",
|
||||||
|
WALLET_TRANSACTION_REQUEST_TIMEOUT_MS,
|
||||||
|
);
|
||||||
const txHashNorm = String(txHash || "").toLowerCase();
|
const txHashNorm = String(txHash || "").toLowerCase();
|
||||||
setLastTxHash(txHashNorm);
|
setLastTxHash(txHashNorm);
|
||||||
setLastPaymentStartedAt(Date.now());
|
setLastPaymentStartedAt(Date.now());
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ AMSC_AWOS_AIRPORTS: Dict[str, Dict[str, str]] = {
|
|||||||
"shanghai": {"icao": "ZSPD", "label": "Shanghai Pudong"},
|
"shanghai": {"icao": "ZSPD", "label": "Shanghai Pudong"},
|
||||||
"beijing": {"icao": "ZBAA", "label": "Beijing Capital"},
|
"beijing": {"icao": "ZBAA", "label": "Beijing Capital"},
|
||||||
"guangzhou": {"icao": "ZGGG", "label": "Guangzhou Baiyun"},
|
"guangzhou": {"icao": "ZGGG", "label": "Guangzhou Baiyun"},
|
||||||
"shenzhen": {"icao": "ZGSZ", "label": "Shenzhen Bao'an"},
|
|
||||||
"chengdu": {"icao": "ZUUU", "label": "Chengdu Shuangliu"},
|
"chengdu": {"icao": "ZUUU", "label": "Chengdu Shuangliu"},
|
||||||
"chongqing": {"icao": "ZUCK", "label": "Chongqing Jiangbei"},
|
"chongqing": {"icao": "ZUCK", "label": "Chongqing Jiangbei"},
|
||||||
"wuhan": {"icao": "ZHHH", "label": "Wuhan Tianhe"},
|
"wuhan": {"icao": "ZHHH", "label": "Wuhan Tianhe"},
|
||||||
|
|||||||
@@ -560,7 +560,7 @@ SETTLEMENT_RUNWAY_PAIRS: Dict[str, Set[Tuple[str, str]]] = {
|
|||||||
|
|
||||||
# All cities with active runway observation data (AMSC AWOS / AMOS).
|
# All cities with active runway observation data (AMSC AWOS / AMOS).
|
||||||
RUNWAY_OBSERVATION_CITIES = {
|
RUNWAY_OBSERVATION_CITIES = {
|
||||||
"shanghai", "beijing", "guangzhou", "shenzhen",
|
"shanghai", "beijing", "guangzhou",
|
||||||
"chengdu", "chongqing", "wuhan", "qingdao",
|
"chengdu", "chongqing", "wuhan", "qingdao",
|
||||||
"seoul", "busan",
|
"seoul", "busan",
|
||||||
}
|
}
|
||||||
@@ -574,7 +574,6 @@ WIND_REGIME: Dict[str, Dict[str, Tuple[int, int]]] = {
|
|||||||
"qingdao": {"sea_breeze": (90, 180), "warm_advection": (200, 300)},
|
"qingdao": {"sea_breeze": (90, 180), "warm_advection": (200, 300)},
|
||||||
"beijing": {"sea_breeze": (120, 200), "warm_advection": (220, 320)},
|
"beijing": {"sea_breeze": (120, 200), "warm_advection": (220, 320)},
|
||||||
"guangzhou": {"sea_breeze": (120, 200), "warm_advection": (200, 300)},
|
"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)},
|
"chengdu": {"sea_breeze": (0, 0), "warm_advection": (0, 0)},
|
||||||
"chongqing": {"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)},
|
"wuhan": {"sea_breeze": (0, 0), "warm_advection": (0, 0)},
|
||||||
|
|||||||
Reference in New Issue
Block a user