all repos — flounder @ 9ca9f79a9bb4c14f1d4a3bdd7f136f7dc86b1d4d

A small site builder for the Gemini protocol

utils.go (view raw)

  1package main
  2
  3import (
  4	"archive/zip"
  5	"fmt"
  6	"io"
  7	"os"
  8	"path"
  9	"path/filepath"
 10	"strings"
 11	"time"
 12)
 13
 14func isGemini(filename string) bool {
 15	extension := path.Ext(filename)
 16	return extension == ".gmi" || extension == ".gemini"
 17}
 18
 19func timeago(t *time.Time) string {
 20	d := time.Since(*t)
 21	if d.Seconds() < 60 {
 22		seconds := int(d.Seconds())
 23		if seconds == 1 {
 24			return "1 second ago"
 25		}
 26		return fmt.Sprintf("%d seconds ago", seconds)
 27	} else if d.Minutes() < 60 {
 28		minutes := int(d.Minutes())
 29		if minutes == 1 {
 30			return "1 minute ago"
 31		}
 32		return fmt.Sprintf("%d minutes ago", minutes)
 33	} else if d.Hours() < 24 {
 34		hours := int(d.Hours())
 35		if hours == 1 {
 36			return "1 hour ago"
 37		}
 38		return fmt.Sprintf("%d hours ago", hours)
 39	} else {
 40		days := int(d.Hours()) / 24
 41		if days == 1 {
 42			return "1 day ago"
 43		}
 44		return fmt.Sprintf("%d days ago", days)
 45	}
 46}
 47
 48// safe
 49func getUserDirectory(username string) string {
 50	// extra filepath.clean just to be safe
 51	userFolder := path.Join(c.FilesDirectory, filepath.Clean(username))
 52	return userFolder
 53}
 54
 55// ugh idk
 56func safeGetFilePath(username string, filename string) string {
 57	return path.Join(getUserDirectory(username), filepath.Clean(filename))
 58}
 59
 60// TODO move into checkIfValidFile. rename it
 61func userHasSpace(user string, newBytes int) bool {
 62	userPath := path.Join(c.FilesDirectory, user)
 63	size, err := dirSize(userPath)
 64	if err != nil || size+int64(newBytes) > c.MaxUserBytes {
 65		return false
 66	}
 67	return true
 68}
 69
 70func dirSize(path string) (int64, error) {
 71	var size int64
 72	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
 73		if err != nil {
 74			return err
 75		}
 76		if !info.IsDir() {
 77			size += info.Size()
 78		}
 79		return err
 80	})
 81	return size, err
 82}
 83
 84/// Perform some checks to make sure the file is OK
 85func checkIfValidFile(filename string, fileBytes []byte) error {
 86	if len(filename) == 0 {
 87		return fmt.Errorf("Please enter a filename")
 88	}
 89	if len(filename) > 256 { // arbitrarily chosen
 90		return fmt.Errorf("Filename is too long")
 91	}
 92	ext := strings.ToLower(path.Ext(filename))
 93	found := false
 94	for _, mimetype := range c.OkExtensions {
 95		if ext == mimetype {
 96			found = true
 97		}
 98	}
 99	if !found {
100		return fmt.Errorf("Invalid file extension: %s", ext)
101	}
102	if len(fileBytes) > c.MaxFileBytes {
103		return fmt.Errorf("File too large. File was %d bytes, Max file size is %d", len(fileBytes), c.MaxFileBytes)
104	}
105	//
106	return nil
107}
108
109func zipit(source string, target io.Writer) error {
110	archive := zip.NewWriter(target)
111
112	info, err := os.Stat(source)
113	if err != nil {
114		return nil
115	}
116
117	var baseDir string
118	if info.IsDir() {
119		baseDir = filepath.Base(source)
120	}
121
122	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
123		if err != nil {
124			return err
125		}
126
127		header, err := zip.FileInfoHeader(info)
128		if err != nil {
129			return err
130		}
131
132		if baseDir != "" {
133			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
134		}
135
136		if info.IsDir() {
137			header.Name += "/"
138		} else {
139			header.Method = zip.Deflate
140		}
141
142		writer, err := archive.CreateHeader(header)
143		if err != nil {
144			return err
145		}
146
147		if info.IsDir() {
148			return nil
149		}
150
151		file, err := os.Open(path)
152		if err != nil {
153			return err
154		}
155		defer file.Close()
156		_, err = io.Copy(writer, file)
157		return err
158	})
159
160	archive.Close()
161
162	return err
163}