<commit_before>package gode

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"runtime"

	"github.com/dickeyxxx/golock"
	"github.com/franela/goreq"
)

var errInvalidSha = errors.New("Invalid SHA")

// IsSetup returns true if node is setup in RootPath
func IsSetup() (bool, error) {
	return isSetup(nodePath, npmPath)
}

func isSetup(nodePath, npmPath string) (bool, error) {
	exists, err := fileExists(nodePath)
	if !exists {
		return exists, err
	}
	return fileExists(npmPath)
}

// Setup downloads and sets up node in the RootPath directory
func Setup() error {
	golock.Lock(lockPath)
	defer golock.Unlock(lockPath)
	t := findTarget()
	if t == nil {
		return errors.New(`node does not offer a prebuilt binary for your OS.
You'll need to compile the tarball from nodejs.org and place it in ~/.heroku/node-v` + Version)
	}
	exists, err := t.isSetup()
	if err != nil {
		return err
	}
	if exists {
		return nil
	}
	if err := t.setup(); err != nil {
		return err
	}
	SetRootPath(rootPath) // essentially sets this node as the current one
	return t.clearOldNodeInstalls()
}

// NeedsUpdate returns true if it is using a node that isn't the latest version
func NeedsUpdate() (bool, error) {
	target := findTarget()
	if target == nil {
		return false, nil
	}
	exists, err := target.isSetup()
	return !exists, err
}

func (t *Target) setupUnix() error {
	err := os.MkdirAll(filepath.Join(rootPath, "node_modules"), 0755)
	if err != nil {
		return err
	}
	resp, err := goreq.Request{Uri: t.URL}.Do()
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		msg, _ := resp.Body.ToString()
		return errors.New(msg)
	}
	getSha, stream := computeSha(resp.Body)
	uncompressed, err := gzip.NewReader(stream)
	if err != nil {
		return err
	}
	tmpDir := tmpDir("node")
	extractTar(tar.NewReader(uncompressed), tmpDir)
	if getSha() != t.Sha {
		return errInvalidSha
	}
	newDir := t.basePath()
	os.RemoveAll(newDir)
	if err := os.Rename(filepath.Join(tmpDir, t.Base), newDir); err != nil {
		return err
	}
	return os.Remove(tmpDir)
}

func (t *Target) setupWindows() error {
	os.RemoveAll(t.basePath())
	if err := os.MkdirAll(t.basePath(), 0755); err != nil {
		return err
	}
	return downloadFile(t.nodePath(), t.URL, t.Sha)
}

func downloadFile(path, url, sha string) error {
	tmp := filepath.Join(tmpDir("download"), "file")
	// TODO: make this work with goreq
	// right now it fails because the body is closed for some reason
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	file, err := os.Create(tmp)
	if err != nil {
		return err
	}
	getSha, stream := computeSha(resp.Body)
	_, err = io.Copy(file, stream)
	if err != nil {
		return err
	}
	file.Close()
	resp.Body.Close()
	if getSha() != sha {
		return errInvalidSha
	}
	err = os.MkdirAll(filepath.Dir(path), 0755)
	if err != nil {
		return err
	}
	os.Remove(path)
	err = os.Rename(tmp, path)
	if err != nil {
		return err
	}
	return os.RemoveAll(filepath.Dir(tmp))
}

func downloadNpm(npmPath string) error {
	modulesDir := filepath.Dir(filepath.Dir(npmPath))
	os.MkdirAll(modulesDir, 0755)
	tmpDir := tmpDir("node")
	zipfile := filepath.Join(tmpDir, "npm.zip")
	err := downloadFile(zipfile, npmURL, npmSha)
	if err != nil {
		return err
	}
	err = extractZip(zipfile, tmpDir)
	if err != nil {
		return err
	}
	os.RemoveAll(filepath.Join(modulesDir, "npm"))
	os.Rename(filepath.Join(tmpDir, "npm-"+NpmVersion), filepath.Join(modulesDir, "npm"))
	if err != nil {
		return err
	}
	return os.RemoveAll(tmpDir)
}

// gets the currently running os and arch target
func findTarget() *Target {
	for _, t := range targets {
		if runtime.GOARCH == t.Arch && runtime.GOOS == t.OS {
			return &t
		}
	}
	return nil
}

func tmpDir(prefix string) string {
	root := filepath.Join(rootPath, "tmp")
	err := os.MkdirAll(root, 0755)
	if err != nil {
		panic(err)
	}
	dir, err := ioutil.TempDir(root, prefix)
	if err != nil {
		panic(err)
	}
	return dir
}
<commit_msg>use system tmp dirg<commit_after>package gode

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"runtime"

	"github.com/dickeyxxx/golock"
	"github.com/franela/goreq"
)

var errInvalidSha = errors.New("Invalid SHA")

// IsSetup returns true if node is setup in RootPath
func IsSetup() (bool, error) {
	return isSetup(nodePath, npmPath)
}

func isSetup(nodePath, npmPath string) (bool, error) {
	exists, err := fileExists(nodePath)
	if !exists {
		return exists, err
	}
	return fileExists(npmPath)
}

// Setup downloads and sets up node in the RootPath directory
func Setup() error {
	golock.Lock(lockPath)
	defer golock.Unlock(lockPath)
	t := findTarget()
	if t == nil {
		return errors.New(`node does not offer a prebuilt binary for your OS.
You'll need to compile the tarball from nodejs.org and place it in ~/.heroku/node-v` + Version)
	}
	exists, err := t.isSetup()
	if err != nil {
		return err
	}
	if exists {
		return nil
	}
	if err := t.setup(); err != nil {
		return err
	}
	SetRootPath(rootPath) // essentially sets this node as the current one
	return t.clearOldNodeInstalls()
}

// NeedsUpdate returns true if it is using a node that isn't the latest version
func NeedsUpdate() (bool, error) {
	target := findTarget()
	if target == nil {
		return false, nil
	}
	exists, err := target.isSetup()
	return !exists, err
}

func (t *Target) setupUnix() error {
	err := os.MkdirAll(filepath.Join(rootPath, "node_modules"), 0755)
	if err != nil {
		return err
	}
	resp, err := goreq.Request{Uri: t.URL}.Do()
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		msg, _ := resp.Body.ToString()
		return errors.New(msg)
	}
	getSha, stream := computeSha(resp.Body)
	uncompressed, err := gzip.NewReader(stream)
	if err != nil {
		return err
	}
	tmpDir := tmpDir("node")
	extractTar(tar.NewReader(uncompressed), tmpDir)
	if getSha() != t.Sha {
		return errInvalidSha
	}
	newDir := t.basePath()
	os.RemoveAll(newDir)
	if err := os.Rename(filepath.Join(tmpDir, t.Base), newDir); err != nil {
		return err
	}
	return os.Remove(tmpDir)
}

func (t *Target) setupWindows() error {
	os.RemoveAll(t.basePath())
	if err := os.MkdirAll(t.basePath(), 0755); err != nil {
		return err
	}
	return downloadFile(t.nodePath(), t.URL, t.Sha)
}

func downloadFile(path, url, sha string) error {
	tmp := filepath.Join(tmpDir("download"), "file")
	// TODO: make this work with goreq
	// right now it fails because the body is closed for some reason
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	file, err := os.Create(tmp)
	if err != nil {
		return err
	}
	getSha, stream := computeSha(resp.Body)
	_, err = io.Copy(file, stream)
	if err != nil {
		return err
	}
	file.Close()
	resp.Body.Close()
	if getSha() != sha {
		return errInvalidSha
	}
	err = os.MkdirAll(filepath.Dir(path), 0755)
	if err != nil {
		return err
	}
	os.Remove(path)
	err = os.Rename(tmp, path)
	if err != nil {
		return err
	}
	return os.RemoveAll(filepath.Dir(tmp))
}

func downloadNpm(npmPath string) error {
	modulesDir := filepath.Dir(filepath.Dir(npmPath))
	os.MkdirAll(modulesDir, 0755)
	tmpDir := tmpDir("node")
	zipfile := filepath.Join(tmpDir, "npm.zip")
	err := downloadFile(zipfile, npmURL, npmSha)
	if err != nil {
		return err
	}
	err = extractZip(zipfile, tmpDir)
	if err != nil {
		return err
	}
	os.RemoveAll(filepath.Join(modulesDir, "npm"))
	os.Rename(filepath.Join(tmpDir, "npm-"+NpmVersion), filepath.Join(modulesDir, "npm"))
	if err != nil {
		return err
	}
	return os.RemoveAll(tmpDir)
}

// gets the currently running os and arch target
func findTarget() *Target {
	for _, t := range targets {
		if runtime.GOARCH == t.Arch && runtime.GOOS == t.OS {
			return &t
		}
	}
	return nil
}

func tmpDir(prefix string) string {
	dir, err := ioutil.TempDir("", prefix)
	if err != nil {
		panic(err)
	}
	return dir
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
)

var hostname = fmt.Sprintf("http://127.0.0.1:%d", 8080)
var executable string = fmt.Sprintf("python -m SimpleHTTPServer %d", 8080)

func start_process(events chan int) {
	command_parts := strings.Split(executable, " ")
	command := exec.Command(command_parts[0], command_parts[1:]...)
	fmt.Printf("Command: %v\n", command)

	stdout, err := command.StdoutPipe()
	if err != nil {
		fmt.Println("Unable to read output from command...")
	}
	stderr, err := command.StderrPipe()
	if err != nil {
		fmt.Println("Unable to read output from command...")
	}

	command.Start()

	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)

	for {
		_, ok := <-events
		if !ok {
			command.Process.Kill()
		}
	}
}

func myHandler(w http.ResponseWriter, my_req *http.Request) {
	request_path := my_req.URL.Path

	target_url, _ := url.Parse(hostname)
	director := func(req *http.Request) {
		targetQuery := target_url.RawQuery
		req.URL.Scheme = target_url.Scheme
		// TODO: adjust request host to assign the request to the appropriate child process
		req.URL.Host = target_url.Host

		// clean up but preserve trailing slash:
		trailing := strings.HasSuffix(req.URL.Path, "/")
		req.URL.Path = path.Join(target_url.Path, req.URL.Path)
		if trailing && !strings.HasSuffix(req.URL.Path, "/") {
			req.URL.Path += "/"
		}

		// preserve query string:
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
	}

	proxy := &httputil.ReverseProxy{Director: director}

	static_handler := http.StripPrefix("/static", http.FileServer(http.Dir("static")))
	admin_template := template.Must(template.ParseFiles("templates/admin.html"))
	admin_handler := func(w http.ResponseWriter, req *http.Request) {
		admin_template.Execute(w, nil)
	}

	//fmt.Printf("path: %s\n", request_path)
	switch {
	case request_path == "/admin":
		//fmt.Printf("admin path...\n")
		admin_handler(w, my_req)
		return
	case strings.HasPrefix(request_path, "/static"):
		//fmt.Printf("static path...\n")
		static_handler.ServeHTTP(w, my_req)
		return
	}
	//fmt.Printf("proxy path...\n")
	proxy.ServeHTTP(w, my_req)
}

type Config struct {
	Host string
	Port int
	/*
	    	Debug bool
	   	Pool struct {
	   		Size int
	   		Template struct {
	   			Name string
	   		}
	   	}
	*/
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func main() {
	// Test reading a config yaml:
	data, error := ioutil.ReadFile("etc/template.conf")
	check(error)
	c := Config{}
	yaml.Unmarshal(data, &c)

	fmt.Printf("Host %s and Port %d\n", c.Host, c.Port)

	events_channel := make(chan int)
	go start_process(events_channel) // TODO MANY PROCESSES, MUCH POOLS
	fmt.Printf("Gophernaut is gopher launch!\n")
	http.ListenAndServe(":8483", http.HandlerFunc(myHandler))
	// TODO: our own ReverseProxy implementation of at least, ServeHTTP so that we can
	// monitor the response codes to track successes and failures
}
<commit_msg>start listening on the std files before starting the process<commit_after>package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
)

var hostname = fmt.Sprintf("http://127.0.0.1:%d", 8080)
var executable string = fmt.Sprintf("python -m SimpleHTTPServer %d", 8080)

func start_process(events chan int) {
	command_parts := strings.Split(executable, " ")
	command := exec.Command(command_parts[0], command_parts[1:]...)
	fmt.Printf("Command: %v\n", command)

	stdout, err := command.StdoutPipe()
	if err != nil {
		fmt.Println("Unable to read output from command...")
	}
	stderr, err := command.StderrPipe()
	if err != nil {
		fmt.Println("Unable to read output from command...")
	}

	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)
	command.Start()

	for {
		_, ok := <-events
		if !ok {
			command.Process.Kill()
		}
	}
}

func myHandler(w http.ResponseWriter, my_req *http.Request) {
	request_path := my_req.URL.Path

	target_url, _ := url.Parse(hostname)
	director := func(req *http.Request) {
		targetQuery := target_url.RawQuery
		req.URL.Scheme = target_url.Scheme
		// TODO: adjust request host to assign the request to the appropriate child process
		req.URL.Host = target_url.Host

		// clean up but preserve trailing slash:
		trailing := strings.HasSuffix(req.URL.Path, "/")
		req.URL.Path = path.Join(target_url.Path, req.URL.Path)
		if trailing && !strings.HasSuffix(req.URL.Path, "/") {
			req.URL.Path += "/"
		}

		// preserve query string:
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
	}

	proxy := &httputil.ReverseProxy{Director: director}

	static_handler := http.StripPrefix("/static", http.FileServer(http.Dir("static")))
	admin_template := template.Must(template.ParseFiles("templates/admin.html"))
	admin_handler := func(w http.ResponseWriter, req *http.Request) {
		admin_template.Execute(w, nil)
	}

	//fmt.Printf("path: %s\n", request_path)
	switch {
	case request_path == "/admin":
		//fmt.Printf("admin path...\n")
		admin_handler(w, my_req)
		return
	case strings.HasPrefix(request_path, "/static"):
		//fmt.Printf("static path...\n")
		static_handler.ServeHTTP(w, my_req)
		return
	}
	//fmt.Printf("proxy path...\n")
	proxy.ServeHTTP(w, my_req)
}

type Config struct {
	Host string
	Port int
	/*
	    	Debug bool
	   	Pool struct {
	   		Size int
	   		Template struct {
	   			Name string
	   		}
	   	}
	*/
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func main() {
	// Test reading a config yaml:
	data, error := ioutil.ReadFile("etc/template.conf")
	check(error)
	c := Config{}
	yaml.Unmarshal(data, &c)

	fmt.Printf("Host %s and Port %d\n", c.Host, c.Port)

	events_channel := make(chan int)
	go start_process(events_channel) // TODO MANY PROCESSES, MUCH POOLS
	fmt.Printf("Gophernaut is gopher launch!\n")
	http.ListenAndServe(":8483", http.HandlerFunc(myHandler))
	// TODO: our own ReverseProxy implementation of at least, ServeHTTP so that we can
	// monitor the response codes to track successes and failures
}
<|endoftext|>


<commit_before>package gotcp

import (
	"bytes"
	"encoding/binary"
	"net"
	"time"
)

type HandleMessageFunc func(task *Task, data []byte)

type HanldeMessageMap [255][256]HandleMessageFunc

type ReadData struct {
	Length int
	Data   []byte
}
type Task struct {
	Entry
	Conn            *net.TCPConn
	in              chan []ReadData
	StopChan        chan bool
	handleReadFun   func(task *Task) ([]ReadData, error)
	handleWriteFun  func(task *Task, data []byte) error
	handleParse     func(task *Task, data []byte) bool
	handleHeartBeat func(task *Task)
	heartBeatTime   time.Duration
	HeartBeatReturn bool
	handleMessage   *HanldeMessageMap
}

func NewTask(c *net.TCPConn, name string) *Task {
	task := &Task{
		Conn:            c,
		in:              make(chan []ReadData),
		StopChan:        make(chan bool),
		handleReadFun:   handleReadFunDefault,
		handleWriteFun:  handleWriteFunDefault,
		handleParse:     handleParseDefault,
		handleHeartBeat: handleHeartBeatRequestDefault,
		heartBeatTime:   time.Second * 10,
		HeartBeatReturn: true,
	}
	task.GetEntryName = func() string { return name }
	return task
}
func (self *Task) SetHandleMessage(handle *HanldeMessageMap) {
	self.handleMessage = handle
}
func (self *Task) ParseMessage(data []byte) {
	if self.handleMessage == nil {
		self.Error("no handleMessage:%d,%d", data[0], data[1])
		return
	}
	if len(data) < 2 {
		self.Error("message can not less then 2 bytes")
		return
	}
	switch fun := self.handleMessage[data[0]][data[1]]; fun {
	case nil:
		self.Error("no parse func for message2:%d,%d", data[0], data[1])
		return
	default:
		fun(self, data)
	}
}
func (self *Task) SetHandleReadFun(fun func(task *Task) ([]ReadData, error)) {
	self.handleReadFun = fun
}
func (self *Task) SetHandleWriteFun(fun func(task *Task, data []byte) error) {
	self.handleWriteFun = fun
}
func (self *Task) SetHandleParseFun(fun func(task *Task, data []byte) bool) {
	self.handleParse = fun
}
func (self *Task) SetHandleHeartBteaFun(fun func(task *Task), dur time.Duration) {
	self.handleHeartBeat = fun
	self.heartBeatTime = dur
}

/*
func (self *Task) SendCmd(ptr unsafe.Pointer, length int) {
	data := make([]byte, 0, 0)
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	header.Data = (*reflect.SliceHeader)(ptr).Data
	header.Len = length
	header.Cap = length
	self.handleWriteFun(self, data)

}
//*/
func (self *Task) SendCmd(v interface{}) {
	buf := new(bytes.Buffer)
	if err := binary.Write(buf, binary.LittleEndian, v); err != nil {
		self.Error("SendCmd err:%s", err.Error())
		return
	}
	self.handleWriteFun(self, buf.Bytes())

}

func (self *Task) GetCmd(data []byte, v interface{}) error {
	buf := bytes.NewBuffer(data)
	if err := binary.Read(buf, binary.BigEndian, v); err != nil {
		self.Error("GetCmd err:%s", err.Error())
		return err
	}
	return nil
}
func (self *Task) Start() {
	go self.startRead()
	go self.startWrite()
}
func (self *Task) Stop() {
	self.Debug("ccccccccccccccccccccccccccccccccccccccccccccccccc")
	self.Conn.Close()
	close(self.StopChan)
}
func (self *Task) startRead() {
	defer close(self.in)
	defer self.Debug("startRead close")
	for {
		data, err := self.handleReadFun(self)
		if err != nil {
			self.Error("read error:%s", err.Error())
			self.Stop()
			break
		}
		self.in <- data
	}
}
func (self *Task) startWrite() {
	heartBeat := time.Tick(self.heartBeatTime)
LOOP:
	for {
		select {
		case <-self.StopChan:
			self.Debug("startWrite close")
			return
		case <-heartBeat:
			self.handleHeartBeat(self)
			if !self.HeartBeatReturn {
				self.Debug("timeout error")
				break LOOP
			}
			self.HeartBeatReturn = false
		case datas, ok := <-self.in:
			if !ok {
				self.Debug("self.in chan err")
				break LOOP
			}
			for _, data := range datas {
				if ok := self.handleParse(self, data.Data); !ok {
					self.ParseMessage(data.Data)
				}
			}
		}
	}
}
<commit_msg>send or recv err call Stop func<commit_after>package gotcp

import (
	"bytes"
	"encoding/binary"
	"net"
	"time"
)

type HandleMessageFunc func(task *Task, data []byte)

type HanldeMessageMap [255][256]HandleMessageFunc

type ReadData struct {
	Length int
	Data   []byte
}
type Task struct {
	Entry
	Conn            *net.TCPConn
	in              chan []ReadData
	StopChan        chan bool
	handleReadFun   func(task *Task) ([]ReadData, error)
	handleWriteFun  func(task *Task, data []byte) error
	handleParse     func(task *Task, data []byte) bool
	handleHeartBeat func(task *Task)
	heartBeatTime   time.Duration
	HeartBeatReturn bool
	handleMessage   *HanldeMessageMap
}

func NewTask(c *net.TCPConn, name string) *Task {
	task := &Task{
		Conn:            c,
		in:              make(chan []ReadData),
		StopChan:        make(chan bool),
		handleReadFun:   handleReadFunDefault,
		handleWriteFun:  handleWriteFunDefault,
		handleParse:     handleParseDefault,
		handleHeartBeat: handleHeartBeatRequestDefault,
		heartBeatTime:   time.Second * 10,
		HeartBeatReturn: true,
	}
	task.GetEntryName = func() string { return name }
	return task
}
func (self *Task) SetHandleMessage(handle *HanldeMessageMap) {
	self.handleMessage = handle
}
func (self *Task) ParseMessage(data []byte) {
	if self.handleMessage == nil {
		self.Error("no handleMessage:%d,%d", data[0], data[1])
		return
	}
	if len(data) < 2 {
		self.Error("message can not less then 2 bytes")
		return
	}
	switch fun := self.handleMessage[data[0]][data[1]]; fun {
	case nil:
		self.Error("no parse func for message2:%d,%d", data[0], data[1])
		return
	default:
		fun(self, data)
	}
}
func (self *Task) SetHandleReadFun(fun func(task *Task) ([]ReadData, error)) {
	self.handleReadFun = fun
}
func (self *Task) SetHandleWriteFun(fun func(task *Task, data []byte) error) {
	self.handleWriteFun = fun
}
func (self *Task) SetHandleParseFun(fun func(task *Task, data []byte) bool) {
	self.handleParse = fun
}
func (self *Task) SetHandleHeartBteaFun(fun func(task *Task), dur time.Duration) {
	self.handleHeartBeat = fun
	self.heartBeatTime = dur
}

/*
func (self *Task) SendCmd(ptr unsafe.Pointer, length int) {
	data := make([]byte, 0, 0)
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	header.Data = (*reflect.SliceHeader)(ptr).Data
	header.Len = length
	header.Cap = length
	self.handleWriteFun(self, data)

}
//*/
func (self *Task) SendCmd(v interface{}) {
	buf := new(bytes.Buffer)
	if err := binary.Write(buf, binary.LittleEndian, v); err != nil {
		self.Error("SendCmd err:%s", err.Error())
		return
	}
	self.handleWriteFun(self, buf.Bytes())

}

func (self *Task) GetCmd(data []byte, v interface{}) error {
	buf := bytes.NewBuffer(data)
	if err := binary.Read(buf, binary.BigEndian, v); err != nil {
		self.Error("GetCmd err:%s", err.Error())
		return err
	}
	return nil
}
func (self *Task) Start() {
	go self.startRead()
	go self.startWrite()
}
func (self *Task) Stop() {
	self.Debug("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd")
	self.Conn.Close()
	close(self.StopChan)
}
func (self *Task) startRead() {
	defer close(self.in)
	defer self.Debug("startRead close")
	for {
		data, err := self.handleReadFun(self)
		if err != nil {
			self.Error("read error:%s", err.Error())
			self.Stop()
			break
		}
		self.in <- data
	}
}
func (self *Task) startWrite() {
	heartBeat := time.Tick(self.heartBeatTime)
LOOP:
	for {
		select {
		case <-self.StopChan:
			self.Debug("startWrite close")
			return
		case <-heartBeat:
			self.handleHeartBeat(self)
			if !self.HeartBeatReturn {
				self.Debug("timeout error")
				break LOOP
			}
			self.HeartBeatReturn = false
		case datas, ok := <-self.in:
			if !ok {
				self.Debug("self.in chan err")
				break LOOP
			}
			for _, data := range datas {
				if ok := self.handleParse(self, data.Data); !ok {
					self.ParseMessage(data.Data)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package buildserver

import (
	"net/http"
	"strconv"

	"github.com/concourse/atc"
	"github.com/concourse/atc/auth"
)

func (s *Server) BuildEvents(w http.ResponseWriter, r *http.Request) {
	buildIDStr := r.FormValue(":build_id")

	buildID, err := strconv.Atoi(buildIDStr)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	build, err := s.db.GetBuild(buildID)
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	censor := false
	if !s.fallback.IsAuthenticated(r) {
		censor = true

		if build.OneOff() {
			auth.Unauthorized(w)
			return
		}

		config, _, err := s.configDB.GetConfig(atc.DefaultPipelineName)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		public, err := config.JobIsPublic(build.JobName)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		if !public {
			auth.Unauthorized(w)
			return
		}
	}

	streamDone := make(chan struct{})

	go func() {
		defer close(streamDone)
		s.eventHandlerFactory(s.db, buildID, censor).ServeHTTP(w, r)
	}()

	select {
	case <-streamDone:
	case <-s.drain:
	}
}
<commit_msg>Add logs for build events<commit_after>package buildserver

import (
	"net/http"
	"strconv"

	"github.com/concourse/atc"
	"github.com/concourse/atc/auth"
)

func (s *Server) BuildEvents(w http.ResponseWriter, r *http.Request) {
	buildIDStr := r.FormValue(":build_id")

	buildID, err := strconv.Atoi(buildIDStr)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	build, err := s.db.GetBuild(buildID)
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	censor := false
	if !s.fallback.IsAuthenticated(r) {
		censor = true

		if build.OneOff() {
			auth.Unauthorized(w)
			return
		}

		config, _, err := s.configDB.GetConfig(atc.DefaultPipelineName)

		if err != nil {
			s.logger.Error("failed-to-get-config", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		public, err := config.JobIsPublic(build.JobName)
		if err != nil {
			s.logger.Error("failed-to-see-job-is-public", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		if !public {
			auth.Unauthorized(w)
			return
		}
	}

	streamDone := make(chan struct{})

	go func() {
		defer close(streamDone)
		s.eventHandlerFactory(s.db, buildID, censor).ServeHTTP(w, r)
	}()

	select {
	case <-streamDone:
	case <-s.drain:
	}
}
<|endoftext|>


<commit_before>package lmod

import (
    "io/ioutil"
    "os"
)

func LoadedModules() ([]string) {

    var modules []string

    flist, err := ioutil.ReadDir("/sys/module")

    if err != nil {
        os.Exit(1)
    }

    for _,element := range flist {
        modules = append(modules, element.Name())
    }

    return modules
}
<commit_msg>go-style error handling instead of a dirty os.Exit(1)<commit_after>package lmod

import (
    "io/ioutil"
    "fmt"
)

func LoadedModules() ([]string, error) {

    var modules []string

    flist, err := ioutil.ReadDir("/sys/module")

    if err != nil {
        return modules, fmt.Errorf("lmod: cannot access loaded module list")
    }

    for _,element := range flist {
        modules = append(modules, element.Name())
    }

    return modules, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package graph

import (
	"fmt"

	"github.com/OWASP/Amass/v3/graphdb"
	"github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/OWASP/Amass/v3/stringfilter"
)

// InsertAddress creates an IP address in the graph and associates it with a source and event.
func (g *Graph) InsertAddress(addr, source, tag, eventID string) (graphdb.Node, error) {
	node, err := g.InsertNodeIfNotExist(addr, "ipaddr")
	if err != nil {
		return node, err
	}

	if err := g.AddNodeToEvent(node, source, tag, eventID); err != nil {
		return node, err
	}

	return node, nil
}

// NameToAddrs obtains each ipaddr Node that the parameter Node has resolved to.
func (g *Graph) NameToAddrs(node graphdb.Node) ([]graphdb.Node, error) {
	nstr := g.db.NodeToID(node)
	if nstr == "" {
		return nil, fmt.Errorf("%s: NameToIPAddrs: Invalid node reference argument", g.String())
	}

	// Attempt to obtain the SRV record out-edge for the Node parameter
	edges, err := g.db.ReadOutEdges(node, "srv_record")
	if err == nil && len(edges) > 0 {
		// A SRV record was discovered for the Node parameter
		for _, edge := range edges {
			if edge.Predicate == "srv_record" {
				// Set the node to the one pointed to by the SRV record
				node = edge.To
				break
			}
		}
	}

	// Traverse CNAME and A/AAAA records
	nodes, err := g.CNAMEToAddrs(node)
	if len(nodes) > 0 {
		return nodes, nil
	}

	return nodes, fmt.Errorf("%s: NameToIPAddrs: No addresses were discovered for %s", g.String(), nstr)
}

// CNAMEToAddrs traverses CNAME records, starting with the parameter Node, and obtains the network addresses they eventually resolve to.
func (g *Graph) CNAMEToAddrs(node graphdb.Node) ([]graphdb.Node, error) {
	cur := node
	var nodes []graphdb.Node
	filter := stringfilter.NewStringFilter()

	// Do not recursively follow the CNAMEs for more than 10 records
traversal:
	for i := 0; i < 10; i++ {
		// Get all the out-edges of interest for the current Node parameter
		edges, err := g.db.ReadOutEdges(cur, "cname_record", "a_record", "aaaa_record")
		if err != nil {
			return nil, fmt.Errorf("%s: CNAMEToAddrs: No records found for Node %s: %v", g.String(), g.db.NodeToID(cur), err)
		}

		for _, edge := range edges {
			if edge.Predicate == "cname_record" {
				if filter.Has(g.db.NodeToID(edge.To)) {
					break traversal
				}

				cur = edge.To
				continue traversal
			}
		}

		for _, edge := range edges {
			nodes = append(nodes, edge.To)
		}
		break
	}

	return nodes, nil
}

// InsertA creates FQDN, IP address and A record edge in the graph and associates them with a source and event.
func (g *Graph) InsertA(fqdn, addr, source, tag, eventID string) error {
	fqdnNode, err := g.InsertFQDN(fqdn, source, tag, eventID)
	if err != nil {
		return err
	}

	ipNode, err := g.InsertAddress(addr, "DNS", requests.DNS, eventID)
	if err != nil {
		return err
	}

	ipEdge := &graphdb.Edge{
		Predicate: "a_record",
		From:      fqdnNode,
		To:        ipNode,
	}

	if err := g.InsertEdge(ipEdge); err != nil {
		return err
	}

	return nil
}

// InsertAAAA creates FQDN, IP address and AAAA record edge in the graph and associates them with a source and event.
func (g *Graph) InsertAAAA(fqdn, addr, source, tag, eventID string) error {
	fqdnNode, err := g.InsertFQDN(fqdn, source, tag, eventID)
	if err != nil {
		return err
	}

	ipNode, err := g.InsertAddress(addr, "DNS", requests.DNS, eventID)
	if err != nil {
		return err
	}

	ipEdge := &graphdb.Edge{
		Predicate: "aaaa_record",
		From:      fqdnNode,
		To:        ipNode,
	}

	if err := g.InsertEdge(ipEdge); err != nil {
		return err
	}

	return nil
}

// HealAddressNodes looks for 'ipaddr' nodes in the graph and creates missing edges to the
// appropriate 'netblock' nodes using data provided by the ASNCache parameter.
func (g *Graph) HealAddressNodes(cache *net.ASNCache, uuid string) error {
	var err error
	cidrToNode := make(map[string]graphdb.Node)

	if cache == nil {
		cache = net.NewASNCache()

		if err = g.asnCacheFill(cache); err != nil {
			return err
		}
	}

	nodes, err := g.AllNodesOfType("ipaddr", uuid)
	if err != nil {
		return err
	}

	for _, node := range nodes {
		addr := g.db.NodeToID(node)

		as := cache.AddrSearch(addr)
		if as == nil {
			continue
		}

		cidr, found := cidrToNode[as.Prefix]
		if !found {
			cidr, err = g.db.ReadNode(as.Prefix, "netblock")
			if err != nil {
				g.InsertInfrastructure(as.ASN, as.Description, addr, as.Prefix, as.Source, as.Tag, uuid)

				cidr, err = g.db.ReadNode(as.Prefix, "netblock")
				if err != nil {
					continue
				}
			}

			cidrToNode[as.Prefix] = cidr
		}

		g.InsertEdge(&graphdb.Edge{
			Predicate: "contains",
			From:      cidr,
			To:        node,
		})
	}

	return nil
}
<commit_msg>graph: fix dropped error<commit_after>// Copyright 2017 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package graph

import (
	"fmt"

	"github.com/OWASP/Amass/v3/graphdb"
	"github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/OWASP/Amass/v3/stringfilter"
)

// InsertAddress creates an IP address in the graph and associates it with a source and event.
func (g *Graph) InsertAddress(addr, source, tag, eventID string) (graphdb.Node, error) {
	node, err := g.InsertNodeIfNotExist(addr, "ipaddr")
	if err != nil {
		return node, err
	}

	if err := g.AddNodeToEvent(node, source, tag, eventID); err != nil {
		return node, err
	}

	return node, nil
}

// NameToAddrs obtains each ipaddr Node that the parameter Node has resolved to.
func (g *Graph) NameToAddrs(node graphdb.Node) ([]graphdb.Node, error) {
	nstr := g.db.NodeToID(node)
	if nstr == "" {
		return nil, fmt.Errorf("%s: NameToIPAddrs: Invalid node reference argument", g.String())
	}

	// Attempt to obtain the SRV record out-edge for the Node parameter
	edges, err := g.db.ReadOutEdges(node, "srv_record")
	if err == nil && len(edges) > 0 {
		// A SRV record was discovered for the Node parameter
		for _, edge := range edges {
			if edge.Predicate == "srv_record" {
				// Set the node to the one pointed to by the SRV record
				node = edge.To
				break
			}
		}
	}

	// Traverse CNAME and A/AAAA records
	nodes, err := g.CNAMEToAddrs(node)

	if len(nodes) > 0 {
		return nodes, err
	}

	return nodes, fmt.Errorf("%s: NameToIPAddrs: No addresses were discovered for %s", g.String(), nstr)
}

// CNAMEToAddrs traverses CNAME records, starting with the parameter Node, and obtains the network addresses they eventually resolve to.
func (g *Graph) CNAMEToAddrs(node graphdb.Node) ([]graphdb.Node, error) {
	cur := node
	var nodes []graphdb.Node
	filter := stringfilter.NewStringFilter()

	// Do not recursively follow the CNAMEs for more than 10 records
traversal:
	for i := 0; i < 10; i++ {
		// Get all the out-edges of interest for the current Node parameter
		edges, err := g.db.ReadOutEdges(cur, "cname_record", "a_record", "aaaa_record")
		if err != nil {
			return nil, fmt.Errorf("%s: CNAMEToAddrs: No records found for Node %s: %v", g.String(), g.db.NodeToID(cur), err)
		}

		for _, edge := range edges {
			if edge.Predicate == "cname_record" {
				if filter.Has(g.db.NodeToID(edge.To)) {
					break traversal
				}

				cur = edge.To
				continue traversal
			}
		}

		for _, edge := range edges {
			nodes = append(nodes, edge.To)
		}
		break
	}

	return nodes, nil
}

// InsertA creates FQDN, IP address and A record edge in the graph and associates them with a source and event.
func (g *Graph) InsertA(fqdn, addr, source, tag, eventID string) error {
	fqdnNode, err := g.InsertFQDN(fqdn, source, tag, eventID)
	if err != nil {
		return err
	}

	ipNode, err := g.InsertAddress(addr, "DNS", requests.DNS, eventID)
	if err != nil {
		return err
	}

	ipEdge := &graphdb.Edge{
		Predicate: "a_record",
		From:      fqdnNode,
		To:        ipNode,
	}

	if err := g.InsertEdge(ipEdge); err != nil {
		return err
	}

	return nil
}

// InsertAAAA creates FQDN, IP address and AAAA record edge in the graph and associates them with a source and event.
func (g *Graph) InsertAAAA(fqdn, addr, source, tag, eventID string) error {
	fqdnNode, err := g.InsertFQDN(fqdn, source, tag, eventID)
	if err != nil {
		return err
	}

	ipNode, err := g.InsertAddress(addr, "DNS", requests.DNS, eventID)
	if err != nil {
		return err
	}

	ipEdge := &graphdb.Edge{
		Predicate: "aaaa_record",
		From:      fqdnNode,
		To:        ipNode,
	}

	if err := g.InsertEdge(ipEdge); err != nil {
		return err
	}

	return nil
}

// HealAddressNodes looks for 'ipaddr' nodes in the graph and creates missing edges to the
// appropriate 'netblock' nodes using data provided by the ASNCache parameter.
func (g *Graph) HealAddressNodes(cache *net.ASNCache, uuid string) error {
	var err error
	cidrToNode := make(map[string]graphdb.Node)

	if cache == nil {
		cache = net.NewASNCache()

		if err = g.asnCacheFill(cache); err != nil {
			return err
		}
	}

	nodes, err := g.AllNodesOfType("ipaddr", uuid)
	if err != nil {
		return err
	}

	for _, node := range nodes {
		addr := g.db.NodeToID(node)

		as := cache.AddrSearch(addr)
		if as == nil {
			continue
		}

		cidr, found := cidrToNode[as.Prefix]
		if !found {
			cidr, err = g.db.ReadNode(as.Prefix, "netblock")
			if err != nil {
				g.InsertInfrastructure(as.ASN, as.Description, addr, as.Prefix, as.Source, as.Tag, uuid)

				cidr, err = g.db.ReadNode(as.Prefix, "netblock")
				if err != nil {
					continue
				}
			}

			cidrToNode[as.Prefix] = cidr
		}

		g.InsertEdge(&graphdb.Edge{
			Predicate: "contains",
			From:      cidr,
			To:        node,
		})
	}

	return nil
}
<|endoftext|>


<commit_before>package grayt

import (
	"math"
)

type grid struct {
	minBound Vector
	maxBound Vector

	stride     Vector
	data       []*link
	resolution triple
}

func newGrid(lambda float64, objs ObjectList) *grid {

	minBound, maxBound := bounds(objs)
	boundDiff := maxBound.Sub(minBound)
	volume := boundDiff.X * boundDiff.Y * boundDiff.Z

	resolutionFactor := math.Pow(lambda*float64(len(objs))/volume, 1.0/3.0)
	resolution := truncate(boundDiff.Scale(resolutionFactor))
	stride := boundDiff.div(resolution.asVector())
	data := make([]*link, resolution.x*resolution.y*resolution.z)

	grid := &grid{
		minBound,
		maxBound,
		stride,
		data,
		resolution,
	}
	grid.populate(objs)

	return grid
}

func bounds(objs ObjectList) (Vector, Vector) {
	inf := math.Inf(+1)
	minBound, maxBound := Vect(+inf, +inf, +inf), Vect(-inf, -inf, -inf)
	for _, obj := range objs {
		min, max := obj.bound()
		minBound = minBound.Min(min)
		maxBound = maxBound.Max(max)
	}
	return minBound, maxBound
}

func (g *grid) populate(objs ObjectList) {
	for _, obj := range objs {
		min, max := obj.bound()
		minCoord := truncate(min.Sub(g.minBound).div(g.stride)).min(g.resolution.sub(triple{1, 1, 1}))
		maxCoord := truncate(max.Sub(g.minBound).div(g.stride)).min(g.resolution.sub(triple{1, 1, 1}))
		var pos triple
		for pos.x = minCoord.x; pos.x <= maxCoord.x; pos.x++ {
			for pos.y = minCoord.y; pos.y <= maxCoord.y; pos.y++ {
				for pos.z = minCoord.z; pos.z <= maxCoord.z; pos.z++ {
					idx := g.dataIndex(pos)
					g.data[idx] = &link{g.data[idx], obj}
				}
			}
		}
	}
}

func (g *grid) closestHit(r ray) (intersection, material, bool) {

	var distance float64
	if !g.insideBoundingBox(r.start) {
		var hit bool
		distance, hit = g.hitBoundingBox(r)
		if !hit {
			return intersection{}, material{}, false
		}
	}

	cellCoordsFloat := g.cellCoordsFloat(r.at(distance))
	pos := g.cellCoordsInt(cellCoordsFloat)
	delta := g.delta(r)
	inc := g.inc(r)
	next := g.next(cellCoordsFloat, r)

	for true {

		if intersection, material, hit := g.findHitInCell(pos, next, r); hit {
			return intersection, material, true
		}

		var exitGrid bool
		next, pos, exitGrid = g.nextCell(next, delta, pos, inc)
		if exitGrid {
			break
		}
	}

	return intersection{}, material{}, false
}

func (g *grid) insideBoundingBox(v Vector) bool {
	return true &&
		v.X >= g.minBound.X && v.X <= g.maxBound.X &&
		v.Y >= g.minBound.Y && v.Y <= g.maxBound.Y &&
		v.Z >= g.minBound.Z && v.Z <= g.maxBound.Z
}

func (g *grid) hitBoundingBox(r ray) (float64, bool) {

	tx1 := (g.minBound.X - r.start.X) / r.dir.X
	tx2 := (g.maxBound.X - r.start.X) / r.dir.X
	ty1 := (g.minBound.Y - r.start.Y) / r.dir.Y
	ty2 := (g.maxBound.Y - r.start.Y) / r.dir.Y
	tz1 := (g.minBound.Z - r.start.Z) / r.dir.Z
	tz2 := (g.maxBound.Z - r.start.Z) / r.dir.Z

	tmin, tmax := math.Inf(-1), math.Inf(+1)

	tmin = math.Max(tmin, math.Min(tx1, tx2))
	tmax = math.Min(tmax, math.Max(tx1, tx2))
	tmin = math.Max(tmin, math.Min(ty1, ty2))
	tmax = math.Min(tmax, math.Max(ty1, ty2))
	tmin = math.Max(tmin, math.Min(tz1, tz2))
	tmax = math.Min(tmax, math.Max(tz1, tz2))

	return tmin, tmin <= tmax && tmin >= 0
}

func (g *grid) cellCoordsFloat(v Vector) Vector {
	return v.
		Sub(g.minBound).
		div(g.stride)
}

func (g *grid) cellCoordsInt(cellCoordsFloat Vector) triple {
	return truncate(cellCoordsFloat).
		min(g.resolution.sub(triple{1, 1, 1})).
		max(triple{})
}

func (g *grid) delta(r ray) Vector {
	return g.stride.
		div(r.dir).
		abs()
}

func (g *grid) inc(r ray) triple {
	return truncate(
		r.dir.sign(),
	)
}

func (g *grid) next(cellCoordsFloat Vector, r ray) Vector {
	return g.cellCoordsInt(cellCoordsFloat).asVector().
		Add(r.dir.
			sign().
			Scale(0.5).
			Add(Vect(0.5, 0.5, 0.5)),
		).
		mul(g.stride).
		Sub(r.start.Sub(g.minBound)).
		div(r.dir)
}

func (g *grid) nextCell(next, delta Vector, pos, inc triple) (Vector, triple, bool) {

	// TODO: Is is numerically stable to keep incrementing next? Could we
	// instead compute it fresh each time? Does it really matter if it's
	// numerically stable?
	var exitGrid bool
	switch {
	case next.X < math.Min(next.Y, next.Z):
		pos.x += inc.x
		next.X += delta.X
		exitGrid = pos.x < 0 && inc.x < 0 || pos.x >= g.resolution.x && inc.x > 0
	case next.Y < next.Z:
		pos.y += inc.y
		next.Y += delta.Y
		exitGrid = pos.y < 0 && inc.y < 0 || pos.y >= g.resolution.y && inc.y > 0
	default:
		pos.z += inc.z
		next.Z += delta.Z
		exitGrid = pos.z < 0 && inc.z < 0 || pos.z >= g.resolution.z && inc.z > 0
	}
	return next, pos, exitGrid
}

func (g *grid) dataIndex(pos triple) int {
	return pos.x + g.resolution.x*pos.y + g.resolution.x*g.resolution.y*pos.z
}

func (g *grid) findHitInCell(pos triple, next Vector, r ray) (intersection, material, bool) {

	var closest struct {
		intersection intersection
		material     material
		hit          bool
	}

	var head *link
	if true &&
		pos.x >= 0 && pos.x < g.resolution.x &&
		pos.y >= 0 && pos.y < g.resolution.y &&
		pos.z >= 0 && pos.z < g.resolution.z {
		head = g.data[g.dataIndex(pos)]
	}

	for link := head; link != nil; link = link.next {
		intersection, hit := link.obj.intersect(r)
		if !hit {
			continue
		}
		nextCell := addULPs(math.Min(next.X, math.Min(next.Y, next.Z)), ulpFudgeFactor)
		if intersection.distance > nextCell {
			continue
		}
		if !closest.hit || intersection.distance < closest.intersection.distance {
			closest.intersection = intersection
			closest.material = link.obj.material
			closest.hit = true
		}
	}

	return closest.intersection, closest.material, closest.hit
}

type link struct {
	next *link
	obj  Object
}
<commit_msg>Remove redundant check index being in range<commit_after>package grayt

import (
	"math"
)

type grid struct {
	minBound Vector
	maxBound Vector

	stride     Vector
	data       []*link
	resolution triple
}

func newGrid(lambda float64, objs ObjectList) *grid {

	minBound, maxBound := bounds(objs)
	boundDiff := maxBound.Sub(minBound)
	volume := boundDiff.X * boundDiff.Y * boundDiff.Z

	resolutionFactor := math.Pow(lambda*float64(len(objs))/volume, 1.0/3.0)
	resolution := truncate(boundDiff.Scale(resolutionFactor))
	stride := boundDiff.div(resolution.asVector())
	data := make([]*link, resolution.x*resolution.y*resolution.z)

	grid := &grid{
		minBound,
		maxBound,
		stride,
		data,
		resolution,
	}
	grid.populate(objs)

	return grid
}

func bounds(objs ObjectList) (Vector, Vector) {
	inf := math.Inf(+1)
	minBound, maxBound := Vect(+inf, +inf, +inf), Vect(-inf, -inf, -inf)
	for _, obj := range objs {
		min, max := obj.bound()
		minBound = minBound.Min(min)
		maxBound = maxBound.Max(max)
	}
	return minBound, maxBound
}

func (g *grid) populate(objs ObjectList) {
	for _, obj := range objs {
		min, max := obj.bound()
		minCoord := truncate(min.Sub(g.minBound).div(g.stride)).min(g.resolution.sub(triple{1, 1, 1}))
		maxCoord := truncate(max.Sub(g.minBound).div(g.stride)).min(g.resolution.sub(triple{1, 1, 1}))
		var pos triple
		for pos.x = minCoord.x; pos.x <= maxCoord.x; pos.x++ {
			for pos.y = minCoord.y; pos.y <= maxCoord.y; pos.y++ {
				for pos.z = minCoord.z; pos.z <= maxCoord.z; pos.z++ {
					idx := g.dataIndex(pos)
					g.data[idx] = &link{g.data[idx], obj}
				}
			}
		}
	}
}

func (g *grid) closestHit(r ray) (intersection, material, bool) {

	var distance float64
	if !g.insideBoundingBox(r.start) {
		var hit bool
		distance, hit = g.hitBoundingBox(r)
		if !hit {
			return intersection{}, material{}, false
		}
	}

	cellCoordsFloat := g.cellCoordsFloat(r.at(distance))
	pos := g.cellCoordsInt(cellCoordsFloat)
	delta := g.delta(r)
	inc := g.inc(r)
	next := g.next(cellCoordsFloat, r)

	for true {

		if intersection, material, hit := g.findHitInCell(pos, next, r); hit {
			return intersection, material, true
		}

		var exitGrid bool
		next, pos, exitGrid = g.nextCell(next, delta, pos, inc)
		if exitGrid {
			break
		}
	}

	return intersection{}, material{}, false
}

func (g *grid) insideBoundingBox(v Vector) bool {
	return true &&
		v.X >= g.minBound.X && v.X <= g.maxBound.X &&
		v.Y >= g.minBound.Y && v.Y <= g.maxBound.Y &&
		v.Z >= g.minBound.Z && v.Z <= g.maxBound.Z
}

func (g *grid) hitBoundingBox(r ray) (float64, bool) {

	tx1 := (g.minBound.X - r.start.X) / r.dir.X
	tx2 := (g.maxBound.X - r.start.X) / r.dir.X
	ty1 := (g.minBound.Y - r.start.Y) / r.dir.Y
	ty2 := (g.maxBound.Y - r.start.Y) / r.dir.Y
	tz1 := (g.minBound.Z - r.start.Z) / r.dir.Z
	tz2 := (g.maxBound.Z - r.start.Z) / r.dir.Z

	tmin, tmax := math.Inf(-1), math.Inf(+1)

	tmin = math.Max(tmin, math.Min(tx1, tx2))
	tmax = math.Min(tmax, math.Max(tx1, tx2))
	tmin = math.Max(tmin, math.Min(ty1, ty2))
	tmax = math.Min(tmax, math.Max(ty1, ty2))
	tmin = math.Max(tmin, math.Min(tz1, tz2))
	tmax = math.Min(tmax, math.Max(tz1, tz2))

	return tmin, tmin <= tmax && tmin >= 0
}

func (g *grid) cellCoordsFloat(v Vector) Vector {
	return v.
		Sub(g.minBound).
		div(g.stride)
}

func (g *grid) cellCoordsInt(cellCoordsFloat Vector) triple {
	return truncate(cellCoordsFloat).
		min(g.resolution.sub(triple{1, 1, 1})).
		max(triple{})
}

func (g *grid) delta(r ray) Vector {
	return g.stride.
		div(r.dir).
		abs()
}

func (g *grid) inc(r ray) triple {
	return truncate(
		r.dir.sign(),
	)
}

func (g *grid) next(cellCoordsFloat Vector, r ray) Vector {
	return g.cellCoordsInt(cellCoordsFloat).asVector().
		Add(r.dir.
			sign().
			Scale(0.5).
			Add(Vect(0.5, 0.5, 0.5)),
		).
		mul(g.stride).
		Sub(r.start.Sub(g.minBound)).
		div(r.dir)
}

func (g *grid) nextCell(next, delta Vector, pos, inc triple) (Vector, triple, bool) {

	// TODO: Is is numerically stable to keep incrementing next? Could we
	// instead compute it fresh each time? Does it really matter if it's
	// numerically stable?
	var exitGrid bool
	switch {
	case next.X < math.Min(next.Y, next.Z):
		pos.x += inc.x
		next.X += delta.X
		exitGrid = pos.x < 0 && inc.x < 0 || pos.x >= g.resolution.x && inc.x > 0
	case next.Y < next.Z:
		pos.y += inc.y
		next.Y += delta.Y
		exitGrid = pos.y < 0 && inc.y < 0 || pos.y >= g.resolution.y && inc.y > 0
	default:
		pos.z += inc.z
		next.Z += delta.Z
		exitGrid = pos.z < 0 && inc.z < 0 || pos.z >= g.resolution.z && inc.z > 0
	}
	return next, pos, exitGrid
}

func (g *grid) dataIndex(pos triple) int {
	return pos.x + g.resolution.x*pos.y + g.resolution.x*g.resolution.y*pos.z
}

func (g *grid) findHitInCell(pos triple, next Vector, r ray) (intersection, material, bool) {

	var closest struct {
		intersection intersection
		material     material
		hit          bool
	}

	for link := g.data[g.dataIndex(pos)]; link != nil; link = link.next {
		intersection, hit := link.obj.intersect(r)
		if !hit {
			continue
		}
		nextCell := addULPs(math.Min(next.X, math.Min(next.Y, next.Z)), ulpFudgeFactor)
		if intersection.distance > nextCell {
			continue
		}
		if !closest.hit || intersection.distance < closest.intersection.distance {
			closest.intersection = intersection
			closest.material = link.obj.material
			closest.hit = true
		}
	}

	return closest.intersection, closest.material, closest.hit
}

type link struct {
	next *link
	obj  Object
}
<|endoftext|>


<commit_before>/*
Copyright 2012 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package groupcache provides a data loading mechanism with caching
// and de-duplication that works across a set of peer processes.
//
// Each data Get first consults its local cache, otherwise delegates
// to the requested key's canonical owner, which then checks its cache
// or finally gets the data.  In the common case, many concurrent
// cache misses across a set of peers for the same key result in just
// one cache fill.
package groupcache

import (
	"errors"
	"math/rand"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	pb "github.com/golang/groupcache/groupcachepb"
	"github.com/golang/groupcache/lru"
	"github.com/golang/groupcache/singleflight"
)

// A Getter loads data for a key.
type Getter interface {
	// Get returns the value identified by key, populating dest.
	//
	// The returned data must be unversioned. That is, key must
	// uniquely describe the loaded data, without an implicit
	// current time, and without relying on cache expiration
	// mechanisms.
	Get(ctx Context, key string, dest Sink) error
}

// A GetterFunc implements Getter with a function.
type GetterFunc func(ctx Context, key string, dest Sink) error

func (f GetterFunc) Get(ctx Context, key string, dest Sink) error {
	return f(ctx, key, dest)
}

var (
	mu     sync.RWMutex
	groups = make(map[string]*Group)

	initPeerServerOnce sync.Once
	initPeerServer     func()
)

// GetGroup returns the named group previously created with NewGroup, or
// nil if there's no such group.
func GetGroup(name string) *Group {
	mu.RLock()
	g := groups[name]
	mu.RUnlock()
	return g
}

// NewGroup creates a coordinated group-aware Getter from a Getter.
//
// The returned Getter tries (but does not guarantee) to run only one
// Get call at once for a given key across an entire set of peer
// processes. Concurrent callers both in the local process and in
// other processes receive copies of the answer once the original Get
// completes.
//
// The group name must be unique for each getter.
func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
	return newGroup(name, cacheBytes, getter, nil)
}

// If peers is nil, the peerPicker is called via a sync.Once to initialize it.
func newGroup(name string, cacheBytes int64, getter Getter, peers PeerPicker) *Group {
	if getter == nil {
		panic("nil Getter")
	}
	mu.Lock()
	defer mu.Unlock()
	initPeerServerOnce.Do(callInitPeerServer)
	if _, dup := groups[name]; dup {
		panic("duplicate registration of group " + name)
	}
	g := &Group{
		name:       name,
		getter:     getter,
		peers:      peers,
		cacheBytes: cacheBytes,
	}
	if fn := newGroupHook; fn != nil {
		fn(g)
	}
	groups[name] = g
	return g
}

// newGroupHook, if non-nil, is called right after a new group is created.
var newGroupHook func(*Group)

// RegisterNewGroupHook registers a hook that is run each time
// a group is created.
func RegisterNewGroupHook(fn func(*Group)) {
	if newGroupHook != nil {
		panic("RegisterNewGroupHook called more than once")
	}
	newGroupHook = fn
}

// RegisterServerStart registers a hook that is run when the first
// group is created.
func RegisterServerStart(fn func()) {
	if initPeerServer != nil {
		panic("RegisterServerStart called more than once")
	}
	initPeerServer = fn
}

func callInitPeerServer() {
	if initPeerServer != nil {
		initPeerServer()
	}
}

// A Group is a cache namespace and associated data loaded spread over
// a group of 1 or more machines.
type Group struct {
	name       string
	getter     Getter
	peersOnce  sync.Once
	peers      PeerPicker
	cacheBytes int64 // limit for sum of mainCache and hotCache size

	// mainCache is a cache of the keys for which this process
	// (amongst its peers) is authorative. That is, this cache
	// contains keys which consistent hash on to this process's
	// peer number.
	mainCache cache

	// hotCache contains keys/values for which this peer is not
	// authorative (otherwise they would be in mainCache), but
	// are popular enough to warrant mirroring in this process to
	// avoid going over the network to fetch from a peer.  Having
	// a hotCache avoids network hotspotting, where a peer's
	// network card could become the bottleneck on a popular key.
	// This cache is used sparingly to maximize the total number
	// of key/value pairs that can stored globally.
	hotCache cache

	// loadGroup ensures that each key is only fetched once
	// (either locally or remotely), regardless of the number of
	// concurrent callers.
	loadGroup singleflight.Group

	// Stats are statistics on the group.
	Stats Stats

	// For expiration functionality.
	expiration    time.Duration
	stalePeriod   time.Duration
	staleDeadline time.Duration
}

// Stats are per-group statistics.
type Stats struct {
	Gets           AtomicInt // any Get request, including from peers
	CacheHits      AtomicInt // either cache was good
	PeerLoads      AtomicInt // either remote load or remote cache hit (not an error)
	PeerErrors     AtomicInt
	Loads          AtomicInt // (gets - cacheHits)
	LoadsDeduped   AtomicInt // after singleflight
	LocalLoads     AtomicInt // total good local loads
	LocalLoadErrs  AtomicInt // total bad local loads
	ServerRequests AtomicInt // gets that came over the network from peers
}

// Name returns the name of the group.
func (g *Group) Name() string {
	return g.name
}

func (g *Group) initPeers() {
	if g.peers == nil {
		g.peers = getPeers()
	}
}

func (g *Group) Get(ctx Context, key string, dest Sink) error {
	g.peersOnce.Do(g.initPeers)
	g.Stats.Gets.Add(1)
	if dest == nil {
		return errors.New("groupcache: nil dest Sink")
	}
	value, cacheHit := g.lookupCache(key)

	if cacheHit {
		g.Stats.CacheHits.Add(1)

		if g.expiration > 0 {
			return g.handleExpiration(ctx, key, dest, value)
		}

		return setSinkView(dest, value)
	}
	return g.loadOnMiss(ctx, key, dest, false)
}

func (g *Group) loadOnMiss(ctx Context, key string, dest Sink, expired bool) error {
	// Optimization to avoid double unmarshalling or copying: keep
	// track of whether the dest was already populated. One caller
	// (if local) will set this; the losers will not. The common
	// case will likely be one caller.
	destPopulated := false
	value, destPopulated, err := g.load(ctx, key, dest, expired)
	if err != nil {
		return err
	}
	if destPopulated {
		return nil
	}

	return setSinkView(dest, value)
}

// load loads key either by invoking the getter locally or by sending it to another machine.
func (g *Group) load(ctx Context, key string, dest Sink, expired bool) (value ByteView, destPopulated bool, err error) {
	g.Stats.Loads.Add(1)
	viewi, err := g.loadGroup.Do(key, func() (interface{}, error) {
		g.Stats.LoadsDeduped.Add(1)
		var value ByteView
		var err error
		if peer, ok := g.peers.PickPeer(key); ok {
			value, err = g.getFromPeer(ctx, peer, key, expired)
			if err == nil {
				g.Stats.PeerLoads.Add(1)
				return value, nil
			}
			g.Stats.PeerErrors.Add(1)
			// TODO(bradfitz): log the peer's error? keep
			// log of the past few for /groupcachez?  It's
			// probably boring (normal task movement), so not
			// worth logging I imagine.
		}
		value, err = g.getLocally(ctx, key, dest)
		if err != nil {
			g.Stats.LocalLoadErrs.Add(1)
			return nil, err
		}
		g.Stats.LocalLoads.Add(1)
		destPopulated = true // only one caller of load gets this return value
		g.populateCache(key, value, &g.mainCache)
		return value, nil
	})
	if err == nil {
		value = viewi.(ByteView)
	}
	return
}

func (g *Group) getLocally(ctx Context, key string, dest Sink) (ByteView, error) {
	err := g.getter.Get(ctx, key, dest)
	if err != nil {
		return ByteView{}, err
	}
	return dest.view()
}

func (g *Group) getFromPeer(ctx Context, peer ProtoGetter, key string, expired bool) (ByteView, error) {
	req := &pb.GetRequest{
		Group: &g.name,
		Key:   &key,
	}
	res := &pb.GetResponse{}
	err := peer.Get(ctx, req, res)
	if err != nil {
		return ByteView{}, err
	}
	value := ByteView{b: res.Value}
	// TODO(bradfitz): use res.MinuteQps or something smart to
	// conditionally populate hotCache.  For now just do it some
	// percentage of the time.
	// If expired is true the value was previously in the hotCache, so must
	// overwrite.
	if expired || rand.Intn(10) == 0 {
		g.populateCache(key, value, &g.hotCache)
	}
	return value, nil
}

func (g *Group) lookupCache(key string) (value ByteView, ok bool) {
	if g.cacheBytes <= 0 {
		return
	}
	value, ok = g.mainCache.get(key)
	if ok {
		return
	}
	value, ok = g.hotCache.get(key)
	return
}

func (g *Group) populateCache(key string, value ByteView, cache *cache) {
	if g.cacheBytes <= 0 {
		return
	}
	cache.add(key, value)

	// Evict items from cache(s) if necessary.
	for {
		mainBytes := g.mainCache.bytes()
		hotBytes := g.hotCache.bytes()
		if mainBytes+hotBytes <= g.cacheBytes {
			return
		}

		// TODO(bradfitz): this is good-enough-for-now logic.
		// It should be something based on measurements and/or
		// respecting the costs of different resources.
		victim := &g.mainCache
		if hotBytes > mainBytes/8 {
			victim = &g.hotCache
		}
		victim.removeOldest()
	}
}

// CacheType represents a type of cache.
type CacheType int

const (
	// The MainCache is the cache for items that this peer is the
	// owner for.
	MainCache CacheType = iota + 1

	// The HotCache is the cache for items that seem popular
	// enough to replicate to this node, even though it's not the
	// owner.
	HotCache
)

// CacheStats returns stats about the provided cache within the group.
func (g *Group) CacheStats(which CacheType) CacheStats {
	switch which {
	case MainCache:
		return g.mainCache.stats()
	case HotCache:
		return g.hotCache.stats()
	default:
		return CacheStats{}
	}
}

// cache is a wrapper around an *lru.Cache that adds synchronization,
// makes values always be ByteView, and counts the size of all keys and
// values.
type cache struct {
	mu         sync.RWMutex
	nbytes     int64 // of all keys and values
	lru        *lru.Cache
	nhit, nget int64
	nevict     int64 // number of evictions
}

func (c *cache) stats() CacheStats {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return CacheStats{
		Bytes:     c.nbytes,
		Items:     c.itemsLocked(),
		Gets:      c.nget,
		Hits:      c.nhit,
		Evictions: c.nevict,
	}
}

func (c *cache) add(key string, value ByteView) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.lru == nil {
		c.lru = &lru.Cache{
			OnEvicted: func(key lru.Key, value interface{}) {
				val := value.(ByteView)
				c.nbytes -= int64(len(key.(string))) + int64(val.Len())
				c.nevict++
			},
		}
	}
	c.lru.Add(key, value)
	c.nbytes += int64(len(key)) + int64(value.Len())
}

func (c *cache) get(key string) (value ByteView, ok bool) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.nget++
	if c.lru == nil {
		return
	}
	vi, ok := c.lru.Get(key)
	if !ok {
		return
	}
	c.nhit++
	return vi.(ByteView), true
}

func (c *cache) removeOldest() {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.lru != nil {
		c.lru.RemoveOldest()
	}
}

func (c *cache) bytes() int64 {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.nbytes
}

func (c *cache) items() int64 {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.itemsLocked()
}

func (c *cache) itemsLocked() int64 {
	if c.lru == nil {
		return 0
	}
	return int64(c.lru.Len())
}

// An AtomicInt is an int64 to be accessed atomically.
type AtomicInt int64

// Add atomically adds n to i.
func (i *AtomicInt) Add(n int64) {
	atomic.AddInt64((*int64)(i), n)
}

// Get atomically gets the value of i.
func (i *AtomicInt) Get() int64 {
	return atomic.LoadInt64((*int64)(i))
}

func (i *AtomicInt) String() string {
	return strconv.FormatInt(i.Get(), 10)
}

// CacheStats are returned by stats accessors on Group.
type CacheStats struct {
	Bytes     int64
	Items     int64
	Gets      int64
	Hits      int64
	Evictions int64
}
<commit_msg>For expiration functionality: Allow disabling hotcache to prevent clients from getting inconsistent data freshness due to unsynchronized clocks in a multi-peer setup.<commit_after>/*
Copyright 2012 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package groupcache provides a data loading mechanism with caching
// and de-duplication that works across a set of peer processes.
//
// Each data Get first consults its local cache, otherwise delegates
// to the requested key's canonical owner, which then checks its cache
// or finally gets the data.  In the common case, many concurrent
// cache misses across a set of peers for the same key result in just
// one cache fill.
package groupcache

import (
	"errors"
	"math/rand"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	pb "github.com/golang/groupcache/groupcachepb"
	"github.com/golang/groupcache/lru"
	"github.com/golang/groupcache/singleflight"
)

// A Getter loads data for a key.
type Getter interface {
	// Get returns the value identified by key, populating dest.
	//
	// The returned data must be unversioned. That is, key must
	// uniquely describe the loaded data, without an implicit
	// current time, and without relying on cache expiration
	// mechanisms.
	Get(ctx Context, key string, dest Sink) error
}

// A GetterFunc implements Getter with a function.
type GetterFunc func(ctx Context, key string, dest Sink) error

func (f GetterFunc) Get(ctx Context, key string, dest Sink) error {
	return f(ctx, key, dest)
}

var (
	mu     sync.RWMutex
	groups = make(map[string]*Group)

	initPeerServerOnce sync.Once
	initPeerServer     func()
)

// GetGroup returns the named group previously created with NewGroup, or
// nil if there's no such group.
func GetGroup(name string) *Group {
	mu.RLock()
	g := groups[name]
	mu.RUnlock()
	return g
}

// NewGroup creates a coordinated group-aware Getter from a Getter.
//
// The returned Getter tries (but does not guarantee) to run only one
// Get call at once for a given key across an entire set of peer
// processes. Concurrent callers both in the local process and in
// other processes receive copies of the answer once the original Get
// completes.
//
// The group name must be unique for each getter.
func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
	return newGroup(name, cacheBytes, getter, nil)
}

// If peers is nil, the peerPicker is called via a sync.Once to initialize it.
func newGroup(name string, cacheBytes int64, getter Getter, peers PeerPicker) *Group {
	if getter == nil {
		panic("nil Getter")
	}
	mu.Lock()
	defer mu.Unlock()
	initPeerServerOnce.Do(callInitPeerServer)
	if _, dup := groups[name]; dup {
		panic("duplicate registration of group " + name)
	}
	g := &Group{
		name:       name,
		getter:     getter,
		peers:      peers,
		cacheBytes: cacheBytes,
	}
	if fn := newGroupHook; fn != nil {
		fn(g)
	}
	groups[name] = g
	return g
}

// newGroupHook, if non-nil, is called right after a new group is created.
var newGroupHook func(*Group)

// RegisterNewGroupHook registers a hook that is run each time
// a group is created.
func RegisterNewGroupHook(fn func(*Group)) {
	if newGroupHook != nil {
		panic("RegisterNewGroupHook called more than once")
	}
	newGroupHook = fn
}

// RegisterServerStart registers a hook that is run when the first
// group is created.
func RegisterServerStart(fn func()) {
	if initPeerServer != nil {
		panic("RegisterServerStart called more than once")
	}
	initPeerServer = fn
}

func callInitPeerServer() {
	if initPeerServer != nil {
		initPeerServer()
	}
}

// A Group is a cache namespace and associated data loaded spread over
// a group of 1 or more machines.
type Group struct {
	name       string
	getter     Getter
	peersOnce  sync.Once
	peers      PeerPicker
	cacheBytes int64 // limit for sum of mainCache and hotCache size

	// mainCache is a cache of the keys for which this process
	// (amongst its peers) is authorative. That is, this cache
	// contains keys which consistent hash on to this process's
	// peer number.
	mainCache cache

	// hotCache contains keys/values for which this peer is not
	// authorative (otherwise they would be in mainCache), but
	// are popular enough to warrant mirroring in this process to
	// avoid going over the network to fetch from a peer.  Having
	// a hotCache avoids network hotspotting, where a peer's
	// network card could become the bottleneck on a popular key.
	// This cache is used sparingly to maximize the total number
	// of key/value pairs that can stored globally.
	hotCache cache

	// loadGroup ensures that each key is only fetched once
	// (either locally or remotely), regardless of the number of
	// concurrent callers.
	loadGroup singleflight.Group

	// Stats are statistics on the group.
	Stats Stats

	// For expiration functionality.
	expiration      time.Duration
	stalePeriod     time.Duration
	staleDeadline   time.Duration
	disableHotCache bool
}

// Stats are per-group statistics.
type Stats struct {
	Gets           AtomicInt // any Get request, including from peers
	CacheHits      AtomicInt // either cache was good
	PeerLoads      AtomicInt // either remote load or remote cache hit (not an error)
	PeerErrors     AtomicInt
	Loads          AtomicInt // (gets - cacheHits)
	LoadsDeduped   AtomicInt // after singleflight
	LocalLoads     AtomicInt // total good local loads
	LocalLoadErrs  AtomicInt // total bad local loads
	ServerRequests AtomicInt // gets that came over the network from peers
}

// Name returns the name of the group.
func (g *Group) Name() string {
	return g.name
}

// DisableHotCache disables writes to the cache used for non-owned cached items.
// May be used with expiration functionality to prevent clients from getting
// inconsistent data freshness due to unsynchronized clocks in a multi-peer
// setup.  This cache is enabled by default.
func (g *Group) DisableHotCache(disable bool) {
	g.disableHotCache = disable
}

func (g *Group) initPeers() {
	if g.peers == nil {
		g.peers = getPeers()
	}
}

func (g *Group) Get(ctx Context, key string, dest Sink) error {
	g.peersOnce.Do(g.initPeers)
	g.Stats.Gets.Add(1)
	if dest == nil {
		return errors.New("groupcache: nil dest Sink")
	}
	value, cacheHit := g.lookupCache(key)

	if cacheHit {
		g.Stats.CacheHits.Add(1)

		if g.expiration > 0 {
			return g.handleExpiration(ctx, key, dest, value)
		}

		return setSinkView(dest, value)
	}
	return g.loadOnMiss(ctx, key, dest, false)
}

func (g *Group) loadOnMiss(ctx Context, key string, dest Sink, expired bool) error {
	// Optimization to avoid double unmarshalling or copying: keep
	// track of whether the dest was already populated. One caller
	// (if local) will set this; the losers will not. The common
	// case will likely be one caller.
	destPopulated := false
	value, destPopulated, err := g.load(ctx, key, dest, expired)
	if err != nil {
		return err
	}
	if destPopulated {
		return nil
	}

	return setSinkView(dest, value)
}

// load loads key either by invoking the getter locally or by sending it to another machine.
func (g *Group) load(ctx Context, key string, dest Sink, expired bool) (value ByteView, destPopulated bool, err error) {
	g.Stats.Loads.Add(1)
	viewi, err := g.loadGroup.Do(key, func() (interface{}, error) {
		g.Stats.LoadsDeduped.Add(1)
		var value ByteView
		var err error
		if peer, ok := g.peers.PickPeer(key); ok {
			value, err = g.getFromPeer(ctx, peer, key, expired)
			if err == nil {
				g.Stats.PeerLoads.Add(1)
				return value, nil
			}
			g.Stats.PeerErrors.Add(1)
			// TODO(bradfitz): log the peer's error? keep
			// log of the past few for /groupcachez?  It's
			// probably boring (normal task movement), so not
			// worth logging I imagine.
		}
		value, err = g.getLocally(ctx, key, dest)
		if err != nil {
			g.Stats.LocalLoadErrs.Add(1)
			return nil, err
		}
		g.Stats.LocalLoads.Add(1)
		destPopulated = true // only one caller of load gets this return value
		g.populateCache(key, value, &g.mainCache)
		return value, nil
	})
	if err == nil {
		value = viewi.(ByteView)
	}
	return
}

func (g *Group) getLocally(ctx Context, key string, dest Sink) (ByteView, error) {
	err := g.getter.Get(ctx, key, dest)
	if err != nil {
		return ByteView{}, err
	}
	return dest.view()
}

func (g *Group) getFromPeer(ctx Context, peer ProtoGetter, key string, expired bool) (ByteView, error) {
	req := &pb.GetRequest{
		Group: &g.name,
		Key:   &key,
	}
	res := &pb.GetResponse{}
	err := peer.Get(ctx, req, res)
	if err != nil {
		return ByteView{}, err
	}
	value := ByteView{b: res.Value}
	// TODO(bradfitz): use res.MinuteQps or something smart to
	// conditionally populate hotCache.  For now just do it some
	// percentage of the time.
	// If expired is true the value was previously in the hotCache, so must
	// overwrite.
	if !g.disableHotCache && (expired || rand.Intn(10) == 0) {
		g.populateCache(key, value, &g.hotCache)
	}
	return value, nil
}

func (g *Group) lookupCache(key string) (value ByteView, ok bool) {
	if g.cacheBytes <= 0 {
		return
	}
	value, ok = g.mainCache.get(key)
	if ok {
		return
	}
	value, ok = g.hotCache.get(key)
	return
}

func (g *Group) populateCache(key string, value ByteView, cache *cache) {
	if g.cacheBytes <= 0 {
		return
	}
	cache.add(key, value)

	// Evict items from cache(s) if necessary.
	for {
		mainBytes := g.mainCache.bytes()
		hotBytes := g.hotCache.bytes()
		if mainBytes+hotBytes <= g.cacheBytes {
			return
		}

		// TODO(bradfitz): this is good-enough-for-now logic.
		// It should be something based on measurements and/or
		// respecting the costs of different resources.
		victim := &g.mainCache
		if hotBytes > mainBytes/8 {
			victim = &g.hotCache
		}
		victim.removeOldest()
	}
}

// CacheType represents a type of cache.
type CacheType int

const (
	// The MainCache is the cache for items that this peer is the
	// owner for.
	MainCache CacheType = iota + 1

	// The HotCache is the cache for items that seem popular
	// enough to replicate to this node, even though it's not the
	// owner.
	HotCache
)

// CacheStats returns stats about the provided cache within the group.
func (g *Group) CacheStats(which CacheType) CacheStats {
	switch which {
	case MainCache:
		return g.mainCache.stats()
	case HotCache:
		return g.hotCache.stats()
	default:
		return CacheStats{}
	}
}

// cache is a wrapper around an *lru.Cache that adds synchronization,
// makes values always be ByteView, and counts the size of all keys and
// values.
type cache struct {
	mu         sync.RWMutex
	nbytes     int64 // of all keys and values
	lru        *lru.Cache
	nhit, nget int64
	nevict     int64 // number of evictions
}

func (c *cache) stats() CacheStats {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return CacheStats{
		Bytes:     c.nbytes,
		Items:     c.itemsLocked(),
		Gets:      c.nget,
		Hits:      c.nhit,
		Evictions: c.nevict,
	}
}

func (c *cache) add(key string, value ByteView) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.lru == nil {
		c.lru = &lru.Cache{
			OnEvicted: func(key lru.Key, value interface{}) {
				val := value.(ByteView)
				c.nbytes -= int64(len(key.(string))) + int64(val.Len())
				c.nevict++
			},
		}
	}
	c.lru.Add(key, value)
	c.nbytes += int64(len(key)) + int64(value.Len())
}

func (c *cache) get(key string) (value ByteView, ok bool) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.nget++
	if c.lru == nil {
		return
	}
	vi, ok := c.lru.Get(key)
	if !ok {
		return
	}
	c.nhit++
	return vi.(ByteView), true
}

func (c *cache) removeOldest() {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.lru != nil {
		c.lru.RemoveOldest()
	}
}

func (c *cache) bytes() int64 {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.nbytes
}

func (c *cache) items() int64 {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.itemsLocked()
}

func (c *cache) itemsLocked() int64 {
	if c.lru == nil {
		return 0
	}
	return int64(c.lru.Len())
}

// An AtomicInt is an int64 to be accessed atomically.
type AtomicInt int64

// Add atomically adds n to i.
func (i *AtomicInt) Add(n int64) {
	atomic.AddInt64((*int64)(i), n)
}

// Get atomically gets the value of i.
func (i *AtomicInt) Get() int64 {
	return atomic.LoadInt64((*int64)(i))
}

func (i *AtomicInt) String() string {
	return strconv.FormatInt(i.Get(), 10)
}

// CacheStats are returned by stats accessors on Group.
type CacheStats struct {
	Bytes     int64
	Items     int64
	Gets      int64
	Hits      int64
	Evictions int64
}
<|endoftext|>


<commit_before>package hal

import (
	"fmt"
	"log"
	"sync"
)

// RouterCTX holds the router's context, including input/output chans.
type RouterCTX struct {
	brokers map[string]Broker
	in      chan *Evt     // messages from brokers --> plugins
	out     chan *Evt     // messages from plugins --> brokers
	update  chan struct{} // to notify the router that the instance list changed
	mut     sync.Mutex
	init    sync.Once
}

var routerSingleton RouterCTX

// Router returns the singleton router context. The router is initialized
// on the first call to this function.
func Router() *RouterCTX {
	routerSingleton.init.Do(func() {
		routerSingleton.in = make(chan *Evt, 1000)
		routerSingleton.out = make(chan *Evt, 1000)
		routerSingleton.update = make(chan struct{}, 1)
		routerSingleton.brokers = make(map[string]Broker)
	})

	return &routerSingleton
}

// forward from one (go) channel to another
// TODO: figure out if this needs to check for closed channels, etc.
func forward(from, to chan *Evt) {
	for {
		select {
		case evt := <-from:
			to <- evt
		}
	}
}

// AddBroker adds a broker to the router and starts forwarding
// events between it and the router.
func (r *RouterCTX) AddBroker(b Broker) {
	r.mut.Lock()
	defer r.mut.Unlock()

	if _, exists := r.brokers[b.Name()]; exists {
		panic(fmt.Sprintf("BUG: broker '%s' added > 1 times.", b.Name()))
	}

	b2r := make(chan *Evt, 1000) // messages from the broker to the router

	// start the broker's event stream
	go b.Stream(b2r)

	// forward events from the broker to the router's input channel
	go forward(b2r, r.in)

	r.brokers[b.Name()] = b
}

func (r *RouterCTX) GetBroker(name string) Broker {
	if broker, exists := r.brokers[name]; exists {
		return broker
	}

	return nil
}

// Route is the main method for the router. It blocks and should be run in a goroutine
// exactly once.
func (r *RouterCTX) Route() {
	for {
		select {
		case evt := <-r.in:
			if evt.Broker == nil {
				panic("BUG: received event with nil Broker. This breaks all the things!")
			}

			go r.processEvent(evt)
		}
	}
}

// processEvent processes one event and is intended to run in a goroutine.
func (r *RouterCTX) processEvent(evt *Evt) {
	var pname string // must be in the recovery handler's scope

	// get a snapshot of the instance list
	// TODO: keep an eye on the cost of copying this list for every message
	pr := PluginRegistry()
	instances := pr.InstanceList()

	// if a plugin panics, catch it & log it
	// TODO: report errors to a channel?
	defer func() {
		if r := recover(); r != nil {
			log.Printf("recovered panic in plugin %q\n", pname)
			log.Printf("panic: %q", r)
		}
	}()

	for _, inst := range instances {
		ibname := inst.Broker.Name()
		pname = inst.Plugin.Name // recovery handler ^ will pick this up in a panic

		// a plugin instance matches on broker, channel, and regex
		// first, check if the instance is attached to a specific broker or generic
		if ibname != evt.Broker.Name() && ibname != gBroker.Name() {
			continue
		}

		// if this is a generic broker instance and the event is marked as not
		// generic, skip it
		if ibname == gBroker.Name() && !evt.IsGeneric {
			continue
		}

		// check if it's the correct channel
		if evt.Channel != inst.Channel {
			continue
		}

		// finally, check message text against the regex
		if inst.Regex != "" && inst.regex.MatchString(evt.Body) {
			// this will copy the struct twice. It's intentional to avoid
			// mutating the evt between calls. The plugin func signature
			// forces the second copy.
			evtcpy := *evt

			// pass the plugin instance pointer to the plugin function so
			// it can access its fields for settings, etc.
			evtcpy.instance = inst

			// call the plugin function
			// this may block other plugins from processing the same event but
			// since it's already in a goroutine, other events won't be blocked
			inst.Func(evtcpy)
		}
	}
}
<commit_msg>fix match-all plugins<commit_after>package hal

import (
	"fmt"
	"log"
	"sync"
)

// RouterCTX holds the router's context, including input/output chans.
type RouterCTX struct {
	brokers map[string]Broker
	in      chan *Evt     // messages from brokers --> plugins
	out     chan *Evt     // messages from plugins --> brokers
	update  chan struct{} // to notify the router that the instance list changed
	mut     sync.Mutex
	init    sync.Once
}

var routerSingleton RouterCTX

// Router returns the singleton router context. The router is initialized
// on the first call to this function.
func Router() *RouterCTX {
	routerSingleton.init.Do(func() {
		routerSingleton.in = make(chan *Evt, 1000)
		routerSingleton.out = make(chan *Evt, 1000)
		routerSingleton.update = make(chan struct{}, 1)
		routerSingleton.brokers = make(map[string]Broker)
	})

	return &routerSingleton
}

// forward from one (go) channel to another
// TODO: figure out if this needs to check for closed channels, etc.
func forward(from, to chan *Evt) {
	for {
		select {
		case evt := <-from:
			to <- evt
		}
	}
}

// AddBroker adds a broker to the router and starts forwarding
// events between it and the router.
func (r *RouterCTX) AddBroker(b Broker) {
	r.mut.Lock()
	defer r.mut.Unlock()

	if _, exists := r.brokers[b.Name()]; exists {
		panic(fmt.Sprintf("BUG: broker '%s' added > 1 times.", b.Name()))
	}

	b2r := make(chan *Evt, 1000) // messages from the broker to the router

	// start the broker's event stream
	go b.Stream(b2r)

	// forward events from the broker to the router's input channel
	go forward(b2r, r.in)

	r.brokers[b.Name()] = b
}

func (r *RouterCTX) GetBroker(name string) Broker {
	if broker, exists := r.brokers[name]; exists {
		return broker
	}

	return nil
}

// Route is the main method for the router. It blocks and should be run in a goroutine
// exactly once.
func (r *RouterCTX) Route() {
	for {
		select {
		case evt := <-r.in:
			if evt.Broker == nil {
				panic("BUG: received event with nil Broker. This breaks all the things!")
			}

			go r.processEvent(evt)
		}
	}
}

// processEvent processes one event and is intended to run in a goroutine.
func (r *RouterCTX) processEvent(evt *Evt) {
	var pname string // must be in the recovery handler's scope

	// get a snapshot of the instance list
	// TODO: keep an eye on the cost of copying this list for every message
	pr := PluginRegistry()
	instances := pr.InstanceList()

	// if a plugin panics, catch it & log it
	// TODO: report errors to a channel?
	defer func() {
		if r := recover(); r != nil {
			log.Printf("recovered panic in plugin %q\n", pname)
			log.Printf("panic: %q", r)
		}
	}()

	for _, inst := range instances {
		ibname := inst.Broker.Name()
		pname = inst.Plugin.Name // recovery handler ^ will pick this up in a panic

		// a plugin instance matches on broker, channel, and regex
		// first, check if the instance is attached to a specific broker or generic
		if ibname != evt.Broker.Name() && ibname != gBroker.Name() {
			continue
		}

		// if this is a generic broker instance and the event is marked as not
		// generic, skip it
		if ibname == gBroker.Name() && !evt.IsGeneric {
			continue
		}

		// check if it's the correct channel
		if evt.Channel != inst.Channel {
			continue
		}

		// finally, check message text against the regex
		if inst.Regex == "" || inst.regex.MatchString(evt.Body) {
			// this will copy the struct twice. It's intentional to avoid
			// mutating the evt between calls. The plugin func signature
			// forces the second copy.
			evtcpy := *evt

			// pass the plugin instance pointer to the plugin function so
			// it can access its fields for settings, etc.
			evtcpy.instance = inst

			// call the plugin function
			// this may block other plugins from processing the same event but
			// since it's already in a goroutine, other events won't be blocked
			inst.Func(evtcpy)
		}
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"errors"
	"fmt"
	"net/url"

	"github.com/astaxie/beego"
	manifestV2 "github.com/docker/distribution/manifest/schema2"
	"github.com/snagles/docker-registry-manager/app/models/manager"
	"github.com/snagles/docker-registry-manager/utils"
)

type ImagesController struct {
	beego.Controller
}

// GetImages returns the template for the images page
func (c *ImagesController) GetImages() {

	registryName := c.Ctx.Input.Param(":registryName")
	repositoryName, _ := url.QueryUnescape(c.Ctx.Input.Param(":splat"))
	repositoryNameEncode := url.QueryEscape(repositoryName)
	c.Data["tagName"] = c.Ctx.Input.Param(":tagName")

	registry, _ := manager.AllRegistries.Registries[registryName]
	c.Data["registry"] = registry

	tag, _ := registry.Repositories[repositoryName].Tags[c.Ctx.Input.Param(":tagName")]
	c.Data["tag"] = tag

	labels := make(map[string]utils.KeywordInfo)
	for _, h := range tag.History {
		// run each command through the keyword lookup
		for _, cmd := range h.Commands {
			for _, keyword := range cmd.Keywords {
				labels[keyword] = utils.KeywordMapping[keyword]
			}
		}
	}
	c.Data["labels"] = labels

	// build the js chart dataset
	type segmentInfo struct {
		Stage    int      `json:"stage"`
		Cmd      string   `json:"cmd"`
		Keywords []string `json:"keywords"`
		Size     string
	}

	type dataset struct {
		Label            string   `json:"label"`
		Data             []int64  `json:"data"`
		BackgroundColor  []string `json:"backgroundColor"`
		BorderColor      []string `json:"borderColor"`
		BorderWidth      int64    `json:"borderWidth"`
		CutoutPercentage int64    `json:"cutoutPercentage"`

		// Custom data fields
		Info []segmentInfo `json:"info"`
	}

	var chart []dataset
	colors := []string{"#43A19E", "#7B43A1", "#F2317A", "#FF9824", "#58CF6C"}
	for i, history := range tag.History {
		ds := dataset{}
		for _, cmd := range history.Commands {
			ds.Data = append(ds.Data, 10)
			color := colors[0]
			colors = append(colors[:0], colors[1:]...)
			ds.BackgroundColor = append(ds.BackgroundColor, color)
			// add stage tooltip info
			ds.Info = append(ds.Info, segmentInfo{Stage: i + 1, Keywords: cmd.Keywords, Cmd: cmd.Cmd})
			colors = append(colors, color)
			if len(history.Commands) != 1 {
				ds.BorderColor = []string{"#FFF"}
				ds.BorderWidth = 1
			}
		}
		chart = append(chart, ds)
	}

	for i := len(chart)/2 - 1; i >= 0; i-- {
		opp := len(chart) - 1 - i
		chart[i], chart[opp] = chart[opp], chart[i]
	}

	c.Data["chart"] = chart
	c.Data["registryName"] = registryName
	c.Data["repositoryNameEncode"] = repositoryNameEncode
	c.Data["repositoryName"] = repositoryName

	// Compare the two manifest layers
	hubManifest, err := manager.HubGetManifest(repositoryName, tag.Name)
	if hubManifest.SchemaVersion == tag.SchemaVersion {
		diffLayers := make(map[string]struct{})
		var size int64
		if err == nil {
			for _, layer := range tag.DeserializedManifest.Layers {
				diffLayers[layer.Digest.String()] = struct{}{}
			}
			for _, layer := range hubManifest.Layers {
				size += layer.Size
				if _, ok := diffLayers[layer.Digest.String()]; ok {
					delete(diffLayers, layer.Digest.String())
				}
			}
		}

		c.Data["dockerHub"] = struct {
			DiffLayers map[string]struct{}
			Manifest   *manifestV2.DeserializedManifest
			ImageURL   string
			Error      error
			Size       int64
		}{
			diffLayers,
			hubManifest,
			fmt.Sprintf("https://hub.docker.com/r/library/%s/tags/%s/", repositoryName, tag.Name),
			err,
			size,
		}
	} else {
		c.Data["dockerHub"] = struct {
			Error    error
			ImageURL string
		}{
			errors.New("Different manifest scheme versions"),
			fmt.Sprintf("https://hub.docker.com/r/library/%s/tags/%s/", repositoryName, tag.Name),
		}
	}

	// Index template
	c.TplName = "images.tpl"
}
<commit_msg>Added check for if no manifest returned from dockerhub<commit_after>package controllers

import (
	"errors"
	"fmt"
	"net/url"

	"github.com/astaxie/beego"
	manifestV2 "github.com/docker/distribution/manifest/schema2"
	"github.com/snagles/docker-registry-manager/app/models/manager"
	"github.com/snagles/docker-registry-manager/utils"
)

type ImagesController struct {
	beego.Controller
}

// GetImages returns the template for the images page
func (c *ImagesController) GetImages() {

	registryName := c.Ctx.Input.Param(":registryName")
	repositoryName, _ := url.QueryUnescape(c.Ctx.Input.Param(":splat"))
	repositoryNameEncode := url.QueryEscape(repositoryName)
	c.Data["tagName"] = c.Ctx.Input.Param(":tagName")

	registry, _ := manager.AllRegistries.Registries[registryName]
	c.Data["registry"] = registry

	tag, _ := registry.Repositories[repositoryName].Tags[c.Ctx.Input.Param(":tagName")]
	c.Data["tag"] = tag

	labels := make(map[string]utils.KeywordInfo)
	for _, h := range tag.History {
		// run each command through the keyword lookup
		for _, cmd := range h.Commands {
			for _, keyword := range cmd.Keywords {
				labels[keyword] = utils.KeywordMapping[keyword]
			}
		}
	}
	c.Data["labels"] = labels

	// build the js chart dataset
	type segmentInfo struct {
		Stage    int      `json:"stage"`
		Cmd      string   `json:"cmd"`
		Keywords []string `json:"keywords"`
		Size     string
	}

	type dataset struct {
		Label            string   `json:"label"`
		Data             []int64  `json:"data"`
		BackgroundColor  []string `json:"backgroundColor"`
		BorderColor      []string `json:"borderColor"`
		BorderWidth      int64    `json:"borderWidth"`
		CutoutPercentage int64    `json:"cutoutPercentage"`

		// Custom data fields
		Info []segmentInfo `json:"info"`
	}

	var chart []dataset
	colors := []string{"#43A19E", "#7B43A1", "#F2317A", "#FF9824", "#58CF6C"}
	for i, history := range tag.History {
		ds := dataset{}
		for _, cmd := range history.Commands {
			ds.Data = append(ds.Data, 10)
			color := colors[0]
			colors = append(colors[:0], colors[1:]...)
			ds.BackgroundColor = append(ds.BackgroundColor, color)
			// add stage tooltip info
			ds.Info = append(ds.Info, segmentInfo{Stage: i + 1, Keywords: cmd.Keywords, Cmd: cmd.Cmd})
			colors = append(colors, color)
			if len(history.Commands) != 1 {
				ds.BorderColor = []string{"#FFF"}
				ds.BorderWidth = 1
			}
		}
		chart = append(chart, ds)
	}

	for i := len(chart)/2 - 1; i >= 0; i-- {
		opp := len(chart) - 1 - i
		chart[i], chart[opp] = chart[opp], chart[i]
	}

	c.Data["chart"] = chart
	c.Data["registryName"] = registryName
	c.Data["repositoryNameEncode"] = repositoryNameEncode
	c.Data["repositoryName"] = repositoryName

	// Compare the two manifest layers
	hubManifest, err := manager.HubGetManifest(repositoryName, tag.Name)
	if hubManifest == nil || err != nil {
		c.Data["dockerHub"] = struct {
			Error error
		}{
			errors.New("Unable to retrieve information from dockerhub: " + err.Error()),
		}
	}
	if hubManifest.SchemaVersion == tag.SchemaVersion {
		diffLayers := make(map[string]struct{})
		var size int64
		if err == nil {
			for _, layer := range tag.DeserializedManifest.Layers {
				diffLayers[layer.Digest.String()] = struct{}{}
			}
			for _, layer := range hubManifest.Layers {
				size += layer.Size
				if _, ok := diffLayers[layer.Digest.String()]; ok {
					delete(diffLayers, layer.Digest.String())
				}
			}
		}

		c.Data["dockerHub"] = struct {
			DiffLayers map[string]struct{}
			Manifest   *manifestV2.DeserializedManifest
			ImageURL   string
			Error      error
			Size       int64
		}{
			diffLayers,
			hubManifest,
			fmt.Sprintf("https://hub.docker.com/r/library/%s/tags/%s/", repositoryName, tag.Name),
			err,
			size,
		}
	} else {
		c.Data["dockerHub"] = struct {
			Error    error
			ImageURL string
		}{
			errors.New("Different manifest scheme versions"),
			fmt.Sprintf("https://hub.docker.com/r/library/%s/tags/%s/", repositoryName, tag.Name),
		}
	}

	// Index template
	c.TplName = "images.tpl"
}
<|endoftext|>


<commit_before>package controllers

import (
	"github.com/julienschmidt/httprouter"
	"github.com/raggaer/castro/app/util"
	"net/http"
)

func ExtensionStatic(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	// Get extension identifier
	id := ps.ByName("id")

	// Check if static file exists
	dir, exists := util.ExtensionStatic.FileExists(id)

	if !exists {
		w.WriteHeader(404)
		return
	}

	// Open desired file
	f, err := dir.Open(ps.ByName("filepath"))

	if err != nil {
		w.WriteHeader(404)
		return
	}

	// Close file handle
	defer f.Close()

	// Get file information
	fi, err := f.Stat()

	if err != nil {
		w.WriteHeader(404)
		return
	}

	// Check if file is directory
	if fi.IsDir() {
		w.WriteHeader(404)
		return
	}

	// Serve file
	http.ServeContent(w, req, fi.Name(), fi.ModTime(), f)
}
<commit_msg>Add manual content type for css and js files<commit_after>package controllers

import (
	"github.com/julienschmidt/httprouter"
	"github.com/raggaer/castro/app/util"
	"net/http"
	"strings"
)

func ExtensionStatic(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	// Get extension identifier
	id := ps.ByName("id")

	// Check if static file exists
	dir, exists := util.ExtensionStatic.FileExists(id)

	if !exists {
		w.WriteHeader(404)
		return
	}

	// Open desired file
	f, err := dir.Open(ps.ByName("filepath"))

	if err != nil {
		w.WriteHeader(404)
		return
	}

	// Close file handle
	defer f.Close()

	// Get file information
	fi, err := f.Stat()

	if err != nil {
		w.WriteHeader(404)
		return
	}

	// Check if file is directory
	if fi.IsDir() {
		w.WriteHeader(404)
		return
	}

	// Set content type to prevent possible problems with http.ServeContent
	if strings.HasPrefix(fi.Name(), ".css") {
		w.Header().Set("Content-Type", "text/css")
	}

	if strings.HasPrefix(fi.Name(), ".js") {
		w.Header().Set("Content-Type", "text/javascript")
	}

	// Serve file
	http.ServeContent(w, req, fi.Name(), fi.ModTime(), f)
}
<|endoftext|>


<commit_before>package hcl

import (
	"fmt"
	"strings"
)

// ValueType is an enum represnting the type of a value in
// a LiteralNode.
type ValueType byte

const (
	ValueTypeUnknown ValueType = iota
	ValueTypeFloat
	ValueTypeInt
	ValueTypeString
	ValueTypeBool
	ValueTypeNil
	ValueTypeList
	ValueTypeObject
)

// Object represents any element of HCL: an object itself, a list,
// a literal, etc.
type Object struct {
	Key   string
	Type  ValueType
	Value interface{}
	Next  *Object
}

// GoStrig is an implementation of the GoStringer interface.
func (o *Object) GoString() string {
	return fmt.Sprintf("*%#v", *o)
}

// Get gets all the objects that match the given key.
//
// It returns the resulting objects as a single Object structure with
// the linked list populated.
func (o *Object) Get(k string, insensitive bool) *Object {
	if o.Type != ValueTypeObject {
		return nil
	}

	for _, o := range o.Elem(true) {
		if o.Key != k {
			if !insensitive || !strings.EqualFold(o.Key, k) {
				continue
			}
		}

		return o
	}

	return nil
}

// Elem returns all the elements that are part of this object.
func (o *Object) Elem(expand bool) []*Object {
	if !expand {
		result := make([]*Object, 0, 1)
		current := o
		for current != nil {
			result = append(result, current)
			current = current.Next
		}

		return result
	}

	switch o.Type {
	case ValueTypeObject:
		return o.Value.([]*Object)
	}

	panic(fmt.Sprintf("Elem not supported for: %s", o.Type))
}

// Len returns the number of objects in this object structure.
func (o *Object) Len() (i int) {
	current := o
	for current != nil {
		i += 1
		current = current.Next
	}

	return
}

// ObjectList is a list of objects.
type ObjectList []*Object

// Flat returns a flattened list structure of the objects.
func (l ObjectList) Flat() []*Object {
	m := make(map[string]*Object)
	result := make([]*Object, 0, len(l))
	for _, obj := range l {
		prev, ok := m[obj.Key]
		if !ok {
			m[obj.Key] = obj
			result = append(result, obj)
			continue
		}

		for prev.Next != nil {
			prev = prev.Next
		}
		prev.Next = obj
	}

	return result
}
<commit_msg>hcl: Elem on nil should return nil<commit_after>package hcl

import (
	"fmt"
	"strings"
)

// ValueType is an enum represnting the type of a value in
// a LiteralNode.
type ValueType byte

const (
	ValueTypeUnknown ValueType = iota
	ValueTypeFloat
	ValueTypeInt
	ValueTypeString
	ValueTypeBool
	ValueTypeNil
	ValueTypeList
	ValueTypeObject
)

// Object represents any element of HCL: an object itself, a list,
// a literal, etc.
type Object struct {
	Key   string
	Type  ValueType
	Value interface{}
	Next  *Object
}

// GoStrig is an implementation of the GoStringer interface.
func (o *Object) GoString() string {
	return fmt.Sprintf("*%#v", *o)
}

// Get gets all the objects that match the given key.
//
// It returns the resulting objects as a single Object structure with
// the linked list populated.
func (o *Object) Get(k string, insensitive bool) *Object {
	if o.Type != ValueTypeObject {
		return nil
	}

	for _, o := range o.Elem(true) {
		if o.Key != k {
			if !insensitive || !strings.EqualFold(o.Key, k) {
				continue
			}
		}

		return o
	}

	return nil
}

// Elem returns all the elements that are part of this object.
func (o *Object) Elem(expand bool) []*Object {
	if !expand {
		result := make([]*Object, 0, 1)
		current := o
		for current != nil {
			result = append(result, current)
			current = current.Next
		}

		return result
	}

	switch o.Type {
	case ValueTypeObject:
		if o.Value == nil {
			return nil
		}

		return o.Value.([]*Object)
	}

	panic(fmt.Sprintf("Elem not supported for: %s", o.Type))
}

// Len returns the number of objects in this object structure.
func (o *Object) Len() (i int) {
	current := o
	for current != nil {
		i += 1
		current = current.Next
	}

	return
}

// ObjectList is a list of objects.
type ObjectList []*Object

// Flat returns a flattened list structure of the objects.
func (l ObjectList) Flat() []*Object {
	m := make(map[string]*Object)
	result := make([]*Object, 0, len(l))
	for _, obj := range l {
		prev, ok := m[obj.Key]
		if !ok {
			m[obj.Key] = obj
			result = append(result, obj)
			continue
		}

		for prev.Next != nil {
			prev = prev.Next
		}
		prev.Next = obj
	}

	return result
}
<|endoftext|>