Skip to content

Commit

Permalink
🐛 Fix error handling and improve handler initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
wesen committed Feb 6, 2025
1 parent 91aae8c commit 380b371
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 35 deletions.
48 changes: 29 additions & 19 deletions pkg/glazed/handlers/datatables/datatables.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import (
"context"
"embed"
"fmt"
"html/template"
"io"
"time"

"github.com/go-go-golems/glazed/pkg/cmds"
"github.com/go-go-golems/glazed/pkg/cmds/layers"
"github.com/go-go-golems/glazed/pkg/cmds/middlewares"
Expand All @@ -22,9 +26,6 @@ import (
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"html/template"
"io"
"time"
)

// DataTables describes the data passed to the template displaying the results of a glazed command.
Expand Down Expand Up @@ -149,7 +150,11 @@ func WithTemplateLookup(lookup render.TemplateLookup) QueryHandlerOption {

func WithTemplateName(templateName string) QueryHandlerOption {
return func(h *QueryHandler) {
h.templateName = templateName
if templateName == "" {
h.templateName = "data-tables.tmpl.html"
} else {
h.templateName = templateName
}
}
}

Expand Down Expand Up @@ -186,14 +191,13 @@ func (qh *QueryHandler) Handle(c echo.Context) error {
// since we have a context there, and there is no need to block the middleware processing.
columnsC := make(chan []types.FieldName, 10)

err := middlewares.ExecuteMiddlewares(description.Layers, parsedLayers,
append(
qh.middlewares,
parka_middlewares.UpdateFromQueryParameters(c, parameters.WithParseStepSource("query")),
middlewares.SetFromDefaults(),
)...,
)

middlewares_ := []middlewares.Middleware{
parka_middlewares.UpdateFromQueryParameters(c,
parameters.WithParseStepSource("query")),
}
middlewares_ = append(middlewares_, qh.middlewares...)
middlewares_ = append(middlewares_, middlewares.SetFromDefaults())
err := middlewares.ExecuteMiddlewares(description.Layers.Clone(), parsedLayers, middlewares_...)
if err != nil {
log.Debug().Err(err).Msg("error executing middlewares")
g := &safegroup.Group{}
Expand Down Expand Up @@ -309,15 +313,18 @@ func (qh *QueryHandler) Handle(c echo.Context) error {
g := &safegroup.Group{}
err_ := err
g.Go(func() error {
log.Debug().Err(err_).Msg("error running command")
// make sure to render the ErrorStream at the bottom, because we would otherwise get into a deadlock with the streaming channels
// NOTE(manuel, 2024-05-14) I'm not sure if with the addition of goroutines this is actually still necessary
//
log.Debug().Msg("sending error to error stream")
defer close(dt_.ErrorStream)

if err_ != nil {
dt_.ErrorStream <- err_.Error()
log.Debug().Err(err_).Msg("error running command")
// make sure to render the ErrorStream at the bottom, because we would otherwise get into a deadlock with the streaming channels
// NOTE(manuel, 2024-05-14) I'm not sure if with the addition of goroutines this is actually still necessary
//
log.Debug().Msg("sending error to error stream")
if err_ != nil {
dt_.ErrorStream <- err_.Error()
}
}
close(dt_.ErrorStream)
return nil
})

Expand Down Expand Up @@ -372,6 +379,9 @@ func (qh *QueryHandler) renderTemplate(
// our own output formatter that renders into an HTML template.
var err error

if qh.lookup == nil {
qh.lookup = NewDataTablesLookupTemplate()
}
t, err := qh.lookup.Lookup(qh.templateName)
if err != nil {
return err
Expand Down
8 changes: 6 additions & 2 deletions pkg/handlers/command-dir/command-dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,12 @@ func NewCommandDirHandlerFromConfig(
generic_command.WithIndexTemplateName(config_.IndexTemplateName),
generic_command.WithMergeAdditionalData(config_.AdditionalData, true),
}
genericHandler, err := generic_command.NewGenericCommandHandler(genericOptions...)
if err != nil {
return nil, err
}
cd := &CommandDirHandler{
GenericCommandHandler: *generic_command.NewGenericCommandHandler(genericOptions...),
GenericCommandHandler: *genericHandler,
}

cd.ParameterFilter.Overrides = config_.Overrides
Expand Down Expand Up @@ -125,7 +129,7 @@ func NewCommandDirHandlerFromConfig(
}
}

err := cd.TemplateLookup.Reload()
err = cd.TemplateLookup.Reload()
if err != nil {
return nil, err
}
Expand Down
20 changes: 14 additions & 6 deletions pkg/handlers/command/command.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package command

import (
"os"
"strings"

"github.com/go-go-golems/glazed/pkg/cmds"
"github.com/go-go-golems/glazed/pkg/cmds/alias"
"github.com/go-go-golems/glazed/pkg/cmds/loaders"
Expand All @@ -10,8 +13,6 @@ import (
"github.com/go-go-golems/parka/pkg/render"
parka "github.com/go-go-golems/parka/pkg/server"
"github.com/pkg/errors"
"os"
"strings"
)

type CommandHandler struct {
Expand Down Expand Up @@ -41,17 +42,21 @@ func WithGenericCommandHandlerOptions(options ...generic_command.GenericCommandH
func NewCommandHandler(
command cmds.Command,
options ...CommandHandlerOption,
) *CommandHandler {
) (*CommandHandler, error) {
genericHandler, err := generic_command.NewGenericCommandHandler()
if err != nil {
return nil, err
}
c := &CommandHandler{
GenericCommandHandler: *generic_command.NewGenericCommandHandler(),
GenericCommandHandler: *genericHandler,
Command: command,
}

for _, opt := range options {
opt(c)
}

return c
return c, nil
}

func LoadCommandFromFile(path string, loader loaders.CommandLoader) (cmds.Command, error) {
Expand Down Expand Up @@ -114,7 +119,10 @@ func NewCommandHandlerFromConfig(
return nil, err
}

c := NewCommandHandler(cmd, WithGenericCommandHandlerOptions(genericOptions...))
c, err := NewCommandHandler(cmd, WithGenericCommandHandlerOptions(genericOptions...))
if err != nil {
return nil, err
}
// TODO(manuel, 2024-05-09) Handle devmode
c.Command = cmd

Expand Down
50 changes: 42 additions & 8 deletions pkg/handlers/generic-command/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package generic_command

import (
"fmt"
"net/http"
"path/filepath"
"strings"

"github.com/go-go-golems/clay/pkg/repositories"
"github.com/go-go-golems/glazed/pkg/cmds"
"github.com/go-go-golems/glazed/pkg/cmds/middlewares"
Expand All @@ -17,9 +21,6 @@ import (
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"net/http"
"path/filepath"
"strings"
)

type GenericCommandHandler struct {
Expand Down Expand Up @@ -49,20 +50,42 @@ type GenericCommandHandler struct {
// path under which the command handler is served
BasePath string

// preMiddlewares are run before the parameter filter middlewares
preMiddlewares []middlewares.Middleware
// postMiddlewares are run after the parameter filter middlewares
postMiddlewares []middlewares.Middleware
// middlewares contains all middlewares in order: pre + parameter filter + post
middlewares []middlewares.Middleware
}

func NewGenericCommandHandler(options ...GenericCommandHandlerOption) *GenericCommandHandler {
func NewGenericCommandHandler(options ...GenericCommandHandlerOption) (*GenericCommandHandler, error) {
handler := &GenericCommandHandler{
AdditionalData: map[string]interface{}{},
TemplateLookup: datatables.NewDataTablesLookupTemplate(),
ParameterFilter: &config.ParameterFilter{},
preMiddlewares: []middlewares.Middleware{},
postMiddlewares: []middlewares.Middleware{},
}

for _, opt := range options {
opt(handler)
}

return handler
// Compute the final middleware chain
parameterMiddlewares := handler.ParameterFilter.ComputeMiddlewares(handler.Stream)
handler.middlewares = append(handler.preMiddlewares, parameterMiddlewares...)
handler.middlewares = append(handler.middlewares, handler.postMiddlewares...)

if handler.TemplateLookup == nil {
handler.TemplateLookup = datatables.NewDataTablesLookupTemplate()
}

err := handler.TemplateLookup.Reload()
if err != nil {
return nil, err
}

return handler, nil
}

type GenericCommandHandlerOption func(handler *GenericCommandHandler)
Expand Down Expand Up @@ -131,10 +154,21 @@ func WithTemplateLookup(lookup render.TemplateLookup) GenericCommandHandlerOptio
}
}

func WithPreMiddlewares(middlewares ...middlewares.Middleware) GenericCommandHandlerOption {
return func(handler *GenericCommandHandler) {
handler.preMiddlewares = append(handler.preMiddlewares, middlewares...)
}
}

func WithPostMiddlewares(middlewares ...middlewares.Middleware) GenericCommandHandlerOption {
return func(handler *GenericCommandHandler) {
handler.postMiddlewares = append(handler.postMiddlewares, middlewares...)
}
}

func (gch *GenericCommandHandler) ServeSingleCommand(server *parka.Server, basePath string, command cmds.Command) error {
gch.BasePath = basePath

gch.middlewares = gch.ParameterFilter.ComputeMiddlewares(gch.Stream)
server.Router.GET(basePath+"/data", func(c echo.Context) error {
return gch.ServeData(c, command)
})
Expand All @@ -159,8 +193,6 @@ func (gch *GenericCommandHandler) ServeRepository(server *parka.Server, basePath
basePath = strings.TrimSuffix(basePath, "/")
gch.BasePath = basePath

gch.middlewares = gch.ParameterFilter.ComputeMiddlewares(gch.Stream)

server.Router.GET(basePath+"/data/*", func(c echo.Context) error {
commandPath := c.Param("*")
commandPath = strings.TrimPrefix(commandPath, "/")
Expand Down Expand Up @@ -311,7 +343,9 @@ func (gch *GenericCommandHandler) ServeDataTables(c echo.Context, command cmds.C
switch v := command.(type) {
case cmds.GlazeCommand:
options := []datatables.QueryHandlerOption{
datatables.WithMiddlewares(gch.preMiddlewares...),
datatables.WithMiddlewares(gch.middlewares...),
datatables.WithMiddlewares(gch.postMiddlewares...),
datatables.WithTemplateLookup(gch.TemplateLookup),
datatables.WithTemplateName(gch.TemplateName),
datatables.WithAdditionalData(gch.AdditionalData),
Expand Down

0 comments on commit 380b371

Please sign in to comment.