Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Integralist/48d35050d5342bb7568f04183b81ca29 to your computer and use it in GitHub Desktop.
Save Integralist/48d35050d5342bb7568f04183b81ca29 to your computer and use it in GitHub Desktop.
[go struct with mutex to encapsulate data from users and help hide required lock implementation] #go #golang #struct #mutex #concurrency #encapsulation
type A struct {
mu sync.Mutex
}
a := &A{}
a.mu.Lock()
defer a.mu.Unlock()
a.Something()
// VS
var hits struct {
sync.Mutex
n int
}
hits.Lock()
hits.n++
hits.Unlock()
package proxy
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
)
// ErrorCodes defines status codes as keys for custom error pages.
type ErrorCodes map[int][]byte
// ErrorHosts defines hosts as keys for supported error codes.
type ErrorHosts map[string]ErrorCodes
// ErrorPages contains custom error pages for host domains by status code.
type ErrorPages struct {
mu sync.RWMutex
pages ErrorHosts
}
// Store sets a given HTML string within the pages map by host/status code.
func (ep *ErrorPages) Store(host string, status int, buf []byte) {
ep.mu.Lock()
defer ep.mu.Unlock()
if !ep.HasHost(host) {
ep.pages[host] = make(ErrorCodes)
}
ep.pages[host][status] = buf
}
// Get retrieves HTML string associated with the given host/status code.
func (ep *ErrorPages) Get(host string, status int) ([]byte, bool) {
ep.mu.RLock()
defer ep.mu.RUnlock()
if !ep.HasHost(host) {
return nil, false
}
if _, ok := ep.pages[host][status]; !ok {
return nil, false
}
return ep.pages[host][status], true
}
// HasHost returns true/false to indicate if pages map contains the given host.
func (ep *ErrorPages) HasHost(host string) bool {
_, ok := ep.pages[host]
return ok
}
// newErrorPages reads the file system and stores the contents of each custom
// error page into an in-memory cache.
//
// example directory structure:
//
// static/
// foo.com/
// 400.html
// 404.html
// 410.html
// 500.html
// bar.com/
// 404.html
// 500.html
// baz.com/
// 404.html
// 500.html
func newErrorPages(parentDir string) *ErrorPages {
var host string
ep := new(ErrorPages)
ep.pages = make(ErrorHosts)
root := "/app/static/"
skip := "static"
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if info.IsDir() && info.Name() == skip {
return nil
}
// track the host so we can ensure the following files are added under it.
if info.IsDir() {
host = info.Name()
return nil
}
// at this point we know we're dealing with a file and not a directory
content, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
// extract status code from filename and populate pages map with file contents.
statusKey, _ := strconv.Atoi(strings.Split(info.Name(), ".html")[0])
fmt.Println(host, path, statusKey)
ep.Store(host, statusKey, content)
return nil
})
return ep
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment