package app import ( "strings" "time" transportcfgpkg "selective-vpn-api/app/transportcfg" ) func prepareSingBoxClientProfile(client TransportClient, checkBinary bool) transportBackendActionResult { if client.Kind != TransportClientSingBox { return transportBackendActionResult{ OK: true, Message: "singbox preflight skipped", } } singBoxProfilesMu.Lock() defer singBoxProfilesMu.Unlock() st := loadSingBoxProfilesState() idx := findSingBoxProfileIndexForClient(st, client.ID) if idx < 0 { return transportBackendActionResult{ OK: false, Code: singBoxProfileCodeNotFound, Message: "singbox profile not linked to client " + client.ID, ExitCode: -1, } } cur := st.Items[idx] now := time.Now().UTC().Format(time.RFC3339Nano) eval := evaluateSingBoxProfile(cur, checkBinary) cur.LastValidatedAt = now cur.UpdatedAt = now if !eval.Valid { cur.LastError = joinSingBoxIssueMessages(eval.Errors) st.Items[idx] = cur _ = saveSingBoxProfilesState(st) return transportBackendActionResult{ OK: false, Code: singBoxProfileCodeValidationFailed, Message: "profile preflight failed: " + strings.TrimSpace(cur.LastError), ExitCode: -1, } } renderPath, err := writeSingBoxRenderedConfig(cur.ID, eval.Config) if err != nil { cur.LastError = err.Error() st.Items[idx] = cur _ = saveSingBoxProfilesState(st) return transportBackendActionResult{ OK: false, Code: singBoxProfileCodeRenderFailed, Message: "profile preflight render failed: " + err.Error(), ExitCode: -1, } } configPath := transportSingBoxConfigPath(client) if strings.TrimSpace(configPath) == "" { configPath = defaultSingBoxAppliedConfigPath(cur.ID) } if err := transportcfgpkg.WriteJSONConfigFile(configPath, eval.Config); err != nil { cur.LastError = err.Error() st.Items[idx] = cur _ = saveSingBoxProfilesState(st) return transportBackendActionResult{ OK: false, Code: singBoxProfileCodeApplyFailed, Message: "profile preflight write failed: " + err.Error(), ExitCode: -1, Stdout: renderPath, } } cur.LastError = "" st.Items[idx] = cur if err := saveSingBoxProfilesState(st); err != nil { return transportBackendActionResult{ OK: false, Code: singBoxProfileCodeSaveFailed, Message: "profile preflight save failed: " + err.Error(), ExitCode: -1, Stdout: renderPath, } } return transportBackendActionResult{ OK: true, ExitCode: 0, Message: "profile preflight ready: " + cur.ID, Stdout: strings.TrimSpace(configPath), Stderr: strings.TrimSpace(renderPath), } }