feat(M6): token-ring protocol complete — task ride+lowest-load claim, topology publish back to token, real worker spawn via claim, incremental log sync e2e

This commit is contained in:
2026-08-18 09:08:22 +08:00
parent e59feb82c1
commit 1a8c362080
2 changed files with 40 additions and 2 deletions

View File

@ -97,6 +97,7 @@ func NewServeMux(h *Handler) (http.Handler, error) {
mux.HandleFunc(apiPrefix+"/cluster/token", auth(h.handleClusterToken))
mux.HandleFunc(apiPrefix+"/cluster/ring", auth(h.handleClusterRing))
mux.HandleFunc(apiPrefix+"/cluster/join", auth(h.handleClusterJoin))
mux.HandleFunc(apiPrefix+"/cluster/task", auth(h.handleClusterTask))
// M6: peer-to-peer binary exchange endpoint (Basic Auth, same creds).
// Not under /api so peers hit it directly; auth still applied.
@ -442,7 +443,33 @@ func (h *Handler) handleClusterJoin(w http.ResponseWriter, r *http.Request) {
}
}
// frpcVersionOf extracts the frpc version from a binary path like
// handleClusterTask accepts a new forward request (intermediate config:
// local/remote/link) and submits it to the ring as a pending task.
func (h *Handler) handleClusterTask(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
methodNotAllowed(w)
return
}
if h.Ring == nil {
http.Error(w, "ring engine not enabled", http.StatusNotFound)
return
}
var req struct {
Local store.Local `json:"local"`
Remote store.Remote `json:"remote"`
Link store.Link `json:"link"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "parse task: "+err.Error(), http.StatusBadRequest)
return
}
tk := h.Ring.SubmitTask(req.Local, req.Remote, req.Link)
writeJSON(w, http.StatusOK, map[string]any{"task": tk})
}
// handleClusterJoin accepts a newcomer join request: the target node inserts
// the newcomer after itself in the ring and returns the updated ring state
// for the newcomer to adopt.
// .../bin/frpc-0.71.0/frpc. Empty when not a versioned cache path.
func frpcVersionOf(binPath string) string {
dir := filepath.Dir(binPath)