Browse Source

refactoring

master
Christian Müller 8 years ago
parent
commit
bea4b5bef9
  1. 75
      render.go
  2. 19
      server.go
  3. 35
      stats.go
  4. 90
      storage.go

75
render.go

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
package main
import (
"errors"
"fmt"
"html/template"
"io/ioutil"
"net/http"
"regexp"
"strings"
"github.com/golang-commonmark/markdown"
"github.com/labstack/echo"
)
var (
errorCodes = map[int]string{
400: "Bad request",
401: "Unauthorized",
404: "Not found",
412: "Precondition failed",
503: "Service unavailable",
}
rexpNewLine = regexp.MustCompile("[\n\r]")
rexpNonAlphaNum = regexp.MustCompile("[`~!@#$%^&*_|+=?;:'\",.<>{}\\/]")
rexpNoScriptIframe = regexp.MustCompile("<.*?(iframe|script).*?>")
rexpLink = regexp.MustCompile("(ht|f)tp://[^\\s]+")
errorUnathorised = errors.New("id or password is wrong")
errorBadRequest = errors.New("password is empty")
)
func errPage(code int, details ...string) *Note {
text := errorCodes[code]
body := text
if len(details) > 0 {
body += ": " + strings.Join(details, ";")
}
n := &Note{
Title: text,
Text: fmt.Sprintf("# %d %s", code, body),
}
n.prepare()
return n
}
func (n *Note) prepare() {
fstLine := rexpNewLine.Split(n.Text, -1)[0]
maxLength := 25
if len(fstLine) < 25 {
maxLength = len(fstLine)
}
n.Text = rexpNoScriptIframe.ReplaceAllString(n.Text, "")
n.Title = strings.TrimSpace(rexpNonAlphaNum.ReplaceAllString(fstLine[:maxLength], ""))
n.Content = mdTmplHTML([]byte(n.Text))
}
var mdRenderer = markdown.New(markdown.HTML(true))
func mdTmplHTML(content []byte) template.HTML {
return template.HTML(mdRenderer.RenderToString(content))
}
func md2html(c echo.Context, name string) (*Note, int) {
path := "assets/markdown/" + name + ".md"
mdContent, err := ioutil.ReadFile(path)
if err != nil {
c.Logger().Errorf("couldn't open markdown page %q: %v", path, err)
code := http.StatusServiceUnavailable
return errPage(code), code
}
c.Logger().Debugf("rendering markdown page %q", name)
return &Note{Title: name, Content: mdTmplHTML(mdContent)}, http.StatusOK
}

19
server.go

