Compare commits

...

5 Commits

Author SHA1 Message Date
Laurent Ulrich
9dd396e95f Reste à prévoir la pagination et la recherche 2025-08-20 16:19:55 +02:00
Laurent Ulrich
10ebdaad4a zz 2025-08-20 08:56:37 +02:00
Laurent Ulrich
8c76f5e6f0 zz 2025-08-19 09:56:13 +02:00
Laurent Ulrich
9f88d84513 Ajout d'un mutex pour pouvoir mettre à jour via une goroutine la liste des messages 2025-08-08 10:59:51 +02:00
Laurent Ulrich
614a6059f5 rien ou presque 2025-08-04 22:01:50 +02:00
10 changed files with 349 additions and 84 deletions

113
blog.go
View File

@@ -1,18 +1,117 @@
package main
import "html/template"
import (
"fmt"
"html/template"
"log"
"strings"
"sync"
"time"
"github.com/PuerkitoBio/goquery"
)
type Post struct {
Id string
Title string
Author string
Date string
HTML template.HTML
Text string
BlogTitle string
Lang string
Id string
Title string
Author string
Date string
DateTime time.Time
HTML template.HTML
ShortText template.HTML
Text string
}
type Blog struct {
Title string
Lang string
Posts []Post
mutex sync.Mutex
}
func (b *Blog) GetPost(Id string) (Post, bool) {
var ret Post
b.mutex.Lock()
defer b.mutex.Unlock()
for _, p := range b.Posts {
if p.Id == Id {
ret = p
ret.BlogTitle = b.Title
ret.Lang = b.Lang
return ret, true
}
}
return ret, false
}
func (p *Post) GenerateExcerpt() {
p.ShortText = ""
if len(p.HTML) > 0 {
heading, err := p.GetFirstHeading(string(p.HTML))
if err != nil {
log.Println(err)
}
paragraph, err := p.GetFirstParagraphs(string(p.HTML))
if err != nil {
log.Println(err)
}
if len(heading) > 0 {
p.ShortText += template.HTML(heading)
}
if len(paragraph) > 0 {
p.ShortText += template.HTML(paragraph)
}
} else {
p.ShortText = template.HTML(p.Text)
}
}
func (p *Post) GetFirstHeading(html string) (string, error) {
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
if err != nil {
return "", err
}
// Chercher le premier titre (h1, h2, h3, h4, h5, h6)
firstHeading := doc.Find("h1, h2, h3, h4, h5, h6").First()
if firstHeading.Length() == 0 {
return "", fmt.Errorf("no heading found")
}
htmlContent, err := goquery.OuterHtml(firstHeading)
if err != nil {
return "", err
}
return htmlContent, nil
}
func (p *Post) GetFirstParagraphs(html string) (string, error) {
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
if err != nil {
return "", err
}
var htmlContent string
var numberOfTextChars int
// Eventuellement trouver un moyen de ne plus examiner le reste du document
// si 200 caractères atteints
doc.Find("p,div,h1,h2,h3,h4,h5").Each(func(i int, s *goquery.Selection) {
if numberOfTextChars < 200 {
numberOfTextChars += len(s.Text())
content, err := goquery.OuterHtml(s)
if err != nil {
log.Println(err)
}
htmlContent += content
}
})
return htmlContent, nil
}

View File

