Files
plainleaf/server/ssr.go
T

97 lines
2.9 KiB
Go

package server
import (
"fmt"
"html/template"
"log"
"net/http"
pathLib "path"
"regexp"
"strings"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
)
// This implements very crude server-side rendered markdown using a Go markdown library
// Note: this not even nearly supports all SilverBullet markdown features. It's best effort.
// The ONLY use case of this is search engine indexing
// It is only activated when the space is both read-only and has no authentication, so basically the silverbullet.md scenario.
// Very crude markdown link replacement
func convertWikiLinksToMarkdown(input string) string {
// Regular expression to match [[text]] patterns
re := regexp.MustCompile(`\[\[([^\]]+)\]\]`)
// Replace all matches with [text](text) format
result := re.ReplaceAllStringFunc(input, func(match string) string {
// Extract the text between [[ and ]]
text := strings.TrimPrefix(match, "[[")
text = strings.TrimSuffix(text, "]]")
return fmt.Sprintf("[%s](%s)", text, text)
})
return result
}
func ServerSideRender(config *ServerConfig, spaceConfig *SpaceConfig, pageName string, w http.ResponseWriter, r *http.Request) {
// Let's fetch the index.html text
indexHtmlBuf, _, _ := config.ClientBundle.ReadFile(indexHtmlPath)
if pageName == "" {
pageName = spaceConfig.IndexPage
}
tpl := template.New("index_html")
tpl.Funcs(template.FuncMap{
"markdown": func(text string) template.HTML {
if text == "" {
// Let's not even bother doing anything
return ""
}
// Setup markdown renderer
var markdownParser = parser.NewWithExtensions(parser.CommonExtensions)
var markdownRenderer = html.NewRenderer(html.RendererOptions{})
text = convertWikiLinksToMarkdown(text)
doc := markdownParser.Parse([]byte(text))
return template.HTML(markdown.Render(doc, markdownRenderer))
},
})
tpl = template.Must(tpl.Parse(string(indexHtmlBuf)))
templateData := struct {
HostPrefix string
Title string
Description string
Content string
AdditionalHeadHTML template.HTML
}{
Title: "SilverBullet",
HostPrefix: config.HostURLPrefix,
AdditionalHeadHTML: spaceConfig.AdditionalHeadHTML,
}
if spaceConfig.ReadOnlyMode && spaceConfig.Auth == nil {
// Read only and without out, let's do some server side rendering
templateData.Title = pathLib.Base(pageName)
// Read page content
pageData, _, err := spaceConfig.SpacePrimitives.ReadFile(fmt.Sprintf("%s.md", pageName))
if err != nil {
log.Printf("Could not read content for page %s", pageName)
} else {
templateData.Content = string(pageData)
}
}
w.Header().Set("Content-type", "text/html")
w.WriteHeader(http.StatusOK)
if err := tpl.Execute(w, templateData); err != nil {
log.Printf("SSR error for %s: %v", pageName, err)
w.Write([]byte("Server error"))
}
}