cvanloo / rmsgo

Remote Storage implementation in Go
The Unlicense
1 stars 0 forks source link

Use options pattern to configure the server (?) #7

Closed cvanloo closed 11 months ago

cvanloo commented 11 months ago

Something like

type ServerOption func(*Settings)

func UseErrorHandler(h ErrorHandlerFunc) ServerOption {
    return func(s *Settings) {
        s.unhandled = h
    }
}

// ...

func Configure(remoteRoot, storageRoot string, options ...ServerOption) error {
    // ...
    g = &Settings{
        // initialize default configuration
    }
    for _, option := range options {
        option(g)
    }
    return nil
}
cvanloo commented 11 months ago

Though there is a problem with this pattern. The setup becomes less flexible.

Setting an option conditionally, like:

opts, err := rmsgo.Configure(*rroot, *sroot)
if err != nil {
    log.Fatal(err)
}
opts.UseErrorHandler(func(err error) {
    log.Fatalf("remote storage: unhandled error: %v", err)
})
opts.UseMiddleware(logger)
if !allOrigins { // allow all is the default in opts
    opts.UseAllowedOrigins(origins.Origins)
}
opts.UseAuthentication(func(r *http.Request, bearer string) (rmsgo.User, bool) {
    return rmsgo.UserReadWrite{}, true
})

…becomes more cumbersome:

if allOrigins {
    err = rmsgo.Configure(
        *rroot, *sroot,
        rmsgo.UseErrorHandler(func(err error) {
            log.Fatalf("remote storage: unhandled error: %v", err)
        }),
        rmsgo.UseMiddleware(logger),
        rmsgo.UseAuthentication(func(r *http.Request, bearer string) (rmsgo.User, bool) {
            return rmsgo.UserReadWrite{}, true
        }),
    )
} else {
    err = rmsgo.Configure(
        *rroot, *sroot,
        rmsgo.UseErrorHandler(func(err error) {
            log.Fatalf("remote storage: unhandled error: %v", err)
        }),
        rmsgo.UseMiddleware(logger),
        rmsgo.UseAuthentication(func(r *http.Request, bearer string) (rmsgo.User, bool) {
            return rmsgo.UserReadWrite{}, true
        }),
        rmsgo.UseAllowedOrigins(origins.Origins),
    )
}
if err != nil {
    log.Fatal(err)
}

…or possibly:

configureOrigins := func() rmsgo.ServerOption {
    if !allOrigins {
        return rmsgo.UseAllowedOrigins(origins.Origins)
    }
    return func(*rmsgo.Settings){}
}
err := rmsgo.Configure(
    *rroot, *sroot,
    rmsgo.UseErrorHandler(func(err error) {
        log.Fatalf("remote storage: unhandled error: %v", err)
    }),
    rmsgo.UseMiddleware(logger),
    rmsgo.UseAuthentication(func(r *http.Request, bearer string) (rmsgo.User, bool) {
        return rmsgo.UserReadWrite{}, true
    }),
    configureOrigins(),
)
if err != nil {
    log.Fatal(err)
}

That we have to precede everything with rmsgo. also doesn't make things look any better.

cvanloo commented 11 months ago

Tried it out here: rmsgo/options-pattern

cvanloo commented 11 months ago

I'll leave it at the current pattern, I think it's more suitable than the options pattern.