24 Commits
Author SHA1 Message Date
杨豪 5f8edd593c fix: normalize literal \n separators in ParseProxyLines
Build and Publish Docker Image / build-and-push (pull_request) Successful in 16m36s
Some frontends stuff multi-line subscription content into a single
string with literal backslash-n sequences. The whole blob parsed as
one URI whose fragment swallowed the remaining links (1 node with a
garbage name instead of N nodes).

Normalize literal \r\n / \n to real newlines at the ParseProxyLines
entry, after format detection and before splitting. Real newline
input and single links are unaffected.

HH-766
2026-08-28 21:23:08 +08:00
杨豪 5a34e739bb feat: HH-773 合集重命名接入 egress geo 缓存、geo 失败降级与每小时补探测
Build and Publish Docker Image / build-and-push (pull_request) Successful in 15m54s
- service: EgressCacheKey 从 handler 下沉复用;MergeCachedEgressGeo 在合集
  重命名前合并缓存 geo 字段(纯缓存读、零网络 I/O);StripEgressGeoFields
  防止 geo 字段泄漏进订阅输出
- filter: geo 检测失败的节点保留 '[别名] 原名'(或纯原名)参与编号/排序,
  不再丢弃
- handler: 每小时 StartEgressRefresher 对启用源补探测缺失/过期的 egress
  缓存(含 TTL 内 error 结果一律跳过);RegisterRoutes 返回 *Deps;
  cmd/server.go 启动定时任务并在 shutdown 时取消
- tests: service 缓存 key 稳定性/合并/管道测试、handler 补探测跳过/TTL/
  过期/取消测试、filter 降级测试;修复 2 个过时测试(mihomo YAML 配置、
  缓存命中路径)
