Skip to content

Commit

Permalink
added server handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
stackdump committed Jan 28, 2024
1 parent 2d78538 commit 05aa4ee
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 27 deletions.
6 changes: 3 additions & 3 deletions image/svg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (
const sampleUrl = "UEsDBAoAAAAAAGMXNlhs0OtB1wwAANcMAAAKAAAAbW9kZWwuanNvbnsKICAibW9kZWxUeXBlIjogInBldHJpTmV0IiwKICAidmVyc2lvbiI6ICJ2MCIsCiAgInBsYWNlcyI6IHsKICAgICJyaWdodDIiOiB7ICJvZmZzZXQiOiAwLCAieCI6IDgxMCwgInkiOiAxNDkgfSwKICAgICJsZWZ0MiI6IHsgIm9mZnNldCI6IDEsICJ4IjogOTQyLCAieSI6IDE1MyB9LAogICAgInJpZ2h0MyI6IHsgIm9mZnNldCI6IDIsICJ4IjogMTE4MiwgInkiOiAyMTggfSwKICAgICJsZWZ0MyI6IHsgIm9mZnNldCI6IDMsICJ4IjogMTI2MCwgInkiOiAzMzkgfSwKICAgICJyaWdodDQiOiB7ICJvZmZzZXQiOiA0LCAieCI6IDExNjksICJ5IjogNzQ0IH0sCiAgICAibGVmdDQiOiB7ICJvZmZzZXQiOiA1LCAieCI6IDEwODIsICJ5IjogODQzIH0sCiAgICAicmlnaHQ1IjogeyAib2Zmc2V0IjogNiwgIngiOiA2MzAsICJ5IjogODU2IH0sCiAgICAibGVmdDUiOiB7ICJvZmZzZXQiOiA3LCAieCI6IDUzMSwgInkiOiA3MjggfSwKICAgICJyaWdodDEiOiB7ICJvZmZzZXQiOiA4LCAieCI6IDQ0MSwgInkiOiAzNTkgfSwKICAgICJsZWZ0MSI6IHsgIm9mZnNldCI6IDksICJ4IjogNTAxLCAieSI6IDI0NCB9LAogICAgImNob3BzdGljazEiOiB7ICJvZmZzZXQiOiAxMCwgImluaXRpYWwiOiAxLCAieCI6IDgxMSwgInkiOiA0MjYgfSwKICAgICJjaG9wc3RpY2syIjogeyAib2Zmc2V0IjogMTEsICJpbml0aWFsIjogMSwgIngiOiA5MzEsICJ5IjogNDM0IH0sCiAgICAiY2hvcHN0aWNrMyI6IHsgIm9mZnNldCI6IDEyLCAiaW5pdGlhbCI6IDEsICJ4IjogOTY5LCAieSI6IDU0NSB9LAogICAgImNob3BzdGljazQiOiB7ICJvZmZzZXQiOiAxMywgImluaXRpYWwiOiAxLCAieCI6IDg2MywgInkiOiA2MTQgfSwKICAgICJjaG9wc3RpY2s1IjogeyAib2Zmc2V0IjogMTQsICJpbml0aWFsIjogMSwgIngiOiA3NzQsICJ5IjogNTM2IH0KICB9LAogICJ0cmFuc2l0aW9ucyI6IHsKICAgICJlYXQxIjogeyAieCI6IDYxMCwgInkiOiAzNzAgfSwKICAgICJ0aGluazEiOiB7ICJ4IjogMzcyLCAieSI6IDI0NyB9LAogICAgImVhdDIiOiB7ICJ4IjogODc0LCAieSI6IDI4MSB9LAogICAgInRoaW5rMiI6IHsgIngiOiA4NzYsICJ5IjogNDIgfSwKICAgICJlYXQzIjogeyAieCI6IDExMTUsICJ5IjogMzQ4IH0sCiAgICAidGhpbmszIjogeyAieCI6IDEzMDksICJ5IjogMjE1IH0sCiAgICAiZWF0NCI6IHsgIngiOiAxMDM0LCAieSI6IDY5MSB9LAogICAgInRoaW5rNCI6IHsgIngiOiAxMjI3LCAieSI6IDg5NiB9LAogICAgImVhdDUiOiB7ICJ4IjogNjczLCAieSI6IDY4OCB9LAogICAgInRoaW5rNSI6IHsgIngiOiA0ODMsICJ5IjogODg3IH0KICB9LAogICJhcmNzIjogWwogICAgeyAic291cmNlIjogImNob3BzdGljazEiLCAidGFyZ2V0IjogImVhdDEiIH0sCiAgICB7ICJzb3VyY2UiOiAiY2hvcHN0aWNrNSIsICJ0YXJnZXQiOiAiZWF0MSIgfSwKICAgIHsgInNvdXJjZSI6ICJlYXQxIiwgInRhcmdldCI6ICJsZWZ0MSIgfSwKICAgIHsgInNvdXJjZSI6ICJlYXQxIiwgInRhcmdldCI6ICJyaWdodDEiIH0sCiAgICB7ICJzb3VyY2UiOiAiZWF0MiIsICJ0YXJnZXQiOiAicmlnaHQyIiB9LAogICAgeyAic291cmNlIjogImVhdDIiLCAidGFyZ2V0IjogImxlZnQyIiB9LAogICAgeyAic291cmNlIjogImNob3BzdGljazEiLCAidGFyZ2V0IjogImVhdDIiIH0sCiAgICB7ICJzb3VyY2UiOiAiY2hvcHN0aWNrMiIsICJ0YXJnZXQiOiAiZWF0MiIgfSwKICAgIHsgInNvdXJjZSI6ICJjaG9wc3RpY2syIiwgInRhcmdldCI6ICJlYXQzIiB9LAogICAgeyAic291cmNlIjogImNob3BzdGljazMiLCAidGFyZ2V0IjogImVhdDMiIH0sCiAgICB7ICJzb3VyY2UiOiAiZWF0MyIsICJ0YXJnZXQiOiAicmlnaHQzIiB9LAogICAgeyAic291cmNlIjogImVhdDMiLCAidGFyZ2V0IjogImxlZnQzIiB9LAogICAgeyAic291cmNlIjogImNob3BzdGljazMiLCAidGFyZ2V0IjogImVhdDQiIH0sCiAgICB7ICJzb3VyY2UiOiAiY2hvcHN0aWNrNCIsICJ0YXJnZXQiOiAiZWF0NCIgfSwKICAgIHsgInNvdXJjZSI6ICJlYXQ0IiwgInRhcmdldCI6ICJsZWZ0NCIgfSwKICAgIHsgInNvdXJjZSI6ICJlYXQ0IiwgInRhcmdldCI6ICJyaWdodDQiIH0sCiAgICB7ICJzb3VyY2UiOiAidGhpbms0IiwgInRhcmdldCI6ICJjaG9wc3RpY2s0IiB9LAogICAgeyAic291cmNlIjogInRoaW5rNCIsICJ0YXJnZXQiOiAiY2hvcHN0aWNrMyIgfSwKICAgIHsgInNvdXJjZSI6ICJyaWdodDQiLCAidGFyZ2V0IjogInRoaW5rNCIgfSwKICAgIHsgInNvdXJjZSI6ICJsZWZ0NCIsICJ0YXJnZXQiOiAidGhpbms0IiB9LAogICAgeyAic291cmNlIjogImNob3BzdGljazUiLCAidGFyZ2V0IjogImVhdDUiIH0sCiAgICB7ICJzb3VyY2UiOiAiY2hvcHN0aWNrNCIsICJ0YXJnZXQiOiAiZWF0NSIgfSwKICAgIHsgInNvdXJjZSI6ICJlYXQ1IiwgInRhcmdldCI6ICJsZWZ0NSIgfSwKICAgIHsgInNvdXJjZSI6ICJlYXQ1IiwgInRhcmdldCI6ICJyaWdodDUiIH0sCiAgICB7ICJzb3VyY2UiOiAidGhpbms1IiwgInRhcmdldCI6ICJjaG9wc3RpY2s1IiB9LAogICAgeyAic291cmNlIjogInRoaW5rNSIsICJ0YXJnZXQiOiAiY2hvcHN0aWNrNCIgfSwKICAgIHsgInNvdXJjZSI6ICJsZWZ0NSIsICJ0YXJnZXQiOiAidGhpbms1IiB9LAogICAgeyAic291cmNlIjogInJpZ2h0NSIsICJ0YXJnZXQiOiAidGhpbms1IiB9LAogICAgeyAic291cmNlIjogImxlZnQxIiwgInRhcmdldCI6ICJ0aGluazEiIH0sCiAgICB7ICJzb3VyY2UiOiAicmlnaHQxIiwgInRhcmdldCI6ICJ0aGluazEiIH0sCiAgICB7ICJzb3VyY2UiOiAidGhpbmsyIiwgInRhcmdldCI6ICJjaG9wc3RpY2sxIiB9LAogICAgeyAic291cmNlIjogInRoaW5rMiIsICJ0YXJnZXQiOiAiY2hvcHN0aWNrMiIgfSwKICAgIHsgInNvdXJjZSI6ICJ0aGluazEiLCAidGFyZ2V0IjogImNob3BzdGljazEiIH0sCiAgICB7ICJzb3VyY2UiOiAidGhpbmsxIiwgInRhcmdldCI6ICJjaG9wc3RpY2s1IiB9LAogICAgeyAic291cmNlIjogInJpZ2h0MyIsICJ0YXJnZXQiOiAidGhpbmszIiB9LAogICAgeyAic291cmNlIjogImxlZnQzIiwgInRhcmdldCI6ICJ0aGluazMiIH0sCiAgICB7ICJzb3VyY2UiOiAidGhpbmszIiwgInRhcmdldCI6ICJjaG9wc3RpY2syIiB9LAogICAgeyAic291cmNlIjogInRoaW5rMyIsICJ0YXJnZXQiOiAiY2hvcHN0aWNrMyIgfSwKICAgIHsgInNvdXJjZSI6ICJyaWdodDIiLCAidGFyZ2V0IjogInRoaW5rMiIgfSwKICAgIHsgInNvdXJjZSI6ICJsZWZ0MiIsICJ0YXJnZXQiOiAidGhpbmsyIiB9CiAgXQp9UEsBAhQACgAAAAAAYxc2WGzQ60HXDAAA1wwAAAoAAAAAAAAAAAAAAAAAAAAAAG1vZGVsLmpzb25QSwUGAAAAAAEAAQA4AAAA/wwAAAAA"

func TestNewSvg(t *testing.T) {

// Load a model from a URL
m := new(model.Model)
m.Base64GzippedJson = sampleUrl
zm := new(model.Zblob)
zm.Base64Zipped = sampleUrl
m := zm.ToModel()
_, mm := m.MetaModel()
x1, y1, width, height := mm.GetViewPort()
i := image.NewSvgFile("/tmp/test.svg", width, height, x1, y1, width, height)
Expand Down
63 changes: 39 additions & 24 deletions model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ import (
"time"
)

// Zblob is a data wrapper for encapsulating a model
type Zblob struct {
ID int64 `json:"-"`
IpfsCid string `json:"cid"`
Base64Zipped string `json:"data"`
Title string `json:"title"`
Description string `json:"description"`
Keywords string `json:"keywords"`
Referer string `json:"-"`
CreatedAt time.Time `json:"created"`
}

type Model struct {
ID int `json:"id"`
IpfsCid string `json:"cid"`
Referer string `json:"-"`
Base64GzippedJson string `json:"data"`
Title string `json:"title"`
Description string `json:"description"`
Keywords string `json:"keywords"`
CreatedAt time.Time `json:"created"`
PublishedAt time.Time `json:"published"`
*Zblob
}

type Document struct {
Expand All @@ -24,32 +28,43 @@ type Document struct {
Description string `json:"description"`
Keywords string `json:"keywords"`
Declaration metamodel.DeclarationObject `json:"declaration"`
PublishedAt time.Time `json:"published"`
}

func (d Document) Cid() string {
return codec.ToOid(codec.Marshal(d)).String()
}

func (m *Model) ToDocument() Document {
func getMetaModel(data string) metamodel.MetaModel {
mm := metamodel.New()
_, ok := mm.UnpackFromUrl("?z="+m.Base64GzippedJson, "model.json")
_, ok := mm.UnpackFromUrl("?z="+data, "model.json")
if !ok {
panic("Failed to unzip model")
}
return mm
}

func assertValid(data string) {
_ = getMetaModel(data)
}

func (z *Zblob) ToModel() Model {
assertValid(z.Base64Zipped)
return Model{Zblob: z}
}
func (z *Zblob) ToDocument() Document {
mm := getMetaModel(z.Base64Zipped)
return Document{
ModelCid: m.IpfsCid,
Title: m.Title,
Description: m.Description,
Keywords: m.Keywords,
ModelCid: z.IpfsCid,
Title: z.Title,
Description: z.Description,
Keywords: z.Keywords,
Declaration: mm.ToDeclarationObject(),
PublishedAt: m.PublishedAt,
}
}

func (d Document) Cid() string {
return codec.ToOid(codec.Marshal(d)).String()
}

func (m *Model) MetaModel() (string, metamodel.MetaModel) {
mm := metamodel.New()
jsonData, ok := mm.UnpackFromUrl("?z="+m.Base64GzippedJson, "model.json")
jsonData, ok := mm.UnpackFromUrl("?z="+m.Base64Zipped, "model.json")
if !ok {
panic("Failed to unzip model")
}
Expand All @@ -60,6 +75,6 @@ func (m *Model) Declare(args ...func(metamodel.Declaration)) {
mm := metamodel.New()
mm.Define(args...)
url, _ := mm.ZipUrl()
m.Base64GzippedJson = url[3:]
m.IpfsCid = codec.ToOid(codec.Marshal(m.Base64GzippedJson)).String()
m.Base64Zipped = url[3:]
m.IpfsCid = codec.ToOid(codec.Marshal(m.Base64Zipped)).String()
}
134 changes: 134 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package server

import (
"encoding/json"
"github.com/pflow-dev/go-metamodel/v2/image"
"github.com/pflow-dev/go-metamodel/v2/metamodel"
"github.com/pflow-dev/go-metamodel/v2/model"
"html/template"
"net/http"
)

type HandlerWithVars = func(vars map[string]string, w http.ResponseWriter, r *http.Request)

type VarsFactory = func(r *http.Request) map[string]string

func WithVars(handler HandlerWithVars, getVarsFunc VarsFactory) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
handler(getVarsFunc(r), w, r)
}
}

type BlobAccessor interface {
Get(id int64) *model.Zblob
GetByCid(cid string) *model.Zblob
GetMaxId() int64
Create(ipfsCid, base64Zipped, title, description, keywords, referrer string) (int64, error)
}
type Storage struct {
Model BlobAccessor
Snippet BlobAccessor
}

type Service interface {
IndexPage() *template.Template
SandboxPage() *template.Template
Event(eventType string, params map[string]interface{})
GetState(r *http.Request) (state metamodel.Vector, ok bool)
CheckForSnippet(hostname string, url string, referrer string) (string, bool)
CheckForModel(hostname string, url string, referrer string) (string, bool)
}
type App struct {
Service
Storage
}

func (app *App) AppPage(vars map[string]string, w http.ResponseWriter, r *http.Request) {
cid, found := app.CheckForModel(r.Host, r.URL.String(), r.Header.Get("Referer"))
if found {
http.Redirect(w, r, "/p/"+cid+"/", http.StatusFound)
return
}
m := model.Model{}
if vars["pflowCid"] != "" {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
m = app.Storage.Model.GetByCid(vars["pflowCid"]).ToModel()
if m.ID != 0 && m.IpfsCid == vars["pflowCid"] {
m.MetaModel()
}
}
_ = app.IndexPage().ExecuteTemplate(w, "index.html", m)
}

func (app *App) SvgHandler(vars map[string]string, w http.ResponseWriter, r *http.Request) {
cid, found := app.CheckForModel(r.Host, r.URL.String(), r.Header.Get("Referer"))
if found {
http.Redirect(w, r, "/img/"+cid+".svg", http.StatusFound)
return
}
if vars["pflowCid"] == "" {
return
}
w.Header().Set("Content-Type", "image/svg+xml ; charset=utf-8")
m := app.Storage.Model.GetByCid(vars["pflowCid"]).ToModel()
_, mm := m.MetaModel()
if m.IpfsCid != vars["pflowCid"] {
return
}
app.Event("viewSvg", map[string]interface{}{
"id": m.ID,
"ipfsCid": m.IpfsCid,
})
x1, y1, width, height := mm.GetViewPort()
i := image.NewSvg(w, width, height, x1, y1, width, height)

state, stateOk := app.GetState(r)
if !stateOk || len(state) != len(mm.Net().Places) {
state = mm.Net().InitialVector()
}
i.Render(mm, state)
}

func (app *App) JsonHandler(vars map[string]string, w http.ResponseWriter, r *http.Request) {
mm := metamodel.New()
cid, found := app.CheckForModel(r.Host, r.URL.String(), r.Header.Get("Referer"))
if found {
http.Redirect(w, r, "/src/"+cid+".json", http.StatusFound)
} else if vars["pflowCid"] != "" {
m := app.Storage.Model.GetByCid(vars["pflowCid"])
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
mm.UnpackFromUrl("?z="+m.Base64Zipped, "model.json")
app.Event("viewJson", map[string]interface{}{
"id": m.ID,
"ipfsCid": m.IpfsCid,
})
data, _ := json.MarshalIndent(mm.ToDeclarationObject(), "", " ")
_, err := w.Write(data)
if err != nil {
panic(err)
}
}
}

func (app *App) SandboxHandler(vars map[string]string, w http.ResponseWriter, r *http.Request) {
cid, found := app.CheckForSnippet(r.Host, r.URL.String(), r.Header.Get("Referer"))
if found {
http.Redirect(w, r, "/sandbox/"+cid+"/", http.StatusFound)
} else if vars["pflowCid"] != "" {
rec := app.Storage.Snippet.GetByCid(vars["pflowCid"])
sourceCode, ok := metamodel.UnzipUrl("?z="+rec.Base64Zipped, "declaration.js")
if !ok {
http.Error(w, "Failed to unzip snippet", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
templateData := struct {
IpfsCid string
SourceCode string
}{
IpfsCid: vars["pflowCid"],
SourceCode: sourceCode,
}
_ = app.SandboxPage().ExecuteTemplate(w, "index.html", templateData)
}
}

0 comments on commit 05aa4ee

Please sign in to comment.