diff --git a/internal/experiment/wireguard/config.go b/internal/experiment/wireguard/config.go index e76afb9653..cb05a10bba 100644 --- a/internal/experiment/wireguard/config.go +++ b/internal/experiment/wireguard/config.go @@ -59,7 +59,7 @@ type options struct { h4 string } -func getOptionsFromConfig(c Config) (options, error) { +func getOptionsFromConfig(c *Config) (options, error) { o := options{} pub, _ := base64.StdEncoding.DecodeString(c.SafePublicKey) diff --git a/internal/experiment/wireguard/doc.go b/internal/experiment/wireguard/doc.go new file mode 100644 index 0000000000..e0cc371cea --- /dev/null +++ b/internal/experiment/wireguard/doc.go @@ -0,0 +1,2 @@ +// Package wireguard contains the wireguard experiment. +package wireguard diff --git a/internal/experiment/wireguard/richerinput.go b/internal/experiment/wireguard/richerinput.go new file mode 100644 index 0000000000..e4321d6e54 --- /dev/null +++ b/internal/experiment/wireguard/richerinput.go @@ -0,0 +1,86 @@ +package wireguard + +import ( + "context" + + "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/targetloading" +) + +// Target is a richer-input target that this experiment should measure. +type Target struct { + // Options contains the configuration. + Options *Config + + // URL is the input URL. + URL string +} + +var _ model.ExperimentTarget = &Target{} + +// Category implements [model.ExperimentTarget]. +func (t *Target) Category() string { + return model.DefaultCategoryCode +} + +// Country implements [model.ExperimentTarget]. +func (t *Target) Country() string { + return model.DefaultCountryCode +} + +// Input implements [model.ExperimentTarget]. +func (t *Target) Input() string { + return t.URL +} + +// String implements [model.ExperimentTarget]. +func (t *Target) String() string { + return t.URL +} + +// NewLoader constructs a new [model.ExperimentTargerLoader] instance. +// +// This function PANICS if options is not an instance of [*openvpn.Config]. +func NewLoader(loader *targetloading.Loader, gopts any) model.ExperimentTargetLoader { + // Panic if we cannot convert the options to the expected type. + // + // We do not expect a panic here because the type is managed by the registry package. + options := gopts.(*Config) + + // Construct the proper loader instance. + return &targetLoader{ + loader: loader, + options: options, + session: loader.Session, + } +} + +// targetLoader loads targets for this experiment. +type targetLoader struct { + loader *targetloading.Loader + options *Config + session targetloading.Session +} + +// Load implements model.ExperimentTargetLoader. +func (tl *targetLoader) Load(ctx context.Context) ([]model.ExperimentTarget, error) { + // TODO(ainghazal): implement remote loading when backend is ready. + + // Attempt to load the static inputs from CLI and files + inputs, err := targetloading.LoadStatic(tl.loader) + + // Handle the case where we couldn't load from CLI or files + if err != nil { + return nil, err + } + + // Build the list of targets that we should measure. + var targets []model.ExperimentTarget + for _, input := range inputs { + targets = append(targets, &Target{ + Options: tl.options, + URL: input, + }) + } + return targets, nil +} diff --git a/internal/experiment/wireguard/wireguard.go b/internal/experiment/wireguard/wireguard.go index 2142ab7c9f..5fc8c60a95 100644 --- a/internal/experiment/wireguard/wireguard.go +++ b/internal/experiment/wireguard/wireguard.go @@ -1,19 +1,17 @@ -// Package wireguard contains the wireguard experiment. package wireguard import ( "context" + "errors" "fmt" "io" "net/http" "net/netip" - "os" "strings" "time" "github.com/ooni/probe-cli/v3/internal/measurexlite" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/amnezia-vpn/amneziawg-go/conn" "github.com/amnezia-vpn/amneziawg-go/device" @@ -29,6 +27,10 @@ const ( defaultNameserver = "8.8.8.8" ) +var ( + ErrInputRequired = errors.New("input is required") +) + // Measurer performs the measurement. type Measurer struct { config Config @@ -53,16 +55,23 @@ func (m Measurer) ExperimentVersion() string { // Run implements model.ExperimentMeasurer.Run. func (m Measurer) Run(ctx context.Context, args *model.ExperimentArgs) error { measurement := args.Measurement - zeroTime := measurement.MeasurementStartTimeSaved - sess := args.Session + zeroTime := measurement.MeasurementStartTimeSaved var err error + // 0. obtain the richer input target, config, and input or panic + if args.Target == nil { + return ErrInputRequired + } + // 1. setup (parse config file) - err = m.setupConfig() - sess.Logger().Debug(string(m.rawconfig)) - if err != nil { + target := args.Target.(*Target) + + // TODO(ainghazal): process the input when the backend hands us one. + config, _ := target.Options, target.URL + + if err := m.setupConfig(config); err != nil { return err } @@ -90,16 +99,12 @@ func (m Measurer) Run(ctx context.Context, args *model.ExperimentArgs) error { return nil } -func (m *Measurer) setupConfig() error { - cfg := readConfigFromFile(m.config.ConfigFile) - opts, err := getOptionsFromConfig(m.config) +func (m *Measurer) setupConfig(config *Config) error { + opts, err := getOptionsFromConfig(config) if err != nil { return err } m.options = opts - if len(cfg) > 0 { - m.rawconfig = cfg - } return nil } @@ -163,24 +168,14 @@ func (m *Measurer) urlget(zeroTime time.Time, logger model.Logger) *URLGetResult } // NewExperimentMeasurer creates a new ExperimentMeasurer. -func NewExperimentMeasurer(config Config) model.ExperimentMeasurer { +func NewExperimentMeasurer() model.ExperimentMeasurer { return Measurer{ - config: config, events: newEventLogger(), options: options{}, testName: testName, } } -func readConfigFromFile(path string) []byte { - cfg, err := os.ReadFile(path) - if err != nil { - return []byte{} - } - runtimex.PanicOnError(err, "cannot open file") - return cfg -} - func (m *Measurer) configureWireguardInterface( logger model.Logger, eventlogger *eventLogger, @@ -226,7 +221,6 @@ endpoint=` + opts.endpoint + ` allowed_ip=0.0.0.0/0 ` } - fmt.Println(ipcStr) dev.IpcSet(ipcStr) err = dev.Up() diff --git a/internal/experiment/wireguard/wireguard_test.go b/internal/experiment/wireguard/wireguard_test.go index ec322f7d61..0cb7975a33 100644 --- a/internal/experiment/wireguard/wireguard_test.go +++ b/internal/experiment/wireguard/wireguard_test.go @@ -4,22 +4,20 @@ import ( "context" "errors" "testing" - "time" "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/experiment/example" + "github.com/ooni/probe-cli/v3/internal/experiment/wireguard" "github.com/ooni/probe-cli/v3/internal/legacy/mockable" "github.com/ooni/probe-cli/v3/internal/model" ) func TestSuccess(t *testing.T) { - m := example.NewExperimentMeasurer(example.Config{ - SleepTime: int64(2 * time.Millisecond), - }, "example") - if m.ExperimentName() != "example" { + m := wireguard.NewExperimentMeasurer() + if m.ExperimentName() != "wireguard" { t.Fatal("invalid ExperimentName") } - if m.ExperimentVersion() != "0.1.0" { + if m.ExperimentVersion() != "0.1.1" { t.Fatal("invalid ExperimentVersion") } ctx := context.Background() @@ -38,10 +36,7 @@ func TestSuccess(t *testing.T) { } func TestFailure(t *testing.T) { - m := example.NewExperimentMeasurer(example.Config{ - SleepTime: int64(2 * time.Millisecond), - ReturnError: true, - }, "example") + m := wireguard.NewExperimentMeasurer() ctx := context.Background() sess := &mockable.Session{MockableLogger: log.Log} callbacks := model.NewPrinterCallbacks(sess.Logger()) diff --git a/internal/registry/wireguard.go b/internal/registry/wireguard.go index 9ca9a6f333..945737072e 100644 --- a/internal/registry/wireguard.go +++ b/internal/registry/wireguard.go @@ -14,15 +14,16 @@ func init() { AllExperiments["wireguard"] = func() *Factory { return &Factory{ build: func(config interface{}) model.ExperimentMeasurer { - return wireguard.NewExperimentMeasurer( - *config.(*wireguard.Config), - ) + return wireguard.NewExperimentMeasurer() }, canonicalName: canonicalName, config: &wireguard.Config{}, enabledByDefault: true, interruptible: true, - inputPolicy: model.InputNone, + // TODO(ainghazal): when the backend is ready to hand us targets, + // we will use InputOrQueryBackend. + inputPolicy: model.InputNone, + newLoader: wireguard.NewLoader, } } }