2026-08-28 16:40:11 +08:00
rogee 9a4e60cf10 HH-683: propagate subscription fetch failures (#1)
Build and Publish Docker Image / build-and-push (push) Failing after 9m58s
2026-08-26 14:18:53 +08:00
rogee c73c2b55cd refactor: rename reads cached egress geo, fallback name-only (no DNS)
RenameCollectionNodes now reads geo info from cached egress-probe fields (country, countryCode, city, flag) on each node instead of doing per-node DNS lookups via DetectGeoWithServer.

When no cached egress data is available (probe not yet run), it falls back to name-based regex only (DetectGeo, no DNS) so the UI is never blocked. The background egress probe (triggered on source create/update) populates the cache asynchronously.

Also: runEgressProbe now stores countryCode and flag emoji from ipwho.is response. egressCacheKey and addCachedEgressInfo updated to include the new fields.

Reverted previous name-first hack on DetectGeoWithServer and DNS cache on geoip.LookupHost — no longer needed since rename doesn't call them.

Collection preview with rename: 30s -> 52ms (with cache miss, name-based fallback).
2026-07-30 19:02:25 +08:00
rogee 8e449c8531 perf: name-first geo detection to avoid serial DNS in collection rename
DetectGeoWithServer was doing GeoIP-first (DNS lookup per node) then falling back to name regex. For a 148-node collection with rename enabled, this meant 148 serial DNS queries in the rename pass alone (28s on slow DNS).

Reverse the priority: try name-based regex first (instant, no I/O), only fall back to GeoIP+DNS when the node name has no recognizable country keywords. Most proxy names already contain country/city info.

Also add in-memory DNS cache in geoip.LookupHost so repeated lookups for the same hostname don't re-resolve.

Collection preview with rename: 30s -> 3s.
2026-07-30 18:40:18 +08:00
rogee eba9fa1be0 fix: egress cache TTL independent from fetcher cache (24h default)
Egress probe results (IP/country/region/city/isp) were cached using the
fetcher's cache_ttl (300s / 5min). After 5 minutes the cache expired and
the node list showed empty Egress IP/Country/Region fields again.

Add a dedicated egress_cache_ttl config (default 24h) so egress data
persists long enough to be useful when re-expanding the node list.
2026-07-29 17:54:15 +08:00
rogee cc38a6f0ba fix: egress cache key mismatch between source and collection preview
Add _sourceAlias and _previewId to the skip list in egressCacheKey so
that nodes from source preview (with _sourceAlias) and collection
preview (without _sourceAlias, after rename) produce the same cache
key. This ensures egress info cached during source-level probe is
visible when expanding collection cards.
2026-07-29 13:29:07 +08:00
rogee ca1f20b3f3 feat: sort collection nodes by name in final output 2026-07-29 11:49:16 +08:00
rogee 585164dca6 fix: drop nodes that fail geo detection in collection rename
Nodes whose country cannot be detected are now filtered out instead of
kept with their original name. This prevents unlabelled/unrenamed nodes
from appearing in collection output.
2026-07-29 11:19:19 +08:00
rogee 71f814d1ce fix: filter out nodes missing server/port before rendering
Nodes with port=0 or empty server cause client-side errors (e.g.
sing-box decode config failures). Filter them at the render dispatch
layer so all targets (sing-box, mihomo, surge, etc.) are protected.
2026-07-29 09:45:09 +08:00
rogee 89802cbaf8 fix: convert Clash network to sing-box transport for vless/vmess
vless outbound was passing Clash's network field (ws/grpc/h2) directly
to sing-box's network field (which only accepts tcp/udp). Extract
clashToSingBoxTransport() to convert ws/grpc/h2/quic/httpupgrade into
sing-box transport objects. Apply to both vless and vmess outbounds.
2026-07-29 07:58:56 +08:00
rogee fbe09f13de fix: egress probe mode direct→rule so traffic goes through proxy node 2026-07-28 23:16:05 +08:00
rogee 55ab656606 feat: add force refresh button to source/collection cards
- Backend: preview handlers accept forceRefresh in request body
- Frontend: Sources & Collections cards get a refresh button that
  bypasses cache and re-fetches from remote
2026-07-28 21:42:12 +08:00
rogee feafb19714 fix: mihomo proxy-group name conflict + error message 2026-07-28 19:30:38 +08:00
rogee 8d396e63d6 fix: replace sing-box with mihomo for egress probe (xhttp support)
mihomo (Clash Meta) natively supports xhttp and all Clash transports.
Build minimal mihomo YAML config directly from the proxy node instead
of converting to sing-box JSON format.
2026-07-28 19:15:11 +08:00
rogee da609e8036 fix: use %02d format for collection rename index 2026-07-28 18:24:25 +08:00
rogee 040e3ebab1 fix: fetcher proxy support, Dockerfile sing-box, rename index format
1. sslinks 403: Cloudflare blocks server IP. Add fetcher.proxy_url config
   so subscription/flow requests can route through an HTTP proxy.

2. Egress probe: Docker image lacked sing-box. Install sing-box v1.11.4
   in the Alpine runtime stage.

3. Collection rename: group by display baseName instead of internal
   groupKey, format index as -N instead of %02d. Fixes double-suffix
   issue where EnsureUniqueProxyNames appended -2/-3 onto existing  02.
2026-07-28 17:38:57 +08:00
rogee 3671c39b7c feat: single Docker image with frontend served from backend
- Dockerfile: 3-stage build (frontend npm build → backend go build → alpine runtime)
- Frontend dist files served from disk at /app/frontend/dist
- server.go: catch-all GET handler serves static files with SPA fallback to index.html
- config.go: new server.frontend_dir option (env: SUB_STORE_SERVER_FRONTEND_DIR)
- API routes (/api/*), download routes, and /health take priority over static serving
2026-07-28 14:52:53 +08:00
rogee de9ac92ede feat: GeoIP-based geo detection + configurable rename template
- Add MaxMind GeoLite2-City mmdb auto-download and IP-based geo lookup
  (covers all 249 countries globally, replacing limited 8-country regex)
- Add RenameOptions with 5 toggleable fields (flag/alias/country/city/index)
  stored as rename_options_json on collections
- Collection rename pipeline uses DetectGeoWithServer(name, server) which
  tries GeoIP lookup first, falls back to name-based regex matching
- Chinese country/city names + emoji flag prefix
- Country-city dedup: skip city when it equals country (e.g. 香港/香港)
- URI fragment encoding: url.QueryEscape -> url.PathEscape (%20 not +)
- Egress cache key excludes name field so renamed nodes still match cache
- Frontend: 5 toggle buttons in collection edit form, default all on
- Migrations: 0004 (source alias + collection rename_enabled),
  0005 (collection rename_options_json)
2026-07-28 14:44:54 +08:00
rogee 389c0d172a update 2026-07-28 10:32:21 +08:00
rogee fc8c23beee refactor: simplify auth and subscription links 2026-07-28 10:32:21 +08:00
rogee 9ec8c956c1 feat: sing-box Clash template support + Docker CI + frontend scaffold
- Clash→sing-box template conversion engine (singbox_template.go)
- Auto-map 40+ Clash rule-providers to sing-box .srs binary rule-sets
- Fix sing-box 1.11+/1.12+ migrations (sniff/block/WireGuard/DNS/rule_set)
- Fix WireGuard URI '+' parsing bug (rawParamGet)
- Add REJECT block outbound for selector group references
- Skip rules referencing rule-sets with no sing-box equivalent
- Verified: sing-box run succeeds with ACL4SSR template (16 rule-sets loaded)
- Add Dockerfile (multi-stage Go build)
- Add GitHub Actions workflow (multi-arch: amd64+arm64, push to ghcr.io)
- Add frontend scaffold (Vue3 + Vite + Tailwind)
2026-07-27 21:56:19 +08:00
rogee cec95ff4e8 test: add comprehensive unit tests — coverage 20.2% → 91.8%
Add 12 test files covering all internal packages:

- internal/util/util_test.go (97.2%)
- internal/model/model_test.go (100.0%)
- internal/config/config_test.go (88.1%)
- internal/template/builtin_test.go (98.8%)
- internal/middleware/middleware_test.go (98.7%)
- internal/database/repo_extra_test.go (85.5%)
- internal/rules/converter_test.go (99.1%)
- internal/service/subscription_test.go (75.7%)
- internal/handler/handler_test.go (90.6%)
- internal/filter/filter_extra_test.go (91.9%)
- internal/proxy/client_parser_test.go (96.1%)
- internal/render/render_extra_test.go (99.2%)

Overall: 91.8% (4033/4400 statements) — exceeds 85% acceptance threshold.
All tests pass, go vet clean, go build clean.
2026-07-27 16:12:28 +08:00
rogee 90e53aa754 chore: sub-store Go 重写项目初始化 2026-07-27 14:38:13 +08:00