all repos — honk @ 2a20b1671d9f032ffffb1023dd104e2e7e4f31ec

my fork of honk

main.go (view raw)

  1//
  2// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
  3//
  4// Permission to use, copy, modify, and distribute this software for any
  5// purpose with or without fee is hereby granted, provided that the above
  6// copyright notice and this permission notice appear in all copies.
  7//
  8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15
 16package main
 17
 18import (
 19	"errors"
 20	"flag"
 21	"fmt"
 22	"html/template"
 23	"io/fs"
 24	golog "log"
 25	"log/syslog"
 26	notrand "math/rand"
 27	"os"
 28	"runtime/pprof"
 29	"sort"
 30	"strings"
 31	"time"
 32
 33	"humungus.tedunangst.com/r/webs/log"
 34)
 35
 36var softwareVersion = "develop"
 37
 38func init() {
 39	notrand.Seed(time.Now().Unix())
 40}
 41
 42var serverName string
 43var serverPrefix string
 44var masqName string
 45var dataDir = "."
 46var viewDir = "."
 47var iconName = "icon.png"
 48var serverMsg template.HTML
 49var aboutMsg template.HTML
 50var loginMsg template.HTML
 51
 52func serverURL(u string, args ...interface{}) string {
 53	return fmt.Sprintf("https://"+serverName+u, args...)
 54}
 55
 56func ElaborateUnitTests() {
 57	user, _ := butwhatabout("test")
 58	syndicate(user, "https://mastodon.social/tags/mastoadmin.rss")
 59}
 60
 61func unplugserver(hostname string) {
 62	db := opendatabase()
 63	xid := fmt.Sprintf("https://%s", hostname)
 64	db.Exec("delete from honkers where xid = ? and flavor = 'dub'", xid)
 65	db.Exec("delete from doovers where rcpt = ?", xid)
 66	xid += "/%"
 67	db.Exec("delete from honkers where xid like ? and flavor = 'dub'", xid)
 68	db.Exec("delete from doovers where rcpt like ?", xid)
 69}
 70
 71func reexecArgs(cmd string) []string {
 72	args := []string{"-datadir", dataDir}
 73	args = append(args, log.Args()...)
 74	args = append(args, cmd)
 75	return args
 76}
 77
 78var elog, ilog, dlog *golog.Logger
 79
 80func errx(msg string, args ...interface{}) {
 81	fmt.Fprintf(os.Stderr, msg+"\n", args...)
 82	os.Exit(1)
 83}
 84
 85var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
 86var memprofile = flag.String("memprofile", "", "write memory profile to this file")
 87var memprofilefd *os.File
 88
 89func usage() {
 90	flag.PrintDefaults()
 91	out := flag.CommandLine.Output()
 92	fmt.Fprintf(out, "\n  available honk commands:\n")
 93	var msgs []string
 94	for n, c := range commands {
 95		msgs = append(msgs, fmt.Sprintf("    %s: %s\n", n, c.help))
 96	}
 97	sort.Strings(msgs)
 98	fmt.Fprintf(out, "%s", strings.Join(msgs, ""))
 99}
100
101func main() {
102	commands["help"] = cmd{
103		help: "you're looking at it",
104		callback: func(args []string) {
105			usage()
106		},
107	}
108	flag.StringVar(&dataDir, "datadir", getenv("HONK_DATADIR", dataDir), "data directory")
109	flag.StringVar(&viewDir, "viewdir", getenv("HONK_VIEWDIR", viewDir), "view directory")
110	flag.Usage = usage
111
112	flag.Parse()
113	if *cpuprofile != "" {
114		f, err := os.Create(*cpuprofile)
115		if err != nil {
116			errx("can't open cpu profile: %s", err)
117		}
118		pprof.StartCPUProfile(f)
119	}
120	if *memprofile != "" {
121		f, err := os.Create(*memprofile)
122		if err != nil {
123			errx("can't open mem profile: %s", err)
124		}
125		memprofilefd = f
126	}
127
128	log.Init(log.Options{Progname: "honk", Facility: syslog.LOG_UUCP})
129	elog = log.E
130	ilog = log.I
131	dlog = log.D
132
133	if os.Geteuid() == 0 {
134		elog.Fatalf("do not run honk as root")
135	}
136
137	err := os.Mkdir(dataDir+"/attachments", 0700)
138	if err != nil && !errors.Is(err, fs.ErrExist) {
139		errx("can't create attachments directory: %s", err)
140	}
141
142	args := flag.Args()
143	cmd := "run"
144	if len(args) > 0 {
145		cmd = args[0]
146	}
147	switch cmd {
148	case "init":
149		commands["init"].callback(args)
150	case "upgrade":
151		commands["upgrade"].callback(args)
152	case "version":
153		commands["version"].callback(args)
154	}
155	db := opendatabase()
156	dbversion := 0
157	getconfig("dbversion", &dbversion)
158	if dbversion != myVersion {
159		elog.Fatal("incorrect database version. run upgrade.")
160	}
161	getconfig("servermsg", &serverMsg)
162	getconfig("aboutmsg", &aboutMsg)
163	getconfig("loginmsg", &loginMsg)
164	getconfig("servername", &serverName)
165	getconfig("masqname", &masqName)
166	if masqName == "" {
167		masqName = serverName
168	}
169	serverPrefix = serverURL("/")
170	getconfig("usersep", &userSep)
171	getconfig("honksep", &honkSep)
172	getconfig("devel", &develMode)
173	if develMode {
174		gogglesDoNothing()
175	}
176	getconfig("fasttimeout", &fastTimeout)
177	getconfig("slowtimeout", &slowTimeout)
178	getconfig("honkwindow", &honkwindow)
179	honkwindow *= 24 * time.Hour
180
181	prepareStatements(db)
182
183	dbx := opendatabasex()
184	prepareStatementsx(dbx)
185
186	c, ok := commands[cmd]
187	if !ok {
188		errx("don't know about %q", cmd)
189	}
190
191	c.callback(args)
192}