package server
import (
"context"
"errors"
"fmt"
"log"
"net/mail"
"runtime"
"github.com/99designs/gqlgen/graphql"
"github.com/vaughan0/go-ini"
gomail "gopkg.in/mail.v2"
"git.sr.ht/~sircmpwn/core-go/auth"
"git.sr.ht/~sircmpwn/core-go/email"
)
// Provides a graphql.RecoverFunc which will print the stack trace, and if
// debug mode is not enabled, email it to the administrator.
func EmailRecover(config ini.File, debug bool, srv string) graphql.RecoverFunc {
return func(ctx context.Context, _origErr interface{}) error {
var (
ok bool
origErr error
)
if origErr, ok = _origErr.(error); !ok {
log.Printf("Unexpected error in recover: %v\n", origErr)
return fmt.Errorf("internal system error")
}
if errors.Is(origErr, context.Canceled) {
return origErr
}
if errors.Is(origErr, context.DeadlineExceeded) {
return origErr
}
if origErr.Error() == "pq: canceling statement due to user request" {
return origErr
}
stack := make([]byte, 32768) // 32 KiB
i := runtime.Stack(stack, false)
log.Println(origErr.Error())
log.Println(string(stack[:i]))
if debug {
return fmt.Errorf("internal system error")
}
to, ok := config.Get("mail", "error-to")
if !ok {
return fmt.Errorf("internal system error")
}
from, _ := config.Get("mail", "error-from")
m := gomail.NewMessage()
sender, err := mail.ParseAddress(from)
if err != nil {
log.Fatalf("Failed to parse sender address")
}
m.SetAddressHeader("From", sender.Address, sender.Name)
recipient, err := mail.ParseAddress(to)
if err != nil {
log.Fatalf("Failed to parse recipient address")
}
m.SetAddressHeader("To", recipient.Address, recipient.Name)
m.SetHeader("Subject", fmt.Sprintf(
"[%s] GraphQL query error: %v", srv, origErr))
quser := auth.ForContext(ctx)
octx := graphql.GetOperationContext(ctx)
m.SetBody("text/plain", fmt.Sprintf(`Error occured processing GraphQL request:
%v
When running the following query on behalf of %s <%s>:
%s
The following stack trace was produced:
%s`, origErr, quser.Username, quser.Email, octx.RawQuery, string(stack[:i])))
email.Enqueue(ctx, m)
return fmt.Errorf("internal system error")
}
}