<commit_before>package filecache

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"time"
)

const VERSION = "1.0.2"

// File size constants for use with FileCache.MaxSize.
// For example, cache.MaxSize = 64 * Megabyte
const (
	Kilobyte = 1024
	Megabyte = 1024 * 1024
	Gigabyte = 1024 * 1024 * 1024
)

var (
	DefaultExpireItem int   = 300 // 5 minutes
	DefaultMaxSize    int64 = 16 * Megabyte
	DefaultMaxItems   int   = 32
	DefaultEvery      int   = 60 // 1 minute
)

var (
	InvalidCacheItem = errors.New("invalid cache item")
	ItemIsDirectory  = errors.New("can't cache a directory")
	ItemNotInCache   = errors.New("item not in cache")
	ItemTooLarge     = errors.New("item too large for cache")
	WriteIncomplete  = errors.New("incomplete write of cache item")
)

var SquelchItemNotInCache = true

// Mumber of items to buffer adding to the file cache.
var NewCachePipeSize = 4

/// CacheItem represents an item in the cache
type cacheItem struct {
	content    []byte
	Size       int64
	Lastaccess time.Time
	Modified   time.Time
}

func (itm *cacheItem) GetReader() io.Reader {
	b := bytes.NewReader(itm.Access())
	return b
}

func (itm *cacheItem) Access() []byte {
	itm.Lastaccess = time.Now()
	return itm.content
}

func cacheFile(path string, maxSize int64) (itm *cacheItem, err error) {
	fi, err := os.Stat(path)
	if err != nil {
		return
	} else if fi.Mode().IsDir() {
		return nil, ItemIsDirectory
	} else if fi.Size() > maxSize {
		return nil, ItemTooLarge
	}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return
	}

	itm = new(cacheItem)
	itm.content = content
	itm.Size = fi.Size()
	itm.Modified = fi.ModTime()
	itm.Lastaccess = time.Now()
	return
}

// FileCache represents a cache in memory.
// An ExpireItem value of 0 means that items should not be expired based
// on time in memory.
type FileCache struct {
	dur        time.Duration
	items      map[string]*cacheItem
	in_pipe    chan string
	MaxItems   int   // Maximum number of files to cache
	MaxSize    int64 // Maximum file size to store
	ExpireItem int   // Seconds a file should be cached for
	Every      int   // Run an expiration check Every seconds
}

// NewDefaultCache returns a new FileCache with sane defaults.
func NewDefaultCache() *FileCache {
	cache := FileCache{time.Since(time.Now()),
		nil, nil,
		DefaultMaxItems,
		DefaultMaxSize,
		DefaultExpireItem,
		DefaultEvery}
	return &cache
}

// add_item is an internal function for adding an item to the cache.
func (cache *FileCache) add_item(name string) (err error) {
	if cache.items == nil {
		return
	}
	ok := cache.InCache(name)
	expired := cache.item_expired(name)
	if ok && !expired {
		return nil
	} else if ok {
		delete(cache.items, name)
	}

	itm, err := cacheFile(name, cache.MaxSize)
	if cache.items != nil && itm != nil {
		cache.items[name] = itm
	} else {
		return
	}
	if !cache.InCache(name) {
		return ItemNotInCache
	}
	return nil
}

// item_listener is a goroutine that listens for incoming files and caches
// them.
func (cache *FileCache) item_listener() {
	for {
		name, ok := <-cache.in_pipe
		if !ok {
			return
		}
		cache.add_item(name)
	}
}

// expire_oldest is used to expire the oldest item in the cache.
// The force argument is used to indicate it should remove at least one
// entry; for example, if a large number of files are cached at once, none
// may appear older than another.
func (cache *FileCache) expire_oldest(force bool) {
	oldest := time.Now()
	oldest_name := ""

	for name, itm := range cache.items {
		if force && oldest_name == "" {
			oldest = itm.Lastaccess
			oldest_name = name
		} else if itm.Lastaccess.Before(oldest) {
			oldest = itm.Lastaccess
			oldest_name = name
		}
	}
	if oldest_name != "" {
		delete(cache.items, oldest_name)
	}
}

// vaccuum is a background goroutine responsible for cleaning the cache.
// It runs periodically, every cache.Every seconds. If cache.Every is set
// to 0, it will not run.
func (cache *FileCache) vaccuum() {
	if cache.Every < 1 {
		return
	}

	for {
		<-time.After(time.Duration(cache.dur))
		if cache.items == nil {
			return
		}
		for name, _ := range cache.items {
			if cache.item_expired(name) {
				delete(cache.items, name)
			}
		}
		for size := cache.Size(); size > cache.MaxItems; size = cache.Size() {
			cache.expire_oldest(true)
		}
	}
}

// FileChanged returns true if file should be expired based on mtime.
// If the file has changed on disk or no longer exists, it should be
// expired.
func (cache *FileCache) changed(name string) bool {
	itm, ok := cache.items[name]
	if !ok || itm == nil {
		return true
	}
	fi, err := os.Stat(name)
	if err != nil {
		return true
	} else if !itm.Modified.Equal(fi.ModTime()) {
		return true
	}
	return false
}

// Expired returns true if the item has not been accessed recently.
func (cache *FileCache) expired(name string) bool {
	itm, ok := cache.items[name]
	if !ok {
		return true
	}
	dur := time.Now().Sub(itm.Lastaccess)
	sec, err := strconv.Atoi(fmt.Sprintf("%0.0f", dur.Seconds()))
	if err != nil {
		return true
	} else if sec >= cache.ExpireItem {
		return true
	}
	return false
}

// item_expired returns true if an item is expired.
func (cache *FileCache) item_expired(name string) bool {
	if cache.changed(name) {
		return true
	} else if cache.ExpireItem != 0 && cache.expired(name) {
		return true
	}
	return false
}

// Active returns true if the cache has been started, and false otherwise.
func (cache *FileCache) Active() bool {
	if cache.in_pipe == nil || cache.items == nil {
		return false
	}
	return true
}

// Size returns the number of entries in the cache.
func (cache *FileCache) Size() int {
	return len(cache.items)
}

// FileSize returns the sum of the file sizes stored in the cache
func (cache *FileCache) FileSize() (totalSize int64) {
	for _, itm := range cache.items {
		totalSize += itm.Size
	}
	return
}

// StoredFiles returns the list of files stored in the cache.
func (cache *FileCache) StoredFiles() (fileList []string) {
	fileList = make([]string, 0)
	for name, _ := range cache.items {
		fileList = append(fileList, name)
	}
	return
}

// InCache returns true if the item is in the cache.
func (cache *FileCache) InCache(name string) bool {
	if cache.changed(name) {
		delete(cache.items, name)
		return false
	}
	_, ok := cache.items[name]
	return ok
}

// WriteItem writes the cache item to the specified io.Writer.
func (cache *FileCache) WriteItem(w io.Writer, name string) (err error) {
	itm, ok := cache.items[name]
	if !ok {
		if !SquelchItemNotInCache {
			err = ItemNotInCache
		}
		return
	}
	r := itm.GetReader()
	itm.Lastaccess = time.Now()
	n, err := io.Copy(w, r)
	if err != nil {
		return
	} else if int64(n) != itm.Size {
		err = WriteIncomplete
		return
	}
	return
}

// GetItem returns the content of the item and a bool if name is present.
// GetItem should be used when you are certain an object is in the cache,
// or if you want to use the cache only.
func (cache *FileCache) GetItem(name string) (content []byte, ok bool) {
	itm, ok := cache.items[name]
	if !ok {
		return
	}
	content = itm.Access()
	return
}

// GetItemString is the same as GetItem, except returning a string.
func (cache *FileCache) GetItemString(name string) (content string, ok bool) {
	itm, ok := cache.items[name]
	if !ok {
		return
	}
	content = string(itm.Access())
	return
}

// ReadFile retrieves the file named by 'name'.
// If the file is not in the cache, load the file and cache the file in the
// background. If the file was not in the cache and the read was successful,
// the error ItemNotInCache is returned to indicate that the item was pulled
// from the filesystem and not the cache, unless the SquelchItemNotInCache
// global option is set; in that case, returns no error.
func (cache *FileCache) ReadFile(name string) (content []byte, err error) {
	if cache.InCache(name) {
		content, _ = cache.GetItem(name)
	} else {
		go cache.Cache(name)
		content, err = ioutil.ReadFile(name)
		if err == nil && !SquelchItemNotInCache {
			err = ItemNotInCache
		}
	}
	return
}

// ReadFileString is the same as ReadFile, except returning a string.
func (cache *FileCache) ReadFileString(name string) (content string, err error) {
	if cache.InCache(name) {
		content, _ = cache.GetItemString(name)
	} else {
		go cache.Cache(name)
		raw, err := ioutil.ReadFile(name)
		if err == nil && !SquelchItemNotInCache {
			err = ItemNotInCache
			content = string(raw)
		}
	}
	return
}

// WriteFile writes the file named by 'name' to the specified io.Writer.
// If the file is in the cache, it is loaded from the cache; otherwise,
// it is read from the filesystem and the file is cached in the background.
func (cache *FileCache) WriteFile(w io.Writer, name string) (err error) {
	if cache.InCache(name) {
		err = cache.WriteItem(w, name)
	} else {
		var fi os.FileInfo
		fi, err = os.Stat(name)
		if err != nil {
			return
		} else if fi.IsDir() {
			return ItemIsDirectory
		}
		go cache.Cache(name)
		var file *os.File
		file, err = os.Open(name)
		if err != nil {
			return
		}
		defer file.Close()
		_, err = io.Copy(w, file)

	}
	return
}

func (cache *FileCache) HttpWriteFile(w http.ResponseWriter, r *http.Request) {
	path, err := url.QueryUnescape(r.URL.String())
	if err != nil {
		http.ServeFile(w, r, r.URL.Path)
	} else if len(path) > 1 {
		path = path[1:len(path)]
	} else {
		http.ServeFile(w, r, ".")
		return
	}

	if cache.InCache(path) {
		var tmp_nam string
		itm := cache.items[path]
		if tmp_nam, err = filepath.Abs(path); err != nil {
			tmp_nam = path
		}
		w.Header().Set("content-length", fmt.Sprintf("%d", itm.Size))
		w.Header().Set("content-disposition",
			fmt.Sprintf("filename=%s", tmp_nam))
		w.Write(itm.Access())
		return
	}
	go cache.Cache(path)
	http.ServeFile(w, r, path)
}

// HttpHandler returns a valid HTTP handler for the given cache.
func HttpHandler(cache *FileCache) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		cache.HttpWriteFile(w, r)
	}
}

// Cache will store the file named by 'name' to the cache.
// This function doesn't return anything as it passes the file onto the
// incoming pipe; the file will be cached asynchronously. Errors will
// not be returned.
func (cache *FileCache) Cache(name string) {
	if cache.Size() == cache.MaxItems {
		cache.expire_oldest(true)
	}
	cache.in_pipe <- name
}

// CacheNow immediately caches the file named by 'name'.
func (cache *FileCache) CacheNow(name string) (err error) {
	if cache.Size() == cache.MaxItems {
		cache.expire_oldest(true)
	}
	return cache.add_item(name)
}

// Start activates the file cache; it will
func (cache *FileCache) Start() error {
	if cache.in_pipe != nil {
		close(cache.in_pipe)
	}
	dur, err := time.ParseDuration(fmt.Sprintf("%ds", cache.Every))
	if err != nil {
		return err
	}
	cache.dur = dur
	cache.items = make(map[string]*cacheItem, 0)
	cache.in_pipe = make(chan string, NewCachePipeSize)
	go cache.item_listener()
	go cache.vaccuum()
	return nil
}

// Stop turns off the file cache.
// This closes the concurrent caching mechanism, destroys the cache, and
// the background scanner that it should stop.
// If there are any items or cache operations ongoing while Stop() is called,
// it is undefined how they will behave.
func (cache *FileCache) Stop() {
	if cache.in_pipe != nil {
		close(cache.in_pipe)
	}
	if cache.items != nil {
		for name, _ := range cache.items {
			delete(cache.items, name)
		}
		cache.items = nil
	}
}

// RemoveItem immediately removes the item from the cache if it is present.
// It returns a boolean indicating whether anything was removed, and an error
// if an error has occurred.
func (cache *FileCache) Remove(name string) (ok bool, err error) {
	_, ok = cache.items[name]
	if !ok {
		return
	}
	delete(cache.items, name)
	_, valid := cache.items[name]
	if valid {
		ok = false
	}
	return
}
<commit_msg>more tweaking of content-disposition header<commit_after>package filecache

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"time"
)

const VERSION = "1.0.2"

// File size constants for use with FileCache.MaxSize.
// For example, cache.MaxSize = 64 * Megabyte
const (
	Kilobyte = 1024
	Megabyte = 1024 * 1024
	Gigabyte = 1024 * 1024 * 1024
)

var (
	DefaultExpireItem int   = 300 // 5 minutes
	DefaultMaxSize    int64 = 16 * Megabyte
	DefaultMaxItems   int   = 32
	DefaultEvery      int   = 60 // 1 minute
)

