diff --git a/internal/parser/all.go b/internal/parser/all.go index 529f917..c5ff8f9 100644 --- a/internal/parser/all.go +++ b/internal/parser/all.go @@ -10,6 +10,7 @@ import ( _ "github.com/joint-online-judge/JOJ3/internal/parser/healthcheck" _ "github.com/joint-online-judge/JOJ3/internal/parser/keyword" _ "github.com/joint-online-judge/JOJ3/internal/parser/log" + _ "github.com/joint-online-judge/JOJ3/internal/parser/plugin" _ "github.com/joint-online-judge/JOJ3/internal/parser/resultdetail" _ "github.com/joint-online-judge/JOJ3/internal/parser/resultstatus" _ "github.com/joint-online-judge/JOJ3/internal/parser/sample" diff --git a/internal/parser/plugin/meta.go b/internal/parser/plugin/meta.go new file mode 100644 index 0000000..63c7939 --- /dev/null +++ b/internal/parser/plugin/meta.go @@ -0,0 +1,21 @@ +// Package plugin provides functionality to load and run parser plugins +// dynamically. It is used for custom parsers. +// The plugin needs to be located at `ModPath` and export a symbol with name +// `SymName` that implements the stage.Parser interface. + +package plugin + +import "github.com/joint-online-judge/JOJ3/internal/stage" + +var name = "plugin" + +type Conf struct { + ModPath string + SymName string `default:"Parser"` +} + +type Plugin struct{} + +func init() { + stage.RegisterParser(name, &Plugin{}) +} diff --git a/internal/parser/plugin/parser.go b/internal/parser/plugin/parser.go new file mode 100644 index 0000000..7aeb616 --- /dev/null +++ b/internal/parser/plugin/parser.go @@ -0,0 +1,31 @@ +package plugin + +import ( + "fmt" + "plugin" + + "github.com/joint-online-judge/JOJ3/internal/stage" +) + +func (*Plugin) Run(results []stage.ExecutorResult, confAny any) ( + []stage.ParserResult, bool, error, +) { + conf, err := stage.DecodeConf[Conf](confAny) + if err != nil { + return nil, true, err + } + plug, err := plugin.Open(conf.ModPath) + if err != nil { + return nil, true, err + } + symParser, err := plug.Lookup(conf.SymName) + if err != nil { + return nil, true, err + } + var parser stage.Parser + parser, ok := symParser.(stage.Parser) + if !ok { + return nil, true, fmt.Errorf("unexpected type from module symbol") + } + return parser.Run(results, confAny) +}