From 97dc50bcfb7d4296dd11348b9d7470821fb6afbc Mon Sep 17 00:00:00 2001
From: Feuerfuchs <git@feuerfuchs.dev>
Date: Mon, 18 May 2020 14:14:25 +0200
Subject: WIP: Refactoring

---
 internal/port/gemini.go | 176 +++++++++++++++++++++++++++++++++++++-----------
 internal/port/gopher.go |   2 +-
 internal/port/main.go   |   2 +
 3 files changed, 140 insertions(+), 40 deletions(-)

(limited to 'internal/port')

diff --git a/internal/port/gemini.go b/internal/port/gemini.go
index f9b0b97..b10da7d 100644
--- a/internal/port/gemini.go
+++ b/internal/port/gemini.go
@@ -1,6 +1,7 @@
 package port
 
 import (
+	"bufio"
 	"bytes"
 	"fmt"
 	"html/template"
@@ -15,11 +16,32 @@ import (
 	"golang.org/x/net/html/charset"
 	"golang.org/x/text/transform"
 
-	"git.vulpes.one/Feuerfuchs/port/port/libgemini"
+	"git.vulpes.one/Feuerfuchs/port/pkg/libgemini"
 
 	"github.com/temoto/robotstxt"
 )
 
+type SectionType byte
+
+const (
+	RAW_TEXT    = SectionType(0)
+	REFLOW_TEXT = SectionType(1)
+	LINK        = SectionType(2)
+)
+
+type Section struct {
+	Type SectionType
+	Text string
+	URL  template.URL
+}
+
+type templateVariables struct {
+	Title    string
+	URI      string
+	Assets   AssetList
+	Sections []Section
+}
+
 var (
 	TermEscapeSGRPattern = regexp.MustCompile("\\[\\d+(;\\d+)*m")
 )
@@ -53,6 +75,80 @@ func resolveURI(uri string, baseURL *url.URL) (resolvedURI string) {
 	return
 }
 
+func parseGeminiDocument(body *bytes.Buffer, uri string, hostport string) (sections []Section) {
+	baseURL, err := url.Parse(fmt.Sprintf(
+		"gemini://%s/%s",
+		hostport,
+		uri,
+	))
+	if err != nil {
+		return []Section{}
+	}
+
+	skipSection := true
+
+	section := Section{
+		Type: RAW_TEXT,
+	}
+
+	scanner := bufio.NewScanner(body)
+
+	for scanner.Scan() {
+		line := strings.Trim(scanner.Text(), "\r\n")
+		line = TermEscapeSGRPattern.ReplaceAllString(line, "")
+
+		linkMatch := libgemini.LinkPattern.FindStringSubmatch(line)
+		if len(linkMatch) != 0 && linkMatch[0] != "" {
+			curType := section.Type
+
+			if !skipSection {
+				sections = append(sections, section)
+			}
+
+			label := linkMatch[2]
+			if label == "" {
+				label = linkMatch[1]
+			}
+
+			sections = append(sections, Section{
+				Type: LINK,
+				Text: label,
+				URL:  template.URL(resolveURI(linkMatch[1], baseURL)),
+			})
+
+			skipSection = false
+			section = Section{
+				Type: curType,
+			}
+		} else {
+			reflowModeMatch := libgemini.ReflowModePattern.FindStringSubmatch(line)
+			if len(reflowModeMatch) != 0 {
+				newType := RAW_TEXT
+				if section.Type == RAW_TEXT {
+					newType = REFLOW_TEXT
+				}
+
+				if !skipSection {
+					sections = append(sections, section)
+				}
+
+				skipSection = false
+				section = Section{
+					Type: newType,
+				}
+			} else {
+				section.Text = section.Text + "\n" + line
+			}
+		}
+	}
+
+	if !skipSection {
+		sections = append(sections, section)
+	}
+
+	return
+}
+
 func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, assetList AssetList, robotsdebug bool) http.HandlerFunc {
 	return func(w http.ResponseWriter, req *http.Request) {
 		agent := req.UserAgent()
@@ -80,13 +176,14 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass
 
 		uri, err := url.QueryUnescape(strings.Join(parts[1:], "/"))
 		if err != nil {
-			if e := tpl.Execute(w, TemplateVariables{
-				Title:    title,
-				URI:      hostport,
-				Assets:   assetList,
-				RawText:  fmt.Sprintf("Error: %s", err),
-				Error:    true,
-				Protocol: "gemini",
+			if e := tpl.Execute(w, templateVariables{
+				Title:  title,
+				URI:    hostport,
+				Assets: assetList,
+				Sections: []Section{{
+					Type: RAW_TEXT,
+					Text: fmt.Sprintf("Error: %s", err),
+				}},
 			}); e != nil {
 				log.Println("Template error: " + e.Error())
 				log.Println(err.Error())
@@ -108,13 +205,14 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass
 		)
 
 		if err != nil {
-			if e := tpl.Execute(w, TemplateVariables{
-				Title:    title,
-				URI:      fmt.Sprintf("%s/%s", hostport, uri),
-				Assets:   assetList,
-				RawText:  fmt.Sprintf("Error: %s", err),
-				Error:    true,
-				Protocol: "gemini",
+			if e := tpl.Execute(w, templateVariables{
+				Title:  title,
+				URI:    fmt.Sprintf("%s/%s", hostport, uri),
+				Assets: assetList,
+				Sections: []Section{{
+					Type: RAW_TEXT,
+					Text: fmt.Sprintf("Error: %s", err),
+				}},
 			}); e != nil {
 				log.Println("Template error: " + e.Error())
 				log.Println(err.Error())
@@ -129,13 +227,14 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass
 				uri,
 			))
 			if err != nil {
-				if e := tpl.Execute(w, TemplateVariables{
-					Title:    title,
-					URI:      fmt.Sprintf("%s/%s", hostport, uri),
-					Assets:   assetList,
-					RawText:  fmt.Sprintf("Error: %s", err),
-					Error:    true,
-					Protocol: "gemini",
+				if e := tpl.Execute(w, templateVariables{
+					Title:  title,
+					URI:    fmt.Sprintf("%s/%s", hostport, uri),
+					Assets: assetList,
+					Sections: []Section{{
+						Type: RAW_TEXT,
+						Text: fmt.Sprintf("Error: %s", err),
+					}},
 				}); e != nil {
 					log.Println("Template error: " + e.Error())
 					log.Println(err.Error())
@@ -148,13 +247,14 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass
 		}
 
 		if int(res.Header.Status/10) != 2 {
-			if err := tpl.Execute(w, TemplateVariables{
-				Title:    title,
-				URI:      fmt.Sprintf("%s/%s", hostport, uri),
-				Assets:   assetList,
-				RawText:  fmt.Sprintf("Error %d: %s", res.Header.Status, res.Header.Meta),
-				Error:    true,
-				Protocol: "gemini",
+			if err := tpl.Execute(w, templateVariables{
+				Title:  title,
+				URI:    fmt.Sprintf("%s/%s", hostport, uri),
+				Assets: assetList,
+				Sections: []Section{{
+					Type: RAW_TEXT,
+					Text: fmt.Sprintf("Error %d: %s", res.Header.Status, res.Header.Meta),
+				}},
 			}); err != nil {
 				log.Println("Template error: " + err.Error())
 			}
@@ -177,24 +277,22 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass
 				writer.Close()
 			}
 
-			var (
-				rawText string
-				items   []Item
-			)
+			var sections []Section
 
 			if strings.HasPrefix(res.Header.Meta, libgemini.MIME_GEMINI) {
-				items = parseGeminiDocument(buf, uri, hostport)
+				sections = parseGeminiDocument(buf, uri, hostport)
 			} else {
-				rawText = buf.String()
+				sections = append(sections, Section{
+					Type: RAW_TEXT,
+					Text: buf.String(),
+				})
 			}
 
-			if err := tpl.Execute(w, TemplateVariables{
+			if err := tpl.Execute(w, templateVariables{
 				Title:    title,
 				URI:      fmt.Sprintf("%s/%s", hostport, uri),
 				Assets:   assetList,
-				Lines:    items,
-				RawText:  rawText,
-				Protocol: "gemini",
+				Sections: sections,
 			}); err != nil {
 				log.Println("Template error: " + err.Error())
 			}
diff --git a/internal/port/gopher.go b/internal/port/gopher.go
index ebeb213..abbc4d9 100644
--- a/internal/port/gopher.go
+++ b/internal/port/gopher.go
@@ -11,7 +11,7 @@ import (
 	"net/url"
 	"strings"
 
-	"git.vulpes.one/Feuerfuchs/port/port/libgopher"
+	"git.vulpes.one/Feuerfuchs/port/pkg/libgopher"
 
 	"github.com/davidbyttow/govips/pkg/vips"
 	"github.com/temoto/robotstxt"
diff --git a/internal/port/main.go b/internal/port/main.go
index 5cdd794..9fa245e 100644
--- a/internal/port/main.go
+++ b/internal/port/main.go
@@ -205,6 +205,8 @@ func ListenAndServe(bind, startpagefile string, robotsfile string, robotsdebug b
 	//
 	//
 
+	var templates *template.Template
+
 	var allFiles []string
 	files, err := ioutil.ReadDir("./tpl")
 	if err != nil {
-- 
cgit v1.2.3-70-g09d2