var (
	InvalidCacheItem = errors.New("invalid cache item")
	ItemIsDirectory  = errors.New("can't cache a directory")
	ItemNotInCache   = errors.New("item not in cache")
	ItemTooLarge     = errors.New("item too large for cache")
	WriteIncomplete  = errors.New("incomplete write of cache item")
)

var SquelchItemNotInCache = true

// Mumber of items to buffer adding to the file cache.
var NewCachePipeSize = 4

/// CacheItem represents an item in the cache
type cacheItem struct {
	content    []byte
	Size       int64
	Lastaccess time.Time
	Modified   time.Time
}

func (itm *cacheItem) GetReader() io.Reader {
	b := bytes.NewReader(itm.Access())
	return b
}

func (itm *cacheItem) Access() []byte {
	itm.Lastaccess = time.Now()
	return itm.content
}

func cacheFile(path string, maxSize int64) (itm *cacheItem, err error) {
	fi, err := os.Stat(path)
	if err != nil {
		return
	} else if fi.Mode().IsDir() {
		return nil, ItemIsDirectory
	} else if fi.Size() > maxSize {
		return nil, ItemTooLarge
	}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return
	}

	itm = new(cacheItem)
	itm.content = content
	itm.Size = fi.Size()
	itm.Modified = fi.ModTime()
	itm.Lastaccess = time.Now()
	return
}

// FileCache represents a cache in memory.
// An ExpireItem value of 0 means that items should not be expired based
// on time in memory.
type FileCache struct {
	dur        time.Duration
	items      map[string]*cacheItem
	in_pipe    chan string
	MaxItems   int   // Maximum number of files to cache
	MaxSize    int64 // Maximum file size to store
	ExpireItem int   // Seconds a file should be cached for
	Every      int   // Run an expiration check Every seconds
}

// NewDefaultCache returns a new FileCache with sane defaults.
func NewDefaultCache() *FileCache {
	cache := FileCache{time.Since(time.Now()),
		nil, nil,
		DefaultMaxItems,
		DefaultMaxSize,
		DefaultExpireItem,
		DefaultEvery}
	return &cache
}

// add_item is an internal function for adding an item to the cache.
func (cache *FileCache) add_item(name string) (err error) {
	if cache.items == nil {
		return
	}
	ok := cache.InCache(name)
	expired := cache.item_expired(name)
	if ok && !expired {
		return nil
	} else if ok {
		delete(cache.items, name)
	}

	itm, err := cacheFile(name, cache.MaxSize)
	if cache.items != nil && itm != nil {
		cache.items[name] = itm
	} else {
		return
	}
	if !cache.InCache(name) {
		return ItemNotInCache
	}
	return nil
}

// item_listener is a goroutine that listens for incoming files and caches
// them.
func (cache *FileCache) item_listener() {
	for {
		name, ok := <-cache.in_pipe
		if !ok {
			return
		}
		cache.add_item(name)
	}
}

// expire_oldest is used to expire the oldest item in the cache.
// The force argument is used to indicate it should remove at least one
// entry; for example, if a large number of files are cached at once, none
// may appear older than another.
func (cache *FileCache) expire_oldest(force bool) {
	oldest := time.Now()
	oldest_name := ""

	for name, itm := range cache.items {
		if force && oldest_name == "" {
			oldest = itm.Lastaccess
			oldest_name = name
		} else if itm.Lastaccess.Before(oldest) {
			oldest = itm.Lastaccess
			oldest_name = name
		}
	}
	if oldest_name != "" {
		delete(cache.items, oldest_name)
	}
}

// vaccuum is a background goroutine responsible for cleaning the cache.
// It runs periodically, every cache.Every seconds. If cache.Every is set
// to 0, it will not run.
func (cache *FileCache) vaccuum() {
	if cache.Every < 1 {
		return
	}

	for {
		<-time.After(time.Duration(cache.dur))
		if cache.items == nil {
			return
		}
		for name, _ := range cache.items {
			if cache.item_expired(name) {
				delete(cache.items, name)
			}
		}
		for size := cache.Size(); size > cache.MaxItems; size = cache.Size() {
			cache.expire_oldest(true)
		}
	}
}

// FileChanged returns true if file should be expired based on mtime.
// If the file has changed on disk or no longer exists, it should be
// expired.
func (cache *FileCache) changed(name string) bool {
	itm, ok := cache.items[name]
	if !ok || itm == nil {
		return true
	}
	fi, err := os.Stat(name)
	if err != nil {
		return true
	} else if !itm.Modified.Equal(fi.ModTime()) {
		return true
	}
	return false
}

// Expired returns true if the item has not been accessed recently.
func (cache *FileCache) expired(name string) bool {
	itm, ok := cache.items[name]
	if !ok {
		return true
	}
	dur := time.Now().Sub(itm.Lastaccess)
	sec, err := strconv.Atoi(fmt.Sprintf("%0.0f", dur.Seconds()))
	if err != nil {
		return true
	} else if sec >= cache.ExpireItem {
		return true
	}
	return false
}

// item_expired returns true if an item is expired.
func (cache *FileCache) item_expired(name string) bool {
	if cache.changed(name) {
		return true
	} else if cache.ExpireItem != 0 && cache.expired(name) {
		return true
	}
	return false
}

// Active returns true if the cache has been started, and false otherwise.
func (cache *FileCache) Active() bool {
	if cache.in_pipe == nil || cache.items == nil {
		return false
	}
	return true
}

// Size returns the number of entries in the cache.
func (cache *FileCache) Size() int {
	return len(cache.items)
}

// FileSize returns the sum of the file sizes stored in the cache
func (cache *FileCache) FileSize() (totalSize int64) {
	for _, itm := range cache.items {
		totalSize += itm.Size
	}
	return
}

// StoredFiles returns the list of files stored in the cache.
func (cache *FileCache) StoredFiles() (fileList []string) {
	fileList = make([]string, 0)
	for name, _ := range cache.items {
		fileList = append(fileList, name)
	}
	return
}

// InCache returns true if the item is in the cache.
func (cache *FileCache) InCache(name string) bool {
	if cache.changed(name) {
		delete(cache.items, name)
		return false
	}
	_, ok := cache.items[name]
	return ok
}

// WriteItem writes the cache item to the specified io.Writer.
func (cache *FileCache) WriteItem(w io.Writer, name string) (err error) {
	itm, ok := cache.items[name]
	if !ok {
		if !SquelchItemNotInCache {
			err = ItemNotInCache
		}
		return
	}
	r := itm.GetReader()
	itm.Lastaccess = time.Now()
	n, err := io.Copy(w, r)
	if err != nil {
		return
	} else if int64(n) != itm.Size {
		err = WriteIncomplete
		return
	}
	return
}

// GetItem returns the content of the item and a bool if name is present.
// GetItem should be used when you are certain an object is in the cache,
// or if you want to use the cache only.
func (cache *FileCache) GetItem(name string) (content []byte, ok bool) {
	itm, ok := cache.items[name]
	if !ok {
		return
	}
	content = itm.Access()
	return
}

// GetItemString is the same as GetItem, except returning a string.
func (cache *FileCache) GetItemString(name string) (content string, ok bool) {
	itm, ok := cache.items[name]
	if !ok {
		return
	}
	content = string(itm.Access())
	return
}

// ReadFile retrieves the file named by 'name'.
// If the file is not in the cache, load the file and cache the file in the
// background. If the file was not in the cache and the read was successful,
// the error ItemNotInCache is returned to indicate that the item was pulled
// from the filesystem and not the cache, unless the SquelchItemNotInCache
// global option is set; in that case, returns no error.
func (cache *FileCache) ReadFile(name string) (content []byte, err error) {
	if cache.InCache(name) {
		content, _ = cache.GetItem(name)
	} else {
		go cache.Cache(name)
		content, err = ioutil.ReadFile(name)
		if err == nil && !SquelchItemNotInCache {
			err = ItemNotInCache
		}
	}
	return
}

// ReadFileString is the same as ReadFile, except returning a string.
func (cache *FileCache) ReadFileString(name string) (content string, err error) {
	if cache.InCache(name) {
		content, _ = cache.GetItemString(name)
	} else {
		go cache.Cache(name)
		raw, err := ioutil.ReadFile(name)
		if err == nil && !SquelchItemNotInCache {
			err = ItemNotInCache
			content = string(raw)
		}
	}
	return
}

// WriteFile writes the file named by 'name' to the specified io.Writer.
// If the file is in the cache, it is loaded from the cache; otherwise,
// it is read from the filesystem and the file is cached in the background.
func (cache *FileCache) WriteFile(w io.Writer, name string) (err error) {
	if cache.InCache(name) {
		err = cache.WriteItem(w, name)
	} else {
		var fi os.FileInfo
		fi, err = os.Stat(name)
		if err != nil {
			return
		} else if fi.IsDir() {
			return ItemIsDirectory
		}
		go cache.Cache(name)
		var file *os.File
		file, err = os.Open(name)
		if err != nil {
			return
		}
		defer file.Close()
		_, err = io.Copy(w, file)

	}
	return
}

func (cache *FileCache) HttpWriteFile(w http.ResponseWriter, r *http.Request) {
	path, err := url.QueryUnescape(r.URL.String())
	if err != nil {
		http.ServeFile(w, r, r.URL.Path)
	} else if len(path) > 1 {
		path = path[1:len(path)]
	} else {
		http.ServeFile(w, r, ".")
		return
	}

	if cache.InCache(path) {
		itm := cache.items[path]
		w.Header().Set("content-length", fmt.Sprintf("%d", itm.Size))
		w.Header().Set("content-disposition",
			fmt.Sprintf("filename=%s", filepath.Base(path)))
		w.Write(itm.Access())
		return
	}
	go cache.Cache(path)
	http.ServeFile(w, r, path)
}

// HttpHandler returns a valid HTTP handler for the given cache.
func HttpHandler(cache *FileCache) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		cache.HttpWriteFile(w, r)
	}
}

// Cache will store the file named by 'name' to the cache.
// This function doesn't return anything as it passes the file onto the
// incoming pipe; the file will be cached asynchronously. Errors will
// not be returned.
func (cache *FileCache) Cache(name string) {
	if cache.Size() == cache.MaxItems {
		cache.expire_oldest(true)
	}
	cache.in_pipe <- name
}

// CacheNow immediately caches the file named by 'name'.
func (cache *FileCache) CacheNow(name string) (err error) {
	if cache.Size() == cache.MaxItems {
		cache.expire_oldest(true)
	}
	return cache.add_item(name)
}

// Start activates the file cache; it will
func (cache *FileCache) Start() error {
	if cache.in_pipe != nil {
		close(cache.in_pipe)
	}
	dur, err := time.ParseDuration(fmt.Sprintf("%ds", cache.Every))
	if err != nil {
		return err
	}
	cache.dur = dur
	cache.items = make(map[string]*cacheItem, 0)
	cache.in_pipe = make(chan string, NewCachePipeSize)
	go cache.item_listener()
	go cache.vaccuum()
	return nil
}

// Stop turns off the file cache.
// This closes the concurrent caching mechanism, destroys the cache, and
// the background scanner that it should stop.
// If there are any items or cache operations ongoing while Stop() is called,
// it is undefined how they will behave.
func (cache *FileCache) Stop() {
	if cache.in_pipe != nil {
		close(cache.in_pipe)
	}
	if cache.items != nil {
		for name, _ := range cache.items {
			delete(cache.items, name)
		}
		cache.items = nil
	}
}

// RemoveItem immediately removes the item from the cache if it is present.
// It returns a boolean indicating whether anything was removed, and an error
// if an error has occurred.
func (cache *FileCache) Remove(name string) (ok bool, err error) {
	_, ok = cache.items[name]
	if !ok {
		return
	}
	delete(cache.items, name)
	_, valid := cache.items[name]
	if valid {
		ok = false
	}
	return
}
<|endoftext|>


<commit_before>package gogadgets

import (
	"labix.org/v2/mgo"
	"strconv"
	"strings"
	"time"
)

type summary struct {
	start time.Time
	n int
	v float64
}

//Recorder takes all the update messages it receives and saves them
//in a mongodb.
type Recorder struct {
	DBHost     string
	DBName     string
	session    *mgo.Session
	collection *mgo.Collection
	status     bool
	connected  bool
	filter     []string
	duration   time.Duration
	history    map[string]summary
}

func NewRecorder(pin *Pin) (OutputDevice, error) {
	i, err := strconv.ParseInt(pin.Args["summarize"], 10, 64)
	var d time.Duration
	if err == nil {
		d = time.Duration(i) * time.Minute
	}
	r := &Recorder{
		DBHost: pin.Args["host"],
		DBName: pin.Args["db"],
		filter: getFilter(pin.Args["filter"]),
		duration: d,
		history: map[string]summary{},
	}
	return r, nil
}

func (r *Recorder) Update(msg *Message) {
	if r.status && msg.Type == "update" {
		r.save(msg)
	}
}

func (r *Recorder) On(val *Value) error {
	err := r.connect()
	if err == nil {
		r.status = true
	}
	return err
}

func (r *Recorder) Off() error {
	if r.session != nil {
		r.session.Close()
	}
	r.status = false
	return nil
}

