error while getting the post; {{$messages.Error}}
-{{else}}
- {{GetChannelTitle $postID}}
- {{$lastAuthor := ""}}
- {{$wasDupLastTime := true}}
- {{range $_, $v := $messages.Messages}}
- {{if or $v.Content $v.Attachments}}
- {{if eq $lastAuthor $v.Author.Username}}
- {{$wasDupLastTime = true}}
- {{else}}
- {{if $wasDupLastTime}}
- {{template "postfooter" $v}}
- {{end}}
-
- {{template "postheader" $v}}
- {{end}}
-
- {{FormatDiscordThings $guildID .Content}}
- {{range $i, $n := .Attachments}}
-
- {{end}}
- {{end}}
- {{$lastAuthor = $v.Author.Username}}
- {{end}}
-{{end}}
-
-{{ define "postheader"}}
-
-
-
- {{PrettyTime .CreatedAt}}
-
-
-
-
- {{.Author.Username}}
-
-
-
-{{end}}
-
-{{ define "postfooter" }}
-
-
-
-{{end}}
\ No newline at end of file
diff --git a/pages/messages.gohtml b/pages/messages.gohtml
deleted file mode 100644
index 4697afa..0000000
--- a/pages/messages.gohtml
+++ /dev/null
@@ -1,29 +0,0 @@
-{{ $guildID := ParseSnowflake (index .Values 0) }}
-{{ $channelID := ParseSnowflake (index .Values 1) }}
-
-
-
-{{ $threads := GetThreadsInChannel $channelID}}
-{{if le (len $threads) 0}}
- no posts found; either the bots not in that server or there's no messages in it.
-{{else}}
- {{GetChannelTitle $channelID}}
-
-
- Posts
- Messages
-
- {{range $i, $v := $threads}}
-
-
- {{$v.Name}}
-
-
- {{len (GetMessagesInChannel $v.ID).Messages}}
-
-
- {{end}}
-
-{{end}}
diff --git a/pages/topics.gohtml b/pages/topics.gohtml
deleted file mode 100644
index 35c7b7b..0000000
--- a/pages/topics.gohtml
+++ /dev/null
@@ -1,27 +0,0 @@
-{{ $guildID := ParseSnowflake (index .Values 0) }}
-{{ $forums := GetForums $guildID }}
-
-
-{{if le (len $forums) 0}}
- no forums found; either the bots not in that server or there's no forum channels in it.
-{{else}}
- {{GetGuildName $guildID}}
-
-
- Forum
- Posts
-
- {{range $i, $v := $forums}}
-
-
- {{$v.Name}}
-
-
- {{len (GetThreadsInChannel $v.ID)}}
-
-
- {{end}}
-
-{{end}}
diff --git a/resources/style.css b/resources/static/style.css
similarity index 96%
rename from resources/style.css
rename to resources/static/style.css
index dcb039d..1f8881d 100644
--- a/resources/style.css
+++ b/resources/static/style.css
@@ -27,6 +27,10 @@ p + br + p {
display: block;
}
+.post-info {
+ white-space: pre-line;
+}
+
.title, .threadnum {
padding: 5px;
}
@@ -92,4 +96,4 @@ p + br + p {
padding: 15px;
margin: 10px 0 50px 0;
background: #ddd;
-}
\ No newline at end of file
+}
diff --git a/resources/templates/error.gohtml b/resources/templates/error.gohtml
new file mode 100644
index 0000000..a0fd8fa
--- /dev/null
+++ b/resources/templates/error.gohtml
@@ -0,0 +1,6 @@
+{{ template "header.gohtml" }}
+{{.StatusCode}} {{.StatusText}}
+{{with .Error}}
+{{.}}
+{{end}}
+{{template "footer.gohtml" }}
diff --git a/pages/footer.gohtml b/resources/templates/footer.gohtml
similarity index 100%
rename from pages/footer.gohtml
rename to resources/templates/footer.gohtml
diff --git a/resources/templates/forum.gohtml b/resources/templates/forum.gohtml
new file mode 100644
index 0000000..aa29d57
--- /dev/null
+++ b/resources/templates/forum.gohtml
@@ -0,0 +1,23 @@
+{{ template "header.gohtml" .}}
+
+
+{{.Forum.Name}}
+
+
+ Posts
+ Messages
+
+ {{range .Posts}}
+
+
+ {{.Name}}
+
+
+ {{.MessageCount}}
+
+
+ {{end}}
+
+{{ template "footer.gohtml" .}}
diff --git a/resources/templates/guild.gohtml b/resources/templates/guild.gohtml
new file mode 100644
index 0000000..c4debb7
--- /dev/null
+++ b/resources/templates/guild.gohtml
@@ -0,0 +1,22 @@
+{{ template "header.gohtml" .}}
+
+ {{.Guild.Name}}
+
+
+ Forum
+ Posts
+
+ {{range $_, $forum := .ForumChannels}}
+
+
+ {{$forum.Name}}
+
+
+ {{len $forum.Posts}}
+
+
+ {{end}}
+
+{{ template "footer.gohtml" .}}
diff --git a/pages/header.gohtml b/resources/templates/header.gohtml
similarity index 84%
rename from pages/header.gohtml
rename to resources/templates/header.gohtml
index 332e8ab..e38e498 100644
--- a/pages/header.gohtml
+++ b/resources/templates/header.gohtml
@@ -3,11 +3,11 @@
-
+
dfs
-
\ No newline at end of file
+
diff --git a/pages/index.gohtml b/resources/templates/index.gohtml
similarity index 92%
rename from pages/index.gohtml
rename to resources/templates/index.gohtml
index 716d4c5..c1f7e39 100644
--- a/pages/index.gohtml
+++ b/resources/templates/index.gohtml
@@ -12,5 +12,5 @@
once the bot is invited, you can go to dfs.ioi-xd.net/(THE ID OF YOUR GUILD) to see the messages within it.
-
currently serving {{GuildNum}} servers.
-{{template "footer.gohtml" }}
\ No newline at end of file
+currently serving {{.GuildCount}} servers.
+{{template "footer.gohtml" }}
diff --git a/resources/templates/post.gohtml b/resources/templates/post.gohtml
new file mode 100644
index 0000000..9a57d4f
--- /dev/null
+++ b/resources/templates/post.gohtml
@@ -0,0 +1,40 @@
+{{ template "header.gohtml" .}}
+
+{{range .MessageGroups}}
+
+
+
+ {{PrettyTime (index . 0).ID.Time}}
+
+
+
+
+ {{(index . 0).Author.Username}}
+
+
+
+ {{range .}}
+ {{with .RenderedContent -}}
+ {{- . -}}
+ {{- end}}
+ {{range .MediaPreviews}}
+
+ {{end}}
+ {{with .PlainAttachments}}
+ Attachments:
+
+ {{end}}
+ {{end}}
+
+
+
+
+{{end}}
+{{ template "footer.gohtml" .}}
diff --git a/server.go b/server.go
new file mode 100644
index 0000000..76cc008
--- /dev/null
+++ b/server.go
@@ -0,0 +1,279 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/fs"
+ "net/http"
+ "sort"
+ "sync"
+ "time"
+
+ "github.com/diamondburned/arikawa/v3/discord"
+ "github.com/diamondburned/arikawa/v3/state"
+ "github.com/diamondburned/arikawa/v3/utils/httputil"
+ "github.com/go-chi/chi/v5"
+)
+
+type server struct {
+ r *chi.Mux
+
+ discord *state.State
+
+ sitemap []byte
+ sitemapUpdated time.Time
+ sitemapMu sync.Mutex
+
+ buffers *sync.Pool
+}
+
+func newServer(discord *state.State, fsys fs.FS) *server {
+ s := new(server)
+ s.discord = discord
+ s.buffers = &sync.Pool{
+ New: func() any {
+ return new(bytes.Buffer)
+ },
+ }
+ r := chi.NewRouter()
+ s.r = r
+ r.Get(`/sitemap.xml`, s.getSitemap)
+ r.Get("/", s.getIndex)
+ r.Route("/{guildID:\\d+}", func(r chi.Router) {
+ r.Get("/", s.getGuild)
+ r.Route("/{forumID:\\d+}", func(r chi.Router) {
+ r.Get("/", s.getForum)
+ r.Route("/{postID:\\d+}", func(r chi.Router) {
+ r.Get("/", s.getPost)
+ })
+ })
+ })
+ r.Get("/static/*", http.FileServer(http.FS(fsys)).ServeHTTP)
+ r.NotFound(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ displayErr(w, http.StatusNotFound, nil)
+ }))
+ return s
+}
+
+func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ s.r.ServeHTTP(w, r)
+}
+
+func (s *server) executeTemplate(w http.ResponseWriter, name string, ctx any) {
+ buf := s.buffers.Get().(*bytes.Buffer)
+ if err := tmpl.ExecuteTemplate(buf, name, ctx); err == nil {
+ io.Copy(w, buf)
+ } else {
+ displayErr(w, http.StatusInternalServerError, err)
+ }
+ buf.Reset()
+ s.buffers.Put(buf)
+}
+
+func displayErr(w http.ResponseWriter, status int, err error) {
+ ctx := struct {
+ Error error
+ StatusText string
+ StatusCode int
+ }{err, http.StatusText(status), status}
+ w.WriteHeader(status)
+ tmpl.ExecuteTemplate(w, "error.gohtml", ctx)
+}
+
+func discordStatusIs(err error, status int) bool {
+ var httperr *httputil.HTTPError
+ if ok := errors.As(err, &httperr); !ok {
+ return false
+ }
+ return httperr.Status == status
+}
+
+func (s *server) getIndex(w http.ResponseWriter, r *http.Request) {
+ guilds, err := s.discord.Cabinet.Guilds()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ ctx := struct {
+ GuildCount int
+ }{len(guilds)}
+ s.executeTemplate(w, "index.gohtml", ctx)
+}
+
+type ForumChannel struct {
+ discord.Channel
+ Posts []discord.Channel
+}
+
+func (s *server) getGuild(w http.ResponseWriter, r *http.Request) {
+ guild, ok := s.guildFromReq(w, r)
+ if !ok {
+ return
+ }
+ ctx := struct {
+ Guild *discord.Guild
+ ForumChannels []ForumChannel
+ }{Guild: guild}
+ channels, err := s.discord.Channels(guild.ID)
+ if err != nil {
+ displayErr(w, http.StatusInternalServerError,
+ fmt.Errorf("fetching guild channels: %s", err))
+ return
+ }
+ threads, err := s.discord.ActiveThreads(guild.ID)
+ if err != nil {
+ displayErr(w, http.StatusInternalServerError,
+ fmt.Errorf("fetching guild active threads: %s", err))
+ return
+ }
+ for _, ch := range channels {
+ if ch.Type == discord.GuildForum {
+ var posts []discord.Channel
+ for _, t := range threads.Threads {
+ if t.ParentID == ch.ID {
+ posts = append(posts, t)
+ }
+ }
+ ctx.ForumChannels = append(ctx.ForumChannels, ForumChannel{
+ ch, posts,
+ })
+ }
+ }
+ s.executeTemplate(w, "guild.gohtml", ctx)
+}
+
+func (s *server) getForum(w http.ResponseWriter, r *http.Request) {
+ guild, ok := s.guildFromReq(w, r)
+ if !ok {
+ return
+ }
+ forum, ok := s.forumFromReq(w, r)
+ if !ok {
+ return
+ }
+ ctx := struct {
+ Guild *discord.Guild
+ Forum *discord.Channel
+ Posts []discord.Channel
+ }{guild, forum, nil}
+ guildThreads, err := s.discord.ActiveThreads(guild.ID)
+ if err != nil {
+ displayErr(w, http.StatusInternalServerError,
+ fmt.Errorf("fetching guild threads: %w", err))
+ }
+ for _, t := range guildThreads.Threads {
+ if t.ParentID == forum.ID {
+ ctx.Posts = append(ctx.Posts, t)
+ }
+ }
+ s.executeTemplate(w, "forum.gohtml", ctx)
+}
+
+func (s *server) getPost(w http.ResponseWriter, r *http.Request) {
+ guild, ok := s.guildFromReq(w, r)
+ if !ok {
+ return
+ }
+ forum, ok := s.forumFromReq(w, r)
+ if !ok {
+ return
+ }
+ post, ok := s.postFromReq(w, r)
+ if !ok {
+ return
+ }
+ ctx := struct {
+ Guild *discord.Guild
+ Forum *discord.Channel
+ Post *discord.Channel
+ MessageGroups [][]Message
+ }{guild, forum, post, nil}
+ msgs, err := s.discord.Client.Messages(post.ID, 0)
+ if err != nil {
+ displayErr(w, http.StatusInternalServerError,
+ fmt.Errorf("fetching post's messages: %w", err))
+ return
+ }
+ sort.Slice(msgs, func(i, j int) bool {
+ return msgs[i].ID < msgs[j].ID
+ })
+ var msgrps [][]Message
+ i := 0
+ for _, m := range msgs {
+ if len(msgrps) == i {
+ grp := []Message{
+ s.message(m),
+ }
+ msgrps = append(msgrps, grp)
+ } else {
+ if msgrps[i][0].Author == m.Author {
+ msgrps[i] = append(msgrps[i], s.message(m))
+ } else {
+ i++
+ }
+ }
+ }
+ ctx.MessageGroups = msgrps
+ s.executeTemplate(w, "post.gohtml", ctx)
+}
+
+func (s *server) guildFromReq(w http.ResponseWriter, r *http.Request) (*discord.Guild, bool) {
+ guildIDsf, err := discord.ParseSnowflake(chi.URLParam(r, "guildID"))
+ if err != nil {
+ displayErr(w, http.StatusBadRequest, err)
+ return nil, false
+ }
+ guildID := discord.GuildID(guildIDsf)
+ guild, err := s.discord.Guild(guildID)
+ if err != nil {
+ if discordStatusIs(err, http.StatusNotFound) {
+ displayErr(w, http.StatusNotFound, nil)
+ } else {
+ displayErr(w, http.StatusInternalServerError,
+ fmt.Errorf("fetching guild: %w", err))
+ }
+ return nil, false
+ }
+ return guild, true
+}
+
+func (s *server) forumFromReq(w http.ResponseWriter, r *http.Request) (*discord.Channel, bool) {
+ forumIDsf, err := discord.ParseSnowflake(chi.URLParam(r, "forumID"))
+ if err != nil {
+ displayErr(w, http.StatusBadRequest, err)
+ return nil, false
+ }
+ forumID := discord.ChannelID(forumIDsf)
+ forum, err := s.discord.Channel(forumID)
+ if err != nil {
+ if discordStatusIs(err, http.StatusNotFound) {
+ displayErr(w, http.StatusNotFound, nil)
+ } else {
+ displayErr(w, http.StatusInternalServerError,
+ fmt.Errorf("fetching forum: %w", err))
+ }
+ return nil, false
+ }
+ return forum, true
+}
+
+func (s *server) postFromReq(w http.ResponseWriter, r *http.Request) (*discord.Channel, bool) {
+ postIDsf, err := discord.ParseSnowflake(chi.URLParam(r, "postID"))
+ if err != nil {
+ displayErr(w, http.StatusBadRequest, err)
+ return nil, false
+ }
+ postID := discord.ChannelID(postIDsf)
+ post, err := s.discord.Channel(postID)
+ if err != nil {
+ if discordStatusIs(err, http.StatusNotFound) {
+ displayErr(w, http.StatusNotFound, nil)
+ } else {
+ displayErr(w, http.StatusInternalServerError,
+ fmt.Errorf("fetching post: %w", err))
+ }
+ return nil, false
+ }
+ return post, true
+}
diff --git a/sitemap.go b/sitemap.go
index 39d731f..c6f583f 100644
--- a/sitemap.go
+++ b/sitemap.go
@@ -2,189 +2,121 @@ package main
import (
"bytes"
- "compress/gzip"
"encoding/xml"
"fmt"
+ "io"
"net/http"
- "strconv"
- "strings"
"time"
- "github.com/disgoorg/snowflake/v2"
+ "github.com/diamondburned/arikawa/v3/discord"
)
-const (
- XMLIndexSettings = `xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"`
- XMLListSettings = `xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"`
- XMLPageHeader = ``
- XMLURLPageHeader = ``
- XMLSitemapPageHeader = ``
- XMLSitemapPageFooter = ` `
- XMLURLPageFooter = ` `
-)
-
-var dontCare = strings.NewReplacer(
- "sitemap-", "",
- "sitemap", "",
- ".xml", "",
-)
-
-type CacheObject struct {
- XMLPage []byte
- LastUpdated int64
- GZipped bool
-}
-
-var Caches map[string]CacheObject
-
-type Sitemap struct {
- Location string `xml:"loc"`
-}
-type SitemapIndex []Sitemap
type URL struct {
+ XMLName string `xml:"url"`
Location string `xml:"loc"`
- LastMod string `xml:"lastmod"`
- Frequency string `xml:"changefreq"`
- Priority float32 `xml:"priority"`
-}
-type URLSet []URL
-
-var XMLPage string // The xml page to serve.
-var LastUpdatedFormat string // obsolete but i'm too tired to remove it
-
-func init() {
- Caches = make(map[string]CacheObject)
+ LastMod string `xml:"lastmod,omitempty"`
+ Frequency string `xml:"changefreq,omitempty"`
+ Priority float32 `xml:"priority,omitempty"`
}
-func XMLServe(w http.ResponseWriter, r *http.Request, pagename string) {
- var XMLPage []byte
- var gz bool
- obj, ok := Caches[pagename]
- // If it's not existent, cache it.
- if !ok {
- XMLPage, gz = XMLPageGen(pagename)
-
- newOBJ := CacheObject{
- XMLPage: XMLPage,
- GZipped: gz,
- LastUpdated: time.Now().Unix(),
- }
- Caches[pagename] = newOBJ
- } else {
- // Otherwise, search the cache.
- lastUpdated := obj.LastUpdated
- // If the time 30 minutes ago is greater then the updated time
- if (time.Now().Unix() - int64(time.Hour*6)) > lastUpdated {
- // Update the cache
- obj.XMLPage, obj.GZipped = XMLPageGen(pagename)
- obj.LastUpdated = time.Now().Unix()
+func (s *server) getSitemap(w http.ResponseWriter, r *http.Request) {
+ s.sitemapMu.Lock()
+ var sitemap []byte
+ var modtime time.Time
+ if s.sitemap == nil || time.Since(s.sitemapUpdated) > 6*time.Hour {
+ buf := s.buffers.Get().(*bytes.Buffer)
+ err := s.writeSitemap(buf)
+ if err != nil {
+ s.sitemapMu.Unlock()
+ buf.Reset()
+ s.buffers.Put(buf)
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
}
- // Otherwise, serve that cached version.
- XMLPage, gz = obj.XMLPage, obj.GZipped
- }
- w.Header().Set("Content-Name", pagename)
- if gz {
- w.Header().Set("Content-Type", "application/gzip")
- w.Header().Set("Content-Disposition", "attachment; filename="+pagename)
+ sitemap := make([]byte, buf.Len())
+ copy(sitemap, buf.Bytes())
+ s.sitemap = sitemap
+ s.sitemapUpdated = time.Now()
+ modtime = s.sitemapUpdated
+ s.sitemapMu.Unlock()
+ buf.Reset()
+ s.buffers.Put(buf)
} else {
- w.Header().Set("Content-Type", "text/xml")
- w.Header().Set("Content-Name", pagename)
+ sitemap = s.sitemap
+ modtime = s.sitemapUpdated
+ s.sitemapMu.Unlock()
}
-
- w.Write(XMLPage)
+ rdr := bytes.NewReader(sitemap)
+ http.ServeContent(w, r, "sitemap.xml", modtime, rdr)
}
-// todo: scrap this function in favor of go-chi's pagnation system.
-func XMLPageGen(pagename string) (XMLPage []byte, gz bool) {
- // get the values and stuff we want from the pagename
- pagename = dontCare.Replace(pagename)
-
- // whether or not to serve the gzipped file
- if strings.Contains(pagename, ".gz") {
- pagename = strings.Replace(pagename, ".gz", "", 1)
- gz = true
- } else {
- gz = false
- }
-
- var XMLResult string
- parts := strings.Split(pagename, "-")
-
- if parts[0] == "" {
- XMLResult = XMLPageGenGuilds()
- } else {
- var guildID int
- guildID, err := strconv.Atoi(parts[0])
- if err != nil {
- return []byte(err.Error()), false
- }
- XMLResult = XMLPageGenThreads(snowflake.ID(guildID))
- }
-
- if gz {
- return GZIPString(XMLResult), true
- } else {
- return []byte(XMLResult), false
- }
+var XMLURLSetStart = xml.StartElement{
+ Name: xml.Name{Local: "urlset"},
+ Attr: []xml.Attr{
+ {xml.Name{Local: "xmlns"}, "http://www.sitemaps.org/schemas/sitemap/0.9"},
+ },
}
-func XMLPageGenGuilds() string {
- var XMLPage bytes.Buffer
- var sitemapIndex SitemapIndex
+var XMLURLSetEnd = XMLURLSetStart.End()
- guilds := Client.Client.Caches().Guilds().All()
- for _, g := range guilds {
- sitemapIndex = append(sitemapIndex, Sitemap{
- Location: fmt.Sprintf("https://dfs.ioi-xd.net/sitemap-%v.xml.gz", g.ID),
- })
+func (s *server) writeSitemap(w io.Writer) error {
+ if _, err := io.WriteString(w, xml.Header); err != nil {
+ return err
}
- output, err := xml.Marshal(sitemapIndex)
- if err != nil {
- return err.Error()
+ enc := xml.NewEncoder(w)
+ var err error
+ if err = enc.EncodeToken(XMLURLSetStart); err != nil {
+ return err
}
- XMLPage.Write([]byte(XMLSitemapPageHeader))
- XMLPage.Write(output)
- XMLPage.Write([]byte(XMLSitemapPageFooter))
- return XMLPage.String()
-}
-
-func XMLPageGenThreads(guildID snowflake.ID) string {
- var XMLPage bytes.Buffer
- var urlIndex URLSet
+ guilds, _ := s.discord.Cabinet.Guilds()
+ for _, guild := range guilds {
+ if err = enc.Encode(URL{
+ Location: fmt.Sprintf("https://dfs.ioi-xd.net/%s", guild.ID),
+ }); err != nil {
+ return err
+ }
- channels := Client.GetForums(guildID)
- for _, c := range channels {
- threads := Client.GetThreadsInChannel(c.ID())
- // todo: have this actually reflect when the channel was last updated.
- lastUpdatedFormat := time.Now().Format(time.RFC3339)
- for _, t := range threads {
- urlIndex = append(urlIndex, URL{
- Location: fmt.Sprintf("https://dfs.ioi-xd.net/%v/%v/%v", guildID, c.ID(), t.ID()),
- LastMod: lastUpdatedFormat,
- Frequency: "hourly",
- Priority: 1.0,
- })
+ channels, err := s.discord.Channels(guild.ID)
+ if err != nil {
+ return err
+ }
+ threads, err := s.discord.ActiveThreads(guild.ID)
+ if err != nil {
+ return err
+ }
+ for _, channel := range channels {
+ if channel.Type != discord.GuildForum {
+ continue
+ }
+ if err = enc.Encode(URL{
+ Location: fmt.Sprintf("https://dfs.ioi-xd.net/%s/%s", guild.ID, channel.ID),
+ }); err != nil {
+ return err
+ }
+ }
+ for _, thread := range threads.Threads {
+ for _, channel := range channels {
+ if channel.Type != discord.GuildForum {
+ continue
+ }
+ if thread.ParentID != channel.ID {
+ continue
+ }
+ if err = enc.Encode(URL{
+ Location: fmt.Sprintf("https://dfs.ioi-xd.net/%s/%s/%s", guild.ID, channel.ID, thread.ID),
+ }); err != nil {
+ return err
+ }
+ break
+ }
}
}
- output, err := xml.Marshal(urlIndex)
- if err != nil {
- return err.Error()
+ if err = enc.EncodeToken(XMLURLSetEnd); err != nil {
+ return err
}
- XMLPage.Write([]byte(XMLURLPageHeader))
- XMLPage.Write(output)
- XMLPage.Write([]byte(XMLURLPageFooter))
- return XMLPage.String()
-}
-
-func GZIPString(page string) (result []byte) {
- var b bytes.Buffer
- gzipWriter := gzip.NewWriter(&b)
- _, err := gzipWriter.Write([]byte(page))
- // todo: better error handling.
- if err != nil {
- fmt.Println(err)
- return
+ if err = enc.Flush(); err != nil {
+ return err
}
- gzipWriter.Close()
- return b.Bytes()
+ _, err = w.Write([]byte{'\n'})
+ return err
}
diff --git a/strings.go b/strings.go
deleted file mode 100644
index 0709438..0000000
--- a/strings.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package main
-
-import (
- "fmt"
- "strings"
- "time"
-
- "github.com/gomarkdown/markdown"
-)
-
-// Capitalize a string
-func Capitalize(value string) string {
- // Treat dashes as spaces
- value = strings.Replace(value, "-", " ", 99)
- valuesplit := strings.Split(value, " ")
- var result string
- for _, v := range valuesplit {
- if len(v) <= 0 {
- continue
- }
- result += strings.ToUpper(v[:1])
- result += v[1:] + " "
- }
- return result
-}
-
-// Trim a string to 128 characters, for meta tags.
-func TrimForMeta(value string) string {
- if len(value) <= 127 {
- return value
- }
- return value[:128] + "..."
-}
-
-// Parsing a markdown string.
-
-func Markdown(val string) []byte {
- return markdown.ToHTML([]byte(val), nil, nil)
-}
-
-// Function for formatting a timestamp as "x hours ago"
-func PrettyTime(timestamp time.Time) string {
- unixTimeDur := time.Now().Sub(timestamp)
-
- if unixTimeDur.Hours() >= 8760 {
- return fmt.Sprintf("%0.f years ago", unixTimeDur.Hours()/8760)
- }
- if unixTimeDur.Hours() >= 730 {
- return fmt.Sprintf("%0.f months ago", unixTimeDur.Hours()/730)
- }
- if unixTimeDur.Hours() >= 168 {
- return fmt.Sprintf("%0.f weeks ago", unixTimeDur.Hours()/168)
- }
- if unixTimeDur.Hours() >= 24 {
- return fmt.Sprintf("%0.f days ago", unixTimeDur.Hours()/24)
- }
- if unixTimeDur.Hours() >= 1 {
- return fmt.Sprintf("%0.f hours ago", unixTimeDur.Hours())
- }
- if unixTimeDur.Minutes() >= 1 {
- return fmt.Sprintf("%0.f minutes ago", unixTimeDur.Minutes())
- }
- return fmt.Sprintf("%0.f seconds ago", unixTimeDur.Seconds())
-}