конфиг выделить изи апп

posts
serr 2025-04-10 21:25:50 +03:00
parent 13ca4c403b
commit 066a30ff7d
13 changed files with 188 additions and 53 deletions

2
go.mod
View File

@ -1,3 +1,5 @@
module main
go 1.23.2
require github.com/gomarkdown/markdown v0.0.0-20250311123330-531bef5e742b

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/gomarkdown/markdown v0.0.0-20250311123330-531bef5e742b h1:EY/KpStFl60qA17CptGXhwfZ+k1sFNJIUNR8DdbcuUk=
github.com/gomarkdown/markdown v0.0.0-20250311123330-531bef5e742b/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=

View File

@ -6,6 +6,7 @@ import (
"main/mvc/controllers"
controllers_pages "main/mvc/controllers/pages"
"main/mvc/models"
models_pages "main/mvc/models/pages"
"main/tools"
"net/http"
)
@ -52,7 +53,7 @@ func setupRoutes(a *models.App) *http.ServeMux {
m := controllers.MiddlewaresChain
// Обработка статических файлов
router.Handle(a.Config.AssetsPath, m(controllers.StaticHandler()))
router.Handle(a.Config.AssetsDir, m(controllers.StaticHandler()))
// Главные странички
{
@ -62,6 +63,11 @@ func setupRoutes(a *models.App) *http.ServeMux {
router.Handle("/", m(controllers_pages.MainPageHandler(a)))
// Обработка страницы со списком постов
router.Handle("/posts/", m(controllers_pages.PostsPageHandler(a)))
// Обработка страничек постов
for key := range models_pages.GetPosts() {
postLink := string(key)
router.Handle(postLink, m(controllers_pages.PostPageHandler(a)))
}
}
return router

View File

@ -2,6 +2,7 @@ package controllers
import (
"log"
"main/mvc/models"
models_pages "main/mvc/models/pages"
"main/tools"

View File

@ -0,0 +1,39 @@
package controllers
import (
"main/mvc/models"
models_pages "main/mvc/models/pages"
"net/http"
)
// Обработчик главной страницы
func PostPageHandler(a *models.App) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error
posts := models_pages.GetPosts()
// Страничка рендерится только если ее нет в кэше
pageData, ok := a.Cache.Get(models_pages.PostPageTmplName)
if !ok {
post := posts[models_pages.PostLink(r.URL.Path)]
pageData, err = models_pages.RenderPostPage(a.Templates, a.Version, post.Data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
a.Cache.Set(models_pages.PostPageTmplName, pageData)
}
SendPostPage(w, pageData.([]byte))
})
}
// Отправляет страницу
func SendPostPage(w http.ResponseWriter, data []byte) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write(data)
}

View File