func (r *Recorder) Status() interface{} {
	return r.status
}

func (r *Recorder) save(msg *Message) {
	if len(r.filter) > 0 {
		if !r.inFilter(msg) {
			return
		}
	}
	if r.duration > 0 {
		r.summarize(msg)
	} else {
		r.doSave(msg)
	}
}

func (r *Recorder) inFilter(msg *Message) bool {
	for _, item := range r.filter {
		if msg.Sender == item {
			return true
		}
	}
	return false
}

func (r *Recorder) summarize(msg *Message) {
	now := time.Now()
	s, ok := r.history[msg.Sender]
	if !ok {
		s = summary{start: now}
	}
	s.n += 1
	f, _ := msg.Value.ToFloat()
	s.v += f
	lapsed := s.start.Sub(now)
	if lapsed >= r.duration {
		msg.Value.Value = s.v / float64(s.n)
		r.doSave(msg)
		delete(r.history, msg.Sender)
	} else {
		r.history[msg.Sender] = s
	}
}

func (r *Recorder) doSave(msg *Message) {
	r.collection.Insert(msg)
}

func (r *Recorder) connect() error {
	session, err := mgo.Dial(r.DBHost)
	if err != nil {
		return err
	}
	r.session = session
	r.collection = session.DB(r.DBName).C("updates")
	return nil
}

func getFilter(filterStr string) []string {
	if len(filterStr) == 0 {
		return []string{}
	}
	return strings.Split(filterStr, ",")
}
<commit_msg>fixed bug in recorder<commit_after>package gogadgets

import (
	"labix.org/v2/mgo"
	"strconv"
	"strings"
	"time"
)

type summary struct {
	start time.Time
	n int
	v float64
}

//Recorder takes all the update messages it receives and saves them
//in a mongodb.
type Recorder struct {
	DBHost     string
	DBName     string
	session    *mgo.Session
	collection *mgo.Collection
	status     bool
	connected  bool
	filter     []string
	duration   time.Duration
	history    map[string]summary
}

func NewRecorder(pin *Pin) (OutputDevice, error) {
	i, err := strconv.ParseInt(pin.Args["summarize"], 10, 64)
	var d time.Duration
	if err == nil {
		d = time.Duration(i) * time.Minute
	}
	r := &Recorder{
		DBHost: pin.Args["host"],
		DBName: pin.Args["db"],
		filter: getFilter(pin.Args["filter"]),
		duration: d,
		history: map[string]summary{},
	}
	return r, nil
}

func (r *Recorder) Update(msg *Message) {
	if r.status && msg.Type == "update" {
		r.save(msg)
	}
}

func (r *Recorder) On(val *Value) error {
	err := r.connect()
	if err == nil {
		r.status = true
	}
	return err
}

func (r *Recorder) Off() error {
	if r.session != nil {
		r.session.Close()
	}
	r.status = false
	return nil
}

func (r *Recorder) Status() interface{} {
	return r.status
}

func (r *Recorder) save(msg *Message) {
	if len(r.filter) > 0 {
		if !r.inFilter(msg) {
			return
		}
	}
	if r.duration > 0 {
		r.summarize(msg)
	} else {
		r.doSave(msg)
	}
}

func (r *Recorder) inFilter(msg *Message) bool {
	for _, item := range r.filter {
		if msg.Sender == item {
			return true
		}
	}
	return false
}

func (r *Recorder) summarize(msg *Message) {
	now := time.Now()
	s, ok := r.history[msg.Sender]
	if !ok {
		s = summary{start: now}
	}
	s.n += 1
	f, _ := msg.Value.ToFloat()
	s.v += f
	lapsed := now.Sub(s.start)
	if lapsed >= r.duration {
		msg.Value.Value = s.v / float64(s.n)
		r.doSave(msg)
		delete(r.history, msg.Sender)
	} else {
		r.history[msg.Sender] = s
	}
}

func (r *Recorder) doSave(msg *Message) {
	r.collection.Insert(msg)
}

func (r *Recorder) connect() error {
	session, err := mgo.Dial(r.DBHost)
	if err != nil {
		return err
	}
	r.session = session
	r.collection = session.DB(r.DBName).C("updates")
	return nil
}

func getFilter(filterStr string) []string {
	if len(filterStr) == 0 {
		return []string{}
	}
	return strings.Split(filterStr, ",")
}
<|endoftext|>


<commit_before>package gofakeit

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"reflect"
)

// XMLOptions defines values needed for json generation
type XMLOptions struct {
	Type          string  `json:"type" xml:"type"` // single or multiple
	RootElement   string  `json:"root_element" xml:"root_element"`
	RecordElement string  `json:"record_element" xml:"record_element"`
	RowCount      int     `json:"row_count" xml:"row_count"`
	Fields        []Field `json:"fields" xml:"fields"`
	Indent        bool    `json:"indent" xml:"indent"`
}

type xmlArray struct {
	XMLName xml.Name
	Array   []xmlMap
}

type xmlMap struct {
	XMLName  xml.Name
	KeyOrder []string
	Map      map[string]interface{} `xml:",chardata"`
}

type xmlEntry struct {
	XMLName xml.Name
	Value   interface{} `xml:",chardata"`
}

func (m xmlMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	if len(m.Map) == 0 {
		return nil
	}

	start.Name = m.XMLName

	err := e.EncodeToken(start)
	if err != nil {
		return err
	}

	err = xmlMapLoop(e, &m)
	if err != nil {
		return err
	}

	return e.EncodeToken(start.End())
}

