Files
newsgo/server/serve.go
ungrentquest 2fd20db19b Adopt cobra & viper.
Define build sign and serve subcommands
2025-04-19 23:11:19 +00:00

157 lines
3.6 KiB
Go

package newsserver
import (
"crypto/sha256"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strings"
stats "github.com/go-i2p/newsgo/server/stats"
"gitlab.com/golang-commonmark/markdown"
)
type NewsServer struct {
NewsDir string
Stats stats.NewsStats
}
var serveTest http.Handler = &NewsServer{}
func (n *NewsServer) ServeHTTP(rw http.ResponseWriter, rq *http.Request) {
path := rq.URL.Path
file := filepath.Join(n.NewsDir, path)
if err := fileCheck(file); err != nil {
log.Println("ServeHTTP:", err.Error())
rw.WriteHeader(404)
return
}
if err := n.ServeFile(file, rq, rw); err != nil {
log.Println("ServeHTTP:", err.Error())
rw.WriteHeader(404)
}
}
func fileCheck(file string) error {
if filepath.Ext(file) == ".svg" {
return nil
}
if _, err := os.Stat(file); err != nil {
return fmt.Errorf("fileCheck: %s", err)
}
return nil
}
func fileType(file string) (string, error) {
base := filepath.Base(file)
if base == "" {
return "", fmt.Errorf("fileType: Invalid file path passed to type determinator")
}
extension := filepath.Ext(base)
switch extension {
case ".su3":
return "application/x-i2p-su3-news", nil
case ".html":
return "text/html", nil
case ".xml":
return "application/rss+xml", nil
case ".atom.xml":
return "application/rss+xml", nil
case ".svg":
return "image/svg+xml", nil
default:
return "text/html", nil
}
}
func openDirectory(wd string) string {
//wd = strings.Replace(wd, leader, "", 1)
files, err := ioutil.ReadDir(wd)
if err != nil {
log.Fatal(err)
}
var readme string
log.Println("Navigating directory:", wd)
nwd := strings.Join(strings.Split(wd, "/")[1:], "/")
readme += fmt.Sprintf("%s\n", filepath.Base(wd))
readme += fmt.Sprintf("%s\n", head(len(filepath.Base(wd))))
readme += fmt.Sprintf("%s\n", "")
readme += fmt.Sprintf("%s\n", "![language stats](langstats.svg)")
readme += fmt.Sprintf("%s\n", "")
readme += fmt.Sprintf("%s\n", "**Directory Listing:**")
readme += fmt.Sprintf("%s\n", "")
for _, file := range files {
if !file.IsDir() {
fmt.Println(file.Name(), file.IsDir())
xname := filepath.Join(wd, file.Name())
bytes, err := ioutil.ReadFile(xname)
if err != nil {
log.Println("Listing error:", err)
}
sum := fmt.Sprintf("%x", sha256.Sum256(bytes))
readme += fmt.Sprintf(" - [%s](%s/%s) : `%d` : `%s` - `%s`\n", file.Name(), filepath.Base(nwd), filepath.Base(file.Name()), file.Size(), file.Mode(), sum)
} else {
fmt.Println(file.Name(), file.IsDir())
readme += fmt.Sprintf(" - [%s](%s/) : `%d` : `%s`\n", file.Name(), file.Name(), file.Size(), file.Mode())
}
}
return readme
}
func hTML(mdtxt string) []byte {
md := markdown.New(markdown.XHTMLOutput(true))
return []byte(md.RenderToString([]byte(mdtxt)))
}
func head(num int) string {
var r string
for i := 0; i < num; i++ {
r += "="
}
return r
}
func (n *NewsServer) ServeFile(file string, rq *http.Request, rw http.ResponseWriter) error {
ftype, err := fileType(file)
if err != nil {
return fmt.Errorf("ServeFile: %s", err)
}
if ftype == "application/x-i2p-su3-news" {
// Log stats here
n.Stats.Increment(rq)
}
rw.Header().Add("Content-Type", ftype)
if ftype == "image/svg+xml" {
n.Stats.Graph(rw)
return nil
}
f, _ := os.Stat(file)
if f.IsDir() {
bytes := hTML(openDirectory(file))
rw.Write(bytes)
return nil
}
bytes, err := ioutil.ReadFile(file)
if err != nil {
return fmt.Errorf("ServeFile: %s", err)
}
log.Println("ServeFile: ", file, ftype)
rw.Write(bytes)
return nil
}
func Serve(newsDir string, newsStats string) *NewsServer {
s := &NewsServer{
NewsDir: newsDir,
Stats: stats.NewsStats{
StateFile: newsStats,
},
}
s.Stats.Load()
return s
}