-
Notifications
You must be signed in to change notification settings - Fork 0
Trade Bridge ZH
Trade Bridge 让浏览器扩展完成所有与交易站相关的工作(实时搜索、抓取、whisper),而 POEFixer 只负责游戏内购买。这样所有交易站流量都留在你真实的浏览器会话中——无需复制 cookie,也省去 cf_clearance 的麻烦——并且这是未来「在另一台 PC 上运行 POEFixer」模式的基础。
你可以使用免费的官方扩展,也可以按下面记录的协议编写自己的扩展。
Trade Bridge 要求你的 POEFixer 许可证拥有 Trade 功能。如果服务器上将 Trade 配置为付费,你需要一个有效的密钥;如果是免费的,则任何人都可以使用。没有相应权限时,桥接会回复
entitlement_required并拒绝购买。
Browser extension POEFixer
live-search WebSocket ─┐
fetch item details │ ws://127.0.0.1:PORT in-game buying:
whisper (teleport) ├─────────────────────► wait teleport → click → verify
(Force teleport, │ buy_request → auto-stash → /hideout
In-demand retry, │ ◄───────────────────── → report result
Rate limiting) ─┘ buy_result
- 扩展掌管一切与交易站打交道的部分。
- POEFixer 掌管游戏客户端内的一切,并暴露一个本地 WebSocket 服务器(即 Trade Bridge),供扩展连接。
- 在此模式下,POEFixer 内置的
tls-client不会被使用,交易站相关控件(Connections、Trade Cookies、Force teleport、In-demand、Rate limiting)都转移到扩展中,并在 POEFixer 里隐藏/禁用。
该扩展随 POEFixer 一起分发。在你的 POEFixer 文件夹中打开 Resources\extension\:
<POEFixer folder>\Resources\extension\
├─ poefixer-extension-chrome.zip ← Chrome / Edge
├─ poefixer-extension-firefox.zip ← Firefox
└─ chrome\ ← unpacked copy used by the "Assisted install" button
完全静默的一键安装是不可能的——浏览器在设计上就会阻止以编程方式安装扩展。你需要为自己的浏览器解压文件,并加载一次。POEFixer 的 Assisted install… 按钮(Configuration → Trade)会替你完成 Chrome/Edge 那部分:它把解压后的
chrome\文件夹路径复制到剪贴板并打开本指南,这样你就可以跳过解压步骤。
- 将
Resources\extension\poefixer-extension-chrome.zip解压到任意文件夹(使manifest.json位于其顶层)。或者在 POEFixer 中点击 Assisted install… 并使用复制到的路径——然后跳到第 4 步。 - 打开
chrome://extensions(Edge:edge://extensions)。 - 启用开发者模式(右上角)。
- 点击加载已解压的扩展程序并选择该文件夹(或粘贴 Assisted-install 路径)。
- 扩展图标出现在工具栏;它会在重启后保持加载。
POEFixer 更新后,随附的扩展也会刷新——打开
chrome://extensions并在扩展卡片上点击重新加载以采用新版本(或重新解压并加载已解压的扩展程序)。
正式版 Firefox 只安装由 Mozilla 签名的扩展,因此请使用临时加载:
- 将
Resources\extension\poefixer-extension-firefox.zip解压到任意文件夹。 - 打开
about:debugging#/runtime/this-firefox。 - 点击 Load Temporary Add-on… 并选择已解压文件夹中的
manifest.json。 - 它会保持加载,直到你重启 Firefox(重启后需重复操作)。
-
持久安装: 在 Firefox 中打开一个由 Mozilla/AMO 签名的
.xpi并确认权限提示即可安装。
- 在 POEFixer 中:Configuration → Trade → Trade data source → Browser extension,记下端口(默认
47362),然后点击 Start bridge。 - 在扩展弹窗中,设置相同的端口——它应显示 Host: connected,POEFixer 中的状态会变绿色并显示扩展的名称和真实版本,例如 "Extension connected (PoeFixerExt/1.1.2)"(版本取自扩展的 manifest——过时的扩展会在此处被标记)。
- 在该浏览器中登录交易站,然后添加你的 Trade Links 并按 Play(见 §3)。
一切都由 POEFixer 控制——扩展弹窗只设置连接端口。
- 在 POEFixer 中:Configuration → Trade → Data source = Browser extension,设置端口,点击 Start bridge。
- 在扩展弹窗中,确认 Host: connected 以及相同的端口。
- 在同一浏览器中登录交易站。
- 在 POEFixer 的 Trade Links(Connections 标签页)中添加你的 trade2 搜索 URL 并按 Play——搜索会被推送到扩展并在那里运行;Stop 会移除它。
- 在 POEFixer 中设置行为(Configuration → Trade):Force teleport、Item is in demand → teleport anyway、Rate limiting——POEFixer 将这些推送到扩展,扩展只需遵从。
- 当某个挂单匹配时,扩展发送 whisper,POEFixer 在游戏内购买。扩展的所有活动都会出现在 POEFixer 的 Logs 中(类别 Trade)。
可靠的实时数据流(自动): 对每个活动搜索,扩展会打开一个固定的后台标签页指向交易页面,并在该页面内部连接实时 WebSocket(正确的 Origin + 你的会话 cookie——与站点本身的做法完全一样)。只需保持在交易站的登录状态即可;你无需手动打开 Live Search。在实时 WS 建立之前,Trade Link 显示 Connecting…,之后显示 Live。关闭该固定标签页会停止搜索。
Manual Buy(立即批量买下一个搜索): 与其等待实时挂单,不如在任意 Trade Link 上按购物车图标立即批量购买。扩展会抓取该搜索中最便宜的匹配挂单(不超过你设定的物品数量,并遵循该链接的货币过滤器),按卖家分组,并逐个通过 POEFixer 进行 whisper + 购买——应用相同的消费限额和自动暂存(auto-stash),最后只回一次藏身处。Manual Buy 与实时搜索(Play)互斥:在开始 Manual Buy 之前停止你的实时搜索,反之亦然。购物车按钮仅在扩展已连接时启用。
该协议是基于 WebSocket 的纯 JSON。任何人都可以实现。POEFixer 托管服务器;你的客户端连接到 ws://127.0.0.1:<port>(默认 47362,可在 Settings 中配置)。
仅当你的许可证拥有 Trade entitlement 时,host 才会执行购买。否则你会收到
{"type":"error","code":"entitlement_required"}。(认证细节有意不予记录。)
先发送 hello;host 回复 welcome。
-
version是扩展 manifest 的版本(semver 字符串,例如"1.1.0")。如果你的扩展比 POEFixer 期望的版本旧,它会检测到不匹配,抑制实时搜索,并禁用购买,直到你重新安装最新扩展。POEFixer 会在 Settings → Trade 中显示警告。在过时状态下尝试购买会收到{"type":"error","code":"outdated_extension"}。 -
allowed:false→ 没有权限(视为「购买一个密钥」);host 会以entitlement_required拒绝购买。 -
token仅在用户于 POEFixer 中启用了配对令牌时才需要(默认关闭)。
在 welcome 之后(以及每当用户在 POEFixer 中更改任何内容时),host 会推送一条 config 消息。程序是唯一的控制面,因此你的扩展必须精确监控这些搜索并遵从此行为:
// host → client
{ "type":"config",
"behavior":{ "forceTeleport":false, "inDemandRetry":true, "rateLimit":true },
"searches":[ { "realm":"poe2", "league":"Standard", "searchId":"…", "note":"…" } ] }host 会定期推送 status:
{ "type":"status", "ready":true, "inGame":true, "attached":true, "busy":false }你必须仅在最近一次 status.ready === true 时才 whisper/teleport。 ready = entitled && attached && in-game && !busy。在未就绪时 whisper 会让角色传送过去,却没有买家来驱动交易。
在你的 whisper 成功后(角色正在传送),发送 buy_request:
// client → host
{ "type":"buy_request", "id":"r-42", "seq":7,
"group":{
"searchId":"…", "groupId":"g-9", "isLastGroup":true,
"items":[ {
"itemId":"...", "stashX":3, "stashY":1, "w":1, "h":1,
"currency":"chaos", "amount":50,
"seller":"AccountName", "stashName":"~price 50 chaos",
"name":"...", "typeLine":"...", "baseType":"...", "rarity":"Rare",
"iconUrl":"https://...", "ilvl":82, "corrupted":false, "identified":true,
"explicitMods":[ "..." ], "implicitMods":[ "..." ],
"league":"Standard", "realm":"poe2",
"hideoutToken":"...", "indexedTime":"..."
} ] } }host 会确认它,可选地发出进度,然后给出单条结果:
{ "type":"ack", "ackSeq":7 }
{ "type":"buy_progress", "id":"r-42", "phase":"teleporting" }
{ "type":"buy_result", "id":"r-42", "seq":11,
"items":[ { "itemId":"...", "ok":true, "reason":"verified" } ],
"summary":{ "bought":1, "failed":0 } }-
group.searchId是该挂单来源的搜索;host 用它把购买绑定到正确的 Trade Link(若省略则回退到第一个活动搜索)。为正确处理多搜索场景请发送它。 -
stashX/stashY是物品在卖家商店中的坐标;w/h是其尺寸——它们驱动游戏内的点击。 - 价格可以扁平发送(
currency/amount,如上所示),也可以嵌套发送("price":{"currency","amount"})——host 两者都接受。 -
hideoutToken仅用于日志记录而携带(你已经用它来 whisper 了)。 - 你**必须确认(ack)**每条
buy_result:发送{"type":"ack","ackSeq":<buy_result.seq>}。
whisper 阶段的结果(保持 POEFixer 日志完整):
{ "type":"trade_event", "seq":8, "stage":"whisper", "outcome":"in_demand", "itemId":"...", "detail":"" }
// outcome ∈ in_demand | whisper_failed | teleport_failed | fetch_error
trade_event也可以携带完整的item对象(与buy_request物品的字段相同)。teleport_failed= 即使在强制重新 whisper 之后,卖家的挂单仍处于 in demand;连同其item一起发送,POEFixer 会将其记录到 Trade Logs 中作为 Teleport Fail。fetch_error/whisper_failed/in_demand是信息性的,进入常规 Logs(类别 Trade)。
将你的活动转发到 POEFixer 的日志(推荐——扩展的所有日志都应在程序中显现):
{ "type":"log", "level":"info", "message":"…" } // shown in POEFixer Logs (category Trade)报告每个搜索的实时 WS 状态,以便 POEFixer 的 Trade Link 显示 Connecting…/Live:
{ "type":"search_status", "searchId":"…", "state":"connected" } // state ∈ connected | closed | error当用户在某个 Trade Link 上点击 Manual Buy(购物车图标)时,host 发送 manual_buy;你的扩展对该搜索执行一次性批量购买,并通过 manual_buy_status 报告生命周期/进度。每个卖家的购买使用普通的 buy_request 流程(§4.3),并设 isLastGroup:false;当 host 收到 state:"done" 后会触发最终的 /hideout。
// host → client: start a one-shot bulk buy of one saved search
{ "type":"manual_buy", "id":"mb-…", "seq":12,
"search":{ "realm":"poe2", "league":"Standard", "searchId":"…", "note":"…" },
"itemCount":10, // 0 = all results
"filters":{ "chaos":{ "min":0, "max":0 } } } // currency → {min,max}; 0 = unbounded
// host → client: cancel an in-progress bulk buy
{ "type":"manual_buy_cancel", "id":"mb-…", "seq":13 }
// client → host: lifecycle + progress (ack-tracked like trade_event)
{ "type":"manual_buy_status", "id":"mb-…", "seq":4,
"state":"started|progress|done|cancelled|error",
"processed":3, "bought":2, "failed":1, "total":10, "detail":"" }- 解析该搜索,抓取最便宜的匹配挂单,应用
filters,按itemCount限制(0 = 全部),按卖家分组,并通过buy_request(isLastGroup:false)购买每一组。 - 在开头发送
manual_buy_status的started,随着各组完成发送progress,并恰好发送一条终止的done/cancelled/error。
-
buy_request和trade_event携带递增的seq;host 会确认它们。保留未确认的帧,并在重连时重新发送(按seq排序)。 -
buy_request.id是幂等键——重新发送的 id 会返回已记录的buy_result(若仍在处理中则返回error: duplicate)。每次购买使用稳定且唯一的 id。 -
buy_result携带一个由你确认的seq。
{ "type":"error", "code":"entitlement_required|not_in_game|busy|duplicate|bad_request|unauthorized|proto_unsupported|outdated_extension", "id":"r-42", "detail":"..." }const ws = new WebSocket("ws://127.0.0.1:47362");
let ready = false, seq = 0, behavior = {}, searches = [];
const log = (message) => ws.send(JSON.stringify({ type:"log", level:"info", message }));
ws.onopen = () => ws.send(JSON.stringify({ type:"hello", proto:1, client:"MyExt/1.0", version:"1.1.0" }));
ws.onmessage = (e) => {
const m = JSON.parse(e.data);
if (m.type === "welcome" && !m.allowed) console.warn("Trade entitlement required");
if (m.type === "config") { behavior = m.behavior; searches = m.searches; } // program controls you
if (m.type === "status") ready = m.ready;
if (m.type === "buy_result") ws.send(JSON.stringify({ type:"ack", ackSeq:m.seq }));
};
// monitor `searches`, obey `behavior`; after YOUR whisper succeeds and ready === true:
function buy(items) {
ws.send(JSON.stringify({ type:"buy_request", id:"r-"+Date.now(), seq:++seq,
group:{ groupId:"g", isLastGroup:true, items } }));
}- Host: disconnected — POEFixer 未运行、桥接未启动,或端口错误。在 Settings → Trade 中启动桥接;让弹窗中的端口与之匹配。
-
entitlement_required— 你的许可证缺少 Trade 功能(服务器上为付费)。 -
not_in_game— POEFixer 未附加/不在游戏中;等待status.ready。 - 实时搜索从不触发 — 确保你在同一浏览器中登录了交易站。扩展会为每个搜索自动打开它自己的固定后台标签页,并在该页面内运行实时 WebSocket;Trade Link 显示 Connecting… 然后 Live。如果它一直停在 Connecting…,请打开该固定标签页确认你已登录。
- 端口被占用 — 在 Settings → Trade 和弹窗中更改端口,然后重启桥接。