func xmlMapLoop(e *xml.Encoder, m *xmlMap) error {
	var err error

	// Check if xmlmap has key order if not create it
	// Get key order by order of fields array
	if m.KeyOrder == nil {
		m.KeyOrder = make([]string, len(m.Map))
		for k := range m.Map {
			m.KeyOrder = append(m.KeyOrder, k)
		}
	}

	for _, key := range m.KeyOrder {
		v := reflect.ValueOf(m.Map[key])

		// Always get underlyning Value of value
		if v.Kind() == reflect.Ptr {
			v = reflect.Indirect(v)
		}

		switch v.Kind() {
		case reflect.Bool,
			reflect.String,
			reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint64,
			reflect.Float32, reflect.Float64:
			err = e.Encode(xmlEntry{XMLName: xml.Name{Local: key}, Value: m.Map[key]})
			if err != nil {
				return err
			}
		case reflect.Slice:
			e.EncodeToken(xml.StartElement{Name: xml.Name{Local: key}})
			for i := 0; i < v.Len(); i++ {
				err = e.Encode(xmlEntry{XMLName: xml.Name{Local: "value"}, Value: v.Index(i).String()})
				if err != nil {
					return err
				}
			}
			e.EncodeToken(xml.EndElement{Name: xml.Name{Local: key}})
		case reflect.Map:
			err = e.Encode(xmlMap{
				XMLName: xml.Name{Local: key},
				Map:     m.Map[key].(map[string]interface{}),
			})
			if err != nil {
				return err
			}
		case reflect.Struct:
			// Convert struct to map[string]interface{}
			// So we can rewrap element
			var inInterface map[string]interface{}
			inrec, _ := json.Marshal(m.Map[key])
			json.Unmarshal(inrec, &inInterface)

			err = e.Encode(xmlMap{
				XMLName: xml.Name{Local: key},
				Map:     inInterface,
			})
			if err != nil {
				return err
			}
		default:
			err = e.Encode(m.Map[key])
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// XML generates an object or an array of objects in json format
func XML(xo *XMLOptions) ([]byte, error) {
	// Check to make sure they passed in a type
	if xo.Type != "single" && xo.Type != "array" {
		return nil, errors.New("Invalid type, must be array or object")
	}

	// Check fields length
	if xo.Fields == nil || len(xo.Fields) <= 0 {
		return nil, errors.New("Must pass fields in order to build json object(s)")
	}

	// Check root element string
	if xo.RootElement == "" {
		xo.RecordElement = "xml"
	}

	// Check record element string
	if xo.RecordElement == "" {
		xo.RecordElement = "record"
	}

	// Get key order by order of fields array
	keyOrder := make([]string, len(xo.Fields))
	for _, f := range xo.Fields {
		keyOrder = append(keyOrder, f.Name)
	}

	if xo.Type == "single" {
		v := xmlMap{
			XMLName:  xml.Name{Local: xo.RootElement},
			KeyOrder: keyOrder,
			Map:      make(map[string]interface{}),
		}

		// Loop through fields and add to them to map[string]interface{}
		for _, field := range xo.Fields {
			// Get function info
			funcInfo := GetFuncLookup(field.Function)
			if funcInfo == nil {
				return nil, errors.New("Invalid function, " + field.Function + " does not exist")
			}

			value, err := funcInfo.Call(&field.Params, funcInfo)
			if err != nil {
				return nil, err
			}

			v.Map[field.Name] = value
		}

		// Marshal into bytes
		var b bytes.Buffer
		x := xml.NewEncoder(&b)
		if xo.Indent {
			x.Indent("", "    ")
		}
		err := x.Encode(v)
		if err != nil {
			return nil, err
		}

		return b.Bytes(), nil
	}

	if xo.Type == "array" {
		// Make sure you set a row count
		if xo.RowCount <= 0 {
			return nil, errors.New("Must have row count")
		}

		xa := xmlArray{
			XMLName: xml.Name{Local: xo.RootElement},
			Array:   make([]xmlMap, xo.RowCount),
		}

		for i := 1; i <= int(xo.RowCount); i++ {
			v := xmlMap{
				XMLName:  xml.Name{Local: xo.RecordElement},
				KeyOrder: keyOrder,
				Map:      make(map[string]interface{}),
			}

			// Loop through fields and add to them to map[string]interface{}
			for _, field := range xo.Fields {
				if field.Function == "autoincrement" {
					v.Map[field.Name] = i
					continue
				}

				// Get function info
				funcInfo := GetFuncLookup(field.Function)
				if funcInfo == nil {
					return nil, errors.New("Invalid function, " + field.Function + " does not exist")
				}

				value, err := funcInfo.Call(&field.Params, funcInfo)
				if err != nil {
					return nil, err
				}

				v.Map[field.Name] = value
			}

			xa.Array = append(xa.Array, v)
		}

		// Marshal into bytes
		var b bytes.Buffer
		x := xml.NewEncoder(&b)
		if xo.Indent {
			x.Indent("", "    ")
		}
		err := x.Encode(xa)
		if err != nil {
			return nil, err
		}

		return b.Bytes(), nil
	}

	return nil, errors.New("Invalid type, must be array or object")
}

func addFileXMLLookup() {
	AddFuncLookup("xml", Info{
		Display:     "XML",
		Category:    "file",
		Description: "Generates an single or an array of elements in xml format",
		Example: `
			<xml>
				<record>
					<first_name>Markus</first_name>
					<last_name>Moen</last_name>
					<password>Dc0VYXjkWABx</password>
				</record>
				<record>
					<first_name>Osborne</first_name>
					<last_name>Hilll</last_name>
					<password>XPJ9OVNbs5lm</password>
				</record>
			</xml>
		`,
		Output: "[]byte",
		Params: []Param{
			{Field: "type", Display: "Type", Type: "string", Default: "single", Options: []string{"single", "array"}, Description: "Type of XML, single or array"},
			{Field: "rootelement", Display: "Root Element", Type: "string", Default: "xml", Description: "Root element wrapper name"},
			{Field: "recordelement", Display: "Record Element", Type: "string", Default: "record", Description: "Record element for each record row"},
			{Field: "rowcount", Display: "Row Count", Type: "int", Default: "100", Description: "Number of rows in JSON array"},
			{Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function to run in json format"},
			{Field: "indent", Display: "Indent", Type: "bool", Default: "false", Description: "Whether or not to add indents and newlines"},
		},
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			xo := XMLOptions{}

			typ, err := info.GetString(m, "type")
			if err != nil {
				return nil, err
			}
			xo.Type = typ

			rootElement, err := info.GetString(m, "rootelement")
			if err != nil {
				return nil, err
			}
			xo.RootElement = rootElement

			recordElement, err := info.GetString(m, "recordelement")
			if err != nil {
				return nil, err
			}
			xo.RecordElement = recordElement

			rowcount, err := info.GetInt(m, "rowcount")
			if err != nil {
				return nil, err
			}
			xo.RowCount = rowcount

			fieldsStr, err := info.GetStringArray(m, "fields")
			if err != nil {
				return nil, err
			}

			// Check to make sure fields has length
			if len(fieldsStr) > 0 {
				xo.Fields = make([]Field, len(fieldsStr))

				for i, f := range fieldsStr {
					// Unmarshal fields string into fields array
					err = json.Unmarshal([]byte(f), &xo.Fields[i])
					if err != nil {
						return nil, errors.New("Unable to decode json string")
					}
				}
			}

			indent, err := info.GetBool(m, "indent")
			if err != nil {
				return nil, err
			}
			xo.Indent = indent

			return XML(&xo)
		},
	})
}
<commit_msg>xml - added method call<commit_after>package gofakeit

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	rand "math/rand"
	"reflect"
)

// XMLOptions defines values needed for json generation
type XMLOptions struct {
	Type          string  `json:"type" xml:"type"` // single or multiple
	RootElement   string  `json:"root_element" xml:"root_element"`
	RecordElement string  `json:"record_element" xml:"record_element"`
	RowCount      int     `json:"row_count" xml:"row_count"`
	Fields        []Field `json:"fields" xml:"fields"`
	Indent        bool    `json:"indent" xml:"indent"`
}

type xmlArray struct {
	XMLName xml.Name
	Array   []xmlMap
}

type xmlMap struct {
	XMLName  xml.Name
	KeyOrder []string
	Map      map[string]interface{} `xml:",chardata"`
}

type xmlEntry struct {
	XMLName xml.Name
	Value   interface{} `xml:",chardata"`
}

func (m xmlMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	if len(m.Map) == 0 {
		return nil
	}

	start.Name = m.XMLName

	err := e.EncodeToken(start)
	if err != nil {
		return err
	}

	err = xmlMapLoop(e, &m)
	if err != nil {
		return err
	}

	return e.EncodeToken(start.End())
}

func xmlMapLoop(e *xml.Encoder, m *xmlMap) error {
	var err error

	// Check if xmlmap has key order if not create it
	// Get key order by order of fields array
	if m.KeyOrder == nil {
		m.KeyOrder = make([]string, len(m.Map))
		for k := range m.Map {
			m.KeyOrder = append(m.KeyOrder, k)
		}
	}

	for _, key := range m.KeyOrder {
		v := reflect.ValueOf(m.Map[key])

		// Always get underlyning Value of value
		if v.Kind() == reflect.Ptr {
			v = reflect.Indirect(v)
		}

		switch v.Kind() {
		case reflect.Bool,
			reflect.String,
			reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint64,
			reflect.Float32, reflect.Float64:
			err = e.Encode(xmlEntry{XMLName: xml.Name{Local: key}, Value: m.Map[key]})
			if err != nil {
				return err
			}
		case reflect.Slice:
			e.EncodeToken(xml.StartElement{Name: xml.Name{Local: key}})
			for i := 0; i < v.Len(); i++ {
				err = e.Encode(xmlEntry{XMLName: xml.Name{Local: "value"}, Value: v.Index(i).String()})
				if err != nil {
					return err
				}
			}
			e.EncodeToken(xml.EndElement{Name: xml.Name{Local: key}})
		case reflect.Map:
			err = e.Encode(xmlMap{
				XMLName: xml.Name{Local: key},
				Map:     m.Map[key].(map[string]interface{}),
			})
			if err != nil {
				return err
			}
		case reflect.Struct:
			// Convert struct to map[string]interface{}
			// So we can rewrap element
			var inInterface map[string]interface{}
			inrec, _ := json.Marshal(m.Map[key])
			json.Unmarshal(inrec, &inInterface)

			err = e.Encode(xmlMap{
				XMLName: xml.Name{Local: key},
				Map:     inInterface,
			})
			if err != nil {
				return err
			}
		default:
			err = e.Encode(m.Map[key])
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// XML generates an object or an array of objects in json format
func XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(globalFaker.Rand, xo) }

// XML generates an object or an array of objects in json format
func (f *Faker) XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(f.Rand, xo) }

func xmlFunc(r *rand.Rand, xo *XMLOptions) ([]byte, error) {
	// Check to make sure they passed in a type
	if xo.Type != "single" && xo.Type != "array" {
		return nil, errors.New("Invalid type, must be array or object")
	}

	// Check fields length
	if xo.Fields == nil || len(xo.Fields) <= 0 {
		return nil, errors.New("Must pass fields in order to build json object(s)")
	}

	// Check root element string
	if xo.RootElement == "" {
		xo.RecordElement = "xml"
	}

	// Check record element string
	if xo.RecordElement == "" {
		xo.RecordElement = "record"
	}

	// Get key order by order of fields array
	keyOrder := make([]string, len(xo.Fields))
	for _, f := range xo.Fields {
		keyOrder = append(keyOrder, f.Name)
	}

	if xo.Type == "single" {
		v := xmlMap{
			XMLName:  xml.Name{Local: xo.RootElement},
			KeyOrder: keyOrder,
			Map:      make(map[string]interface{}),
		}

		// Loop through fields and add to them to map[string]interface{}
		for _, field := range xo.Fields {
			// Get function info
			funcInfo := GetFuncLookup(field.Function)
			if funcInfo == nil {
				return nil, errors.New("Invalid function, " + field.Function + " does not exist")
			}

			value, err := funcInfo.Call(&field.Params, funcInfo)
			if err != nil {
				return nil, err
			}

			v.Map[field.Name] = value
		}

		// Marshal into bytes
		var b bytes.Buffer
		x := xml.NewEncoder(&b)
		if xo.Indent {
			x.Indent("", "    ")
		}
		err := x.Encode(v)
		if err != nil {
			return nil, err
		}

		return b.Bytes(), nil
	}

	if xo.Type == "array" {
		// Make sure you set a row count
		if xo.RowCount <= 0 {
			return nil, errors.New("Must have row count")
		}

		xa := xmlArray{
			XMLName: xml.Name{Local: xo.RootElement},
			Array:   make([]xmlMap, xo.RowCount),
		}

		for i := 1; i <= int(xo.RowCount); i++ {
			v := xmlMap{
				XMLName:  xml.Name{Local: xo.RecordElement},
				KeyOrder: keyOrder,
				Map:      make(map[string]interface{}),
			}

			// Loop through fields and add to them to map[string]interface{}
			for _, field := range xo.Fields {
				if field.Function == "autoincrement" {
					v.Map[field.Name] = i
					continue
				}

				// Get function info
				funcInfo := GetFuncLookup(field.Function)
				if funcInfo == nil {
					return nil, errors.New("Invalid function, " + field.Function + " does not exist")
				}

				value, err := funcInfo.Call(&field.Params, funcInfo)
				if err != nil {
					return nil, err
				}

				v.Map[field.Name] = value
			}

			xa.Array = append(xa.Array, v)
		}

		// Marshal into bytes
		var b bytes.Buffer
		x := xml.NewEncoder(&b)
		if xo.Indent {
			x.Indent("", "    ")
		}
		err := x.Encode(xa)
		if err != nil {
			return nil, err
		}

		return b.Bytes(), nil
	}

	return nil, errors.New("Invalid type, must be array or object")
}

func addFileXMLLookup() {
	AddFuncLookup("xml", Info{
		Display:     "XML",
		Category:    "file",
		Description: "Generates an single or an array of elements in xml format",
		Example: `
			<xml>
				<record>
					<first_name>Markus</first_name>
					<last_name>Moen</last_name>
					<password>Dc0VYXjkWABx</password>
				</record>
				<record>
					<first_name>Osborne</first_name>
					<last_name>Hilll</last_name>
					<password>XPJ9OVNbs5lm</password>
				</record>
			</xml>
		`,
		Output: "[]byte",
		Params: []Param{
			{Field: "type", Display: "Type", Type: "string", Default: "single", Options: []string{"single", "array"}, Description: "Type of XML, single or array"},
			{Field: "rootelement", Display: "Root Element", Type: "string", Default: "xml", Description: "Root element wrapper name"},
			{Field: "recordelement", Display: "Record Element", Type: "string", Default: "record", Description: "Record element for each record row"},
			{Field: "rowcount", Display: "Row Count", Type: "int", Default: "100", Description: "Number of rows in JSON array"},
			{Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function to run in json format"},
			{Field: "indent", Display: "Indent", Type: "bool", Default: "false", Description: "Whether or not to add indents and newlines"},
		},
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			xo := XMLOptions{}

			typ, err := info.GetString(m, "type")
			if err != nil {
				return nil, err
			}
			xo.Type = typ

			rootElement, err := info.GetString(m, "rootelement")
			if err != nil {
				return nil, err
			}
			xo.RootElement = rootElement

			recordElement, err := info.GetString(m, "recordelement")
			if err != nil {
				return nil, err
			}
			xo.RecordElement = recordElement

			rowcount, err := info.GetInt(m, "rowcount")
			if err != nil {
				return nil, err
			}
			xo.RowCount = rowcount

			fieldsStr, err := info.GetStringArray(m, "fields")
			if err != nil {
				return nil, err
			}

			// Check to make sure fields has length
			if len(fieldsStr) > 0 {
				xo.Fields = make([]Field, len(fieldsStr))

				for i, f := range fieldsStr {
					// Unmarshal fields string into fields array
					err = json.Unmarshal([]byte(f), &xo.Fields[i])
					if err != nil {
						return nil, errors.New("Unable to decode json string")
					}
				}
			}

			indent, err := info.GetBool(m, "indent")
			if err != nil {
				return nil, err
			}
			xo.Indent = indent

			return XML(&xo)
		},
	})
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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 gobgp

import (
	"fmt"

	tpb "github.com/google/kne/proto/topo"
	"github.com/google/kne/topo/node"
	"google.golang.org/protobuf/proto"
)

func New(nodeImpl *node.Impl) (node.Node, error) {
	cfg := defaults(nodeImpl.Proto)
	proto.Merge(cfg, nodeImpl.Proto)
	node.FixServices(cfg)
	n := &Node{
		Impl: nodeImpl,
	}
	proto.Merge(n.Impl.Proto, cfg)
	return n, nil
}

type Node struct {
	*node.Impl
}

func defaults(pb *tpb.Node) *tpb.Node {
	return &tpb.Node{
		Config: &tpb.Config{
			Image:        "hfam/gobgp:latest",
			Command:      []string{"/usr/local/bin/gobgpd", "-f", "/gobgp.conf", "-t", "yaml"},
			EntryCommand: fmt.Sprintf("kubectl exec -it %s -- /bin/bash", pb.Name),
			ConfigPath:   "/",
			ConfigFile:   "gobgp.conf",
		},
	}
}

func init() {
	node.Register(tpb.Node_GOBGP, New)
	node.Vendor(tpb.Vendor_GOBGP, New)
}
<commit_msg>Modify gobgp node with new pattern<commit_after>// Copyright 2021 Google LLC
//
// 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 gobgp

import (
	"fmt"

	tpb "github.com/google/kne/proto/topo"
	"github.com/google/kne/topo/node"
)

func New(nodeImpl *node.Impl) (node.Node, error) {
	if nodeImpl == nil {
		return nil, fmt.Errorf("nodeImpl can not be nil")
	}
	if nodeImpl.Proto == nil {
		return nil, fmt.Errorf("nodeImpl.Proto cannot be nil")
	}
	cfg := defaults(nodeImpl.Proto)
	node.FixServices(cfg)
	n := &Node{
		Impl: nodeImpl,
	}
	return n, nil
}

type Node struct {
	*node.Impl
}

func defaults(pb *tpb.Node) *tpb.Node {
	if pb.Config == nil {
		pb.Config = &tpb.Config{}
	}
	if pb.Config.Image == "" {
		pb.Config.Image = "hfam/gobgp:latest"
	}
	if len(pb.GetConfig().GetCommand()) == 0 {
		pb.Config.Command = []string{"/usr/local/bin/gobgpd", "-f", "/gobgp.conf", "-t", "yaml"}
	}
	if pb.Config.EntryCommand == "" {
		pb.Config.EntryCommand = fmt.Sprintf("kubectl exec -it %s -- /bin/bash", pb.Name)
	}
	if pb.Config.ConfigPath == "" {
		pb.Config.ConfigPath = "/"
	}
	if pb.Config.ConfigFile == "" {
		pb.Config.ConfigFile = "gobgp.conf"
	}
	return pb
}

func init() {
	node.Register(tpb.Node_GOBGP, New)
	node.Vendor(tpb.Vendor_GOBGP, New)
}
<|endoftext|>


<commit_before>package vfs

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"

	"github.com/cozy/cozy-stack/pkg/config/config"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/previewfs"
)

// ServePDFPreview will send the preview image for a PDF.
func ServePDFPreview(w http.ResponseWriter, req *http.Request, fs VFS, doc *FileDoc) error {
	name := fmt.Sprintf("%s-preview.jpg", doc.ID())
	modtime := doc.UpdatedAt
	if doc.CozyMetadata != nil && doc.CozyMetadata.UploadedAt != nil {
		modtime = *doc.CozyMetadata.UploadedAt
	}
	buf, err := preview(fs, doc)
	if err != nil {
		return err
	}
	http.ServeContent(w, req, name, modtime, bytes.NewReader(buf.Bytes()))
	return nil
}

func preview(fs VFS, doc *FileDoc) (*bytes.Buffer, error) {
	cache := previewfs.SystemCache()
	if buf, err := cache.Get(doc.MD5Sum); err == nil {
		return buf, nil
	}

	buf, err := generatePreview(fs, doc)
	_ = cache.Set(doc.MD5Sum, buf)
	return buf, err
}

func generatePreview(fs VFS, doc *FileDoc) (*bytes.Buffer, error) {
	f, err := fs.OpenFile(doc)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	tempDir, err := ioutil.TempDir("", "magick")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tempDir)
	envTempDir := fmt.Sprintf("MAGICK_TEMPORARY_PATH=%s", tempDir)
	env := []string{envTempDir}

	convertCmd := config.GetConfig().Jobs.ImageMagickConvertCmd
	if convertCmd == "" {
		convertCmd = "convert"
	}
	args := []string{
		"-limit", "Memory", "2GB",
		"-limit", "Map", "3GB",
		"-[0]",           // Takes the input from stdin
		"-quality", "82", // A good compromise between file size and quality
		"-interlace", "none", // Don't use progressive JPEGs, they are heavier
		"-thumbnail", "1080x1920>", // Makes a thumbnail that fits inside the given format
		"-colorspace", "sRGB", // Use the colorspace recommended for web, sRGB
		"jpg:-", // Send the output on stdout, in JPEG format
	}

	var stdout, stderr bytes.Buffer
	cmd := exec.Command(convertCmd, args...)
	cmd.Env = env
	cmd.Stdin = f
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		// Truncate very long messages
		msg := stderr.String()
		if len(msg) > 4000 {
			msg = msg[:4000]
		}
		logger.WithNamespace("pdf_preview").
			WithField("stderr", msg).
			WithField("file_id", doc.ID()).
			Errorf("imagemagick failed: %s", err)
		return nil, err
	}
	return &stdout, nil
}
<commit_msg>Fix a panic on preview module<commit_after>package vfs

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"

	"github.com/cozy/cozy-stack/pkg/config/config"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/previewfs"
)

// ServePDFPreview will send the preview image for a PDF.
func ServePDFPreview(w http.ResponseWriter, req *http.Request, fs VFS, doc *FileDoc) error {
	name := fmt.Sprintf("%s-preview.jpg", doc.ID())
	modtime := doc.UpdatedAt
	if doc.CozyMetadata != nil && doc.CozyMetadata.UploadedAt != nil {
		modtime = *doc.CozyMetadata.UploadedAt
	}
	buf, err := preview(fs, doc)
	if err != nil {
		return err
	}
	http.ServeContent(w, req, name, modtime, bytes.NewReader(buf.Bytes()))
	return nil
}

func preview(fs VFS, doc *FileDoc) (*bytes.Buffer, error) {
	cache := previewfs.SystemCache()
	if buf, err := cache.Get(doc.MD5Sum); err == nil {
		return buf, nil
	}

	buf, err := generatePreview(fs, doc)
	if err != nil {
		return nil, err
	}
	_ = cache.Set(doc.MD5Sum, buf)
	return buf, nil
}

func generatePreview(fs VFS, doc *FileDoc) (*bytes.Buffer, error) {
	f, err := fs.OpenFile(doc)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	tempDir, err := ioutil.TempDir("", "magick")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tempDir)
	envTempDir := fmt.Sprintf("MAGICK_TEMPORARY_PATH=%s", tempDir)
	env := []string{envTempDir}

	convertCmd := config.GetConfig().Jobs.ImageMagickConvertCmd
	if convertCmd == "" {
		convertCmd = "convert"
	}
	args := []string{
		"-limit", "Memory", "2GB",
		"-limit", "Map", "3GB",
		"-[0]",           // Takes the input from stdin
		"-quality", "82", // A good compromise between file size and quality
		"-interlace", "none", // Don't use progressive JPEGs, they are heavier
		"-thumbnail", "1080x1920>", // Makes a thumbnail that fits inside the given format
		"-colorspace", "sRGB", // Use the colorspace recommended for web, sRGB
		"jpg:-", // Send the output on stdout, in JPEG format
	}

	var stdout, stderr bytes.Buffer
	cmd := exec.Command(convertCmd, args...)
	cmd.Env = env
	cmd.Stdin = f
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		// Truncate very long messages
		msg := stderr.String()
		if len(msg) > 4000 {
			msg = msg[:4000]
		}
		logger.WithNamespace("pdf_preview").
			WithField("stderr", msg).
			WithField("file_id", doc.ID()).
			Errorf("imagemagick failed: %s", err)
		return nil, err
	}
	return &stdout, nil
}
<|endoftext|>


<commit_before>package models

import (
        "database/sql"
        "fmt"
        _ "github.com/lib/pq"
        "os"
)

const (
        connection_format string  = "user=%s dbname=%s sslmode=disable password=%s host=%s"
        db_name                   = "ciudad_gourmet"
)

func stablishConnection() (*sql.DB, error) {
        user := os.Getenv("POSTGRESQL_USER")
        pass := os.Getenv("POSTGRESQL_PASS")
        host := os.Getenv("PGHOST")
        connection_params := fmt.Sprintf(connection_format, user, db_name, pass, host)
        db, err := sql.Open("postgres", connection_params)

        if err != nil {
                println("error open")
                return nil, err
        }
        return db, nil
}
<commit_msg>Fixing DB name<commit_after>package models

import (
        "database/sql"
        "fmt"
        _ "github.com/lib/pq"
        "os"
)

const (
        connection_format string  = "user=%s dbname=%s sslmode=disable password=%s host=%s"
        db_name                   = "ps2_db"
)

func stablishConnection() (*sql.DB, error) {
        user := os.Getenv("POSTGRESQL_USER")
        pass := os.Getenv("POSTGRESQL_PASS")
        host := os.Getenv("PGHOST")
        connection_params := fmt.Sprintf(connection_format, user, db_name, pass, host)
        db, err := sql.Open("postgres", connection_params)

        if err != nil {
                println("error open")
                return nil, err
        }
        return db, nil
}
<|endoftext|>


<commit_before>package oak

import (
	"bufio"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"

	"github.com/oakmound/oak/v2/oakerr"

	"github.com/davecgh/go-spew/spew"
	"github.com/oakmound/oak/v2/collision"
	"github.com/oakmound/oak/v2/dlog"
	"github.com/oakmound/oak/v2/event"
	"github.com/oakmound/oak/v2/mouse"
	"github.com/oakmound/oak/v2/render"
	"github.com/oakmound/oak/v2/render/mod"
)

var (
	viewportLocked = true
	commands       = make(map[string]func([]string))
)

// AddCommand adds a console command to call fn when
// '<s> <args>' is input to the console. fn will be called
// with args split on whitespace.
func AddCommand(s string, fn func([]string)) error {
	if _, ok := commands[s]; ok {
		return oakerr.ExistingElement{
			InputName:   "s",
			InputType:   "string",
			Overwritten: false,
		}
	}
	dlog.Info("Adding command", s)
	commands[s] = fn
	return nil
}

// ForceAddCommand adds or overwrites a console command to call fn when
// '<s> <args>' is input to the console. fn will be called
// with args split on whitespace. If a command is overwritten
// the overwritten command will be returned.
func ForceAddCommand(s string, fn func([]string)) func([]string) {

	existing, overwritten := commands[s]
	if overwritten {
		dlog.Info("Overwriting command", s)
	} else {
		dlog.Info("Adding command", s)
	}
	commands[s] = fn
	return existing
}

// ClearCommand clears an existing debug command by key: <s>
func ClearCommand(s string) {
	delete(commands, s)
}

// ResetCommands will throw out all existing debug commands from the
// debug console.
func ResetCommands() {
	commands = map[string]func([]string){}
}

// GetDebugKeys returns the current debug console commands as a string array
func GetDebugKeys() []string {
	dkeys := make([]string, len(commands))
	i := 0
	for k := range commands {
		dkeys[i] = k
		i++
	}
	return dkeys
}

func debugConsole(resetCh, skipScene chan bool, input io.Reader) {
	scanner := bufio.NewScanner(input)
	spew.Config.DisableMethods = true
	spew.Config.MaxDepth = 2

	// built in commands
	if conf.LoadBuiltinCommands {
		dlog.ErrorCheck(AddCommand("viewport", viewportCommands))
		dlog.ErrorCheck(AddCommand("fade", fadeCommands))
		dlog.ErrorCheck(AddCommand("skip", skipCommands(skipScene)))
		dlog.ErrorCheck(AddCommand("print", printCommands))
		dlog.ErrorCheck(AddCommand("mouse", mouseCommands))
		dlog.ErrorCheck(AddCommand("move", moveWindow))
		dlog.ErrorCheck(AddCommand("fullscreen", fullScreen))
		dlog.ErrorCheck(AddCommand("quit", func([]string) { Quit() }))
	}

	for {
		select {
		case <-resetCh: //reset all vars in debug console that save state
			viewportLocked = true
		default:
		}
		for scanner.Scan() {
			tokenString := strings.Fields(scanner.Text())
			if len(tokenString) == 0 {
				continue
			}
			if fn, ok := commands[tokenString[0]]; ok {
				fn(tokenString[1:])
			} else {
				fmt.Println("Unknown command", tokenString[0])
			}
		}
	}
}

func parseTokenAsInt(tokenString []string, arrIndex int, defaultVal int) int {
	if len(tokenString) > arrIndex {
		tmp, err := strconv.Atoi(tokenString[arrIndex])
		if err == nil {
			return tmp
		}
	}
	return defaultVal
}

func mouseDetails(nothing int, mevent interface{}) int {
	me := mevent.(mouse.Event)
	x := int(me.X()) + ViewPos.X
	y := int(me.Y()) + ViewPos.Y
	loc := collision.NewUnassignedSpace(float64(x), float64(y), 16, 16)
	results := collision.Hits(loc)
	fmt.Println("Mouse at:", x, y, "rel:", me.X(), me.Y())
	if len(results) == 0 {
		results = mouse.Hits(loc)
	}
	if len(results) > 0 {
		i := int(results[0].CID)
		if i > 0 && event.HasEntity(i) {
			e := event.GetEntity(i)
			spew.Dump(e)
		} else {
			fmt.Println("No entity ", i)
		}
	}

	return 0
}

func viewportCommands(tokenString []string) {
	switch tokenString[0] {
	case "unlock":
		if viewportLocked {
			speed := parseTokenAsInt(tokenString, 1, 5)
			viewportLocked = false
			event.GlobalBind(moveViewportBinding(speed), event.Enter)
		} else {
			fmt.Println("Viewport is already unbound")
		}
	case "lock":
		if viewportLocked {
			fmt.Println("Viewport is already locked")
		} else {
			viewportLocked = true
		}
	default:
		fmt.Println("Unrecognized command for viewport")
	}
}

func fadeCommands(tokenString []string) {
	toFade, ok := render.GetDebugRenderable(tokenString[0])
	fadeVal := parseTokenAsInt(tokenString, 1, 255)
	if ok {
		toFade.(render.Modifiable).Filter(mod.Fade(fadeVal))
	} else {
		fmt.Println("Could not fade input")
	}
}

func skipCommands(skipScene chan bool) func(tokenString []string) {
	return func(tokenString []string) {
		switch tokenString[0] {
		case "scene":
			skipScene <- true
		default:
			fmt.Println("Bad Skip Input")
		}
	}
}

func printCommands(tokenString []string) {
	if i, err := strconv.Atoi(tokenString[0]); err == nil {
		if i > 0 && event.HasEntity(i) {
			e := event.GetEntity(i)
			fmt.Println(reflect.TypeOf(e), e)
		} else {
			fmt.Println("No entity ", i)
		}
	} else {
		fmt.Println("Unable to parse", tokenString[0])
	}
}

func mouseCommands(tokenString []string) {
	switch tokenString[0] {
	case "details":
		event.GlobalBind(mouseDetails, "MouseRelease")
	default:
		fmt.Println("Bad Mouse Input")
	}
}

func moveWindow(in []string) {
	if len(in) < 4 {
		dlog.Error("Insufficient integer arguments for moving window")
		return
	}
	ints := make([]int, 4)
	var err error
	for i := range ints {
		ints[i], err = strconv.Atoi(in[i])
		if err != nil {
			dlog.Error(err)
			return
		}
	}
	err = MoveWindow(ints[0], ints[1], ints[2], ints[3])
	dlog.ErrorCheck(err)
}

func fullScreen(sub []string) {
	on := true
	if len(sub) > 0 {
		if sub[0] == "off" {
			on = false
		}
	}
	err := SetFullScreen(on)
	dlog.ErrorCheck(err)
}

// RunCommand runs a command added with AddCommand.
// It's intended use is making it easier to
// alias commands/subcommands.
// It returns an error if the command doesn't exist.
func RunCommand(cmd string, args ...string) error {
	fn, ok := commands[cmd]
	if ok == false {
		return fmt.Errorf("Unknown command %s",cmd)
	}
	fn(args)
	return nil
}
<commit_msg>chore reduce panic potential in debug console.<commit_after>package oak

import (
	"bufio"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"

	"github.com/oakmound/oak/v2/oakerr"

	"github.com/davecgh/go-spew/spew"
	"github.com/oakmound/oak/v2/collision"
	"github.com/oakmound/oak/v2/dlog"
	"github.com/oakmound/oak/v2/event"
	"github.com/oakmound/oak/v2/mouse"
	"github.com/oakmound/oak/v2/render"
	"github.com/oakmound/oak/v2/render/mod"
)

var (
	viewportLocked = true
	commands       = make(map[string]func([]string))
)

// AddCommand adds a console command to call fn when
// '<s> <args>' is input to the console. fn will be called
// with args split on whitespace.
func AddCommand(s string, fn func([]string)) error {
	if _, ok := commands[s]; ok {
		return oakerr.ExistingElement{
			InputName:   "s",
			InputType:   "string",
			Overwritten: false,
		}
	}
	dlog.Info("Adding command", s)
	commands[s] = fn
	return nil
}

// ForceAddCommand adds or overwrites a console command to call fn when
// '<s> <args>' is input to the console. fn will be called
// with args split on whitespace. If a command is overwritten
// the overwritten command will be returned.
func ForceAddCommand(s string, fn func([]string)) func([]string) {

	existing, overwritten := commands[s]
	if overwritten {
		dlog.Info("Overwriting command", s)
	} else {
		dlog.Info("Adding command", s)
	}
	commands[s] = fn
	return existing
}

// ClearCommand clears an existing debug command by key: <s>
func ClearCommand(s string) {
	delete(commands, s)
}

// ResetCommands will throw out all existing debug commands from the
// debug console.
func ResetCommands() {
	commands = map[string]func([]string){}
}

// GetDebugKeys returns the current debug console commands as a string array
func GetDebugKeys() []string {
	dkeys := make([]string, len(commands))
	i := 0
	for k := range commands {
		dkeys[i] = k
		i++
	}
	return dkeys
}

func debugConsole(resetCh, skipScene chan bool, input io.Reader) {
	scanner := bufio.NewScanner(input)
	spew.Config.DisableMethods = true
	spew.Config.MaxDepth = 2

	// built in commands
	if conf.LoadBuiltinCommands {
		dlog.ErrorCheck(AddCommand("viewport", viewportCommands))
		dlog.ErrorCheck(AddCommand("fade", fadeCommands))
		dlog.ErrorCheck(AddCommand("skip", skipCommands(skipScene)))
		dlog.ErrorCheck(AddCommand("print", printCommands))
		dlog.ErrorCheck(AddCommand("mouse", mouseCommands))
		dlog.ErrorCheck(AddCommand("move", moveWindow))
		dlog.ErrorCheck(AddCommand("fullscreen", fullScreen))
		dlog.ErrorCheck(AddCommand("quit", func([]string) { Quit() }))
	}

	for {
		select {
		case <-resetCh: //reset all vars in debug console that save state
			viewportLocked = true
		default:
		}
		for scanner.Scan() {
			tokenString := strings.Fields(scanner.Text())
			if len(tokenString) == 0 {
				continue
			}
			if fn, ok := commands[tokenString[0]]; ok {
				fn(tokenString[1:])
			} else {
				fmt.Println("Unknown command", tokenString[0])
			}
		}
	}
}

func parseTokenAsInt(tokenString []string, arrIndex int, defaultVal int) int {
	if len(tokenString) > arrIndex {
		tmp, err := strconv.Atoi(tokenString[arrIndex])
		if err == nil {
			return tmp
		}
	}
	return defaultVal
}

func mouseDetails(nothing int, mevent interface{}) int {
	me := mevent.(mouse.Event)
	x := int(me.X()) + ViewPos.X
	y := int(me.Y()) + ViewPos.Y
	loc := collision.NewUnassignedSpace(float64(x), float64(y), 16, 16)
	results := collision.Hits(loc)
	fmt.Println("Mouse at:", x, y, "rel:", me.X(), me.Y())
	if len(results) == 0 {
		results = mouse.Hits(loc)
	}
	if len(results) > 0 {
		i := int(results[0].CID)
		if i > 0 && event.HasEntity(i) {
			e := event.GetEntity(i)
			spew.Dump(e)
		} else {
			fmt.Println("No entity ", i)
		}
	}

	return 0
}

func viewportCommands(tokenString []string) {
	if len(tokenString) > 0 {
		fmt.Println("Input must start with the name of the viewport operation to perform.")
		return
	}
	switch tokenString[0] {
	case "unlock":
		if viewportLocked {
			speed := parseTokenAsInt(tokenString, 1, 5)
			viewportLocked = false
			event.GlobalBind(moveViewportBinding(speed), event.Enter)
		} else {
			fmt.Println("Viewport is already unbound")
		}
	case "lock":
		if viewportLocked {
			fmt.Println("Viewport is already locked")
		} else {
			viewportLocked = true
		}
	default:
		fmt.Println("Unrecognized command for viewport")
	}
}

func fadeCommands(tokenString []string) {
	if len(tokenString) > 0 {
		fmt.Println("Input must start with the name of the renderable to fade")
		return
	}
	toFade, ok := render.GetDebugRenderable(tokenString[0])
	fadeVal := parseTokenAsInt(tokenString, 1, 255)
	if ok {
		toFade.(render.Modifiable).Filter(mod.Fade(fadeVal))
	} else {
		fmt.Println("Could not fade input")
	}
}

func skipCommands(skipScene chan bool) func(tokenString []string) {
	return func(tokenString []string) {
		if len(tokenString) != 1 {
			fmt.Println("Input must be a single string from the following (\"scene\"). ")
			return
		}
		switch tokenString[0] {
		case "scene":
			skipScene <- true
		default:
			fmt.Println("Bad Skip Input")
		}
	}
}

func printCommands(tokenString []string) {
	if len(tokenString) != 1 {
		fmt.Println("Input must be a single number that corresponds to an entity.")
		return
	}
	i, err := strconv.Atoi(tokenString[0])
	if err != nil {
		fmt.Println("Unable to parse", tokenString[0])
		return
	}
	if i > 0 && event.HasEntity(i) {
		e := event.GetEntity(i)
		fmt.Println(reflect.TypeOf(e), e)
	} else {
		fmt.Println("No entity ", i)
	}

}

func mouseCommands(tokenString []string) {
	if len(tokenString) != 1 {
		fmt.Println("Input must be a single string from the following (\"details\") ")
		return
	}
	switch tokenString[0] {
	case "details":
		event.GlobalBind(mouseDetails, "MouseRelease")
	default:
		fmt.Println("Bad Mouse Input")
	}
}

func moveWindow(in []string) {
	if len(in) < 4 {
		dlog.Error("Insufficient integer arguments for moving window")
		return
	}
	ints := make([]int, 4)
	var err error
	for i := range ints {
		ints[i], err = strconv.Atoi(in[i])
		if err != nil {
			dlog.Error(err)
			return
		}
	}
	err = MoveWindow(ints[0], ints[1], ints[2], ints[3])
	dlog.ErrorCheck(err)
}

func fullScreen(sub []string) {
	on := true
	if len(sub) > 0 {
		if sub[0] == "off" {
			on = false
		}
	}
	err := SetFullScreen(on)
	dlog.ErrorCheck(err)
}

// RunCommand runs a command added with AddCommand.
// It's intended use is making it easier to
// alias commands/subcommands.
// It returns an error if the command doesn't exist.
func RunCommand(cmd string, args ...string) error {
	fn, ok := commands[cmd]
	if ok == false {
		return fmt.Errorf("Unknown command %s", cmd)
	}
	fn(args)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"strings"
	"text/template"
)

type generateOption struct {
	formatGoCode bool

	outputData []byte
}

// 字段首字母大写
func publicFieldName(name string) string {
	return strings.ToUpper(string(name[0])) + name[1:]
}

func generateCode(templateName, templateStr, output string, model interface{}, opt *generateOption) {

	var err error

	if opt == nil {
		opt = &generateOption{}
	}

	var bf bytes.Buffer

	tpl, err := template.New(templateName).Parse(templateStr)
	if err != nil {
		goto OnError
	}

	err = tpl.Execute(&bf, model)
	if err != nil {
		goto OnError
	}

	if opt.formatGoCode {
		if err = formatCode(&bf); err != nil {
			fmt.Println("format golang code err", err)
		}
	}

	opt.outputData = bf.Bytes()

	if output != "" {

		err = ioutil.WriteFile(output, bf.Bytes(), 0666)

		if err != nil {
			goto OnError
		}
	}
	return

OnError:
	fmt.Println(err)
	os.Exit(1)
}

func formatCode(bf *bytes.Buffer) error {

	fset := token.NewFileSet()

	ast, err := parser.ParseFile(fset, "", bf, parser.ParseComments)
	if err != nil {
		return err
	}

	bf.Reset()

	err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(bf, fset, ast)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>fixed : output file when dir is not ready<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

type generateOption struct {
	formatGoCode bool

	outputData []byte
}

// 字段首字母大写
func publicFieldName(name string) string {
	return strings.ToUpper(string(name[0])) + name[1:]
}

func generateCode(templateName, templateStr, output string, model interface{}, opt *generateOption) {

	var err error

	if opt == nil {
		opt = &generateOption{}
	}

	var bf bytes.Buffer

	tpl, err := template.New(templateName).Parse(templateStr)
	if err != nil {
		goto OnError
	}

	err = tpl.Execute(&bf, model)
	if err != nil {
		goto OnError
	}

	if opt.formatGoCode {
		if err = formatCode(&bf); err != nil {
			fmt.Println("format golang code err", err)
		}
	}

	opt.outputData = bf.Bytes()

	if output != "" {

		os.MkdirAll(filepath.Dir(output), 666)

		err = ioutil.WriteFile(output, bf.Bytes(), 0666)

		if err != nil {
			goto OnError
		}
	}
	return

OnError:
	fmt.Println(err)
	os.Exit(1)
}

func formatCode(bf *bytes.Buffer) error {

	fset := token.NewFileSet()

	ast, err := parser.ParseFile(fset, "", bf, parser.ParseComments)
	if err != nil {
		return err
	}

	bf.Reset()

	err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(bf, fset, ast)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>Factor out encryption/decryption top-level from file management.<commit_after><|endoftext|>


<commit_before>/*
	Package seo4ajax provides a library for accessing the SEO4Ajax prerender service.
	Before using, you need to set ServerIp to a valid IP address.
*/
package seo4ajax

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/go-kit/kit/log"
)

var (
	// ErrNoToken is returned when the client isn't provided a API token
	ErrNoToken = errors.New("no token given")
	// seo4ajax responded with a cache miss
	ErrCacheMiss     = errors.New("cache miss from seo4ajax")
	ErrUnknownStatus = errors.New("Unkonwn Status Code")
	errRedirect      = errors.New("SEO4AJAX: do not follow redirect")

	regexInvalidUserAgent = regexp.MustCompile(`(?i:bing|msnbot|yandexbot|pinterest.*ios|mail\.ru)`)
	regexValidUserAgent   = regexp.MustCompile(`(?i:bot|google|crawler|spider|archiver|pinterest|facebookexternalhit|flipboardproxy)`)
	regexPath             = regexp.MustCompile(`.*(\.[^?]{2,4}$|\.[^?]{2,4}?.*)`)
)

// Config is the Seo4Ajax Client config
type Config struct {
	Log       log.Logger
	Next      http.Handler
	Transport http.RoundTripper
	Server    string        // seo4ajax api server, defaults to http://api.seo4ajax.com
	Token     string        // seo4ajax token, must be set
	IP        string        // server IP, defaults to 127.0.0.1
	Timeout   time.Duration // retry timeout, defaults to 30s
	// s4a supports client side caching and returns an empty 304 if the content hasn't changed.
	// If UnconditionalFetch set to true the client side caching headers (If-Modified-Since and If-None-Match)
	// are removed
	UnconditionalFetch bool
	// FetchErrorStatus is the http status code returned if the fetch from seo4ajax fails
	FetchErrorStatus int
	// FetchTimeout is the http timeout for a single fetch attempt
	FetchTimeout time.Duration
}

// Client is the Seo4Ajax Client
type Client struct {
	log                log.Logger
	next               http.Handler
	server             string
	token              string
	ip                 string
	timeout            time.Duration
	http               *http.Client
	unconditionalFetch bool
	fetchErrorStatus   int
	fetchTimeout       time.Duration
}

// New creates a new Seo4Ajax client. Returns an error if no token is provided
func New(cfg Config) (*Client, error) {
	if cfg.Log == nil {
		cfg.Log = log.NewNopLogger()
	}
	if cfg.Server == "" {
		cfg.Server = "http://api.seo4ajax.com"
	}
	if cfg.Token == "" {
		return nil, ErrNoToken
	}
	if cfg.IP == "" {
		cfg.IP = "127.0.0.1"
	}
	if cfg.Timeout < time.Second {
		cfg.Timeout = 30 * time.Second
	}
	if cfg.Transport == nil {
		cfg.Transport = http.DefaultTransport
	}
	if cfg.FetchErrorStatus == 0 {
		cfg.FetchErrorStatus = http.StatusServiceUnavailable
	}

	c := &Client{
		log:                cfg.Log,
		server:             cfg.Server,
		token:              cfg.Token,
		ip:                 cfg.IP,
		timeout:            cfg.Timeout,
		next:               cfg.Next,
		unconditionalFetch: cfg.UnconditionalFetch,
		fetchErrorStatus:   cfg.FetchErrorStatus,
	}
	c.http = &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return errRedirect
		},
		Transport: cfg.Transport,
	}
	if cfg.FetchTimeout > 0 {
		c.http.Timeout = cfg.FetchTimeout
	}
	return c, nil
}

