From 44e7e634eb7c92b2187ca90975c67fa464183e19 Mon Sep 17 00:00:00 2001
From: ernest micklei
Date: Thu, 25 Sep 2025 12:49:54 +0200
Subject: [PATCH 01/11] initial
---
service.go | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/service.go b/service.go
index 07b0852..7fe0011 100644
--- a/service.go
+++ b/service.go
@@ -44,6 +44,7 @@ func (s *service) init() {
type service struct {
explorer *explorer
indexTemplate *template.Template
+ httpServer *http.Server
}
// NewService creates a new to explore one or more values (structures).
@@ -53,6 +54,36 @@ func NewService(labelValuePairs ...any) Service {
return s
}
+// Break will listen and serve on the given http port and path.
+// it accepts 0 or 1 Options to override defaults.
+// The explorer page will have a button "Resume" that stops the server
+// and unblocks the go-routine that started it.
+func (s *service) Break(opts ...Options) {
+ if len(opts) > 0 {
+ s.explorer.options = &opts[0]
+ }
+ port := s.explorer.options.httpPort()
+ serveMux := s.explorer.options.serveMux()
+ rootPath := s.explorer.options.rootPath()
+ serveMux.Handle(rootPath, s)
+ server := &http.Server{
+ Addr: fmt.Sprintf(":%d", port),
+ Handler: serveMux,
+ }
+ s.httpServer = server
+ if err := server.ListenAndServe(); err != nil {
+ slog.Error("[structexplorer] failed to start service", "err", err)
+ }
+}
+
+func (s *service) resume() {
+ if s.httpServer == nil {
+ return
+ }
+ s.httpServer.Close()
+ s.httpServer = nil
+}
+
// Start will listen and serve on the given http port and path.
// it accepts 0 or 1 Options to override defaults.
func (s *service) Start(opts ...Options) {
@@ -64,7 +95,7 @@ func (s *service) Start(opts ...Options) {
rootPath := s.explorer.options.rootPath()
slog.Info(fmt.Sprintf("starting go struct explorer at http://localhost:%d%s on %v", port, rootPath, s.explorer.rootKeys()))
serveMux.Handle(rootPath, s)
- if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
+ if err := http.ListenAndServe(fmt.Sprintf(":%d", port), serveMux); err != nil {
slog.Error("[structexplorer] failed to start service", "err", err)
}
}
@@ -204,6 +235,10 @@ func (s *service) serveInstructions(w http.ResponseWriter, r *http.Request) {
case "clear":
s.explorer.removeNonRootObjects()
return
+ case "resume":
+ s.resume()
+ return
+
default:
slog.Warn("[structexplorer] invalid direction", "action", cmd.Action)
http.Error(w, "invalid action", http.StatusBadRequest)
From 8162b3ae92c020f03e5ecee89ac9a06e06305218 Mon Sep 17 00:00:00 2001
From: ernest micklei
Date: Thu, 25 Sep 2025 14:44:41 +0200
Subject: [PATCH 02/11] add example break
---
examples/break/main_test.go | 18 ++++++++++++++++++
index_tmpl.html | 3 +++
open.go | 21 +++++++++++++++++++++
script.js | 14 ++++++++++++--
service.go | 12 ++++++++----
5 files changed, 62 insertions(+), 6 deletions(-)
create mode 100644 examples/break/main_test.go
create mode 100644 open.go
diff --git a/examples/break/main_test.go b/examples/break/main_test.go
new file mode 100644
index 0000000..4665051
--- /dev/null
+++ b/examples/break/main_test.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "log"
+ "testing"
+
+ "github.com/emicklei/structexplorer"
+)
+
+func TestWithBreak(t *testing.T) {
+ target := struct{ Field string }{Field: "hello"}
+
+ log.Println("before opening the explorer to see state")
+
+ structexplorer.NewService("debugging", target).Break()
+
+ log.Println("after opening the explorer to see state")
+}
diff --git a/index_tmpl.html b/index_tmpl.html
index 0503364..c5f85af 100644
--- a/index_tmpl.html
+++ b/index_tmpl.html
@@ -121,6 +121,9 @@
🔄
+