package ui import ( "context" "embed" "fmt" "io/fs" "net/http" "time" "github.com/bettercap/bettercap/v2/session" ) var ( //go:embed ui web embed.FS ) type UIModule struct { session.SessionModule server *http.Server } func NewUIModule(s *session.Session) *UIModule { mod := &UIModule{ SessionModule: session.NewSessionModule("ui", s), server: &http.Server{}, } mod.SessionModule.Requires("api.rest") mod.AddHandler(session.NewModuleHandler("ui on", "", "Start the web user interface.", func(args []string) error { return mod.Start() })) mod.AddHandler(session.NewModuleHandler("ui off", "", "Stop the web user interface.", func(args []string) error { return mod.Stop() })) mod.AddParam(session.NewStringParameter("ui.address", "127.0.0.1", session.IPv4Validator, "Address to bind the web ui to.")) mod.AddParam(session.NewIntParameter("ui.port", "8080", "Port to bind the web ui server to.")) return mod } func (mod *UIModule) Name() string { return "ui" } func (mod *UIModule) Description() string { return "Web User Interface." } func (mod *UIModule) Author() string { return "Simone Margaritelli " } func (mod *UIModule) Configure() (err error) { var ip string var port int if mod.Running() { return session.ErrAlreadyStarted(mod.Name()) } else if err, ip = mod.StringParam("ui.address"); err != nil { return err } else if err, port = mod.IntParam("ui.port"); err != nil { return err } mod.server.Addr = fmt.Sprintf("%s:%d", ip, port) dist, _ := fs.Sub(web, "ui") mod.server.Handler = http.FileServer(http.FS(dist)) return nil } func (mod *UIModule) Start() error { if err := mod.Configure(); err != nil { return err } mod.SetRunning(true, func() { var err error mod.Info("web ui starting on http://%s", mod.server.Addr) err = mod.server.ListenAndServe() if err != nil && err != http.ErrServerClosed { panic(err) } }) return nil } func (mod *UIModule) Stop() error { return mod.SetRunning(false, func() { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() mod.server.Shutdown(ctx) }) }