@ -32,7 +32,7 @@ func AppInit(configPath string) (*App, error) {
}
// Загрузка шаблонов
if err := a.loadTemplates(a.Config.TemplatesPath, a.Config.TemplatesExt); err != nil {
if err := a.loadTemplates(a.Config.TemplatesDir, a.Config.TemplatesExt); err != nil {
log.Fatal(err)
}

View File

@ -6,15 +6,16 @@ import (
)
type Config struct {
AssetsPath string
TemplatesPath string
TemplatesExt string
LocalIP string
LocalPort string
ServerIP string
ServerPort string
ServerDomain string
Port string
PostsDir string
AssetsDir string
TemplatesDir string
TemplatesExt string
LocalIP string
LocalPort string
ServerIP string
ServerPort string
ServerDomain string
Port string
}
func ConfigInit() *Config {

View File

@ -1,36 +1,55 @@
package models
import (
"bytes"
"html/template"
"time"
)
type PostName string
type PostLink string
const (
// Имя соответствующего шаблона
PostPageTmplName = "post.gohtml"
)
type Post struct {
Name PostName // имя поста
Link string // ссылка на пост
Preview string // превью поста
Data string // содержание
CreateTimestamp int64 // время создания
Link PostLink
Preview template.HTML
Data template.HTML
CreateTimestamp int64
}
// NewPost создает новый пост
func NewPost(name, link, data string) *Post {
// preview - первые 500 символов содержания
var preview string
if len(data) > 500 {
preview = data[:500] + "..."
} else {
preview = data
func RenderPostPage(templates *template.Template, version int64, data template.HTML) ([]byte, error) {
var pageData bytes.Buffer
context := map[string]any{
"version": version,
"renderingTimestamp": time.Now().Unix(),
"data": data,
}
post := &Post{
Name: PostName(name),
Link: link,
Preview: preview,
Data: data,
if err := templates.ExecuteTemplate(&pageData, PostPageTmplName, context); err != nil {
return nil, err
}
return pageData.Bytes(), nil
}
func NewPost(link string, data []byte) *Post {
previewBuf := make([]byte, 0, 503)
if len(data) > 500 {
previewBuf = append(previewBuf, data[:500]...)
previewBuf = append(previewBuf, '.', '.', '.')
} else {
previewBuf = append(previewBuf, data...)
}
return &Post{
Link: PostLink(link),
Preview: template.HTML(previewBuf),
Data: template.HTML(data),
CreateTimestamp: time.Now().Unix(),
}
return post
}

View File

@ -2,7 +2,13 @@ package models
import (
"bytes"
"fmt"
"html/template"
"io"
"log"
"main/tools"
"os"
"path/filepath"
"strings"
"time"
)
@ -12,28 +18,53 @@ const (
PostsPageTmplName = "posts.gohtml"
)
type Posts map[PostName]Post
type Posts map[PostLink]*Post
var (
posts = Posts{
"post 1": *NewPost(
"post 1",
"/post-1/",
"full content 1 with more than 100 characters Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam euismod...",
),
"post 2": *NewPost(
"post 2",
"/post-2/",
"full content 2",
),
"post 3": *NewPost(
"post 3",
"/post-3/",
strings.Repeat("This is post 3 content. ", 30),
),
}
posts = Posts{}
)
func init() {
if err := LoadPosts("posts/"); err != nil {
log.Fatalf("%v", err)
}
}
func GetPosts() Posts {
return posts
}
func LoadPosts(dir string) error {
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
if !f.IsDir() && strings.HasSuffix(f.Name(), ".md") {
file, err := os.Open(path)
if err != nil {
return err
}
md, err := io.ReadAll(file)
if err != nil {
return err
}
html := tools.MdToHTML(md)
link := fmt.Sprintf("/%s/", strings.TrimSuffix(filepath.Base(path), ".md"))
posts[PostLink(link)] = NewPost(link, html)
}
return nil
})
if err != nil {
return err
}
return nil
}
func RenderPostsPage(templates *template.Template, version int64) ([]byte, error) {
var pageData bytes.Buffer

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
{{ template "head" . }}
<body>
{{ template "header" . }}
<main>
<div>
{{ .data }}
</div>
</main>
{{ template "footer" . }}
</body>
</html>

View File

@ -7,9 +7,6 @@
{{ range $key, $post := .posts }}
<div>
<h1>
{{ $post.Name }}
</h1>
<p>
{{ $post.Preview }}
</p>

2
posts/test.md Normal file
View File

@ -0,0 +1,2 @@
# Это тестовый пост
Этот пост был написан в файле формата .md

22
tools/parse.go Normal file
View File

@ -0,0 +1,22 @@
package tools
import (
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
)
// Принимает байты .md, отдает .html
func MdToHTML(md []byte) []byte {
// create markdown parser with extensions
extensions := parser.CommonExtensions | parser.NoEmptyLineBeforeBlock
p := parser.NewWithExtensions(extensions)
doc := p.Parse(md)
// create HTML renderer with extensions
htmlFlags := html.CommonFlags | html.HrefTargetBlank
opts := html.RendererOptions{Flags: htmlFlags}
renderer := html.NewRenderer(opts)
return markdown.Render(doc, renderer)
}