173 lines
4.6 KiB
Go
173 lines
4.6 KiB
Go
package datastar
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type MergeFragmentOptions struct {
|
|
EventID string
|
|
RetryDuration time.Duration
|
|
Selector string
|
|
MergeMode FragmentMergeMode
|
|
SettleDuration time.Duration
|
|
UseViewTransitions bool
|
|
}
|
|
|
|
type MergeFragmentOption func(*MergeFragmentOptions)
|
|
|
|
func WithSelectorf(selectorFormat string, args ...any) MergeFragmentOption {
|
|
selector := fmt.Sprintf(selectorFormat, args...)
|
|
return WithSelector(selector)
|
|
}
|
|
|
|
func WithSelector(selector string) MergeFragmentOption {
|
|
return func(o *MergeFragmentOptions) {
|
|
o.Selector = selector
|
|
}
|
|
}
|
|
|
|
func WithMergeMode(merge FragmentMergeMode) MergeFragmentOption {
|
|
return func(o *MergeFragmentOptions) {
|
|
o.MergeMode = merge
|
|
}
|
|
}
|
|
|
|
func WithSettleDuration(d time.Duration) MergeFragmentOption {
|
|
return func(o *MergeFragmentOptions) {
|
|
o.SettleDuration = d
|
|
}
|
|
}
|
|
|
|
func WithUseViewTransitions(useViewTransition bool) MergeFragmentOption {
|
|
return func(o *MergeFragmentOptions) {
|
|
o.UseViewTransitions = useViewTransition
|
|
}
|
|
}
|
|
|
|
func (sse *ServerSentEventGenerator) MergeFragments(fragment string, opts ...MergeFragmentOption) error {
|
|
options := &MergeFragmentOptions{
|
|
EventID: "",
|
|
RetryDuration: DefaultSseRetryDuration,
|
|
Selector: "",
|
|
MergeMode: FragmentMergeModeMorph,
|
|
SettleDuration: DefaultFragmentsSettleDuration,
|
|
}
|
|
for _, opt := range opts {
|
|
opt(options)
|
|
}
|
|
|
|
sendOptions := make([]SSEEventOption, 0, 2)
|
|
if options.EventID != "" {
|
|
sendOptions = append(sendOptions, WithSSEEventId(options.EventID))
|
|
}
|
|
if options.RetryDuration > 0 {
|
|
sendOptions = append(sendOptions, WithSSERetryDuration(options.RetryDuration))
|
|
}
|
|
|
|
dataRows := make([]string, 0, 4)
|
|
if options.Selector != "" {
|
|
dataRows = append(dataRows, SelectorDatalineLiteral+options.Selector)
|
|
}
|
|
if options.MergeMode != FragmentMergeModeMorph {
|
|
dataRows = append(dataRows, MergeModeDatalineLiteral+string(options.MergeMode))
|
|
}
|
|
if options.SettleDuration > 0 && options.SettleDuration != DefaultFragmentsSettleDuration {
|
|
settleDuration := strconv.Itoa(int(options.SettleDuration.Milliseconds()))
|
|
dataRows = append(dataRows, SettleDurationDatalineLiteral+settleDuration)
|
|
}
|
|
if options.UseViewTransitions {
|
|
dataRows = append(dataRows, UseViewTransitionDatalineLiteral+"true")
|
|
}
|
|
|
|
if fragment != "" {
|
|
parts := strings.Split(fragment, "\n")
|
|
for _, part := range parts {
|
|
dataRows = append(dataRows, FragmentsDatalineLiteral+part)
|
|
}
|
|
}
|
|
|
|
if err := sse.Send(
|
|
EventTypeMergeFragments,
|
|
dataRows,
|
|
sendOptions...,
|
|
); err != nil {
|
|
return fmt.Errorf("failed to send fragment: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type RemoveFragmentsOptions struct {
|
|
EventID string
|
|
RetryDuration time.Duration
|
|
SettleDuration time.Duration
|
|
UseViewTransitions *bool
|
|
}
|
|
|
|
type RemoveFragmentsOption func(*RemoveFragmentsOptions)
|
|
|
|
func WithRemoveEventID(id string) RemoveFragmentsOption {
|
|
return func(o *RemoveFragmentsOptions) {
|
|
o.EventID = id
|
|
}
|
|
}
|
|
|
|
func WithRemoveRetryDuration(d time.Duration) RemoveFragmentsOption {
|
|
return func(o *RemoveFragmentsOptions) {
|
|
o.RetryDuration = d
|
|
}
|
|
}
|
|
|
|
func WithRemoveSettleDuration(d time.Duration) RemoveFragmentsOption {
|
|
return func(o *RemoveFragmentsOptions) {
|
|
o.SettleDuration = d
|
|
}
|
|
}
|
|
|
|
func WithRemoveUseViewTransitions(useViewTransition bool) RemoveFragmentsOption {
|
|
return func(o *RemoveFragmentsOptions) {
|
|
o.UseViewTransitions = &useViewTransition
|
|
}
|
|
}
|
|
|
|
func (sse *ServerSentEventGenerator) RemoveFragments(selector string, opts ...RemoveFragmentsOption) error {
|
|
if selector == "" {
|
|
panic("missing " + SelectorDatalineLiteral)
|
|
}
|
|
|
|
options := &RemoveFragmentsOptions{
|
|
EventID: "",
|
|
RetryDuration: DefaultSseRetryDuration,
|
|
SettleDuration: DefaultFragmentsSettleDuration,
|
|
UseViewTransitions: nil,
|
|
}
|
|
for _, opt := range opts {
|
|
opt(options)
|
|
}
|
|
|
|
dataRows := []string{SelectorDatalineLiteral + selector}
|
|
if options.SettleDuration > 0 && options.SettleDuration != DefaultFragmentsSettleDuration {
|
|
settleDuration := strconv.Itoa(int(options.SettleDuration.Milliseconds()))
|
|
dataRows = append(dataRows, SettleDurationDatalineLiteral+settleDuration)
|
|
}
|
|
if options.UseViewTransitions != nil {
|
|
dataRows = append(dataRows, UseViewTransitionDatalineLiteral+strconv.FormatBool(*options.UseViewTransitions))
|
|
}
|
|
|
|
sendOptions := make([]SSEEventOption, 0, 2)
|
|
if options.EventID != "" {
|
|
sendOptions = append(sendOptions, WithSSEEventId(options.EventID))
|
|
}
|
|
if options.RetryDuration > 0 {
|
|
sendOptions = append(sendOptions, WithSSERetryDuration(options.RetryDuration))
|
|
}
|
|
|
|
if err := sse.Send(EventTypeRemoveFragments, dataRows, sendOptions...); err != nil {
|
|
return fmt.Errorf("failed to send remove: %w", err)
|
|
}
|
|
return nil
|
|
}
|