Skip to content

Commit

Permalink
feat(libserver): adding support for web sockets and improving context…
Browse files Browse the repository at this point in the history
… api.
  • Loading branch information
razshare committed Jan 25, 2025
1 parent adffec6 commit f750a77
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 44 deletions.
37 changes: 19 additions & 18 deletions libserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"net/url"
"os"
"path/filepath"
"regexp"
"rogchap.com/v8go"
"strings"
"sync"
Expand Down Expand Up @@ -262,11 +263,6 @@ func ServerTemporaryDirectoryClear(self *Server) {
}
}

// ReceiveParameter reads a path parameter and returns the value.
func ReceiveParameter(self *Request, name string) string {
return self.HttpRequest.PathValue(name)
}

// ReceiveMessage reads the contents of the message and returns the value.
func ReceiveMessage(self *Request) string {
if self.webSocket != nil {
Expand Down Expand Up @@ -335,6 +331,11 @@ func ReceiveQuery(self *Request, name string) string {
return self.HttpRequest.URL.Query().Get(name)
}

// ReceivePath reads a path fields and returns the value.
func ReceivePath(self *Request, name string) string {
return self.HttpRequest.PathValue(name)
}

// ReceiveHeader reads a header field and returns the value.
func ReceiveHeader(self *Request, key string) string {
return self.HttpRequest.Header.Get(key)
Expand Down Expand Up @@ -402,7 +403,7 @@ func ServerStop(self *Server) {
}
}

var sveltePagesToPaths = map[string]string{}
var pathParametersPattern = regexp.MustCompile(`{([^{}]+)}`)

// ServerWithSveltePage creates a request handler that serves a svelte page.
func ServerWithSveltePage(self *Server, pattern string, pageId string, configure func(*Request) *SveltePageConfiguration) {
Expand All @@ -420,8 +421,8 @@ func ServerWithSveltePage(self *Server, pattern string, pageId string, configure
configuration.Globals = map[string]v8go.FunctionCallback{}
}

if nil == configuration.Props {
configuration.Props = map[string]interface{}{}
if nil == configuration.Data {
configuration.Data = map[string]interface{}{}
}

parseMultipartFormError := request.HttpRequest.ParseMultipartForm(1024)
Expand All @@ -436,17 +437,17 @@ func ServerWithSveltePage(self *Server, pattern string, pageId string, configure
}
}

configuration.Globals["query"] = func(info *v8go.FunctionCallbackInfo) *v8go.Value {

return nil
path := map[string]string{}
for _, name := range pathParametersPattern.FindAllStringSubmatch(pattern, -1) {
if len(name) < 1 {
continue
}
path[name[1]] = request.HttpRequest.PathValue(name[1])
}

configuration.Props["pagesToPaths"] = sveltePagesToPaths
configuration.Props["pageId"] = pageId
configuration.Props["query"] = request.HttpRequest.URL.Query()
configuration.Props["form"] = request.HttpRequest.Form

SendSveltePage(response, configuration)
configuration.Data["path"] = path
configuration.Data["query"] = request.HttpRequest.URL.Query()
configuration.Data["form"] = request.HttpRequest.Form
SendSveltePage(response, pageId, configuration)
})
})
})
Expand Down
40 changes: 28 additions & 12 deletions libsvelte.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func SveltePrepareEnd() {
builder.WriteString(fmt.Sprintf(" import %s from '%s'\n", strings.ToUpper(id), fileName))
}
builder.WriteString(" import {setContext} from 'svelte'\n")
builder.WriteString(" let {pageId, pagesToPaths, ...data} = $props()\n")
builder.WriteString(" let {pageId, paths, data} = $props()\n")
builder.WriteString(" let reactiveData = $state({...data})\n")
builder.WriteString(" setContext(\"data\", reactiveData)\n")
builder.WriteString(" setContext(\"page\", page)\n")
Expand Down Expand Up @@ -244,18 +244,30 @@ func render(response *Response, stringProps string, globals map[string]v8go.Func

type SveltePageConfiguration struct {
Render RenderMode
Props map[string]interface{}
Data map[string]interface{}
Globals map[string]v8go.FunctionCallback
}

var sveltePagesToPaths = map[string]string{}

type svelteRouterProps struct {
PageId string `json:"pageId"`
Data map[string]interface{} `json:"data"`
Paths map[string]string `json:"paths"`
}

var noScriptPattern = regexp.MustCompile(`<script.*>.*</script>`)

// SendSveltePage renders and echos a svelte page.
func SendSveltePage(response *Response, configuration *SveltePageConfiguration) {
func SendSveltePage(
response *Response,
pageId string,
configuration *SveltePageConfiguration,
) {
if nil == configuration {
configuration = &SveltePageConfiguration{
Render: ModeFull,
Props: map[string]interface{}{},
Data: map[string]interface{}{},
Globals: map[string]v8go.FunctionCallback{},
}
}
Expand All @@ -280,16 +292,20 @@ func SendSveltePage(response *Response, configuration *SveltePageConfiguration)
indexBytes = indexBytesLocal
}

bytesProps, jsonError := json.Marshal(configuration.Props)
routerPropsBytes, jsonError := json.Marshal(svelteRouterProps{
PageId: pageId,
Data: configuration.Data,
Paths: sveltePagesToPaths,
})
if jsonError != nil {
ServerNotifyError(response.server, jsonError)
return
}
stringProps := string(bytesProps)
routerPropsString := string(routerPropsBytes)

var index string
if ModeFull == configuration.Render {
head, body, renderError := render(response, stringProps, configuration.Globals)
head, body, renderError := render(response, routerPropsString, configuration.Globals)
if renderError != nil {
ServerNotifyError(response.server, renderError)
return
Expand All @@ -313,8 +329,8 @@ func SendSveltePage(response *Response, configuration *SveltePageConfiguration)
),
"<!--app-data-->",
fmt.Sprintf(
`<script type="application/javascript">function data(){return %s}</script>`,
stringProps,
`<script type="application/javascript">function props(){return %s}</script>`,
routerPropsString,
),
1,
)
Expand All @@ -338,13 +354,13 @@ func SendSveltePage(response *Response, configuration *SveltePageConfiguration)
),
"<!--app-data-->",
fmt.Sprintf(
`<script type="application/javascript">function data(){return %s}</script>`,
stringProps,
`<script type="application/javascript">function props(){return %s}</script>`,
routerPropsString,
),
1,
)
} else if ModeServer == configuration.Render {
head, body, renderError := render(response, stringProps, configuration.Globals)
head, body, renderError := render(response, routerPropsString, configuration.Globals)
if renderError != nil {
ServerNotifyError(response.server, renderError)
return
Expand Down
14 changes: 6 additions & 8 deletions libsvelte_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ func TestEchoSveltePageModeServer(test *testing.T) {
test.Fatal(err)
})
ServerWithRequestHandler(server, "GET /", func(server *Server, request *Request, response *Response) {
SendSveltePage(response, &SveltePageConfiguration{
SendSveltePage(response, "welcome", &SveltePageConfiguration{
Render: ModeServer,
Props: map[string]interface{}{
"pageId": "welcome",
"name": "world",
Data: map[string]interface{}{
"name": "world",
},
Globals: map[string]v8go.FunctionCallback{},
})
Expand Down Expand Up @@ -50,11 +49,10 @@ func TestEchoSveltePageModeClient(test *testing.T) {
test.Fatal(err)
})
ServerWithRequestHandler(server, "GET /", func(server *Server, request *Request, response *Response) {
SendSveltePage(response, &SveltePageConfiguration{
SendSveltePage(response, "welcome", &SveltePageConfiguration{
Render: ModeClient,
Props: map[string]interface{}{
"pageId": "welcome",
"name": "world",
Data: map[string]interface{}{
"name": "world",
},
Globals: map[string]v8go.FunctionCallback{},
})
Expand Down
2 changes: 1 addition & 1 deletion vite-project/render.client.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mount } from "svelte";
import RenderClient from "./render.client.svelte";
// @ts-ignore
mount(RenderClient, { target: target(), props: data() });
mount(RenderClient, { target: target(), props: props() });
6 changes: 3 additions & 3 deletions vite-project/render.client.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import Async from './async.svelte'
import {setContext} from "svelte";
let {pageId, pagesToPaths, ...data} = $props()
let {pageId, paths: paths, data} = $props()
let reactivePageId = $state(pageId)
let reactiveData = $state({...data})
setContext("data", reactiveData)
Expand All @@ -13,10 +13,10 @@
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
function page(pageId){
if (!pagesToPaths[pageId]) {
if (!paths[pageId]) {
return
}
let path = pagesToPaths[pageId]
let path = paths[pageId]
const resolved = {}
for(let key in data) {
resolved[key] = false
Expand Down
Loading

0 comments on commit f750a77

Please sign in to comment.