2424//
2525// # Auto-resolved vars
2626//
27- // Set a var's value to "auto" in run.json and the runner picks:
27+ // Set a var's value to an AUTO placeholder in run.json and the runner picks:
2828//
29- // PORT, SOCKS_PORT, UPSTREAM_PORT → random free TCP port
30- // UUID → new UUID v4
31- // PASSWORD → 16 random bytes, hex-encoded
29+ // {{AUTO_PORT}}, {{AUTO_TCP_PORT}}, {{AUTO_UDP_PORT}},
30+ // {{AUTO_QUIC_PORT}}, {{AUTO_SOCKS_PORT}}, {{AUTO_UPSTREAM_PORT}} → random free TCP port
31+ // {{AUTO_UUID}} → new UUID v4
32+ // {{AUTO_PASSWORD}} → 16 random bytes, hex-encoded
3233package tmpl
3334
3435import (
@@ -85,8 +86,8 @@ func init() {
8586 })
8687}
8788
88- // Render renders src as a Pongo2/Jinja2 template against vars, resolves "auto"
89- // values , then optionally strips JSON5 extensions.
89+ // Render renders src as a Pongo2/Jinja2 template against vars, resolves {{AUTO_*}}
90+ // sentinels , then optionally strips JSON5 extensions.
9091//
9192// stripJSON5 (optional, default true): when false, JSON5 comments and trailing
9293// commas are kept in the output — useful for cores that accept JSON5, or for
@@ -95,7 +96,7 @@ func init() {
9596// Returns: rendered bytes, fully-resolved vars map, error.
9697func Render (src []byte , vars map [string ]string , stripJSON5 ... bool ) ([]byte , map [string ]string , error ) {
9798 doStrip := len (stripJSON5 ) == 0 || stripJSON5 [0 ]
98- // 1. Resolve "auto" vars before rendering so the template sees real values.
99+ // 1. Resolve {{AUTO_*}} sentinels before rendering so the template sees real values.
99100 resolved , err := resolveAuto (vars )
100101 if err != nil {
101102 return nil , nil , err
@@ -206,16 +207,22 @@ func buildContext(resolved map[string]string) pongo2.Context {
206207 return ctx
207208}
208209
209- // resolveAuto returns a copy of vars with "auto" values resolved.
210+ // autoPlaceholder returns the {{AUTO_KEY}} sentinel for a given var name.
211+ // Used when checking if a var value requests auto-resolution.
212+ func autoPlaceholder (key string ) string { return "{{AUTO_" + key + "}}" }
213+
214+ // resolveAuto returns a copy of vars with {{AUTO_*}} sentinels resolved.
215+ // Using explicit placeholders (instead of the bare string "auto") avoids
216+ // false matches when a config legitimately contains the word "auto".
210217func resolveAuto (vars map [string ]string ) (map [string ]string , error ) {
211218 out := make (map [string ]string , len (vars ))
212219 for k , v := range vars {
213220 out [k ] = v
214221 }
215222
216- // All recognized port vars — "auto" gets a random free port each.
223+ // Port vars — {{AUTO_PORT}} etc. get a random free port each.
217224 for _ , k := range []string {"PORT" , "TCP_PORT" , "UDP_PORT" , "SOCKS_PORT" , "UPSTREAM_PORT" , "QUIC_PORT" } {
218- if out [k ] == "auto" {
225+ if out [k ] == autoPlaceholder ( k ) {
219226 p , err := freePort ()
220227 if err != nil {
221228 return nil , fmt .Errorf ("tmpl: free port for %s: %w" , k , err )
@@ -238,24 +245,24 @@ func resolveAuto(vars map[string]string) (map[string]string, error) {
238245
239246 // Built-in protocol defaults — override in vars if needed.
240247 builtinDefaults := map [string ]string {
241- "LOG_LEVEL" : "error" ,
242- "VLESS_ENC" : "none" ,
243- "VLESS_DEC" : "none" ,
244- "VLESS_FLOW" : "" ,
245- "HOST_NAME" : "example.com" ,
246- "SNI_NAME" : "example.com" ,
248+ "LOG_LEVEL" : "error" ,
249+ "VLESS_ENC" : "none" ,
250+ "VLESS_DEC" : "none" ,
251+ "VLESS_FLOW" : "" ,
252+ "HOST_NAME" : "example.com" ,
253+ "SNI_NAME" : "example.com" ,
247254 }
248255 for k , def := range builtinDefaults {
249256 if out [k ] == "" {
250257 out [k ] = def
251258 }
252259 }
253260
254- if out ["UUID" ] == "auto" {
261+ if out ["UUID" ] == autoPlaceholder ( "UUID" ) {
255262 out ["UUID" ] = uuid .New ().String ()
256263 }
257264
258- if out ["PASSWORD" ] == "auto" {
265+ if out ["PASSWORD" ] == autoPlaceholder ( "PASSWORD" ) {
259266 b := make ([]byte , 16 )
260267 if _ , err := rand .Read (b ); err != nil {
261268 return nil , fmt .Errorf ("tmpl: rand password: %w" , err )
0 commit comments