tvl-depot/users/wpcarro/gopkgs/utils/utils.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

132 lines
2.9 KiB
Go
Raw Normal View History

// Some utility functions to tidy up my Golang.
package utils
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"os"
"os/user"
"path/filepath"
)
// Return the absolute path to the current uesr's home directory.
func HomeDir() string {
user, err := user.Current()
if err != nil {
log.Fatal(err)
}
return user.HomeDir
}
// Returns true if `info` is a symlink.
func IsSymlink(info os.FileMode) bool {
return info&os.ModeSymlink != 0
}
// Return true if `path` exists and false otherwise.
func FileExists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
} else {
return true
}
}
// Return the absolute file path of `file` using the following resolution
// strategy:
// - Traverse and search upwards until you reach the user's home directory
// - Return the first path in `backupPaths` that exists
// - Fail
func Resolve(fileName string, backupPaths []string) string {
// TODO(wpcarro): Drop hardcoding when whoami behaves as expected.
boundary := "/home"
cwd := "."
files, _ := ioutil.ReadDir(cwd)
for {
fullCwd, _ := filepath.Abs(cwd)
if fullCwd == boundary {
break
}
for _, file := range files {
if file.Name() == fileName {
path, _ := filepath.Abs(cwd + "/" + file.Name())
return path
}
}
cwd += "/.."
files, _ = ioutil.ReadDir(cwd)
}
// TODO(wpcarro): Support expanding these paths to allow the consumer to
// pass in relative paths, and paths with "~" in them.
for _, backup := range backupPaths {
if FileExists(backup) {
return backup
}
}
log.Fatal("Cannot find a run.json to use.")
// This code should be unreachable.
return ""
}
// Call log.Fatal with `err` when it's not nil.
func FailOn(err error) {
if err != nil {
log.Fatal(err)
}
}
Create server for managing Monzo credentials I created a server to manage my access and refresh tokens. This server exposes a larger API than it needs to at the moment, but that should change. The goal is to expose a GET at /token to retrieve a valid access token. The server should take care of refreshing tokens before they expire and getting entirely new tokens, should they become so stale that I need to re-authorize my application. A lot of my development of this project has been clumsy. I'm new to Go; I didn't understand OAuth2.0; I'm learning concurrent programming (outside of the context of comfortable Elixir/Erlang). My habits for writing programs in compiled languages feels amateurish. I find myself dropping log.Println's all over the source code when I should be using proper debugging tools like Delve and properly logging with things like httputil.Dump{Request,Response}. The application right now is in a transitional state. There is still plenty of code in main.go that belongs in tokens.go. For instance, the client authorization code belongs in the tokens server. Another question I haven't answered is where is the monzo client that I can use to make function calls like `monzo.Transactions` or `monzo.Accounts`? The benefit of having a tokens server is that it allows me to maintain state of the tokens while I'm developing. This way, I can stop and start main.go without disturbing the state of the access tokens. Of course this isn't the primary benefit, which is to abstract over the OAuth details and expose an API that gives me an access token whenever I request one. The first benefit that I listed could and perhaps should be solved by introducing some simple persistence. I'd like to write the access tokens to disk when I shutdown the tokens server and read them from disk when I start the tokens server. This will come. I could have done this before introducing the tokens server, and it would have saved me a few hours I think. Where has my time gone? Mostly I've been re-authorizing my client unnecessarily. This process is expensive because it opens a web browser, asks me to enter my email address, sends me an email, I then click the link in that email. Overall this takes maybe 1-3 minutes in total. Before my tokens server existed, however, I was doing this about 10-20 times per hour. It's a little disappointing that I didn't rectify this earlier. I'd like to remain vigilant and avoid making similar workflow mistakes as I move ahead.
2020-02-09 02:07:36 +01:00
// Prints the verbose form of an HTTP request.
func DebugRequest(req *http.Request) {
bytes, _ := httputil.DumpRequest(req, true)
fmt.Println(string(bytes))
}
// Prints out the verbose form of an HTTP response.
func DebugResponse(res *http.Response) {
bytes, _ := httputil.DumpResponse(res, true)
fmt.Println(string(bytes))
}
Create server for managing Monzo credentials I created a server to manage my access and refresh tokens. This server exposes a larger API than it needs to at the moment, but that should change. The goal is to expose a GET at /token to retrieve a valid access token. The server should take care of refreshing tokens before they expire and getting entirely new tokens, should they become so stale that I need to re-authorize my application. A lot of my development of this project has been clumsy. I'm new to Go; I didn't understand OAuth2.0; I'm learning concurrent programming (outside of the context of comfortable Elixir/Erlang). My habits for writing programs in compiled languages feels amateurish. I find myself dropping log.Println's all over the source code when I should be using proper debugging tools like Delve and properly logging with things like httputil.Dump{Request,Response}. The application right now is in a transitional state. There is still plenty of code in main.go that belongs in tokens.go. For instance, the client authorization code belongs in the tokens server. Another question I haven't answered is where is the monzo client that I can use to make function calls like `monzo.Transactions` or `monzo.Accounts`? The benefit of having a tokens server is that it allows me to maintain state of the tokens while I'm developing. This way, I can stop and start main.go without disturbing the state of the access tokens. Of course this isn't the primary benefit, which is to abstract over the OAuth details and expose an API that gives me an access token whenever I request one. The first benefit that I listed could and perhaps should be solved by introducing some simple persistence. I'd like to write the access tokens to disk when I shutdown the tokens server and read them from disk when I start the tokens server. This will come. I could have done this before introducing the tokens server, and it would have saved me a few hours I think. Where has my time gone? Mostly I've been re-authorizing my client unnecessarily. This process is expensive because it opens a web browser, asks me to enter my email address, sends me an email, I then click the link in that email. Overall this takes maybe 1-3 minutes in total. Before my tokens server existed, however, I was doing this about 10-20 times per hour. It's a little disappointing that I didn't rectify this earlier. I'd like to remain vigilant and avoid making similar workflow mistakes as I move ahead.
2020-02-09 02:07:36 +01:00
// Make a simple GET request to `url`. Fail if anything returns an error. I'd
// like to accumulate a library of these, so that I can write scrappy Go
// quickly. For now, this function just returns the body of the response back as
// a string.
func SimpleGet(url string, headers map[string]string, debug bool) string {
Create server for managing Monzo credentials I created a server to manage my access and refresh tokens. This server exposes a larger API than it needs to at the moment, but that should change. The goal is to expose a GET at /token to retrieve a valid access token. The server should take care of refreshing tokens before they expire and getting entirely new tokens, should they become so stale that I need to re-authorize my application. A lot of my development of this project has been clumsy. I'm new to Go; I didn't understand OAuth2.0; I'm learning concurrent programming (outside of the context of comfortable Elixir/Erlang). My habits for writing programs in compiled languages feels amateurish. I find myself dropping log.Println's all over the source code when I should be using proper debugging tools like Delve and properly logging with things like httputil.Dump{Request,Response}. The application right now is in a transitional state. There is still plenty of code in main.go that belongs in tokens.go. For instance, the client authorization code belongs in the tokens server. Another question I haven't answered is where is the monzo client that I can use to make function calls like `monzo.Transactions` or `monzo.Accounts`? The benefit of having a tokens server is that it allows me to maintain state of the tokens while I'm developing. This way, I can stop and start main.go without disturbing the state of the access tokens. Of course this isn't the primary benefit, which is to abstract over the OAuth details and expose an API that gives me an access token whenever I request one. The first benefit that I listed could and perhaps should be solved by introducing some simple persistence. I'd like to write the access tokens to disk when I shutdown the tokens server and read them from disk when I start the tokens server. This will come. I could have done this before introducing the tokens server, and it would have saved me a few hours I think. Where has my time gone? Mostly I've been re-authorizing my client unnecessarily. This process is expensive because it opens a web browser, asks me to enter my email address, sends me an email, I then click the link in that email. Overall this takes maybe 1-3 minutes in total. Before my tokens server existed, however, I was doing this about 10-20 times per hour. It's a little disappointing that I didn't rectify this earlier. I'd like to remain vigilant and avoid making similar workflow mistakes as I move ahead.
2020-02-09 02:07:36 +01:00
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
for k, v := range headers {
req.Header.Add(k, v)
}
res, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if debug {
DebugRequest(req)
DebugResponse(res)
Create server for managing Monzo credentials I created a server to manage my access and refresh tokens. This server exposes a larger API than it needs to at the moment, but that should change. The goal is to expose a GET at /token to retrieve a valid access token. The server should take care of refreshing tokens before they expire and getting entirely new tokens, should they become so stale that I need to re-authorize my application. A lot of my development of this project has been clumsy. I'm new to Go; I didn't understand OAuth2.0; I'm learning concurrent programming (outside of the context of comfortable Elixir/Erlang). My habits for writing programs in compiled languages feels amateurish. I find myself dropping log.Println's all over the source code when I should be using proper debugging tools like Delve and properly logging with things like httputil.Dump{Request,Response}. The application right now is in a transitional state. There is still plenty of code in main.go that belongs in tokens.go. For instance, the client authorization code belongs in the tokens server. Another question I haven't answered is where is the monzo client that I can use to make function calls like `monzo.Transactions` or `monzo.Accounts`? The benefit of having a tokens server is that it allows me to maintain state of the tokens while I'm developing. This way, I can stop and start main.go without disturbing the state of the access tokens. Of course this isn't the primary benefit, which is to abstract over the OAuth details and expose an API that gives me an access token whenever I request one. The first benefit that I listed could and perhaps should be solved by introducing some simple persistence. I'd like to write the access tokens to disk when I shutdown the tokens server and read them from disk when I start the tokens server. This will come. I could have done this before introducing the tokens server, and it would have saved me a few hours I think. Where has my time gone? Mostly I've been re-authorizing my client unnecessarily. This process is expensive because it opens a web browser, asks me to enter my email address, sends me an email, I then click the link in that email. Overall this takes maybe 1-3 minutes in total. Before my tokens server existed, however, I was doing this about 10-20 times per hour. It's a little disappointing that I didn't rectify this earlier. I'd like to remain vigilant and avoid making similar workflow mistakes as I move ahead.
2020-02-09 02:07:36 +01:00
}
if res.StatusCode == http.StatusOK {
bytes, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
return string(bytes)
} else {
log.Println(res)
log.Fatalf("HTTP status code of response not OK: %v\n", res.StatusCode)
return ""
}
}