Skip to content

Commit

Permalink
add support for resolving links locally
Browse files Browse the repository at this point in the history
Specify a command line argument to resolve a link locally and exit.

Also add a new flag, -resolve-from-backup, which loads a snapshot into
an in-memory database and resolves the specified link.
  • Loading branch information
willnorris committed Dec 6, 2022
1 parent 9d1e45f commit af7ceb5
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 5 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,7 @@ Only links that don't already exist in the database will be added.
golink -snapshot links.json

[JSON lines]: https://jsonlines.org/

You can also resolve links locally using a snapshot file:

golink -resolve-from-backup links.json go/link
47 changes: 42 additions & 5 deletions golink.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ import (
const defaultHostname = "go"

var (
verbose = flag.Bool("verbose", false, "be verbose")
sqlitefile = flag.String("sqlitedb", "", "path of SQLite database to store links")
dev = flag.String("dev-listen", "", "if non-empty, listen on this addr and run in dev mode; auto-set sqlitedb if empty and don't use tsnet")
snapshot = flag.String("snapshot", "", "file path of snapshot file")
hostname = flag.String("hostname", defaultHostname, "service name")
verbose = flag.Bool("verbose", false, "be verbose")
sqlitefile = flag.String("sqlitedb", "", "path of SQLite database to store links")
dev = flag.String("dev-listen", "", "if non-empty, listen on this addr and run in dev mode; auto-set sqlitedb if empty and don't use tsnet")
snapshot = flag.String("snapshot", "", "file path of snapshot file")
hostname = flag.String("hostname", defaultHostname, "service name")
resolveFromBackup = flag.String("resolve-from-backup", "", "resolve a link from snapshot file and exit")
)

var stats struct {
Expand All @@ -66,6 +67,16 @@ var localClient *tailscale.LocalClient
func Run() error {
flag.Parse()

// if resolving from backup, set sqlitefile and snapshot flags to
// restore links into an in-memory sqlite database.
if *resolveFromBackup != "" {
*sqlitefile = ":memory:"
snapshot = resolveFromBackup
if flag.NArg() != 1 {
log.Fatal("--resolve-from-backup also requires a link to be resolved")
}
}

if *sqlitefile == "" {
if devMode() {
tmpdir, err := ioutil.TempDir("", "golink_dev_*")
Expand Down Expand Up @@ -102,6 +113,16 @@ func Run() error {
log.Printf("initializing stats: %v", err)
}

// if link specified on command line, resolve and exit
if flag.NArg() > 0 {
destination, err := resolveLink(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
fmt.Println(destination)
os.Exit(0)
}

// flush stats periodically
go flushStatsLoop()

Expand Down Expand Up @@ -588,3 +609,19 @@ func restoreLastSnapshot() error {
}
return bs.Err()
}

func resolveLink(link string) (string, error) {
// if link specified as "go/name", trim "go" prefix.
// Remainder will parse as URL with no scheme or host
link = strings.TrimPrefix(link, *hostname)
u, err := url.Parse(link)
if err != nil {
return "", err
}
short, remainder, _ := strings.Cut(strings.TrimPrefix(u.RequestURI(), "/"), "/")
l, err := db.Load(short)
if err != nil {
return "", err
}
return expandLink(l.Long, expandEnv{Now: time.Now().UTC(), Path: remainder})
}
57 changes: 57 additions & 0 deletions golink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,60 @@ func TestExpandLink(t *testing.T) {
})
}
}

func TestResolveLink(t *testing.T) {
var err error
db, err = NewSQLiteDB(":memory:")
if err != nil {
t.Fatal(err)
}
db.Save(&Link{Short: "meet", Long: "https://meet.google.com/lookup/"})
db.Save(&Link{Short: "cs", Long: "http://codesearch/{{with .Path}}search?q={{.}}{{end}}"})

tests := []struct {
link string
want string
}{
{
link: "meet",
want: "https://meet.google.com/lookup/",
},
{
link: "meet/foo",
want: "https://meet.google.com/lookup/foo",
},
{
link: "go/meet/foo",
want: "https://meet.google.com/lookup/foo",
},
{
link: "http://go/meet/foo",
want: "https://meet.google.com/lookup/foo",
},
{
// if absolute URL provided, host doesn't actually matter
link: "http://mygo/meet/foo",
want: "https://meet.google.com/lookup/foo",
},
{
link: "cs",
want: "http://codesearch/",
},
{
link: "cs/term",
want: "http://codesearch/search?q=term",
},
}
for _, tt := range tests {
name := "golink " + tt.link
t.Run(name, func(t *testing.T) {
got, err := resolveLink(tt.link)
if err != nil {
t.Error(err)
}
if got != tt.want {
t.Errorf("ResolveLink(%q) = %q; want %q", tt.link, got, tt.want)
}
})
}
}

0 comments on commit af7ceb5

Please sign in to comment.