wangjia 4a76134ca9 feat(server/pay): 查单对账开通(reconcile-on-read)——付完不再干等 webhook
「付完刷新等十几秒」的服务端主因:GetOrder 的 activated 只认本地 row=paid,而 row
只有 webhook 到账才翻;webhook 投递+退避重投正是那十几秒。GetOrder 其实早已调 pay
网关查单(st),却只当 pay_status 展示、没用来开通。

改法(仅 pangolin,pay 无需改):GetOrder 拿到网关 st 后,若 st.Status=="paid" 但本地
row 未 paid → 用 st 拼 webhookEvent 就地调 settle(复用 webhook 同一段幂等开通逻辑),
把「等 webhook」压成「付完下一拍查单即开通」。webhook 保留作兜底。

- Handler 加可选 settler(orderSettler 接口,*WebhookHandler 已满足)+ SetSettler;
  main.go 装配时 payHandler.SetSettler(payWebhook)。
- 幂等双保险:row.Status!="paid" 守卫 + settle 内锁行/已 paid 短路 → 重复轮询/并发查
  不二次开通、不二次发奖。settle 失败仅记日志,退回旧展示由下一拍或 webhook 兜。
- channel 查单不返回 → 回退 row.Method(仅影响渠道显示)。成功状态词 "paid" 已对齐
  pay 仓 model.OrderStatusV2,提为 payOrderPaid 常量并注释「改前对齐 pay 契约」。
- 信任模型一致:主动调 pay 自有接口(server→server,order_no 持有凭据),与现有把
  st.Status 当 pay_status 透传同源,非接收外部推送,不需 webhook 那样验签。

测试:新增端到端 sqlite——网关 paid→就地开通(activated + 台账翻 paid + 真授予订阅)
且重复轮询幂等(仍 1 条订阅);网关 pending→不开通。go test ./... 全绿、vet 干净。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
2026-09-06 09:37:54 +08:00

Pangolin

面向中国大陆用户的终端 VPN(科学上网)项目。

Phase 0 现状

数据面两条线,容器化、经 Gitea Actions 自动部署到节点,与现网服务隔离:

  • Xray VLESS + REALITY(主线,经宿主 nginx SNI 分流)
  • sing-box Hysteria2(晚高峰加速线,UDP 443)

部署细节见 deploy/README.md

S
Description
vpn
Readme 56 MiB
client 1.2.7 Latest
2026-09-08 04:38:03 +00:00
Languages
Go 36%
Dart 21.2%
JavaScript 13%
HTML 12.8%
Shell 4.6%
Other 12.2%