LoadModule loads the Caddy module(s) from the specified field of the parent struct pointer and returns the loaded module(s). The struct pointer and its field name as a string are necessary so that reflection can be used to read the struct tag on the field to get the module namespace and inline modul
(structPointer any, fieldName string)
| 186 | // successfully, this method clears the json.RawMessage(s) in the field since |
| 187 | // the raw JSON is no longer needed, and this allows the GC to free up memory. |
| 188 | func (ctx Context) LoadModule(structPointer any, fieldName string) (any, error) { |
| 189 | val := reflect.ValueOf(structPointer).Elem().FieldByName(fieldName) |
| 190 | typ := val.Type() |
| 191 | |
| 192 | field, ok := reflect.TypeOf(structPointer).Elem().FieldByName(fieldName) |
| 193 | if !ok { |
| 194 | panic(fmt.Sprintf("field %s does not exist in %#v", fieldName, structPointer)) |
| 195 | } |
| 196 | |
| 197 | opts, err := ParseStructTag(field.Tag.Get("caddy")) |
| 198 | if err != nil { |
| 199 | panic(fmt.Sprintf("malformed tag on field %s: %v", fieldName, err)) |
| 200 | } |
| 201 | |
| 202 | moduleNamespace, ok := opts["namespace"] |
| 203 | if !ok { |
| 204 | panic(fmt.Sprintf("missing 'namespace' key in struct tag on field %s", fieldName)) |
| 205 | } |
| 206 | inlineModuleKey := opts["inline_key"] |
| 207 | |
| 208 | var result any |
| 209 | |
| 210 | switch val.Kind() { |
| 211 | case reflect.Slice: |
| 212 | if isJSONRawMessage(typ) { |
| 213 | // val is `json.RawMessage` ([]uint8 under the hood) |
| 214 | |
| 215 | if inlineModuleKey == "" { |
| 216 | panic("unable to determine module name without inline_key when type is not a ModuleMap") |
| 217 | } |
| 218 | val, err := ctx.loadModuleInline(inlineModuleKey, moduleNamespace, val.Interface().(json.RawMessage)) |
| 219 | if err != nil { |
| 220 | return nil, err |
| 221 | } |
| 222 | result = val |
| 223 | } else if isJSONRawMessage(typ.Elem()) { |
| 224 | // val is `[]json.RawMessage` |
| 225 | |
| 226 | if inlineModuleKey == "" { |
| 227 | panic("unable to determine module name without inline_key because type is not a ModuleMap") |
| 228 | } |
| 229 | var all []any |
| 230 | for i := 0; i < val.Len(); i++ { |
| 231 | val, err := ctx.loadModuleInline(inlineModuleKey, moduleNamespace, val.Index(i).Interface().(json.RawMessage)) |
| 232 | if err != nil { |
| 233 | return nil, fmt.Errorf("position %d: %v", i, err) |
| 234 | } |
| 235 | all = append(all, val) |
| 236 | } |
| 237 | result = all |
| 238 | } else if typ.Elem().Kind() == reflect.Slice && isJSONRawMessage(typ.Elem().Elem()) { |
| 239 | // val is `[][]json.RawMessage` |
| 240 | |
| 241 | if inlineModuleKey == "" { |
| 242 | panic("unable to determine module name without inline_key because type is not a ModuleMap") |
| 243 | } |
| 244 | var all [][]any |
| 245 | for i := 0; i < val.Len(); i++ { |