Files
bxh/scripts/amap_js_api_probe.mjs

148 lines
4.8 KiB
JavaScript

import http from "node:http";
import { spawn } from "node:child_process";
import { readFileSync } from "node:fs";
import path from "node:path";
function readEnvKey(path, key) {
const txt = readFileSync(path, "utf8");
for (const line of txt.split(/\r?\n/)) {
if (line.trim().startsWith(`${key}=`)) return line.split("=").slice(1).join("=").trim();
}
return "";
}
function httpJson(url) {
return new Promise((resolve, reject) => {
http.get(url, (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(e);
}
});
}).on("error", reject);
});
}
class Cdp {
constructor(wsUrl) {
this.ws = new WebSocket(wsUrl);
this.seq = 1;
this.pending = new Map();
this.ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.id && this.pending.has(msg.id)) {
const { resolve, reject } = this.pending.get(msg.id);
this.pending.delete(msg.id);
if (msg.error) reject(new Error(JSON.stringify(msg.error)));
else resolve(msg.result);
}
};
}
async open() {
await new Promise((resolve, reject) => {
this.ws.onopen = resolve;
this.ws.onerror = reject;
});
}
call(method, params = {}) {
const id = this.seq++;
this.ws.send(JSON.stringify({ id, method, params }));
return new Promise((resolve, reject) => this.pending.set(id, { resolve, reject }));
}
close() {
this.ws.close();
}
}
async function wait(ms) {
await new Promise((resolve) => setTimeout(resolve, ms));
}
async function main() {
const root = path.resolve(new URL("..", import.meta.url).pathname, "..");
const envPath = process.env.TRAVEL_KG_ENV_PATH || path.join(root, ".env");
const key = readEnvKey(envPath, "AMAP_JS_KEY");
const security = readEnvKey(envPath, "AMAP_SECURITY_JSCODE");
if (!key || !security) throw new Error("missing AMap JS key/security");
const chrome = spawn(
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
[
"--headless=new",
"--disable-gpu",
"--no-first-run",
"--no-default-browser-check",
"--remote-debugging-port=9229",
"--user-data-dir=/tmp/znkg-amap-cdp-profile",
"http://localhost:8102/admin/plaza/graph",
],
{ stdio: "ignore" },
);
try {
let pages = null;
for (let i = 0; i < 30; i += 1) {
try {
pages = await httpJson("http://127.0.0.1:9229/json");
if (pages?.[0]?.webSocketDebuggerUrl) break;
} catch {}
await wait(300);
}
if (!pages?.[0]?.webSocketDebuggerUrl) throw new Error("Chrome CDP not ready");
const cdp = new Cdp(pages[0].webSocketDebuggerUrl);
await cdp.open();
await cdp.call("Runtime.enable");
await wait(800);
const expr = `
(async () => {
window._AMapSecurityConfig = { securityJsCode: ${JSON.stringify(security)} };
await new Promise((resolve, reject) => {
if (window.AMap) return resolve();
const s = document.createElement('script');
s.src = 'https://webapi.amap.com/maps?v=2.0&key=${encodeURIComponent(key)}&plugin=AMap.PlaceSearch,AMap.Driving';
s.onload = resolve;
s.onerror = () => reject(new Error('amap script load failed'));
document.head.appendChild(s);
});
const place = await new Promise((resolve, reject) => {
const ps = new AMap.PlaceSearch({ city: '安顺市', pageSize: 3, extensions: 'all' });
ps.search('黄果树风景名胜区', (status, result) => {
if (status === 'complete') resolve(result.poiList?.pois || []);
else reject(new Error(status + ':' + JSON.stringify(result)));
});
});
const first = place[0] || {};
const driving = await new Promise((resolve, reject) => {
const d = new AMap.Driving();
d.search([106.630153,26.647661], [first.location.lng, first.location.lat], (status, result) => {
if (status === 'complete') resolve(result.routes?.[0] || {});
else reject(new Error(status + ':' + JSON.stringify(result)));
});
});
return {
placeCount: place.length,
firstName: first.name,
firstId: first.id,
firstLocation: first.location ? [first.location.lng, first.location.lat].join(',') : '',
firstPhotos: (first.photos || []).length,
distance: driving.distance,
time: driving.time,
};
})()
`;
const out = await cdp.call("Runtime.evaluate", { expression: expr, awaitPromise: true, returnByValue: true });
console.log(JSON.stringify(out, null, 2));
cdp.close();
} finally {
chrome.kill();
}
}
main().catch((err) => {
console.error(err);
process.exit(1);
});