@@ -14,10 +14,15 @@ type MailBoxConfiguration struct {
SSL string
InBox string
}
type ServiceConfiguration struct {
Address string
Port string
}
type BlogConfiguration struct {
Title string
ShortName string
MailBox MailBoxConfiguration
Service ServiceConfiguration
}
func (configuration *BlogConfiguration) Prompt() error {
@@ -31,7 +36,7 @@ func (configuration *BlogConfiguration) Prompt() error {
return err
}
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(configuration.ShortName) {
return fmt.Errorf("short same invalid")
return fmt.Errorf("short name invalid")
}
/*
@@ -72,6 +77,16 @@ func (configuration *BlogConfiguration) Prompt() error {
if err != nil {
return err
}
configuration.Service.Address, err = prompt("Listen address", nil, "127.0.0.1", configuration.Service.Address, false)
if err != nil {
return err
}
configuration.Service.Port, err = prompt("Listen port", nil, "8080", configuration.Service.Port, false)
if err != nil {
return err
}
return nil
}

6
go.mod
View File

@@ -3,12 +3,14 @@ module passke.org/mailblog
go 1.23.2
require (
github.com/PuerkitoBio/goquery v1.10.3
github.com/emersion/go-imap/v2 v2.0.0-beta.5
github.com/emersion/go-message v0.18.1
golang.org/x/net v0.6.0
golang.org/x/net v0.39.0
)
require (
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/text v0.24.0 // indirect
)

44
go.sum
View File

@@ -1,39 +1,79 @@
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/emersion/go-imap/v2 v2.0.0-beta.5 h1:H3858DNmBuXyMK1++YrQIRdpKE1MwBc+ywBtg3n+0wA=
github.com/emersion/go-imap/v2 v2.0.0-beta.5/go.mod h1:BZTFHsS1hmgBkFlHqbxGLXk2hnRqTItUgwjSSCsYNAk=
github.com/emersion/go-message v0.18.1 h1:tfTxIoXFSFRwWaZsgnqS1DSZuGpYGzSmCZD8SK3QA2E=
github.com/emersion/go-message v0.18.1/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -3,14 +3,23 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{{.Title}}</title>
<link rel="stylesheet" href="../styles.css">
<title>{{.BlogTitle}}</title>
</head>
<h1>{{.Title}}</h1>
<h1 class="blogtitle"><a href="/proxy/8080/">{{.BlogTitle}}</a></h1>
<body>
<h2>{{(index .Posts 0).Title}}</h2>
<div>
{{(index .Posts 0).HTML}}
<article class="post">
<header class="postheader">
<h2 class="posttitle">{{.Title}}</h2>
<p class="postdate"><time datetime="{{.Date}}">{{.Date}}</Time></p>
</header>
<div class="postcontent">
{{ if .HTML }}
{{.HTML}}
{{ else }}
{{.Text}}
{{ end }}
</div>
</article>
</body>
</html>

View File

@@ -4,24 +4,20 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{{.Title}}</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>{{.Title}}</h1>
<h1 class="blogtitle"><a href="/proxy/8080/">{{.Title}}</a></h1>
{{range .Posts}}
<article>
<a href=/proxy/8080/post/{{ .Id }}>
<h2>{{.Title}}</h2>
</a>
<article class="shortpost">
<header class="shortpostheader">
<h2 class="shortposttitle"><a href=/proxy/8080/post/{{ .Id }}>{{.Title}}</a></h2>
<p class="shortpostdate"><time datetime="{{.Date}}">{{.Date}}</Time></p>
</header>
<div>
{{.HTML}}
<blockquote class="shortpostcontent">{{.ShortText}}</blockquote>
</div>
<footer>
<p>
{{.Date}}
</p>
</footer>
</article>
{{ end }}
</body>
</html>

59
html/styles.css Normal file
View File

@@ -0,0 +1,59 @@
a:link {
color: black;
text-decoration: none;
}
a:visited {
color: black;
text-decoration: none;
}
a:hover {
color: orange;
text-decoration: none;
}
.blogtitle {
color: coral;
text-decoration:underline;
}
/*
.shortpost {
}
.shortpostheader {
}
*/
.shortposttitle {
font-weight: bold;
}
.shortpostdate {
font-style: italic;
font-size: smaller;
font-weight: lighter;
}
/*
.shortpostcontent {
}
*/
/*
.post {
}
.postheader {
}
*/
.posttitle {
font-weight: bold;
}
.postdate {
font-style: italic;
font-size: smaller;
font-weight: lighter;
}
/*
.postcontent {
}
*/

31
imap.go
View File

@@ -7,6 +7,7 @@ import (
"io"
"log"
"mime"
"sort"
"strconv"
"strings"
@@ -69,12 +70,11 @@ func (mb *MailBox) Connect() error {
log.Println("Error connnecting to", imapServer, ":", err)
return err
}
log.Println("Connected")
err = mb.Client.Login(mb.User, mb.Password).Wait()
if err != nil {
log.Fatal("failed to login:", err)
}
log.Println("Logged in")
return nil
}
func (mb *MailBox) ListFolders() ([]string, error) {
@@ -119,10 +119,13 @@ func (mb *MailBox) GetMessages() ([]Post, error) {
post.Id = messages[0].Envelope.MessageID
post.Title = post.Title[5:] // remove first chars = blog+whitespace
post.Author = messages[0].Envelope.From[0].Name
post.Date = messages[0].Envelope.Date.String()
post.Author = messages[0].Envelope.To[0].Name
post.Date = messages[0].Envelope.Date.Format("2006/01/02 15:04")
post.DateTime = messages[0].Envelope.Date
section := messages[0].FindBodySection(bodySection)
ioReader := bytes.NewReader(section)
mailReader, err := mail.CreateReader(ioReader)
if err != nil {
@@ -155,7 +158,10 @@ func (mb *MailBox) GetMessages() ([]Post, error) {
}
switch mediaType {
case "text/plain":
post.Text = string(body)
if len(post.HTML) == 0 {
post.Text = string(body)
post.GenerateExcerpt()
}
case "text/html":
post.HTML = ""
nodes, err := html.Parse(strings.NewReader(string(body)))
@@ -168,20 +174,19 @@ func (mb *MailBox) GetMessages() ([]Post, error) {
post.HTML = ""
break
}
log.Println("Trying to generate html for", htmlNode.Data)
var buf bytes.Buffer
err = nil
for child := htmlNode.FirstChild; child != nil; child = child.NextSibling {
log.Println("html for", child.Data)
if err = html.Render(&buf, child); err != nil {
err = html.Render(&buf, child)
if err != nil {
post.HTML = ""
break
}
}
if err == nil {
post.HTML = template.HTML(buf.String())
post.GenerateExcerpt()
}
default:
log.Println("Content-Type:", part.Header.Get("Content-Type"))
@@ -193,6 +198,9 @@ func (mb *MailBox) GetMessages() ([]Post, error) {
}
posts = append(posts, post)
}
sort.Slice(posts, func(i, j int) bool {
return posts[i].DateTime.After(posts[j].DateTime)
})
return posts, nil
}
@@ -201,15 +209,10 @@ func (mb *MailBox) Close() {
}
func findHTMLNode(node *html.Node) (*html.Node, error) {
if node.Type == html.ElementNode {
log.Println(node.Data)
}
if node.Type == html.ElementNode && node.Data == "body" {
log.Println("Found", node.Data)
return node, nil
}
for e := node.FirstChild; e != nil; e = node.NextSibling {
log.Println("Search in", e.Data)
n, err := findHTMLNode(e)
if err == nil {
return n, nil

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"log"
"os"
"time"
)
//go:embed html/index.tmpl
@@ -14,6 +15,9 @@ var indexTemplate string
//go:embed html/entry.tmpl
var entryTemplate string
//go:embed html/styles.css
var nativeCSS string
func main() {
var err error
@@ -25,7 +29,9 @@ func main() {
if err != nil {
log.Fatal(err)
}
file, err := os.Open(fmt.Sprintf("%s/.config/mailblog.json", home))
configurationFileName := fmt.Sprintf("%s/.config/mailblog.json", home)
file, err := os.Open(configurationFileName)
if err == nil {
defer file.Close()
decoder := json.NewDecoder(file)
@@ -53,20 +59,38 @@ func main() {
}
}
var mb MailBox
mb.Configure(&configuration.MailBox)
err = mb.Connect()
if err != nil {
log.Fatal(err)
}
defer mb.Close()
var blog Blog
blog.Lang = "fr-FR"
blog.Title = configuration.Title
blog.Posts, err = mb.GetMessages()
if err != nil {
log.Fatal(err)
}
StartServer(&blog)
go MailboxFetcher(configuration, &blog)
StartServer(configuration, &blog)
}
func MailboxFetcher(configuration BlogConfiguration, blog *Blog) {
var mb MailBox
mb.Configure(&configuration.MailBox)
for {
err := mb.Connect()
if err != nil {
log.Fatal(err)
}
posts, err := mb.GetMessages()
if err != nil {
log.Println(err)
mb.Close()
time.Sleep(10 * time.Second)
continue
}
mb.Close()
blog.mutex.Lock()
blog.Posts = posts
blog.mutex.Unlock()
time.Sleep(10 * time.Second)
}
}

68
web.go
View File

@@ -3,55 +3,73 @@ package main
import (
"html/template"
"log"
"net"
"net/http"
)
func StartServer(blog *Blog) {
func StartServer(configuration BlogConfiguration, blog *Blog) {
http.HandleFunc("GET /{$}",
mux := http.NewServeMux()
/* Handle home page (/): list of blog entries */
mux.HandleFunc("GET /{$}",
func(w http.ResponseWriter, r *http.Request) {
log.Printf("%+v", r.Header)
tpl, err := template.New("index").Parse(indexTemplate)
if err != nil {
log.Fatal(err)
}
blog.mutex.Lock()
defer blog.mutex.Unlock()
err = tpl.ExecuteTemplate(w, "index", blog)
if err != nil {
log.Fatal(err)
}
})
http.HandleFunc("GET /post/{id}",
/* Handle one post display(/post/{post ID}) */
mux.HandleFunc("GET /post/{id}",
func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
log.Println("showing post:", id)
for _, p := range blog.Posts {
log.Println("Examining:", p.Id)
if p.Id == id {
tpl, err := template.New("entry").Parse(entryTemplate)
if err != nil {
log.Fatal(err)
}
var post Blog
post.Title = blog.Title
post.Lang = blog.Lang
post.Posts = make([]Post, 1)
post.Posts[0] = p
err = tpl.ExecuteTemplate(w, "entry", post)
if err != nil {
log.Fatal(err)
}
return
}
post, found := blog.GetPost(id)
if !found {
w.WriteHeader(404)
}
tpl, err := template.New("entry").Parse(entryTemplate)
if err != nil {
log.Fatal(err)
}
err = tpl.ExecuteTemplate(w, "entry", post)
if err != nil {
log.Fatal(err)
}
w.WriteHeader(404)
})
http.HandleFunc("GET /favicon.ico",
mux.HandleFunc("GET /styles.css",
func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/css")
w.Write([]byte(nativeCSS))
})
mux.HandleFunc("GET /favicon.ico",
func(w http.ResponseWriter, r *http.Request) {
log.Println("favicon.ico")
w.WriteHeader(200)
})
http.ListenAndServe("0.0.0.0:8080", nil)
addr := net.JoinHostPort(configuration.Service.Address, configuration.Service.Port)
server := &http.Server{
Addr: addr,
Handler: mux,
}
server.ListenAndServe()
//http.ListenAndServe(addr, server)
}
/*
func isCodeServerProxy(r *http.Request) bool {
return len(r.Header.Get("code-server-session")) > 0
}
*/