Skip to content

Commit

Permalink
make the service a http.Handler
Browse files Browse the repository at this point in the history
  • Loading branch information
emicklei committed Jun 21, 2024
1 parent 99e54ff commit c1435b2
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 20 deletions.
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@
[![GoDoc](https://pkg.go.dev/badge/github.com/emicklei/structexplorer)](https://pkg.go.dev/github.com/emicklei/structexplorer)
[![codecov](https://codecov.io/gh/emicklei/structexplorer/branch/master/graph/badge.svg)](https://codecov.io/gh/emicklei/structexplorer)

A Go Struct Explorer Service that offers a remote (HTTP) inspection of any Go struct.
A Go Struct Explorer Service (http.Handler) that offers remote inspection of any Go struct and its references.

## install

go get github.com/emicklei/structexplorer

## usage

structexplorer.NewService("some structure", aStruct).Start()
structexplorer.NewService("some structure", yourStruct).Start()

or as HTTP Handler:

s := structexplorer.NewService("some structure", yourStruct)
http.ListenAndServe(":8080", s)

then a HTTP service will be started

Expand All @@ -26,7 +35,12 @@ then a HTTP service will be started
- z : show or hide fields which currently have zero value ("",0,nil,false)
- x : remove the struct from the page

Note: if the list contains just one structural value then selecting it can be skipped for ⇊ and ⇉.

## examples

See folder `examples` for simple programs.

## Example of exploring a [yaegi](https://github.com/traefik/yaegi) program
### example of exploring a [yaegi](https://github.com/traefik/yaegi) program

![program](./doc/explore_yaegi.png "Yaegi explore")
Binary file added doc/testingT.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions examples/handler/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"log"
"net/http"
"time"

"github.com/emicklei/structexplorer"
)

func main() {
log.Println("use service as handler on http://localhost:8080")
http.ListenAndServe(":8080", structexplorer.NewService("test", time.Now()))
}
1 change: 1 addition & 0 deletions examples/inside_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
![test](../doc/testingT.png "explore the tester")
12 changes: 12 additions & 0 deletions examples/inside_test/inside_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"testing"

"github.com/emicklei/structexplorer"
)

func TestExplore(t *testing.T) {
// lets explore the "t" ; do it within 30 seconds before it timeouts
structexplorer.NewService("testing.T", t).Start()
}
9 changes: 5 additions & 4 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function explore(row, column, selectNode, action) {
}
console.log(row, column, selectNode.value, action);
const xhr = new XMLHttpRequest();
xhr.open("POST", instructionURL(window.location.href));
xhr.open("POST", window.location.href);
xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8")
xhr.send(JSON.stringify({
row: row,
Expand All @@ -15,9 +15,6 @@ function explore(row, column, selectNode, action) {
}));
xhr.onload = function () { window.location.reload(); }
}
function instructionURL(href) {
return href.endsWith("/") ? href + "instructions" : href + "/instructions";
}
// Return an array of the selected option values in the control.
// Select is an HTML select element.
function getSelectValues(select) {
Expand All @@ -32,5 +29,9 @@ function getSelectValues(select) {
result.push(opt.value || opt.text);
}
}
if (result.length == 0 && options.length == 1) {
opt = options[0];
result.push(opt.value || opt.text);
}
return result;
}
35 changes: 22 additions & 13 deletions service.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,31 +85,45 @@ type service struct {
indexTemplate *template.Template
}

// Service is the HTTP service to explore one or more values (structures).
// Service is an HTTP Handler to explore one or more values (structures).
type Service interface {
http.Handler
// Start accepts 0 or 1 Options
Start(opts ...Options)
}

// NewService creates a new to explore one or more values (structures).
func NewService(labelValuePairs ...any) Service {
return &service{explorer: newExplorerOnAll(labelValuePairs...)}
s := &service{explorer: newExplorerOnAll(labelValuePairs...)}
s.init()
return s
}

// Start accepts 0 or 1 Options, implements Service
// 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) {
if len(opts) > 0 {
s.explorer.options = &opts[0]
}
s.init()
port := s.explorer.options.httpPort()
serveMux := s.explorer.options.serveMux()
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.HandleFunc(rootPath, s.serveIndex)
serveMux.HandleFunc(path.Join(rootPath, "/instructions"), s.serveInstructions)
serveMux.Handle(rootPath, s)
if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
slog.Error("failed to start server", "err", err)
slog.Error("failed to start service", "err", err)
}
}

// ServeHTTP implements http.Handler
func (s *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
s.serveIndex(w, r)
case http.MethodPost:
s.serveInstructions(w, r)
default:
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
}

Expand All @@ -130,10 +144,6 @@ type uiInstruction struct {
}

func (s *service) serveInstructions(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
cmd := uiInstruction{}
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
Expand All @@ -153,8 +163,7 @@ func (s *service) serveInstructions(w http.ResponseWriter, r *http.Request) {
if s.explorer.canRemoveObjectAt(cmd.Row, cmd.Column) {
s.explorer.removeObjectAt(cmd.Row, cmd.Column)
} else {
o := s.explorer.objectAt(cmd.Row, cmd.Column)
slog.Warn("cannot remove root struct", "object", o.label, "row", cmd.Row, "column", cmd.Column)
slog.Warn("cannot remove root struct", "object", fromAccess.label, "row", cmd.Row, "column", cmd.Column)
}
return
case "toggleZeros":
Expand Down

0 comments on commit c1435b2

Please sign in to comment.