Expands patterns of the form `${param}` in `pattern`, looking up each such `param` in the `args` map and substituting its value. (`\$` is replaced with `$`.) It is an error if any `param` has no value, or if its value is not a string or integer.
(pattern string, args map[string]any, user auth.User)
| 303 | // (`\$` is replaced with `$`.) |
| 304 | // It is an error if any `param` has no value, or if its value is not a string or integer. |
| 305 | func expandPattern(pattern string, args map[string]any, user auth.User) (string, error) { |
| 306 | if strings.IndexByte(pattern, '$') < 0 { |
| 307 | return pattern, nil |
| 308 | } |
| 309 | var err error |
| 310 | channel := kChannelPropertyRegexp.ReplaceAllStringFunc(pattern, func(matched string) string { |
| 311 | if err != nil { |
| 312 | return "" |
| 313 | } else if matched == "\\$" { |
| 314 | return "$" |
| 315 | } else if !strings.HasPrefix(matched, "${") || !strings.HasSuffix(matched, "}") { |
| 316 | err = base.HTTPErrorf(http.StatusInternalServerError, "missing curly-brace in pattern %q", matched) |
| 317 | return "" |
| 318 | } |
| 319 | arg := matched[2 : len(matched)-1] |
| 320 | |
| 321 | // Look up the argument: |
| 322 | if strings.HasPrefix(arg, "args.") { |
| 323 | var rval reflect.Value |
| 324 | rval, err = evalKeyPath(args, arg[5:]) |
| 325 | if err != nil { |
| 326 | return "" |
| 327 | } |
| 328 | |
| 329 | // Convert `rval` to a string: |
| 330 | for rval.Kind() == reflect.Interface { |
| 331 | rval = rval.Elem() |
| 332 | } |
| 333 | if rval.Kind() == reflect.String { |
| 334 | return rval.String() |
| 335 | } else if rval.CanInt() || rval.CanUint() || rval.CanFloat() || rval.Kind() == reflect.Bool { |
| 336 | return fmt.Sprintf("%v", rval) |
| 337 | } else { |
| 338 | err = base.HTTPErrorf(http.StatusBadRequest, "argument %q must be a string or number or boolean, not %v", arg, rval.Kind()) |
| 339 | return "" |
| 340 | } |
| 341 | } else if arg == "context.user.name" { |
| 342 | if user == nil { |
| 343 | return "" |
| 344 | } else { |
| 345 | return user.Name() |
| 346 | } |
| 347 | } else { |
| 348 | err = base.HTTPErrorf(http.StatusInternalServerError, "invalid variable expression %q", matched) |
| 349 | return "" |
| 350 | } |
| 351 | }) |
| 352 | return channel, err |
| 353 | } |
| 354 | |
| 355 | // Evaluates a "key path", like "points[3].x.y" on a JSON-based map. |
| 356 | func evalKeyPath(root map[string]any, keyPath string) (reflect.Value, error) { |