// WrapForMW takes a giving interface and asserts it into a DriveMiddleware or // wraps it if needed, returning the middleware. func WrapForMW(wm interface{}) DriveMiddleware { var localWM DriveMiddleware switch wm.(type) { case func(context.Context, error, interface{}) (interface{}, error): localWM = WrapMiddleware(wm.(func(context.Context, error, interface{}) (interface{}, error))) case []func(context.Context, error, interface{}) (interface{}, error): fm := wm.([]fractals.Handler) localWM = WrapMiddleware(fm...) case func(interface{}) fractals.Handler: localWM = WrapMiddleware(wm.(func(interface{}) fractals.Handler)(fractals.IdentityHandler())) case func(context.Context, *Request) error: elx := wm.(func(context.Context, *Request) error) localWM = func(ctx context.Context, rw *Request) (*Request, error) { if err := elx(ctx, rw); err != nil { return nil, err } return rw, nil } case func(ctx context.Context, rw *Request) (*Request, error): localWM = wm.(func(ctx context.Context, rw *Request) (*Request, error)) default: mws := fractals.MustWrap(wm) localWM = WrapMiddleware(mws) } return localWM }
// WrapMiddleware wraps a Handler or lifted Handler from the slices of Handlers // which when runned must return either a (*Request, io.WriteTo, io.Reader,[]byte), // if it matches others except a *Request, then their contents will be written to // the response and the *Request passed in will be returned, this allows the // flexibility of multiple writers based on some operations. // if the returned value matches non of these types, then an error is returned. // When running the Handler if it returns an error then that error is returned // as well. func WrapMiddleware(handlers ...fractals.Handler) DriveMiddleware { var handle fractals.Handler if len(handlers) > 1 { handle = fractals.Lift(handlers...)(fractals.IdentityHandler()) } else { handle = handlers[0] } return func(ctx context.Context, rw *Request) (*Request, error) { res, err := handle(ctx, nil, rw) if err != nil { return nil, err } // If the response is nil, then forward the request object. if res == nil { return rw, nil } // If its not nil, then check if it matches a series of types else // return an error. switch res.(type) { case []byte: if _, err := rw.Res.Write(res.([]byte)); err != nil { return nil, err } return rw, nil case io.Reader: rd := res.(io.Reader) if _, err := io.Copy(rw.Res, rd); err != nil { return nil, err } return rw, nil case io.WriterTo: wt := res.(io.WriterTo) if _, err := wt.WriteTo(rw.Res); err != nil { return nil, err } return rw, nil case *Request: return res.(*Request), nil default: return nil, errors.New("Invalid Type, Require *Request type") } } }
// FileServer returns a handler capable of serving different files from the provided // directory but using inputed URL path. func FileServer(dir string, prefix string) fractals.Handler { var stripper fractals.Handler if prefix != "" { stripper = fs.StripPrefix(prefix) } else { stripper = fractals.IdentityHandler() } return fractals.SubLift(func(rw *Request, data []byte) (*Request, error) { if _, err := rw.Res.Write(data); err != nil { return nil, err } return rw, nil }, IdentityMiddlewareHandler(), MimeWriter(), PathName(), stripper, fs.ResolvePathStringIn(dir), fs.ReadFile()) }