Compare commits
2 Commits
547bec5eb7
...
5822152537
| Author | SHA1 | Date |
|---|---|---|
|
|
5822152537 | |
|
|
cb21c3a498 |
|
|
@ -1,3 +1,4 @@
|
||||||
.bin
|
.bin
|
||||||
.vscode
|
.vscode
|
||||||
riffraff
|
riffraff
|
||||||
|
data.json
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"encoding/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
ListenAddress string `json:"listenAddress"`
|
|
||||||
DataPath string `json:"dataPath"`
|
|
||||||
Shortcuts Shortcuts `json:"shortcuts"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadConfig(configPath string) (Config, error) {
|
|
||||||
var configuration Config
|
|
||||||
file, err := os.Open(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return configuration, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
decoder := json.NewDecoder(file)
|
|
||||||
|
|
||||||
if err := decoder.Decode(&configuration); err != nil {
|
|
||||||
return configuration, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if configuration.Shortcuts == nil {
|
|
||||||
configuration.Shortcuts = make(map[string]string)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if _, ok := configuration.Shortcuts["*"]; !ok {
|
|
||||||
configuration.Shortcuts["*"] = DefaultSearchProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration.Shortcuts["help"] = "/"
|
|
||||||
|
|
||||||
if configuration.ListenAddress == "" {
|
|
||||||
configuration.ListenAddress = "127.0.0.1"
|
|
||||||
}
|
|
||||||
|
|
||||||
if configuration.DataPath == "" {
|
|
||||||
configuration.DataPath = "."
|
|
||||||
}
|
|
||||||
|
|
||||||
return configuration, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveShortcuts(path string, shorts Shortcuts) error {
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadShortcuts(path string) (Shortcuts, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
@ -10,9 +10,10 @@ import (
|
||||||
|
|
||||||
type Shortcuts map[string]string
|
type Shortcuts map[string]string
|
||||||
|
|
||||||
func NewServer(tp TemplateRenderer, shorts Shortcuts, accessLogging bool) http.Handler {
|
func NewServer(tp TemplateRenderer, shortcutStore *ShortcutStore, accessLogging bool) http.Handler {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
|
shorts, _ := shortcutStore.LoadShortcuts()
|
||||||
ss := &CommandHandler{
|
ss := &CommandHandler{
|
||||||
Mutex: &sync.Mutex{},
|
Mutex: &sync.Mutex{},
|
||||||
Shortcuts: shorts,
|
Shortcuts: shorts,
|
||||||
|
|
@ -24,14 +25,14 @@ func NewServer(tp TemplateRenderer, shorts Shortcuts, accessLogging bool) http.H
|
||||||
"Content-Type": []string{"application/opensearchdescription+xml"},
|
"Content-Type": []string{"application/opensearchdescription+xml"},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
handlerFunc := searchHandler(ss, accessLogging)
|
handlerFunc := searchHandler(ss, shortcutStore, accessLogging)
|
||||||
mux.HandleFunc("/search", handlerFunc)
|
mux.HandleFunc("/search", handlerFunc)
|
||||||
mux.HandleFunc("/search_to_home", handlerFunc)
|
mux.HandleFunc("/search_to_home", handlerFunc)
|
||||||
|
|
||||||
return mux
|
return mux
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchHandler(scs *CommandHandler, logAccess bool) http.HandlerFunc {
|
func searchHandler(scs *CommandHandler, shortcutStore *ShortcutStore, logAccess bool) http.HandlerFunc {
|
||||||
accessLogger := log.New(os.Stdout, "[access] ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
|
accessLogger := log.New(os.Stdout, "[access] ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
|
||||||
|
|
||||||
return func(res http.ResponseWriter, req *http.Request) {
|
return func(res http.ResponseWriter, req *http.Request) {
|
||||||
|
|
@ -45,6 +46,15 @@ func searchHandler(scs *CommandHandler, logAccess bool) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
accessLogger.Printf("'%s' %s -> 302 %s", commandString, action.Action, action.Location)
|
accessLogger.Printf("'%s' %s -> 302 %s", commandString, action.Action, action.Location)
|
||||||
|
|
||||||
|
if action.Action != "lookup" {
|
||||||
|
if err := shortcutStore.SaveShortcuts(scs.Shortcuts); err != nil {
|
||||||
|
accessLogger.Printf("'%s' %s -> could not save shortcuts database file: %v", commandString, action.Action, err)
|
||||||
|
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
http.Redirect(res, req, action.Location, http.StatusFound)
|
http.Redirect(res, req, action.Location, http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,13 @@ func (c *CommandHandler) getShortcut(key string, input ...string) Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewDefaultShortcuts() (Shortcuts) {
|
||||||
|
return Shortcuts{
|
||||||
|
"*": DefaultSearchProvider,
|
||||||
|
"help": "/",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Action string
|
Action string
|
||||||
Name string
|
Name string
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"log"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ShortcutStore struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShortcutData struct {
|
||||||
|
Shortcuts Shortcuts `json:"shortcuts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *ShortcutStore) Init() error {
|
||||||
|
defaultSS := NewDefaultShortcuts()
|
||||||
|
if _, err := os.Stat(ss.Path); os.IsNotExist(err) {
|
||||||
|
log.Printf("file doesn't exist %s: %v", ss.Path, err)
|
||||||
|
if err := ss.SaveShortcuts(defaultSS); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if _, err := ss.LoadShortcuts(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *ShortcutStore) SaveShortcuts(shorts Shortcuts) error {
|
||||||
|
// remove help shortcut
|
||||||
|
|
||||||
|
file, err := os.Create(ss.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
temp := Shortcuts{}
|
||||||
|
|
||||||
|
for k, v := range shorts {
|
||||||
|
if k != "help" {
|
||||||
|
temp[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sc := ShortcutData{ Shortcuts: temp }
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(file)
|
||||||
|
encoder.SetIndent("", "\t")
|
||||||
|
if err := encoder.Encode(&sc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *ShortcutStore) LoadShortcuts() (Shortcuts, error) {
|
||||||
|
var sc ShortcutData
|
||||||
|
file, err := os.Open(ss.Path)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsExist(err) {
|
||||||
|
return NewDefaultShortcuts(), nil
|
||||||
|
}
|
||||||
|
return sc.Shortcuts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
finfo, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return sc.Shortcuts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if finfo.Size() == 0 {
|
||||||
|
return NewDefaultShortcuts(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
|
||||||
|
if err := decoder.Decode(&sc); err != nil {
|
||||||
|
return sc.Shortcuts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc.Shortcuts == nil {
|
||||||
|
return NewDefaultShortcuts(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.Shortcuts["help"] = "/"
|
||||||
|
|
||||||
|
if v, ok := sc.Shortcuts["*"]; !ok || v == "" {
|
||||||
|
sc.Shortcuts["*"] = DefaultSearchProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
return sc.Shortcuts, nil
|
||||||
|
}
|
||||||
14
main.go
14
main.go
|
|
@ -12,23 +12,25 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
port := flag.Int("port", 80, "port to listen on")
|
port := flag.Int("port", 80, "port to listen on")
|
||||||
cfgPath := flag.String("config", "./config.json", "path to config file")
|
bindAddr := flag.String("bind", "0.0.0.0", "interface to bind to")
|
||||||
|
dbPath := flag.String("data", "./data.json", "path to save shortcut database")
|
||||||
enableAccessLogging := flag.Bool("accesslog", true, "Enable access logging")
|
enableAccessLogging := flag.Bool("accesslog", true, "Enable access logging")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
box := packr.NewBox("./internal/templates")
|
box := packr.NewBox("./internal/templates")
|
||||||
tp := internal.TemplateRenderer{FS: box}
|
tp := internal.TemplateRenderer{FS: box}
|
||||||
|
|
||||||
config, err := internal.LoadConfig(*cfgPath)
|
ss := &internal.ShortcutStore{Path: *dbPath}
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("could not load config from file: %v", err)
|
if err := ss.Init(); err != nil {
|
||||||
|
log.Fatalf("could not access database file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
server := internal.NewServer(tp, config.Shortcuts, *enableAccessLogging)
|
server := internal.NewServer(tp, ss, *enableAccessLogging)
|
||||||
|
|
||||||
log.SetPrefix("[INFO] ")
|
log.SetPrefix("[INFO] ")
|
||||||
|
|
||||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress, *port)
|
addr := fmt.Sprintf("%s:%d", *bindAddr, *port)
|
||||||
log.Printf("Listening @ %s", addr)
|
log.Printf("Listening @ %s", addr)
|
||||||
log.Fatal(http.ListenAndServe(addr, server))
|
log.Fatal(http.ListenAndServe(addr, server))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
makefile
17
makefile
|
|
@ -1,7 +1,7 @@
|
||||||
APP := riffraff
|
APP := riffraff
|
||||||
|
|
||||||
dev: clean .bin/$(APP)-dev
|
dev: clean .bin/$(APP)-dev
|
||||||
./.bin/$(APP)-dev -port 8080 -accesslog=true
|
./.bin/$(APP)-dev -port 8080 -accesslog=true -data=data.json
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -v ./...
|
go test -v ./...
|
||||||
|
|
@ -29,6 +29,21 @@ build: .bin/$(APP)
|
||||||
clean:
|
clean:
|
||||||
rm -rf .bin
|
rm -rf .bin
|
||||||
|
|
||||||
|
clobber: clean
|
||||||
|
rm -rf data.json
|
||||||
|
|
||||||
|
data.json:
|
||||||
|
cat <<EOF >> ./data.json
|
||||||
|
{
|
||||||
|
"shortcuts": {
|
||||||
|
"*": "https://duckduckgo.com/%s",
|
||||||
|
"fb": "https://facebook.com",
|
||||||
|
"gh": "https://github.com",
|
||||||
|
"gitemoji": "https://www.webfx.com/tools/emoji-cheat-sheet/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
packr:
|
packr:
|
||||||
go get -u github.com/gobuffalo/packr/packr
|
go get -u github.com/gobuffalo/packr/packr
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue