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 "flag"
20 "fmt"
21 "html/template"
22 golog "log"
23 "log/syslog"
24 notrand "math/rand"
25 "os"
26 "runtime/pprof"
27 "sort"
28 "strings"
29 "time"
30
31 "humungus.tedunangst.com/r/webs/log"
32)
33
34var softwareVersion = "develop"
35
36func init() {
37 notrand.Seed(time.Now().Unix())
38}
39
40var serverName string
41var serverPrefix string
42var masqName string
43var dataDir = "."
44var viewDir = "."
45var iconName = "icon.png"
46var serverMsg template.HTML
47var aboutMsg template.HTML
48var loginMsg template.HTML
49
50func serverURL(u string, args ...interface{}) string {
51 return fmt.Sprintf("https://"+serverName+u, args...)
52}
53
54func ElaborateUnitTests() {
55 user, _ := butwhatabout("test")
56 syndicate(user, "https://mastodon.social/tags/mastoadmin.rss")
57}
58
59func unplugserver(hostname string) {
60 db := opendatabase()
61 xid := fmt.Sprintf("https://%s", hostname)
62 db.Exec("delete from honkers where xid = ? and flavor = 'dub'", xid)
63 db.Exec("delete from doovers where rcpt = ?", xid)
64 xid += "/%"
65 db.Exec("delete from honkers where xid like ? and flavor = 'dub'", xid)
66 db.Exec("delete from doovers where rcpt like ?", xid)
67}
68
69func reexecArgs(cmd string) []string {
70 args := []string{"-datadir", dataDir}
71 args = append(args, log.Args()...)
72 args = append(args, cmd)
73 return args
74}
75
76var elog, ilog, dlog *golog.Logger
77
78func errx(msg string, args ...interface{}) {
79 fmt.Fprintf(os.Stderr, msg+"\n", args...)
80 os.Exit(1)
81}
82
83var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
84var memprofile = flag.String("memprofile", "", "write memory profile to this file")
85var memprofilefd *os.File
86
87func usage() {
88 flag.PrintDefaults()
89 out := flag.CommandLine.Output()
90 fmt.Fprintf(out, "\n available honk commands:\n")
91 var msgs []string
92 for n, c := range commands {
93 msgs = append(msgs, fmt.Sprintf(" %s: %s\n", n, c.help))
94 }
95 sort.Strings(msgs)
96 fmt.Fprintf(out, "%s", strings.Join(msgs, ""))
97}
98
99func main() {
100 commands["help"] = cmd{
101 help: "you're looking at it",
102 callback: func(args []string) {
103 usage()
104 },
105 }
106 flag.StringVar(&dataDir, "datadir", getenv("HONK_DATADIR", dataDir), "data directory")
107 flag.StringVar(&viewDir, "viewdir", getenv("HONK_VIEWDIR", viewDir), "view directory")
108 flag.Usage = usage
109
110 flag.Parse()
111 if *cpuprofile != "" {
112 f, err := os.Create(*cpuprofile)
113 if err != nil {
114 errx("can't open cpu profile: %s", err)
115 }
116 pprof.StartCPUProfile(f)
117 }
118 if *memprofile != "" {
119 f, err := os.Create(*memprofile)
120 if err != nil {
121 errx("can't open mem profile: %s", err)
122 }
123 memprofilefd = f
124 }
125
126 log.Init(log.Options{Progname: "honk", Facility: syslog.LOG_UUCP})
127 elog = log.E
128 ilog = log.I
129 dlog = log.D
130
131 if os.Geteuid() == 0 {
132 elog.Fatalf("do not run honk as root")
133 }
134
135 args := flag.Args()
136 cmd := "run"
137 if len(args) > 0 {
138 cmd = args[0]
139 }
140 switch cmd {
141 case "init":
142 commands["init"].callback(args)
143 case "upgrade":
144 commands["upgrade"].callback(args)
145 case "version":
146 commands["version"].callback(args)
147 }
148 db := opendatabase()
149 dbversion := 0
150 getconfig("dbversion", &dbversion)
151 if dbversion != myVersion {
152 elog.Fatal("incorrect database version. run upgrade.")
153 }
154 getconfig("servermsg", &serverMsg)
155 getconfig("aboutmsg", &aboutMsg)
156 getconfig("loginmsg", &loginMsg)
157 getconfig("servername", &serverName)
158 getconfig("masqname", &masqName)
159 if masqName == "" {
160 masqName = serverName
161 }
162 serverPrefix = serverURL("/")
163 getconfig("usersep", &userSep)
164 getconfig("honksep", &honkSep)
165 getconfig("devel", &develMode)
166 if develMode {
167 gogglesDoNothing()
168 }
169 getconfig("fasttimeout", &fastTimeout)
170 getconfig("slowtimeout", &slowTimeout)
171 getconfig("honkwindow", &honkwindow)
172 honkwindow *= 24 * time.Hour
173
174 prepareStatements(db)
175
176 c, ok := commands[cmd]
177 if !ok {
178 errx("don't know about %q", cmd)
179 }
180
181 c.callback(args)
182}