@ -5,6 +5,7 @@ import ( @@ -5,6 +5,7 @@ import (
"html/template"
"io"
"io/ioutil"
"math"
"net/http"
"net/url"
"os"
@ -74,7 +75,7 @@ func main() { @@ -74,7 +75,7 @@ func main() {
}
}
defer stats.Store(n.ID, views+1)
if n.Fraud() {
if fraudelent(n) {
n.Ads = mdTmplHTML(ads)
}
c.Logger().Debugf("/%q requested; response code: %d", n.ID, code)
@ -160,14 +161,10 @@ func get(vals url.Values, key string) string { @@ -160,14 +161,10 @@ func get(vals url.Values, key string) string {
return ""
}
func md2html(c echo.Context, name string) (*Note, int) {
path := "assets/markdown/" + name + ".md"
mdContent, err := ioutil.ReadFile(path)
if err != nil {
c.Logger().Errorf("couldn't open markdown page %q: %v", path, err)
code := http.StatusServiceUnavailable
return errPage(code), code
}
c.Logger().Debugf("rendering markdown page %q", name)
return &Note{Title: name, Content: mdTmplHTML(mdContent)}, http.StatusOK
func fraudelent(n *Note) bool {
stripped := rexpLink.ReplaceAllString(n.Text, "")
l1 := len(n.Text)
l2 := len(stripped)
return n.Views > 100 &&
int(math.Ceil(100*float64(l1-l2)/float64(l1))) > fraudThreshold
}

35
stats.go

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
package main
import (
"database/sql"
"sync"
"time"
"github.com/labstack/echo"
)
const statsSavingInterval = 1 * time.Minute
func persistStats(logger echo.Logger, db *sql.DB, stats *sync.Map) {
for {
time.Sleep(statsSavingInterval)
tx, err := db.Begin()
if err != nil {
logger.Error(err)
return
}
c := 0
stats.Range(func(id, views interface{}) bool {
stmt, _ := tx.Prepare("update notes set views = ? where id = ?")
_, err := stmt.Exec(views, id)
if err == nil {
c++
}
stmt.Close()
defer stats.Delete(id)
return true
})
tx.Commit()
logger.Infof("successfully persisted %d values", c)
}
}

90
storage.go

@ -4,18 +4,13 @@ import ( @@ -4,18 +4,13 @@ import (
"bytes"
"crypto/sha256"
"database/sql"
"errors"
"fmt"
"html/template"
"math"
"math/rand"
"net/http"
"regexp"
"strings"
"sync"
"time"
"github.com/golang-commonmark/markdown"
"github.com/labstack/echo"
)
@ -24,27 +19,8 @@ func init() { @@ -24,27 +19,8 @@ func init() {
}
const (
idLength = 5
statsSavingInterval = 1 * time.Minute
fraudThreshold = 7
)
var (
errorCodes = map[int]string{
400: "Bad request",
401: "Unauthorized",
404: "Not found",
412: "Precondition failed",
503: "Service unavailable",
}
rexpNewLine = regexp.MustCompile("[\n\r]")
rexpNonAlphaNum = regexp.MustCompile("[`~!@#$%^&*_|+=?;:'\",.<>{}\\/]")
rexpNoScriptIframe = regexp.MustCompile("<.*?(iframe|script).*?>")
rexpLink = regexp.MustCompile("(ht|f)tp://[^\\s]+")
errorUnathorised = errors.New("id or password is wrong")
errorBadRequest = errors.New("password is empty")
idLength = 5
fraudThreshold = 7
)
type Note struct {
@ -54,55 +30,6 @@ type Note struct { @@ -54,55 +30,6 @@ type Note struct {
Content, Ads template.HTML
}
func errPage(code int, details ...string) *Note {
text := errorCodes[code]
body := text
if len(details) > 0 {
body += ": " + strings.Join(details, ";")
}
n := &Note{
Title: text,
Text: fmt.Sprintf("# %d %s", code, body),
}
n.prepare()
return n
}
func (n *Note) prepare() {
fstLine := rexpNewLine.Split(n.Text, -1)[0]
maxLength := 25
if len(fstLine) < 25 {
maxLength = len(fstLine)
}
n.Text = rexpNoScriptIframe.ReplaceAllString(n.Text, "")
n.Title = strings.TrimSpace(rexpNonAlphaNum.ReplaceAllString(fstLine[:maxLength], ""))
n.Content = mdTmplHTML([]byte(n.Text))
}
func persistStats(logger echo.Logger, db *sql.DB, stats *sync.Map) {
for {
time.Sleep(statsSavingInterval)
tx, err := db.Begin()
if err != nil {
logger.Error(err)
return
}
c := 0
stats.Range(func(id, views interface{}) bool {
stmt, _ := tx.Prepare("update notes set views = ? where id = ?")
_, err := stmt.Exec(views, id)
if err == nil {
c++
}
stmt.Close()
defer stats.Delete(id)
return true
})
tx.Commit()
logger.Infof("successfully persisted %d values", c)
}
}
func save(c echo.Context, db *sql.DB, n *Note) (*Note, error) {
if n.Password != "" {
n.Password = fmt.Sprintf("%x", sha256.Sum256([]byte(n.Password)))
@ -201,16 +128,3 @@ func load(c echo.Context, db *sql.DB) (*Note, int) { @@ -201,16 +128,3 @@ func load(c echo.Context, db *sql.DB) (*Note, int) {
}
return n, http.StatusOK
}
var mdRenderer = markdown.New(markdown.HTML(true))
func mdTmplHTML(content []byte) template.HTML {
return template.HTML(mdRenderer.RenderToString(content))
}
func (n *Note) Fraud() bool {
stripped := rexpLink.ReplaceAllString(n.Text, "")
l1 := len(n.Text)
l2 := len(stripped)
return int(math.Ceil(100*float64(l1-l2)/float64(l1))) > fraudThreshold
}

Loading…
Cancel
Save