Skip to content

Instantly share code, notes, and snippets.

@coolaj86
Last active October 12, 2025 00:58
Show Gist options
  • Select an option

  • Save coolaj86/4691e077c2f86e64ca0a089627a0c6a9 to your computer and use it in GitHub Desktop.

Select an option

Save coolaj86/4691e077c2f86e64ca0a089627a0c6a9 to your computer and use it in GitHub Desktop.

Revisions

  1. coolaj86 revised this gist Oct 12, 2025. 1 changed file with 1 addition and 448 deletions.
    449 changes: 1 addition & 448 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -1,448 +1 @@
    GoDoc Tricks: <https://pkg.go.dev/github.com/fluhus/godoc-tricks>

    ## Browser Extension

    https://chrome.google.com/webstore/detail/go-search-extension/epanejkfcekejmmfbcpbcbigfpefbnlb

    ## new project

    ```bash
    go mod init github.com/coolaj86/projectname
    ```

    ## tools package

    ```bash
    mkdir -p tools

    go get github.com/goware/modvendor
    go get github.com/kyleconroy/sqlc/cmd/sqlc@latest

    go mod vendor
    go run -mod=vendor github.com/goware/modvendor -copy="**/*.c **/*.h **/*.proto" -v
    ```

    `build.go`

    ```go
    //go:generate go run -mod=vendor github.com/kyleconroy/sqlc/cmd/sqlc generate

    package main
    ```

    `tools/tools.go`:

    ```go
    //go:build tools

    package tools

    import (
    // for the modvendor command
    _ "github.com/goware/modvendor"

    // for the sqlc command
    _ "github.com/kyleconroy/sqlc/cmd/sqlc"
    )
    ```

    ```bash
    go mod tidy

    go generate -mod=vendor ./...
    ```

    ## go.mod exclude and replace

    ```txt
    module github.com/example/project
    require (
    github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc
    github.com/google/uuid v1.1.0
    )
    exclude github.com/SermoDigital/jose v0.9.1
    replace github.com/google/uuid v1.1.0 => git.coolaj86.com/coolaj86/uuid.go v1.1.1
    ```

    See <https://stackoverflow.com/a/53824026/151312>.

    ## Array Sort, Contains, ...

    ```go
    sort.Strings(haystack)
    ```

    ```go
    func contains(haystack []string, needle string) bool {
    i := sort.SearchStrings(haystack, needle)
    return i < len(haystack) && needle == haystack[i]
    }
    ```

    ## Internationalization

    https://phrase.com/blog/posts/internationalization-i18n-go/

    ### HTTP Request

    In part from https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/

    ```go
    c := &http.Client{
    Transport: &http.Transport{
    Dial: (&net.Dialer{
    Timeout: 30 * time.Second,
    KeepAlive: 30 * time.Second,
    }).Dial,
    TLSHandshakeTimeout: 10 * time.Second,
    ResponseHeaderTimeout: 10 * time.Second,
    ExpectContinueTimeout: 1 * time.Second,
    }
    }

    c := make(chan struct{})
    timer := time.AfterFunc(5*time.Second, func() {
    close(c)
    })

    // Serve 256 bytes every second.
    req, err := http.NewRequest("GET", "http://httpbin.org/range/2048?duration=8&chunk_size=256", nil)
    if err != nil {
    log.Fatal(err)
    }
    req.Cancel = c

    log.Println("Sending request...")
    resp, err := c.Do(req)
    if err != nil {
    log.Fatal(err)
    }
    defer resp.Body.Close()
    ```

    ### Base64 (and Random IDs)

    ```go
    s := base64.RawURLEncoding.EncodeToString([]byte(data))
    ```

    ```go
    b, err := base64.RawURLEncoding.DecodeString(s)
    ```

    ### Random IDs

    ```go
    var Rando = rand.Reader
    b := make([]byte, 16)
    n, err := Rando.Read(b)
    id := base64.RawURLEncoding.EncodeToString(b)
    ```

    ## Parse Fractional Seconds

    ```go
    func ParseSeconds(s string) (int64, int64, error) {
    seconds, err := strconv.ParseFloat(s, 64)
    if nil != err {
    return 0.0, 0.0, err
    }
    secs, nanos := SecondsToInts(seconds)
    return secs, nanos, nil
    }

    func SecondsToInts(seconds float64) (int64, int64) {
    secs := math.Floor(seconds)
    nanos := math.Round((seconds - secs) * 1_000_000_000)
    return int64(secs), int64(nanos)
    }
    ```

    ```go
    func ParseSeconds(secs string) (int64, int64, error) {
    // "789.0123" => []string{"789", "0123"}
    parts := strings.Split(secs, ".")
    if len(parts) > 2 {
    return 0, 0, errors.New("could not parse as seconds")
    } else if len(parts) < 2 {
    // no nanoseconds, just seconds
    // "789" => []string{"789"}
    s, err := strconv.ParseInt(parts[0], 10, 64)
    return s, 0, err
    }

    // convert the second's part
    s, err := strconv.ParseInt(parts[0], 10, 64)
    if nil != err {
    return 0, 0, err
    }

    // get nanoseconds from fractional second
    d, err := time.ParseDuration("0." + parts[1] + "s")
    return s, d.Nanoseconds(), err
    }
    ```

    ## Parse Unix Time

    ```go
    func ParseUnixTime(seconds string) (time.Time, error) {
    secs, nano, err := ParseSeconds(seconds)
    if nil != err {
    return time.Time{}, err
    }

    return time.Unix(secs, nano), nil
    }
    ```

    ## Time to Unix Seconds

    ```go
    func ToUnixSeconds(t time.Time) float64 {
    // 1614236182.651912345
    secs := float64(t.Unix()) // 1614236182
    nanos := float64(t.Nanosecond()) / 1_000_000_000.0 // 0.651912345

    // in my case I want to truncate the precision to milliseconds
    nanos = math.Round((10000 * nanos) / 10000) // 0.6519

    s := secs + nanos // 1614236182.651912345
    return s
    }
    ```

    ## Left Pad and Right Pad

    ```go
    // Left pad up to 10 spaces
    fmt.Sprintf("'%*s'", 10, "Hello")
    // ' Hello'

    // Right pad up to 10 spaces
    fmt.Sprintf("'Hello%-*s'", 10, "Hello")
    // 'Hello '

    // Left pad up to 10 zeros
    fmt.Sprintf("'%0*s'\n", 10, "Hello")
    // '00000Hello'

    // Right pad up to 10 zeros... psych!
    fmt.Sprintf("'%-0*s'\n", 10, "Hello")
    // 'Hello '
    ```

    # HTTP Request

    ```go
    func SafeRequest(req *http.Request) (*http.Response, error) {
    var netTransport = &http.Transport{
    Dial: (&net.Dialer{
    Timeout: 5 * time.Second,
    }).Dial,
    TLSHandshakeTimeout: 5 * time.Second,
    }
    var netClient = &http.Client{
    Timeout: time.Second * 10,
    Transport: netTransport,
    }
    response, err := netClient.Do(req)
    if nil != err {
    return nil, err
    }
    body := response.Body
    response.Body = io.LimitReader(body, 1024 * 1024)
    //response.Body = MaxBytesReader(body, 1024*1024)
    return response, nil
    }
    ```

    # HTTP Server

    ```go
    srv := &http.Server{
    Addr: runOpts.Addr,
    Handler: r,
    ReadHeaderTimeout: 2 * time.Second,
    ReadTimeout: 10 * time.Second,
    WriteTimeout: 20 * time.Second,
    MaxHeaderBytes: 1024 * 1024, // 1MiB
    }
    if err := srv.ListenAndServe(); nil != err {
    fmt.Fprintf(os.Stderr, "%s", err)
    os.Exit(1)
    return
    }
    ```

    ### HTTP Test Server

    ```go
    var srv *httptest.Server

    func TestMain(m *testing.M) {
    // math/rand.Seed(0)

    srv = httptest.NewServer(mux)
    os.Exit(m.Run())
    }
    ```

    ```go
    client := srv.Client()
    urlstr, _ := url.Parse(srv.URL + "/debug/verify?exp=false")

    req := &http.Request{
    Method: "POST",
    URL: urlstr,
    //Body: ioutil.NopCloser(bytes.NewReader(jws)),
    Header: http.Header{},
    }
    req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", jwt))
    res, err := client.Do(req)
    if nil != err {
    t.Error(err)
    return
    }
    data, err := ioutil.ReadAll(res.Body)
    if nil != err {
    t.Error(err)
    return
    }
    if 200 != res.StatusCode {
    log.Printf(string(data))
    t.Error(fmt.Errorf("bad status code: %d", res.StatusCode))
    return
    }
    ```

    # HTTP Handler

    ```go
    r.Body = http.MaxBytesReader(w, r.Body, 1 << 20)
    ```

    # Tee HTTP Body

    TODO

    # Security

    ### Compare

    ```go
    import "crypto/subtle"

    func ConstantTimeCompare(x, y []byte) bool {
    return 1 == subtle.ConstantTimeCompare(x, y)
    }
    ```

    # Error Strategies

    - [`os.IsNotFound`](https://golang.org/pkg/os/#IsNotExist)
    - [`csv.ParseError`](https://golang.org/pkg/encoding/csv/#ParseError)

    - `go clean -testcache`

    # JSON to Go

    - https://mholt.github.io/json-to-go/

    # JSON to Postgres

    https://numidian.io/convert/json/to/postgres

    # 410 Gone

    ```bash
    export GO111MODULE=on
    export GOPROXY=direct
    export GOSUMDB=off
    ```

    ## X-Hub-Signature

    ```go
    const (
    // sha1Prefix is the prefix used by GitHub before the HMAC hexdigest.
    sha1Prefix = "sha1"
    // sha256Prefix and sha512Prefix are provided for future compatibility.
    sha256Prefix = "sha256"
    sha512Prefix = "sha512"
    // signatureHeader is the GitHub header key used to pass the HMAC hexdigest.
    signatureHeader = "X-Hub-Signature"
    )

    if len(secretToken) > 0 {
    sig := r.Header.Get(signatureHeader)
    if err := ValidateSignature(sig, body, secretToken); err != nil {
    return nil, err
    }
    }

    // ValidateSignature validates the signature for the given payload.
    // signature is the GitHub hash signature delivered in the X-Hub-Signature header.
    // payload is the JSON payload sent by GitHub Webhooks.
    // secretToken is the GitHub Webhook secret token.
    //
    // GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
    func ValidateSignature(signature string, payload, secretToken []byte) error {
    messageMAC, hashFunc, err := messageMAC(signature)
    if err != nil {
    return err
    }
    if !checkMAC(payload, messageMAC, secretToken, hashFunc) {
    return errors.New("payload signature check failed")
    }
    return nil
    }

    // checkMAC reports whether messageMAC is a valid HMAC tag for message.
    func checkMAC(message, messageMAC, key []byte, hashFunc func() hash.Hash) bool {
    expectedMAC := genMAC(message, key, hashFunc)
    return hmac.Equal(messageMAC, expectedMAC)
    }

    // messageMAC returns the hex-decoded HMAC tag from the signature and its
    // corresponding hash function.
    func messageMAC(signature string) ([]byte, func() hash.Hash, error) {
    if signature == "" {
    return nil, nil, errors.New("missing signature")
    }
    sigParts := strings.SplitN(signature, "=", 2)
    if len(sigParts) != 2 {
    return nil, nil, fmt.Errorf("error parsing signature %q", signature)
    }

    var hashFunc func() hash.Hash
    switch sigParts[0] {
    case sha1Prefix:
    hashFunc = sha1.New
    case sha256Prefix:
    hashFunc = sha256.New
    case sha512Prefix:
    hashFunc = sha512.New
    default:
    return nil, nil, fmt.Errorf("unknown hash type prefix: %q", sigParts[0])
    }

    buf, err := hex.DecodeString(sigParts[1])
    if err != nil {
    return nil, nil, fmt.Errorf("error decoding signature %q: %v", signature, err)
    }
    return buf, hashFunc, nil
    }
    ```

    ## Build Tags

    | Build Tag Syntax | Build Tag Sample | Boolean Statement |
    | -------------- | ---------------- | ---------------- |
    | Space-separated elements | // +build pro enterprise | pro OR enterprise |
    | Comma-separated elements | // +build pro,enterprise | pro AND enterprise |
    | Exclamation point elements | // +build !pro | NOT pro |
    Moved to https://github.com/therootcompany/software-development/wiki/Go-Cheatsheet
  2. AJ ONeal revised this gist Aug 3, 2022. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -83,6 +83,10 @@ func contains(haystack []string, needle string) bool {
    }
    ```

    ## Internationalization

    https://phrase.com/blog/posts/internationalization-i18n-go/

    ### HTTP Request

    In part from https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/
  3. AJ ONeal revised this gist May 5, 2022. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -72,6 +72,10 @@ See <https://stackoverflow.com/a/53824026/151312>.

    ## Array Sort, Contains, ...

    ```go
    sort.Strings(haystack)
    ```

    ```go
    func contains(haystack []string, needle string) bool {
    i := sort.SearchStrings(haystack, needle)
  4. AJ ONeal revised this gist May 5, 2022. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -70,6 +70,15 @@ replace github.com/google/uuid v1.1.0 => git.coolaj86.com/coolaj86/uuid.go v1.1.

    See <https://stackoverflow.com/a/53824026/151312>.

    ## Array Sort, Contains, ...

    ```go
    func contains(haystack []string, needle string) bool {
    i := sort.SearchStrings(haystack, needle)
    return i < len(haystack) && needle == haystack[i]
    }
    ```

    ### HTTP Request

    In part from https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/
  5. AJ ONeal revised this gist Apr 14, 2022. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,9 @@
    GoDoc Tricks: <https://pkg.go.dev/github.com/fluhus/godoc-tricks>

    ## Browser Extension

    https://chrome.google.com/webstore/detail/go-search-extension/epanejkfcekejmmfbcpbcbigfpefbnlb

    ## new project

    ```bash
  6. AJ ONeal revised this gist Apr 13, 2022. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -43,6 +43,8 @@ import (
    ```

    ```bash
    go mod tidy

    go generate -mod=vendor ./...
    ```

  7. AJ ONeal revised this gist Apr 13, 2022. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -10,13 +10,20 @@ go mod init github.com/coolaj86/projectname

    ```bash
    mkdir -p tools

    go get github.com/goware/modvendor
    go get github.com/kyleconroy/sqlc/cmd/sqlc@latest

    go mod vendor
    go run -mod=vendor github.com/goware/modvendor -copy="**/*.c **/*.h **/*.proto" -v
    ```

    `build.go`

    ```go
    //go:generate go run -mod=vendor github.com/kyleconroy/sqlc/cmd/sqlc generate

    package main
    ```

    `tools/tools.go`:
    @@ -27,6 +34,10 @@ go get github.com/kyleconroy/sqlc/cmd/sqlc@latest
    package tools

    import (
    // for the modvendor command
    _ "github.com/goware/modvendor"

    // for the sqlc command
    _ "github.com/kyleconroy/sqlc/cmd/sqlc"
    )
    ```
  8. AJ ONeal revised this gist Apr 13, 2022. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -31,6 +31,10 @@ import (
    )
    ```

    ```bash
    go generate -mod=vendor ./...
    ```

    ## go.mod exclude and replace

    ```txt
  9. AJ ONeal revised this gist Apr 13, 2022. 1 changed file with 8 additions and 1 deletion.
    9 changes: 8 additions & 1 deletion Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -10,6 +10,13 @@ go mod init github.com/coolaj86/projectname

    ```bash
    mkdir -p tools
    go get github.com/kyleconroy/sqlc/cmd/sqlc@latest
    ```

    `build.go`

    ```go
    //go:generate go run -mod=vendor github.com/kyleconroy/sqlc/cmd/sqlc generate
    ```

    `tools/tools.go`:
    @@ -20,7 +27,7 @@ mkdir -p tools
    package tools

    import (
    _ "github.com/UnnoTed/fileb0x"
    _ "github.com/kyleconroy/sqlc/cmd/sqlc"
    )
    ```

  10. AJ ONeal revised this gist Apr 13, 2022. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -44,6 +44,8 @@ See <https://stackoverflow.com/a/53824026/151312>.

    ### HTTP Request

    In part from https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/

    ```go
    c := &http.Client{
    Transport: &http.Transport{
  11. AJ ONeal revised this gist Apr 13, 2022. 1 changed file with 36 additions and 1 deletion.
    37 changes: 36 additions & 1 deletion Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -42,7 +42,42 @@ replace github.com/google/uuid v1.1.0 => git.coolaj86.com/coolaj86/uuid.go v1.1.

    See <https://stackoverflow.com/a/53824026/151312>.

    ## Base64 (and Random IDs)
    ### HTTP Request

    ```go
    c := &http.Client{
    Transport: &http.Transport{
    Dial: (&net.Dialer{
    Timeout: 30 * time.Second,
    KeepAlive: 30 * time.Second,
    }).Dial,
    TLSHandshakeTimeout: 10 * time.Second,
    ResponseHeaderTimeout: 10 * time.Second,
    ExpectContinueTimeout: 1 * time.Second,
    }
    }

    c := make(chan struct{})
    timer := time.AfterFunc(5*time.Second, func() {
    close(c)
    })

    // Serve 256 bytes every second.
    req, err := http.NewRequest("GET", "http://httpbin.org/range/2048?duration=8&chunk_size=256", nil)
    if err != nil {
    log.Fatal(err)
    }
    req.Cancel = c

    log.Println("Sending request...")
    resp, err := c.Do(req)
    if err != nil {
    log.Fatal(err)
    }
    defer resp.Body.Close()
    ```

    ### Base64 (and Random IDs)

    ```go
    s := base64.RawURLEncoding.EncodeToString([]byte(data))
  12. AJ ONeal revised this gist Mar 9, 2022. 1 changed file with 24 additions and 0 deletions.
    24 changes: 24 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,29 @@
    GoDoc Tricks: <https://pkg.go.dev/github.com/fluhus/godoc-tricks>

    ## new project

    ```bash
    go mod init github.com/coolaj86/projectname
    ```

    ## tools package

    ```bash
    mkdir -p tools
    ```

    `tools/tools.go`:

    ```go
    //go:build tools

    package tools

    import (
    _ "github.com/UnnoTed/fileb0x"
    )
    ```

    ## go.mod exclude and replace

    ```txt
  13. AJ ONeal revised this gist Mar 8, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    GoDoc Tricks: https://pkg.go.dev/github.com/fluhus/godoc-tricks
    GoDoc Tricks: <https://pkg.go.dev/github.com/fluhus/godoc-tricks>

    ## go.mod exclude and replace

  14. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -102,11 +102,11 @@ func ToUnixSeconds(t time.Time) float64 {
    secs := float64(t.Unix()) // 1614236182
    nanos := float64(t.Nanosecond()) / 1_000_000_000.0 // 0.651912345

    // in my case I want to truncate the precision to milliseconds
    nanos = Math.Round(10_000 * nanos / 10_000) // 0.6519
    // in my case I want to truncate the precision to milliseconds
    nanos = math.Round((10000 * nanos) / 10000) // 0.6519

    s := secs + nanos // 1614236182.651912345
    return s
    s := secs + nanos // 1614236182.651912345
    return s
    }
    ```

  15. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -51,7 +51,7 @@ func ParseSeconds(s string) (int64, int64, error) {

    func SecondsToInts(seconds float64) (int64, int64) {
    secs := math.Floor(seconds)
    nanos := math.Round((seconds - secs) * 1000000000)
    nanos := math.Round((seconds - secs) * 1_000_000_000)
    return int64(secs), int64(nanos)
    }
    ```
    @@ -99,14 +99,14 @@ func ParseUnixTime(seconds string) (time.Time, error) {
    ```go
    func ToUnixSeconds(t time.Time) float64 {
    // 1614236182.651912345
    secs := float64(t.Unix()) // 1614236182
    nanos := float64(t.UnixNano()) / 1000000000 // 0.651912345
    secs := float64(t.Unix()) // 1614236182
    nanos := float64(t.Nanosecond()) / 1_000_000_000.0 // 0.651912345

    // in my case I want to truncate the precision to milliseconds
    nanos = Math.Round(10000 * nanos / 10000) // 0.6519
    nanos = Math.Round(10_000 * nanos / 10_000) // 0.6519

    s := secs + nanos // 1614236182.651912345
    return s
    return s
    }
    ```

  16. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -106,6 +106,7 @@ func ToUnixSeconds(t time.Time) float64 {
    nanos = Math.Round(10000 * nanos / 10000) // 0.6519

    s := secs + nanos // 1614236182.651912345
    return s
    }
    ```

  17. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -41,9 +41,9 @@ id := base64.RawURLEncoding.EncodeToString(b)

    ```go
    func ParseSeconds(s string) (int64, int64, error) {
    seconds, err := strconv.ParseFloat(s, 64)
    if nil != err {
    return 0.0, 0.0, error
    seconds, err := strconv.ParseFloat(s, 64)
    if nil != err {
    return 0.0, 0.0, err
    }
    secs, nanos := SecondsToInts(seconds)
    return secs, nanos, nil
    @@ -52,7 +52,7 @@ func ParseSeconds(s string) (int64, int64, error) {
    func SecondsToInts(seconds float64) (int64, int64) {
    secs := math.Floor(seconds)
    nanos := math.Round((seconds - secs) * 1000000000)
    return secs, nanos
    return int64(secs), int64(nanos)
    }
    ```

  18. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -39,6 +39,23 @@ id := base64.RawURLEncoding.EncodeToString(b)

    ## Parse Fractional Seconds

    ```go
    func ParseSeconds(s string) (int64, int64, error) {
    seconds, err := strconv.ParseFloat(s, 64)
    if nil != err {
    return 0.0, 0.0, error
    }
    secs, nanos := SecondsToInts(seconds)
    return secs, nanos, nil
    }

    func SecondsToInts(seconds float64) (int64, int64) {
    secs := math.Floor(seconds)
    nanos := math.Round((seconds - secs) * 1000000000)
    return secs, nanos
    }
    ```

    ```go
    func ParseSeconds(secs string) (int64, int64, error) {
    // "789.0123" => []string{"789", "0123"}
  19. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 15 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -77,6 +77,21 @@ func ParseUnixTime(seconds string) (time.Time, error) {
    }
    ```

    ## Time to Unix Seconds

    ```go
    func ToUnixSeconds(t time.Time) float64 {
    // 1614236182.651912345
    secs := float64(t.Unix()) // 1614236182
    nanos := float64(t.UnixNano()) / 1000000000 // 0.651912345

    // in my case I want to truncate the precision to milliseconds
    nanos = Math.Round(10000 * nanos / 10000) // 0.6519

    s := secs + nanos // 1614236182.651912345
    }
    ```

    ## Left Pad and Right Pad

    ```go
  20. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 17 additions and 4 deletions.
    21 changes: 17 additions & 4 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    GoDoc Tricks: https://pkg.go.dev/github.com/fluhus/godoc-tricks

    # go.mod exclude and replace
    ## go.mod exclude and replace

    ```txt
    module github.com/example/project
    @@ -18,7 +18,7 @@ replace github.com/google/uuid v1.1.0 => git.coolaj86.com/coolaj86/uuid.go v1.1.

    See <https://stackoverflow.com/a/53824026/151312>.

    # Base64 (and Random IDs)
    ## Base64 (and Random IDs)

    ```go
    s := base64.RawURLEncoding.EncodeToString([]byte(data))
    @@ -37,7 +37,7 @@ n, err := Rando.Read(b)
    id := base64.RawURLEncoding.EncodeToString(b)
    ```

    # Parse Fractional Seconds
    ## Parse Fractional Seconds

    ```go
    func ParseSeconds(secs string) (int64, int64, error) {
    @@ -64,7 +64,20 @@ func ParseSeconds(secs string) (int64, int64, error) {
    }
    ```

    # Pad Right
    ## Parse Unix Time

    ```go
    func ParseUnixTime(seconds string) (time.Time, error) {
    secs, nano, err := ParseSeconds(seconds)
    if nil != err {
    return time.Time{}, err
    }

    return time.Unix(secs, nano), nil
    }
    ```

    ## Left Pad and Right Pad

    ```go
    // Left pad up to 10 spaces
  21. AJ ONeal revised this gist Feb 25, 2021. 1 changed file with 47 additions and 0 deletions.
    47 changes: 47 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -37,6 +37,53 @@ n, err := Rando.Read(b)
    id := base64.RawURLEncoding.EncodeToString(b)
    ```

    # Parse Fractional Seconds

    ```go
    func ParseSeconds(secs string) (int64, int64, error) {
    // "789.0123" => []string{"789", "0123"}
    parts := strings.Split(secs, ".")
    if len(parts) > 2 {
    return 0, 0, errors.New("could not parse as seconds")
    } else if len(parts) < 2 {
    // no nanoseconds, just seconds
    // "789" => []string{"789"}
    s, err := strconv.ParseInt(parts[0], 10, 64)
    return s, 0, err
    }

    // convert the second's part
    s, err := strconv.ParseInt(parts[0], 10, 64)
    if nil != err {
    return 0, 0, err
    }

    // get nanoseconds from fractional second
    d, err := time.ParseDuration("0." + parts[1] + "s")
    return s, d.Nanoseconds(), err
    }
    ```

    # Pad Right

    ```go
    // Left pad up to 10 spaces
    fmt.Sprintf("'%*s'", 10, "Hello")
    // ' Hello'

    // Right pad up to 10 spaces
    fmt.Sprintf("'Hello%-*s'", 10, "Hello")
    // 'Hello '

    // Left pad up to 10 zeros
    fmt.Sprintf("'%0*s'\n", 10, "Hello")
    // '00000Hello'

    // Right pad up to 10 zeros... psych!
    fmt.Sprintf("'%-0*s'\n", 10, "Hello")
    // 'Hello '
    ```

    # HTTP Request

    ```go
  22. AJ ONeal revised this gist Nov 3, 2020. 1 changed file with 18 additions and 0 deletions.
    18 changes: 18 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,23 @@
    GoDoc Tricks: https://pkg.go.dev/github.com/fluhus/godoc-tricks

    # go.mod exclude and replace

    ```txt
    module github.com/example/project
    require (
    github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc
    github.com/google/uuid v1.1.0
    )
    exclude github.com/SermoDigital/jose v0.9.1
    replace github.com/google/uuid v1.1.0 => git.coolaj86.com/coolaj86/uuid.go v1.1.1
    ```

    See <https://stackoverflow.com/a/53824026/151312>.

    # Base64 (and Random IDs)

    ```go
  23. AJ ONeal revised this gist Oct 27, 2020. 1 changed file with 20 additions and 17 deletions.
    37 changes: 20 additions & 17 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -22,23 +22,26 @@ id := base64.RawURLEncoding.EncodeToString(b)
    # HTTP Request

    ```go
    type
    var netTransport = &http.Transport{
    Dial: (&net.Dialer{
    Timeout: 5 * time.Second,
    }).Dial,
    TLSHandshakeTimeout: 5 * time.Second,
    }
    var netClient = &http.Client{
    Timeout: time.Second * 10,
    Transport: netTransport,
    }
    response, _ := netClient.Get(url)
    body := response.Body
    defer func() {
    _ = body.Close()
    }()
    response.Body = io.LimitReader(body, 1024 * 1024)
    func SafeRequest(req *http.Request) (*http.Response, error) {
    var netTransport = &http.Transport{
    Dial: (&net.Dialer{
    Timeout: 5 * time.Second,
    }).Dial,
    TLSHandshakeTimeout: 5 * time.Second,
    }
    var netClient = &http.Client{
    Timeout: time.Second * 10,
    Transport: netTransport,
    }
    response, err := netClient.Do(req)
    if nil != err {
    return nil, err
    }
    body := response.Body
    response.Body = io.LimitReader(body, 1024 * 1024)
    //response.Body = MaxBytesReader(body, 1024*1024)
    return response, nil
    }
    ```

    # HTTP Server
  24. AJ ONeal revised this gist Oct 27, 2020. 1 changed file with 17 additions and 1 deletion.
    18 changes: 17 additions & 1 deletion Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,23 @@ id := base64.RawURLEncoding.EncodeToString(b)
    # HTTP Request

    ```go

    type
    var netTransport = &http.Transport{
    Dial: (&net.Dialer{
    Timeout: 5 * time.Second,
    }).Dial,
    TLSHandshakeTimeout: 5 * time.Second,
    }
    var netClient = &http.Client{
    Timeout: time.Second * 10,
    Transport: netTransport,
    }
    response, _ := netClient.Get(url)
    body := response.Body
    defer func() {
    _ = body.Close()
    }()
    response.Body = io.LimitReader(body, 1024 * 1024)
    ```

    # HTTP Server
  25. AJ ONeal revised this gist Oct 9, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@ s := base64.RawURLEncoding.EncodeToString([]byte(data))
    ```

    ```go
    b, err := b64.RawURLEncoding.DecodeString(s)
    b, err := base64.RawURLEncoding.DecodeString(s)
    ```

    ### Random IDs
  26. AJ ONeal revised this gist Oct 5, 2020. 1 changed file with 5 additions and 6 deletions.
    11 changes: 5 additions & 6 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -205,9 +205,8 @@ func messageMAC(signature string) ([]byte, func() hash.Hash, error) {

    ## Build Tags

    ```
    Build Tag Syntax Build Tag Sample Boolean Statement
    Space-separated elements // +build pro enterprise pro OR enterprise
    Comma-separated elements // +build pro,enterprise pro AND enterprise
    Exclamation point elements // +build !pro NOT pro
    ```
    | Build Tag Syntax | Build Tag Sample | Boolean Statement |
    | -------------- | ---------------- | ---------------- |
    | Space-separated elements | // +build pro enterprise | pro OR enterprise |
    | Comma-separated elements | // +build pro,enterprise | pro AND enterprise |
    | Exclamation point elements | // +build !pro | NOT pro |
  27. AJ ONeal revised this gist Oct 5, 2020. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -201,4 +201,13 @@ func messageMAC(signature string) ([]byte, func() hash.Hash, error) {
    }
    return buf, hashFunc, nil
    }
    ```

    ## Build Tags

    ```
    Build Tag Syntax Build Tag Sample Boolean Statement
    Space-separated elements // +build pro enterprise pro OR enterprise
    Comma-separated elements // +build pro,enterprise pro AND enterprise
    Exclamation point elements // +build !pro NOT pro
    ```
  28. AJ ONeal revised this gist Oct 5, 2020. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -132,6 +132,16 @@ export GOSUMDB=off
    ## X-Hub-Signature

    ```go
    const (
    // sha1Prefix is the prefix used by GitHub before the HMAC hexdigest.
    sha1Prefix = "sha1"
    // sha256Prefix and sha512Prefix are provided for future compatibility.
    sha256Prefix = "sha256"
    sha512Prefix = "sha512"
    // signatureHeader is the GitHub header key used to pass the HMAC hexdigest.
    signatureHeader = "X-Hub-Signature"
    )

    if len(secretToken) > 0 {
    sig := r.Header.Get(signatureHeader)
    if err := ValidateSignature(sig, body, secretToken); err != nil {
  29. AJ ONeal revised this gist Oct 5, 2020. 1 changed file with 36 additions and 0 deletions.
    36 changes: 36 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -155,4 +155,40 @@ func ValidateSignature(signature string, payload, secretToken []byte) error {
    }
    return nil
    }

    // checkMAC reports whether messageMAC is a valid HMAC tag for message.
    func checkMAC(message, messageMAC, key []byte, hashFunc func() hash.Hash) bool {
    expectedMAC := genMAC(message, key, hashFunc)
    return hmac.Equal(messageMAC, expectedMAC)
    }

    // messageMAC returns the hex-decoded HMAC tag from the signature and its
    // corresponding hash function.
    func messageMAC(signature string) ([]byte, func() hash.Hash, error) {
    if signature == "" {
    return nil, nil, errors.New("missing signature")
    }
    sigParts := strings.SplitN(signature, "=", 2)
    if len(sigParts) != 2 {
    return nil, nil, fmt.Errorf("error parsing signature %q", signature)
    }

    var hashFunc func() hash.Hash
    switch sigParts[0] {
    case sha1Prefix:
    hashFunc = sha1.New
    case sha256Prefix:
    hashFunc = sha256.New
    case sha512Prefix:
    hashFunc = sha512.New
    default:
    return nil, nil, fmt.Errorf("unknown hash type prefix: %q", sigParts[0])
    }

    buf, err := hex.DecodeString(sigParts[1])
    if err != nil {
    return nil, nil, fmt.Errorf("error decoding signature %q: %v", signature, err)
    }
    return buf, hashFunc, nil
    }
    ```
  30. AJ ONeal revised this gist Oct 5, 2020. 1 changed file with 28 additions and 0 deletions.
    28 changes: 28 additions & 0 deletions Go-Cheatsheet.md
    Original file line number Diff line number Diff line change
    @@ -127,4 +127,32 @@ https://numidian.io/convert/json/to/postgres
    export GO111MODULE=on
    export GOPROXY=direct
    export GOSUMDB=off
    ```

    ## X-Hub-Signature

    ```go
    if len(secretToken) > 0 {
    sig := r.Header.Get(signatureHeader)
    if err := ValidateSignature(sig, body, secretToken); err != nil {
    return nil, err
    }
    }

    // ValidateSignature validates the signature for the given payload.
    // signature is the GitHub hash signature delivered in the X-Hub-Signature header.
    // payload is the JSON payload sent by GitHub Webhooks.
    // secretToken is the GitHub Webhook secret token.
    //
    // GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
    func ValidateSignature(signature string, payload, secretToken []byte) error {
    messageMAC, hashFunc, err := messageMAC(signature)
    if err != nil {
    return err
    }
    if !checkMAC(payload, messageMAC, secretToken, hashFunc) {
    return errors.New("payload signature check failed")
    }
    return nil
    }
    ```