// IsPrerender returns true, when Seo4Ajax shall be used for the given http Request.
// The logic is taken from https://github.com/seo4ajax/connect-s4a/blob/master/lib/connect-s4a.js
func IsPrerender(r *http.Request) bool {
	if r.Method != "GET" && r.Method != "HEAD" {
		return false
	}

	if strings.Contains(r.URL.RawQuery, "_escaped_fragment_") {
		return true
	}

	if regexInvalidUserAgent.MatchString(r.Header.Get("User-Agent")) {
		return false
	}

	if regexPath.MatchString(r.URL.Path) {
		return false
	}

	return regexValidUserAgent.MatchString(r.Header.Get("User-Agent"))
}

// ServeHTTP will serve the prerendered page if this is a prerender request.
// If no upstream handler is set it will return an error. Otherwise it will
// just invoke the upstream handler. This way it can be either used as an
// HTTP middleware intercepting any prerender requests or an regular HTTP
// handler (if next is nil) to serve only prerender request
func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if IsPrerender(r) {
		c.GetPrerenderedPage(w, r)
		return
	}

	if c.next == nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	c.next.ServeHTTP(w, r)
	return
}

// GetPrerenderedPage returns the prerendered html from the seo4ajax api
func (c *Client) GetPrerenderedPage(w http.ResponseWriter, r *http.Request) {
	var outputStarted bool
	opFunc := func() error {
		req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s%s", c.server, c.token, cleanPath(r.URL)), nil)
		if err != nil {
			return err
		}

		req.Header = r.Header
		ips := []string{c.ip}
		if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
			ips = append(ips, xff)
		}
		req.Header.Set("X-Forwarded-For", strings.Join(ips, ", "))

		if c.unconditionalFetch {
			req.Header.Del("If-Modified-Since")
			req.Header.Del("If-None-Match")
		}

		resp, err := c.http.Do(req)
		if err != nil && !strings.HasSuffix(err.Error(), errRedirect.Error()) {
			return err
		}
		defer resp.Body.Close()

		if resp.StatusCode == http.StatusFound {
			http.Redirect(w, r, resp.Header.Get("Location"), http.StatusFound)
			return nil
		}

		if resp.StatusCode != http.StatusOK {
			// retry
			return fmt.Errorf("expected 200 status code, got %d", resp.StatusCode)
		}

		for header, val := range resp.Header {
			w.Header()[header] = val
		}

		outputStarted = true
		// as soon as we start writing the body we must return nil, otherwise we'll
		// mess up the HTTP response by calling response.WriteHeader multiple times
		_, err = io.Copy(w, resp.Body)
		return err
	}

	bo := backoff.NewExponentialBackOff()
	bo.InitialInterval = 50 * time.Millisecond
	bo.MaxInterval = 30 * time.Second
	if c.timeout > 0 {
		bo.MaxElapsedTime = c.timeout
	}
	err := backoff.Retry(opFunc, bo)
	if err != nil {
		c.log.Log("level", "warn", "msg", "Upstream request failed", "err", err)
		if !outputStarted {
			http.Error(w, "Upstream error", c.fetchErrorStatus)
			return
		}
	}
	return
}

func cleanPath(u *url.URL) string {
	cpy := *u
	if len(cpy.Path) == 0 {
		cpy.Path = "/"
	} else if cpy.Path[0] != '/' {
		cpy.Path = "/" + cpy.Path
	}

	cpy.Scheme = ""
	cpy.Opaque = ""
	cpy.User = nil
	cpy.Host = ""

	return cpy.String()
}
<commit_msg>add conditional bailout on 503 upstream responses<commit_after>/*
	Package seo4ajax provides a library for accessing the SEO4Ajax prerender service.
	Before using, you need to set ServerIp to a valid IP address.
*/
package seo4ajax

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/go-kit/kit/log"
)

var (
	// ErrNoToken is returned when the client isn't provided a API token
	ErrNoToken = errors.New("no token given")
	// seo4ajax responded with a cache miss
	ErrCacheMiss     = errors.New("cache miss from seo4ajax")
	ErrUnknownStatus = errors.New("Unkonwn Status Code")
	errRedirect      = errors.New("SEO4AJAX: do not follow redirect")

	regexInvalidUserAgent = regexp.MustCompile(`(?i:bing|msnbot|yandexbot|pinterest.*ios|mail\.ru)`)
	regexValidUserAgent   = regexp.MustCompile(`(?i:bot|google|crawler|spider|archiver|pinterest|facebookexternalhit|flipboardproxy)`)
	regexPath             = regexp.MustCompile(`.*(\.[^?]{2,4}$|\.[^?]{2,4}?.*)`)
)

// Config is the Seo4Ajax Client config
type Config struct {
	Log       log.Logger
	Next      http.Handler
	Transport http.RoundTripper
	Server    string        // seo4ajax api server, defaults to http://api.seo4ajax.com
	Token     string        // seo4ajax token, must be set
	IP        string        // server IP, defaults to 127.0.0.1
	Timeout   time.Duration // retry timeout, defaults to 30s
	// s4a supports client side caching and returns an empty 304 if the content hasn't changed.
	// If UnconditionalFetch set to true the client side caching headers (If-Modified-Since and If-None-Match)
	// are removed
	UnconditionalFetch bool
	// FetchErrorStatus is the http status code returned if the fetch from seo4ajax fails
	FetchErrorStatus int
	// FetchTimeout is the http timeout for a single fetch attempt
	FetchTimeout time.Duration
	// RetryUnavailable advises the retry loop to retry a fetch on 503 upstream results until success or Timeout
	RetryUnavailable bool
}

// Client is the Seo4Ajax Client
type Client struct {
	log                log.Logger
	next               http.Handler
	server             string
	token              string
	ip                 string
	timeout            time.Duration
	http               *http.Client
	unconditionalFetch bool
	fetchErrorStatus   int
	fetchTimeout       time.Duration
	retryUnavailable   bool
}

// New creates a new Seo4Ajax client. Returns an error if no token is provided
func New(cfg Config) (*Client, error) {
	if cfg.Log == nil {
		cfg.Log = log.NewNopLogger()
	}
	if cfg.Server == "" {
		cfg.Server = "http://api.seo4ajax.com"
	}
	if cfg.Token == "" {
		return nil, ErrNoToken
	}
	if cfg.IP == "" {
		cfg.IP = "127.0.0.1"
	}
	if cfg.Timeout < time.Second {
		cfg.Timeout = 30 * time.Second
	}
	if cfg.Transport == nil {
		cfg.Transport = http.DefaultTransport
	}
	if cfg.FetchErrorStatus == 0 {
		cfg.FetchErrorStatus = http.StatusServiceUnavailable
	}

	c := &Client{
		log:                cfg.Log,
		server:             cfg.Server,
		token:              cfg.Token,
		ip:                 cfg.IP,
		timeout:            cfg.Timeout,
		next:               cfg.Next,
		unconditionalFetch: cfg.UnconditionalFetch,
		fetchErrorStatus:   cfg.FetchErrorStatus,
		retryUnavailable:   cfg.RetryUnavailable,
	}
	c.http = &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return errRedirect
		},
		Transport: cfg.Transport,
	}
	if cfg.FetchTimeout > 0 {
		c.http.Timeout = cfg.FetchTimeout
	}
	return c, nil
}

// IsPrerender returns true, when Seo4Ajax shall be used for the given http Request.
// The logic is taken from https://github.com/seo4ajax/connect-s4a/blob/master/lib/connect-s4a.js
func IsPrerender(r *http.Request) bool {
	if r.Method != "GET" && r.Method != "HEAD" {
		return false
	}

	if strings.Contains(r.URL.RawQuery, "_escaped_fragment_") {
		return true
	}

	if regexInvalidUserAgent.MatchString(r.Header.Get("User-Agent")) {
		return false
	}

	if regexPath.MatchString(r.URL.Path) {
		return false
	}

	return regexValidUserAgent.MatchString(r.Header.Get("User-Agent"))
}

// ServeHTTP will serve the prerendered page if this is a prerender request.
// If no upstream handler is set it will return an error. Otherwise it will
// just invoke the upstream handler. This way it can be either used as an
// HTTP middleware intercepting any prerender requests or an regular HTTP
// handler (if next is nil) to serve only prerender request
func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if IsPrerender(r) {
		c.GetPrerenderedPage(w, r)
		return
	}

	if c.next == nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	c.next.ServeHTTP(w, r)
	return
}

// GetPrerenderedPage returns the prerendered html from the seo4ajax api
func (c *Client) GetPrerenderedPage(w http.ResponseWriter, r *http.Request) {
	var outputStarted bool
	opFunc := func() error {
		req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s%s", c.server, c.token, cleanPath(r.URL)), nil)
		if err != nil {
			return err
		}

		req.Header = r.Header
		ips := []string{c.ip}
		if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
			ips = append(ips, xff)
		}
		req.Header.Set("X-Forwarded-For", strings.Join(ips, ", "))

		if c.unconditionalFetch {
			req.Header.Del("If-Modified-Since")
			req.Header.Del("If-None-Match")
		}

		resp, err := c.http.Do(req)
		if err != nil && !strings.HasSuffix(err.Error(), errRedirect.Error()) {
			return err
		}
		defer resp.Body.Close()

		if resp.StatusCode == http.StatusFound {
			http.Redirect(w, r, resp.Header.Get("Location"), http.StatusFound)
			return nil
		}

		// conditionally terminate retry loop if the status code is 503
		if !c.retryUnavailable {
			if resp.StatusCode == http.StatusServiceUnavailable {
				return backoff.Permanent(errors.New("page not yet rendered"))
			}
		}

		if resp.StatusCode != http.StatusOK {
			// retry
			return fmt.Errorf("expected 200 status code, got %d", resp.StatusCode)
		}

		for header, val := range resp.Header {
			w.Header()[header] = val
		}

		outputStarted = true
		// as soon as we start writing the body we must return nil, otherwise we'll
		// mess up the HTTP response by calling response.WriteHeader multiple times
		_, err = io.Copy(w, resp.Body)
		return err
	}

	bo := backoff.NewExponentialBackOff()
	bo.InitialInterval = 50 * time.Millisecond
	bo.MaxInterval = 30 * time.Second
	if c.timeout > 0 {
		bo.MaxElapsedTime = c.timeout
	}
	err := backoff.Retry(opFunc, bo)
	if err != nil {
		c.log.Log("level", "warn", "msg", "Upstream request failed", "err", err)
		if !outputStarted {
			http.Error(w, "Upstream error", c.fetchErrorStatus)
			return
		}
	}
	return
}

func cleanPath(u *url.URL) string {
	cpy := *u
	if len(cpy.Path) == 0 {
		cpy.Path = "/"
	} else if cpy.Path[0] != '/' {
		cpy.Path = "/" + cpy.Path
	}

	cpy.Scheme = ""
	cpy.Opaque = ""
	cpy.User = nil
	cpy.Host = ""

	return cpy.String()
}
<|endoftext|>


<commit_before><commit_msg>Add Sequence.OffFade<commit_after><|endoftext|>


<commit_before>package main

import (
	. "rapid"
)

type Temp struct {
	Name string
}

func main() {

	Route("/", func(c Connection) string {
		return c.View("index.html")
	})

	Route("/test", func(c Connection) string {

		obj := Temp{"Dominic"}
		return c.Render("test.html", obj)
	})

	Route("/hello", func(c Connection) string {
		return "Testing"
	})

	PublicFolder("public")

	StartServer(3000)
}
<commit_msg>Updated demo to use anonymous struct<commit_after>package main

import (
	. "rapid"
)

func main() {

	Route("/", func(c Connection) string {
		return c.View("index.html")
	})

	Route("/test", func(c Connection) string {

		obj := struct {
			Name string
		}{"Dominic"}
		return c.Render("test.html", obj)
	})

	Route("/hello", func(c Connection) string {
		return "Testing"
	})

	PublicFolder("public")

	StartServer(3000)
}
<|endoftext|>


<commit_before>package medtronic

import (
	"time"
)

const (
	Settings CommandCode = 0xC0
)

type SettingsInfo struct {
	AutoOff              time.Duration
	InsulinAction        time.Duration
	InsulinConcentration int // 50 or 100
	MaxBolus             int // milliUnits
	MaxBasal             int // milliUnits
	RfEnabled            bool
	SelectedPattern      int
}

func (pump *Pump) Settings() SettingsInfo {
	// Format of response depends on the pump family.
	newer := pump.Family() >= 23
	result := pump.Execute(Settings, func(data []byte) interface{} {
		if newer {
			if len(data) < 26 || data[0] != 25 {
				return nil
			}
		} else {
			if len(data) < 22 || data[0] != 21 {
				return nil
			}
		}
		info := SettingsInfo{
			AutoOff:          time.Duration(data[1]) * time.Hour,
			MaxBolus:         int(data[6]) * 100,
			SelectedPattern: int(data[12]),
			RfEnabled:        data[13] == 1,
			InsulinAction:    time.Duration(data[18]) * time.Hour,
		}
		switch data[10] {
		case 0:
			info.InsulinConcentration = 100
		case 1:
			info.InsulinConcentration = 50
		default:
			return nil
		}
		if newer {
			info.MaxBasal = twoByteInt(data[8:10]) * 25
		} else {
			info.MaxBasal = twoByteInt(data[7:9]) * 100
		}
		return info
	})
	if pump.Error() != nil {
		return SettingsInfo{}
	}
	return result.(SettingsInfo)
}
<commit_msg>gofmt settings.go<commit_after>package medtronic

