Skip to content

Commit

Permalink
viewer has been extracted, but still depends on internal svelte rende…
Browse files Browse the repository at this point in the history
…ring
  • Loading branch information
matthewmueller committed Jul 23, 2022
1 parent 297986c commit 28d36a0
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 10 deletions.
51 changes: 46 additions & 5 deletions example/basic/viewer/svelte/svelte.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ import (
"fmt"
"io/fs"
"net/http"
"strings"

"github.com/livebud/bud/framework/view/ssr"
"github.com/livebud/bud/package/js"
"github.com/livebud/bud/package/router"
)

func New(fsys fs.FS, vm js.VM) *Viewer {
return &Viewer{fsys, vm}
return &Viewer{fsys, http.FS(fsys), vm}
}

type Viewer struct {
fsys fs.FS
hfs http.FileSystem
vm js.VM
}

Expand All @@ -41,10 +44,48 @@ func (v *Viewer) Render(w http.ResponseWriter, viewPath string, props interface{
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Println("got result", result)
return
// Unmarshal the response
res := new(ssr.Response)
if err := json.Unmarshal([]byte(result), res); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if res.Status < 100 || res.Status > 999 {
err := fmt.Errorf("view: invalid status code %d", res.Status)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
headers := w.Header()
for key, value := range res.Headers {
headers.Set(key, value)
}
w.WriteHeader(res.Status)
w.Write([]byte(res.Body))
}

func (v *Viewer) Serve(router *router.Router) {
router.Get("/bud/view/:path*", http.HandlerFunc(v.serveClient))
router.Get("/bud/node_modules/:path*", http.HandlerFunc(v.serveClient))
}

func (v *Viewer) Serve(r *router.Router) {
// Serving files!
func (v *Viewer) serveClient(w http.ResponseWriter, r *http.Request) {
file, err := v.hfs.Open(r.URL.Path)
if err != nil {
// TODO: swap with logger
fmt.Println("view: open error", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
stat, err := file.Stat()
if err != nil {
// TODO: swap with logger
fmt.Println("view: stat error", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Maintain support to resolve and run "/bud/node_modules/livebud/runtime".
if strings.HasPrefix(r.URL.Path, "/bud/node_modules/") {
w.Header().Add("Content-Type", "text/javascript")
}
http.ServeContent(w, r, r.URL.Path, stat.ModTime(), file)
}
2 changes: 1 addition & 1 deletion framework/controller/controller.gotext
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type {{ $.Pascal }}Controller struct {
// {{ $.Pascal }}{{$action.Pascal}}Action struct
type {{ $.Pascal }}{{$action.Pascal}}Action struct {
{{- if $action.View }}
View view.Server
{{/* View view.Server */}}
Viewer view.Viewer
{{- end }}
{{- with $provider := $action.Provider }}
Expand Down
7 changes: 5 additions & 2 deletions framework/web/web.gotext
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,19 @@ func New(
router.{{ $action.Method }}(`{{ $action.Route }}`, controller.{{ $action.CallName }})
{{- end }}
{{- end }}
{{- if $.HasView }}
viewer.Serve(router)
{{- end }}
// Compose the middleware together
middleware := middleware.Compose(
middleware.MethodOverride(),
router,
{{- if $.ShowWelcome }}
welcome,
{{- end }}
{{- if $.HasView }}
{{/* {{- if $.HasView }}
view,
{{- end }}
{{- end }} */}}
{{- if $.HasPublic }}
public,
{{- end }}
Expand Down
26 changes: 24 additions & 2 deletions package/budclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,30 @@ func (c *client) Script(path, script string) error {
return fmt.Errorf("budclient: script not implemented yet")
}

func (c *client) Eval(path, expression string) (string, error) {
return "", fmt.Errorf("budclient: eval not implemented yet")
type JS struct {
Path string
Expr string
}

func (c *client) Eval(name, expr string) (string, error) {
body, err := json.Marshal(JS{name, expr})
if err != nil {
return "", err
}
url := c.baseURL + "/eval"
res, err := c.httpClient.Post(url, "application/json", bytes.NewReader(body))
if err != nil {
return "", err
}
defer res.Body.Close()
resBody, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
if res.StatusCode != http.StatusOK {
return "", fmt.Errorf("budclient: eval returned unexpected %d. %s", res.StatusCode, resBody)
}
return string(resBody), nil
}

// Render a path with props on the dev server
Expand Down
23 changes: 23 additions & 0 deletions package/budserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func New(fsys fs.FS, bus pubsub.Client, log log.Interface, vm js.VM) *Server {
router.Post("/bud/events", http.HandlerFunc(server.createEvent))
// Open a file
router.Get("/open/:path*", http.HandlerFunc(server.openFile))
// Eval some JS
router.Post("/eval", http.HandlerFunc(server.evalJS))
return server
}

Expand Down Expand Up @@ -145,6 +147,27 @@ func (s *Server) openFile(w http.ResponseWriter, r *http.Request) {
s.log.Debug("devserver: opened", "file", filePath)
}

func (s *Server) evalJS(w http.ResponseWriter, r *http.Request) {
s.log.Debug("devserver: evaling")
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
var input budclient.JS
if err := json.Unmarshal(body, &input); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
result, err := s.vm.Eval(input.Path, input.Expr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Write([]byte(result))
s.log.Debug("devserver: evaled")
}

func (s *Server) createEvent(w http.ResponseWriter, r *http.Request) {
// Read the body
body, err := io.ReadAll(r.Body)
Expand Down

0 comments on commit 28d36a0

Please sign in to comment.