62 lines
1.2 KiB
Go
62 lines
1.2 KiB
Go
package console
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/signal"
|
|
"time"
|
|
)
|
|
|
|
type C[A any] struct {
|
|
io.Reader
|
|
io.Writer
|
|
err io.Writer
|
|
args A
|
|
abort func()
|
|
cancelfns []func(context.Context) error
|
|
}
|
|
|
|
func New[A any](args A) (context.Context, *C[A]) {
|
|
ctx := context.Background()
|
|
ctx, abort := context.WithCancel(ctx)
|
|
ctx, stop := signal.NotifyContext(ctx, os.Interrupt)
|
|
go func() { <-ctx.Done(); stop() }() // restore interrupt function
|
|
|
|
console := &C[A]{Reader: os.Stdin, Writer: os.Stdout, err: os.Stderr, args: args, abort: abort}
|
|
return ctx, console
|
|
}
|
|
|
|
func (c *C[A]) Args() A {
|
|
return c.args
|
|
}
|
|
func (c *C[A]) Shutdown() error {
|
|
fmt.Fprintln(c.err, "shutting down ", len(c.cancelfns), " cancel functions...")
|
|
defer fmt.Fprintln(c.err, "done")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
c.abort()
|
|
var err error
|
|
for _, fn := range c.cancelfns {
|
|
err = errors.Join(err, fn(ctx))
|
|
}
|
|
return err
|
|
}
|
|
func (c *C[A]) AddCancel(fn func(context.Context) error) { c.cancelfns = append(c.cancelfns, fn) }
|
|
|
|
func (c *C[A]) IfFatal(err error) {
|
|
if err == nil {
|
|
return
|
|
}
|
|
fmt.Fprintln(c.err, err)
|
|
err = c.Shutdown()
|
|
if err != nil {
|
|
fmt.Fprintln(c.err, err)
|
|
}
|
|
os.Exit(1)
|
|
}
|