Update comments and documentation for Golang SDK (#827)
* externalize interface compatibility for two optional template engines Templ and GoStar are currently module dependencies for Golang SDK. They should not be required for 1.0 release. This step replaces two component interfaces with copies that ensure compatibility without having to include various optional engines as dependencies with each Datastar deployment. * update comments and documentation for Golang SDK Added comments to `execute.go` file. I will make similar changes to other files. I submit those as a way of getting feedback. The only public API change is the removal of execute script options struct. It is changed to private by letter case because the options pattern is used to configure script execution. The struct serves no purpose and pollutes the public API.
This commit is contained in:
parent
5a894a0139
commit
686d12ad2a
108
sdk/go/README.md
108
sdk/go/README.md
|
@ -1,89 +1,87 @@
|
|||
# Go SDK for Datastar
|
||||
|
||||
[](https://pkg.go.dev/github.com/starfederation/datastar)
|
||||
[](https://pkg.go.dev/github.com/starfederation/datastar)
|
||||
|
||||
Implements the [SDK spec](../README.md) and exposes an abstract
|
||||
ServerSentEventGenerator struct that can be used to implement runtime specific
|
||||
classes.
|
||||
|
||||
Usage is straightforward:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
datastar "github.com/starfederation/datastar/sdk/go"
|
||||
datastar "github.com/starfederation/datastar/sdk/go"
|
||||
)
|
||||
|
||||
const port = 9001
|
||||
|
||||
func main() {
|
||||
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
||||
mux := http.NewServeMux()
|
||||
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
||||
mux := http.NewServeMux()
|
||||
|
||||
cdn := "https://cdn.jsdelivr.net/gh/starfederation/datastar@develop/bundles/datastar.js"
|
||||
style := "display:flex;flex-direction:column;background-color:oklch(25.3267% 0.015896
|
||||
252.417568);height:100vh;justify-content:center;align-items:center;font-family:ui-sans-serif, system-ui, sans-serif,
|
||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';"
|
||||
cdn := "https://cdn.jsdelivr.net/gh/starfederation/datastar@develop/bundles/datastar.js"
|
||||
style := "display:flex;flex-direction:column;background-color:oklch(25.3267% 0.015896 252.417568);height:100vh;justify-content:center;align-items:center;font-family:ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';"
|
||||
|
||||
page := []byte(fmt.Sprintf(`
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
page := []byte(fmt.Sprintf(`
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||
<script type="module" defer src="%s"></script>
|
||||
</head>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||
<script type="module" defer src="%s"></script>
|
||||
</head>
|
||||
|
||||
<body style="%s">
|
||||
<span id="feed" data-on-load="%s"></span>
|
||||
</body>
|
||||
<body style="%s">
|
||||
<span id="feed" data-on-load="%s"></span>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
`, cdn, style, datastar.GetSSE("/stream")))
|
||||
</html>
|
||||
`, cdn, style, datastar.GetSSE("/stream")))
|
||||
|
||||
mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(page)
|
||||
})
|
||||
mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(page)
|
||||
})
|
||||
|
||||
mux.HandleFunc("GET /stream", func(w http.ResponseWriter, r *http.Request) {
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
mux.HandleFunc("GET /stream", func(w http.ResponseWriter, r *http.Request) {
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
sse := datastar.NewSSE(w, r)
|
||||
sse := datastar.NewSSE(w, r)
|
||||
for {
|
||||
select {
|
||||
case <-r.Context().Done():
|
||||
logger.Debug("Client connection closed")
|
||||
return
|
||||
case <-ticker.C:
|
||||
bytes := make([]byte, 3)
|
||||
|
||||
for {
|
||||
select {
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
logger.Error("Error generating random bytes: ", slog.String("error", err.Error()))
|
||||
return
|
||||
}
|
||||
hexString := hex.EncodeToString(bytes)
|
||||
frag := fmt.Sprintf(`<span id="feed" style="color:#%s;border:1px solid #%s;border-radius:0.25rem;padding:1rem;">%s</span>`, hexString, hexString, hexString)
|
||||
|
||||
case <-r.Context().Done(): logger.Debug("Client connection closed") return case <-ticker.C: bytes :=make([]byte, 3) _,
|
||||
err :=rand.Read(bytes) if err !=nil { logger.Error("Error generating random bytes: ", slog.String(" error",
|
||||
err.Error())) return } hexString :=hex.EncodeToString(bytes) frag :=fmt.Sprintf(`<span id="feed"
|
||||
style="color:#%s;border:1px solid #%s;border-radius:0.25rem;padding:1rem;">%s</span>`, hexString, hexString,
|
||||
hexString)
|
||||
|
||||
sse.MergeFragments(frag)
|
||||
}
|
||||
}
|
||||
sse.MergeFragments(frag)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
logger.Info(fmt.Sprintf("Server starting at 0.0.0.0:%d", port))
|
||||
if err := http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", port), mux); err != nil {
|
||||
logger.Error("Error starting server:", slog.String("error", err.Error()))
|
||||
logger.Error("Error starting server:", slog.String("error", err.Error()))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
}
|
||||
```
|
||||
## Examples
|
||||
|
||||
## Examples
|
||||
|
||||
The [Datastar website](https://data-star.dev) acts as a [set of
|
||||
examples](https://github.com/starfederation/datastar/tree/develop/site) for how to use the SDK.
|
||||
The [Datastar website](https://data-star.dev) acts as a [set of examples](https://github.com/starfederation/datastar/tree/develop/site) for how to use the SDK.
|
||||
|
|
|
@ -7,33 +7,48 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type ExecuteScriptOptions struct {
|
||||
// executeScriptOptions hold script options that will be translated to [SSEEventOptions].
|
||||
type executeScriptOptions struct {
|
||||
EventID string
|
||||
RetryDuration time.Duration
|
||||
Attributes []string
|
||||
AutoRemove *bool
|
||||
}
|
||||
|
||||
type ExecuteScriptOption func(*ExecuteScriptOptions)
|
||||
// ExecuteScriptOption configures script execution event that will be sent to the client.
|
||||
type ExecuteScriptOption func(*executeScriptOptions)
|
||||
|
||||
// WithExecuteScriptEventID configures an optional event ID for the script execution event.
|
||||
// The client message field [lastEventId] will be set to this value.
|
||||
// If the next event does not have an event ID, the last used event ID will remain.
|
||||
//
|
||||
// [lastEventId]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/lastEventId
|
||||
func WithExecuteScriptEventID(id string) ExecuteScriptOption {
|
||||
return func(o *ExecuteScriptOptions) {
|
||||
return func(o *executeScriptOptions) {
|
||||
o.EventID = id
|
||||
}
|
||||
}
|
||||
|
||||
// WithExecuteScriptRetryDuration overrides the [DefaultRetryDuration] for this script
|
||||
// execution only.
|
||||
func WithExecuteScriptRetryDuration(retryDuration time.Duration) ExecuteScriptOption {
|
||||
return func(o *ExecuteScriptOptions) {
|
||||
return func(o *executeScriptOptions) {
|
||||
o.RetryDuration = retryDuration
|
||||
}
|
||||
}
|
||||
|
||||
// WithExecuteScriptAttributes overrides the default script attribute
|
||||
// value `type module`, which renders as `<script type="module">` in client's browser.
|
||||
// Each attribute should include a pair of plain words representing the attribute name and value
|
||||
// without any formatting.
|
||||
func WithExecuteScriptAttributes(attributes ...string) ExecuteScriptOption {
|
||||
return func(o *ExecuteScriptOptions) {
|
||||
return func(o *executeScriptOptions) {
|
||||
o.Attributes = attributes
|
||||
}
|
||||
}
|
||||
|
||||
// WithExecuteScriptAttributeKVs is an alternative option for [WithExecuteScriptAttributes].
|
||||
// Even parameters are keys, odd parameters are their values.
|
||||
func WithExecuteScriptAttributeKVs(kvs ...string) ExecuteScriptOption {
|
||||
if len(kvs)%2 != 0 {
|
||||
panic("WithExecuteScriptAttributeKVs requires an even number of arguments")
|
||||
|
@ -46,14 +61,16 @@ func WithExecuteScriptAttributeKVs(kvs ...string) ExecuteScriptOption {
|
|||
return WithExecuteScriptAttributes(attributes...)
|
||||
}
|
||||
|
||||
// WithExecuteScriptAutoRemove requires the client to eliminate the script element after its execution.
|
||||
func WithExecuteScriptAutoRemove(autoremove bool) ExecuteScriptOption {
|
||||
return func(o *ExecuteScriptOptions) {
|
||||
return func(o *executeScriptOptions) {
|
||||
o.AutoRemove = &autoremove
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteScript runs a script in the client browser. Seperate commands with semicolons.
|
||||
func (sse *ServerSentEventGenerator) ExecuteScript(scriptContents string, opts ...ExecuteScriptOption) error {
|
||||
options := &ExecuteScriptOptions{
|
||||
options := &executeScriptOptions{
|
||||
RetryDuration: DefaultSseRetryDuration,
|
||||
Attributes: []string{"type module"},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue