Skip to content

Trade Bridge ZH

Lafko edited this page Jun 22, 2026 · 1 revision

← Home


Trade Bridge(浏览器扩展)

Trade Bridge 让浏览器扩展完成所有与交易站相关的工作(实时搜索、抓取、whisper),而 POEFixer 只负责游戏内购买。这样所有交易站流量都留在你真实的浏览器会话中——无需复制 cookie,也省去 cf_clearance 的麻烦——并且这是未来「在另一台 PC 上运行 POEFixer」模式的基础。

你可以使用免费的官方扩展,也可以按下面记录的协议编写自己的扩展。

Trade Bridge 要求你的 POEFixer 许可证拥有 Trade 功能。如果服务器上将 Trade 配置为付费,你需要一个有效的密钥;如果是免费的,则任何人都可以使用。没有相应权限时,桥接会回复 entitlement_required 并拒绝购买。


1. 工作原理

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 里隐藏/禁用。

2. 安装扩展

该扩展随 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\ 文件夹路径复制到剪贴板并打开本指南,这样你就可以跳过解压步骤。

Chrome / Edge

  1. Resources\extension\poefixer-extension-chrome.zip 解压到任意文件夹(使 manifest.json 位于其顶层)。或者在 POEFixer 中点击 Assisted install… 并使用复制到的路径——然后跳到第 4 步。
  2. 打开 chrome://extensions(Edge:edge://extensions)。
  3. 启用开发者模式(右上角)。
  4. 点击加载已解压的扩展程序并选择该文件夹(或粘贴 Assisted-install 路径)。
  5. 扩展图标出现在工具栏;它会在重启后保持加载。

POEFixer 更新后,随附的扩展也会刷新——打开 chrome://extensions 并在扩展卡片上点击重新加载以采用新版本(或重新解压并加载已解压的扩展程序)。

Firefox

正式版 Firefox 只安装由 Mozilla 签名的扩展,因此请使用临时加载:

  1. Resources\extension\poefixer-extension-firefox.zip 解压到任意文件夹。
  2. 打开 about:debugging#/runtime/this-firefox
  3. 点击 Load Temporary Add-on… 并选择已解压文件夹中的 manifest.json
  4. 它会保持加载,直到你重启 Firefox(重启后需重复操作)。
  • 持久安装: 在 Firefox 中打开一个由 Mozilla/AMO 签名的 .xpi 并确认权限提示即可安装。

然后进行连接

  1. 在 POEFixer 中:Configuration → Trade → Trade data source → Browser extension,记下端口(默认 47362),然后点击 Start bridge
  2. 在扩展弹窗中,设置相同的端口——它应显示 Host: connected,POEFixer 中的状态会变绿色并显示扩展的名称和真实版本,例如 "Extension connected (PoeFixerExt/1.1.2)"(版本取自扩展的 manifest——过时的扩展会在此处被标记)。
  3. 在该浏览器中登录交易站,然后添加你的 Trade Links 并按 Play(见 §3)。

3. 使用方法

一切都由 POEFixer 控制——扩展弹窗只设置连接端口

  1. 在 POEFixer 中:Configuration → Trade → Data source = Browser extension,设置端口,点击 Start bridge
  2. 在扩展弹窗中,确认 Host: connected 以及相同的端口
  3. 在同一浏览器中登录交易站。
  4. 在 POEFixer 的 Trade Links(Connections 标签页)中添加你的 trade2 搜索 URL 并按 Play——搜索会被推送到扩展并在那里运行;Stop 会移除它。
  5. 在 POEFixer 中设置行为(Configuration → Trade):Force teleportItem is in demand → teleport anywayRate limiting——POEFixer 将这些推送到扩展,扩展只需遵从。
  6. 当某个挂单匹配时,扩展发送 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 之前停止你的实时搜索,反之亦然。购物车按钮仅在扩展已连接时启用。


4. 编写你自己的扩展 — Trade Bridge API (PTBP)

该协议是基于 WebSocket 的纯 JSON。任何人都可以实现。POEFixer 托管服务器;你的客户端连接到 ws://127.0.0.1:<port>(默认 47362,可在 Settings 中配置)。

仅当你的许可证拥有 Trade entitlement 时,host 才会执行购买。否则你会收到 {"type":"error","code":"entitlement_required"}。(认证细节有意不予记录。)

4.1 握手

先发送 hello;host 回复 welcome

// client → host
{ "type":"hello", "proto":1, "client":"MyExtension/1.0", "version":"1.1.0", "token":"<optional>" }
// host → client
{ "type":"welcome", "proto":1, "host":"POEFixer", "allowed":true, "paid":false, "ready":false }
  • 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":"" } ] }

4.2 就绪状态 — 仅在 ready 时 whisper

host 会定期推送 status

{ "type":"status", "ready":true, "inGame":true, "attached":true, "busy":false }

你必须仅在最近一次 status.ready === true 时才 whisper/teleport。 ready = entitled && attached && in-game && !busy。在未就绪时 whisper 会让角色传送过去,却没有买家来驱动交易。

4.3 购买流程

在你的 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>}

4.4 whisper 阶段事件 + 日志(ext → host)

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 Failfetch_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

4.5 Manual buy (host-driven bulk buy)

当用户在某个 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_requestisLastGroup:false)购买每一组。
  • 在开头发送 manual_buy_statusstarted,随着各组完成发送 progress,并恰好发送一条终止的 done / cancelled / error

4.6 可靠性

  • buy_requesttrade_event 携带递增的 seq;host 会确认它们。保留未确认的帧,并在重连时重新发送(按 seq 排序)。
  • buy_request.id幂等键——重新发送的 id 会返回已记录的 buy_result(若仍在处理中则返回 error: duplicate)。每次购买使用稳定且唯一的 id。
  • buy_result 携带一个由确认的 seq

4.7 错误

{ "type":"error", "code":"entitlement_required|not_in_game|busy|duplicate|bad_request|unauthorized|proto_unsupported|outdated_extension", "id":"r-42", "detail":"..." }

4.8 最小客户端(JavaScript)

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 } }));
}

5. 故障排查

  • Host: disconnected — POEFixer 未运行、桥接未启动,或端口错误。在 Settings → Trade 中启动桥接;让弹窗中的端口与之匹配。
  • entitlement_required — 你的许可证缺少 Trade 功能(服务器上为付费)。
  • not_in_game — POEFixer 未附加/不在游戏中;等待 status.ready
  • 实时搜索从不触发 — 确保你在同一浏览器中登录了交易站。扩展会为每个搜索自动打开它自己的固定后台标签页,并在该页面内运行实时 WebSocket;Trade Link 显示 Connecting… 然后 Live。如果它一直停在 Connecting…,请打开该固定标签页确认你已登录。
  • 端口被占用 — 在 Settings → Trade 和弹窗中更改端口,然后重启桥接。

← Home

Clone this wiki locally