import (
	"time"
)

const (
	Settings CommandCode = 0xC0
)

type SettingsInfo struct {
	AutoOff              time.Duration
	InsulinAction        time.Duration
	InsulinConcentration int // 50 or 100
	MaxBolus             int // milliUnits
	MaxBasal             int // milliUnits
	RfEnabled            bool
	SelectedPattern      int
}

func (pump *Pump) Settings() SettingsInfo {
	// Format of response depends on the pump family.
	newer := pump.Family() >= 23
	result := pump.Execute(Settings, func(data []byte) interface{} {
		if newer {
			if len(data) < 26 || data[0] != 25 {
				return nil
			}
		} else {
			if len(data) < 22 || data[0] != 21 {
				return nil
			}
		}
		info := SettingsInfo{
			AutoOff:         time.Duration(data[1]) * time.Hour,
			MaxBolus:        int(data[6]) * 100,
			SelectedPattern: int(data[12]),
			RfEnabled:       data[13] == 1,
			InsulinAction:   time.Duration(data[18]) * time.Hour,
		}
		switch data[10] {
		case 0:
			info.InsulinConcentration = 100
		case 1:
			info.InsulinConcentration = 50
		default:
			return nil
		}
		if newer {
			info.MaxBasal = twoByteInt(data[8:10]) * 25
		} else {
			info.MaxBasal = twoByteInt(data[7:9]) * 100
		}
		return info
	})
	if pump.Error() != nil {
		return SettingsInfo{}
	}
	return result.(SettingsInfo)
}
<|endoftext|>


<commit_before><commit_msg>Some things needs to be seen closer to when they are used<commit_after><|endoftext|>


<commit_before>package hoverfly

import (
	"os"
	"strconv"
	"sync"

	log "github.com/Sirupsen/logrus"
)

// Configuration - initial structure of configuration
type Configuration struct {
	AdminPort    string
	ProxyPort    string
	Mode         string
	Destination  string
	Middleware   string
	DatabaseName string

	Verbose     bool
	Development bool

	SecretKey          []byte
	JWTExpirationDelta int
	AuthEnabled        bool

	SL             *StoppableListener
	ProxyControlWG sync.WaitGroup

	mu sync.Mutex
}

// SetMode - provides safe way to set new mode
func (c *Configuration) SetMode(mode string) {
	c.mu.Lock()
	c.Mode = mode
	c.mu.Unlock()
}

// GetMode - provides safe way to get current mode
func (c *Configuration) GetMode() (mode string) {
	c.mu.Lock()
	mode = c.Mode
	c.mu.Unlock()
	return
}

// DefaultPort - default proxy port
const DefaultPort = "8500"

// DefaultAdminPort - default admin interface port
const DefaultAdminPort = "8888"

// DefaultDatabaseName - default database name that will be created
// or used by Hoverfly
const DefaultDatabaseName = "requests.db"

// DefaultJWTExpirationDelta - default token expiration if environment variable is no provided
const DefaultJWTExpirationDelta = 72

// Environment variables
const (
	HoverflyAuthEnabledEV     = "HoverflyAuthEnabled"
	HoverflySecretEV          = "HoverflySecret"
	HoverflyTokenExpirationEV = "HoverflyTokenExpiration"

	HoverflyAdminPortEV = "AdminPort"
	HoverflyProxyPortEV = "ProxyPort"

	HoverflyDBEV         = "HoverflyDB"
	HoverflyMiddlewareEV = "HoverflyMiddleware"
)

// InitSettings gets and returns initial configuration from env
// variables or sets defaults
func InitSettings() *Configuration {

	var appConfig Configuration
	// getting default admin interface port
	if os.Getenv(HoverflyAdminPortEV) != "" {
		appConfig.AdminPort = os.Getenv(HoverflyAdminPortEV)
	} else {
		appConfig.AdminPort = DefaultAdminPort
	}

	// getting proxy port
	if os.Getenv(HoverflyProxyPortEV) != "" {
		appConfig.ProxyPort = os.Getenv(HoverflyProxyPortEV)
	} else {
		appConfig.ProxyPort = DefaultPort
	}

	databaseName := os.Getenv(HoverflyDBEV)
	if databaseName == "" {
		databaseName = DefaultDatabaseName
	}
	appConfig.DatabaseName = databaseName

	if os.Getenv(HoverflySecretEV) != "" {
		appConfig.SecretKey = []byte(os.Getenv(HoverflySecretEV))
	} else {
		appConfig.SecretKey = GetRandomName(10)
	}

	if os.Getenv(HoverflyTokenExpirationEV) != "" {

		exp, err := strconv.Atoi(os.Getenv(HoverflyTokenExpirationEV))
		if err != nil {
			log.WithFields(log.Fields{
				"error":                   err.Error(),
				"HoverflyTokenExpiration": os.Getenv(HoverflyTokenExpirationEV),
			}).Error("failed to get token exipration delta, using default value")
			exp = DefaultJWTExpirationDelta
		}
		appConfig.JWTExpirationDelta = exp

	} else {
		appConfig.JWTExpirationDelta = DefaultJWTExpirationDelta
	}

	if os.Getenv(HoverflyAuthEnabledEV) == "true" {
		appConfig.AuthEnabled = true
	} else {
		appConfig.AuthEnabled = false
	}

	// middleware configuration
	appConfig.Middleware = os.Getenv(HoverflyMiddlewareEV)

	return &appConfig
}
<commit_msg>adde stopProxy function<commit_after>package hoverfly

import (
	"os"
	"strconv"
	"sync"

	log "github.com/Sirupsen/logrus"
)

// Configuration - initial structure of configuration
type Configuration struct {
	AdminPort    string
	ProxyPort    string
	Mode         string
	Destination  string
	Middleware   string
	DatabaseName string

	Verbose     bool
	Development bool

	SecretKey          []byte
	JWTExpirationDelta int
	AuthEnabled        bool

	SL             *StoppableListener
	ProxyControlWG sync.WaitGroup

	mu sync.Mutex
}

// SetMode - provides safe way to set new mode
func (c *Configuration) SetMode(mode string) {
	c.mu.Lock()
	c.Mode = mode
	c.mu.Unlock()
}

// GetMode - provides safe way to get current mode
func (c *Configuration) GetMode() (mode string) {
	c.mu.Lock()
	mode = c.Mode
	c.mu.Unlock()
	return
}

// StopProxy - stops proxy
func (c *Configuration) StopProxy() {
	c.mu.Lock()
	c.SL.Stop()
	c.ProxyControlWG.Wait()
	c.mu.Unlock()
}

// DefaultPort - default proxy port
const DefaultPort = "8500"

// DefaultAdminPort - default admin interface port
const DefaultAdminPort = "8888"

// DefaultDatabaseName - default database name that will be created
// or used by Hoverfly
const DefaultDatabaseName = "requests.db"

// DefaultJWTExpirationDelta - default token expiration if environment variable is no provided
const DefaultJWTExpirationDelta = 72

// Environment variables
const (
	HoverflyAuthEnabledEV     = "HoverflyAuthEnabled"
	HoverflySecretEV          = "HoverflySecret"
	HoverflyTokenExpirationEV = "HoverflyTokenExpiration"

	HoverflyAdminPortEV = "AdminPort"
	HoverflyProxyPortEV = "ProxyPort"

	HoverflyDBEV         = "HoverflyDB"
	HoverflyMiddlewareEV = "HoverflyMiddleware"
)

// InitSettings gets and returns initial configuration from env
// variables or sets defaults
func InitSettings() *Configuration {

	var appConfig Configuration
	// getting default admin interface port
	if os.Getenv(HoverflyAdminPortEV) != "" {
		appConfig.AdminPort = os.Getenv(HoverflyAdminPortEV)
	} else {
		appConfig.AdminPort = DefaultAdminPort
	}

	// getting proxy port
	if os.Getenv(HoverflyProxyPortEV) != "" {
		appConfig.ProxyPort = os.Getenv(HoverflyProxyPortEV)
	} else {
		appConfig.ProxyPort = DefaultPort
	}

	databaseName := os.Getenv(HoverflyDBEV)
	if databaseName == "" {
		databaseName = DefaultDatabaseName
	}
	appConfig.DatabaseName = databaseName

	if os.Getenv(HoverflySecretEV) != "" {
		appConfig.SecretKey = []byte(os.Getenv(HoverflySecretEV))
	} else {
		appConfig.SecretKey = GetRandomName(10)
	}

	if os.Getenv(HoverflyTokenExpirationEV) != "" {

		exp, err := strconv.Atoi(os.Getenv(HoverflyTokenExpirationEV))
		if err != nil {
			log.WithFields(log.Fields{
				"error":                   err.Error(),
				"HoverflyTokenExpiration": os.Getenv(HoverflyTokenExpirationEV),
			}).Error("failed to get token exipration delta, using default value")
			exp = DefaultJWTExpirationDelta
		}
		appConfig.JWTExpirationDelta = exp

	} else {
		appConfig.JWTExpirationDelta = DefaultJWTExpirationDelta
	}

	if os.Getenv(HoverflyAuthEnabledEV) == "true" {
		appConfig.AuthEnabled = true
	} else {
		appConfig.AuthEnabled = false
	}

	// middleware configuration
	appConfig.Middleware = os.Getenv(HoverflyMiddlewareEV)

	return &appConfig
}
<|endoftext|>


<commit_before>package shell

import (
	"fmt"
	"github.com/iuv/xx/base"
	"strings"
)

func Ip(port string) {
	sys := base.Sys()
	if sys == "mac" {
		exe("en0", "inet ", port)
	} else if sys == "linux" {
		exe("eth0", "inet ", port)
	}
}

func exe(e, key, port string) {
	ret := base.Exec("ifconfig")
	en0 := strings.Index(ret, e)
	inet := en0 + strings.Index(ret[en0:], key) + 5
	end := inet + strings.Index(ret[inet:], " ")
	ret = ret[inet:end]
	addr := strings.Index(ret, "addr:")
	if addr > 0 {
		ret = ret[addr+5:]
	}
	fmt.Println("Local IP: " + ret)
	fmt.Println("HTTP Server: http://" + ret)
	fmt.Println("HTTP Server: http://" + ret + ":8080")
	if port != "" {
		fmt.Println("HTTP Server: http://" + ret + ":" + port)
	}
	// 获取外网ip
	ret = base.Exec("curl ifconfig.io")
	if ret != "" && !strings.HasPrefix(ret, "curl") {
		fmt.Println("Public Network IP: " + ret)
	}
}
<commit_msg>修正获取ip异常情况（异常情况下默认输出所有本地ip）<commit_after>package shell

import (
	"fmt"
	"github.com/iuv/xx/base"
	"strings"
)

func Ip(port string) {
	sys := base.Sys()
	var ret int
	if sys == "mac" {
		ret = exe("en0", "inet ", port)
	} else if sys == "linux" {
		ret = exe("eth0", "inet ", port)
		if ret < 0 {
			ret = exe("ens33", "inet ", port)
		}
	}
	if ret < 0 {
		def(port)
	}
}

func def(port string) {
	ret := base.Exec("ifconfig")
	rets := strings.Split(ret, "\n")
	for _, ip := range rets {
		inet := strings.Index(ip, "inet ")
		if inet < 0 {
			continue
		}
		inet = inet + 5
		end := inet + strings.Index(ip[inet:], " ")
		ip = ip[inet:end]
		addr := strings.Index(ip, "addr:")
		if addr > 0 {
			ip = ip[addr+5:]
		}
		fmt.Println("Local IP: " + ip)
		if port != "" {
			fmt.Println("HTTP Server: http://" + ip + ":" + port)
		} else {
			fmt.Println("HTTP Server: http://" + ip)
			fmt.Println("HTTP Server: http://" + ip + ":8080")
		}
	}
	// 获取外网ip
	ret = base.Exec("curl ifconfig.io")
	if ret != "" && !strings.HasPrefix(ret, "curl") {
		fmt.Println("Public Network IP: " + ret)
	}
}

func exe(e, key, port string) int {
	ret := base.Exec("ifconfig")
	en0 := strings.Index(ret, e)
	if en0 < 0 {
		return en0
	}
	inet := en0 + strings.Index(ret[en0:], key) + 5
	end := inet + strings.Index(ret[inet:], " ")
	ret = ret[inet:end]
	addr := strings.Index(ret, "addr:")
	if addr > 0 {
		ret = ret[addr+5:]
	}
	fmt.Println("Local IP: " + ret)
	fmt.Println("HTTP Server: http://" + ret)
	fmt.Println("HTTP Server: http://" + ret + ":8080")
	if port != "" {
		fmt.Println("HTTP Server: http://" + ret + ":" + port)
	}
	// 获取外网ip
	ret = base.Exec("curl ifconfig.io")
	if ret != "" && !strings.HasPrefix(ret, "curl") {
		fmt.Println("Public Network IP: " + ret)
	}
	return 0
}
<|endoftext|>