<commit_before>package libnetwork

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/libnetwork/datastore"
)

func (c *controller) initStores() error {
	c.Lock()
	if c.cfg == nil {
		c.Unlock()
		return nil
	}
	scopeConfigs := c.cfg.Scopes
	c.Unlock()

	for scope, scfg := range scopeConfigs {
		store, err := datastore.NewDataStore(scope, scfg)
		if err != nil {
			return err
		}
		c.Lock()
		c.stores = append(c.stores, store)
		c.Unlock()
	}

	c.startWatch()
	return nil
}

func (c *controller) closeStores() {
	for _, store := range c.getStores() {
		store.Close()
	}
}

func (c *controller) getStore(scope string) datastore.DataStore {
	c.Lock()
	defer c.Unlock()

	for _, store := range c.stores {
		if store.Scope() == scope {
			return store
		}
	}

	return nil
}

func (c *controller) getStores() []datastore.DataStore {
	c.Lock()
	defer c.Unlock()

	return c.stores
}

func (c *controller) getNetworkFromStore(nid string) (*network, error) {
	for _, store := range c.getStores() {
		n := &network{id: nid, ctrlr: c}
		err := store.GetObject(datastore.Key(n.Key()...), n)
		if err != nil && err != datastore.ErrKeyNotFound {
			return nil, fmt.Errorf("could not find network %s: %v", nid, err)
		}

		// Continue searching in the next store if the key is not found in this store
		if err == datastore.ErrKeyNotFound {
			continue
		}

		ec := &endpointCnt{n: n}
		err = store.GetObject(datastore.Key(ec.Key()...), ec)
		if err != nil {
			return nil, fmt.Errorf("could not find endpoint count for network %s: %v", n.Name(), err)
		}

		n.epCnt = ec
		return n, nil
	}

	return nil, fmt.Errorf("network %s not found", nid)
}

func (c *controller) getNetworksForScope(scope string) ([]*network, error) {
	var nl []*network

	store := c.getStore(scope)
	if store == nil {
		return nil, nil
	}

	kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix),
		&network{ctrlr: c})
	if err != nil && err != datastore.ErrKeyNotFound {
		return nil, fmt.Errorf("failed to get networks for scope %s: %v",
			scope, err)
	}

	for _, kvo := range kvol {
		n := kvo.(*network)
		n.ctrlr = c

		ec := &endpointCnt{n: n}
		err = store.GetObject(datastore.Key(ec.Key()...), ec)
		if err != nil {
			return nil, fmt.Errorf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
		}

		n.epCnt = ec
		nl = append(nl, n)
	}

	return nl, nil
}

func (c *controller) getNetworksFromStore() ([]*network, error) {
	var nl []*network

	for _, store := range c.getStores() {
		kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix),
			&network{ctrlr: c})
		if err != nil && err != datastore.ErrKeyNotFound {
			return nil, fmt.Errorf("failed to get networks for scope %s: %v",
				store.Scope(), err)
		}

		// Continue searching in the next store if no keys found in this store
		if err == datastore.ErrKeyNotFound {
			continue
		}

		for _, kvo := range kvol {
			n := kvo.(*network)
			n.ctrlr = c

			ec := &endpointCnt{n: n}
			err = store.GetObject(datastore.Key(ec.Key()...), ec)
			if err != nil {
				return nil, fmt.Errorf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
			}

			n.epCnt = ec
			nl = append(nl, n)
		}
	}

	return nl, nil
}

func (n *network) getEndpointFromStore(eid string) (*endpoint, error) {
	for _, store := range n.ctrlr.getStores() {
		ep := &endpoint{id: eid, network: n}
		err := store.GetObject(datastore.Key(ep.Key()...), ep)
		if err != nil && err != datastore.ErrKeyNotFound {
			return nil, fmt.Errorf("could not find endpoint %s: %v", eid, err)
		}

		// Continue searching in the next store if the key is not found in this store
		if err == datastore.ErrKeyNotFound {
			continue
		}

		return ep, nil
	}

	return nil, fmt.Errorf("endpoint %s not found", eid)
}

func (n *network) getEndpointsFromStore() ([]*endpoint, error) {
	var epl []*endpoint

	tmp := endpoint{network: n}
	for _, store := range n.getController().getStores() {
		kvol, err := store.List(datastore.Key(tmp.KeyPrefix()...), &endpoint{network: n})
		if err != nil && err != datastore.ErrKeyNotFound {
			return nil,
				fmt.Errorf("failed to get endpoints for network %s scope %s: %v",
					n.Name(), store.Scope(), err)
		}

		// Continue searching in the next store if no keys found in this store
		if err == datastore.ErrKeyNotFound {
			continue
		}

		for _, kvo := range kvol {
			ep := kvo.(*endpoint)
			ep.network = n
			epl = append(epl, ep)
		}
	}

	return epl, nil
}

func (c *controller) updateToStore(kvObject datastore.KVObject) error {
	cs := c.getStore(kvObject.DataScope())
	if cs == nil {
		log.Warnf("datastore for scope %s not initialized. kv object %s is not added to the store", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
		return nil
	}

	if err := cs.PutObjectAtomic(kvObject); err != nil {
		if err == datastore.ErrKeyModified {
			return err
		}
		return fmt.Errorf("failed to update store for object type %T: %v", kvObject, err)
	}

	return nil
}

func (c *controller) deleteFromStore(kvObject datastore.KVObject) error {
	cs := c.getStore(kvObject.DataScope())
	if cs == nil {
		log.Debugf("datastore for scope %s not initialized. kv object %s is not deleted from datastore", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
		return nil
	}

retry:
	if err := cs.DeleteObjectAtomic(kvObject); err != nil {
		if err == datastore.ErrKeyModified {
			if err := cs.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
				return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
			}
			goto retry
		}
		return err
	}

	return nil
}

type netWatch struct {
	localEps  map[string]*endpoint
	remoteEps map[string]*endpoint
	stopCh    chan struct{}
}

func (c *controller) getLocalEps(nw *netWatch) []*endpoint {
	c.Lock()
	defer c.Unlock()

	var epl []*endpoint
	for _, ep := range nw.localEps {
		epl = append(epl, ep)
	}

	return epl
}

func (c *controller) watchSvcRecord(ep *endpoint) {
	c.watchCh <- ep
}

func (c *controller) unWatchSvcRecord(ep *endpoint) {
	c.unWatchCh <- ep
}

func (c *controller) networkWatchLoop(nw *netWatch, ep *endpoint, ecCh <-chan datastore.KVObject) {
	for {
		select {
		case <-nw.stopCh:
			return
		case o := <-ecCh:
			ec := o.(*endpointCnt)

			epl, err := ec.n.getEndpointsFromStore()
			if err != nil {
				break
			}

			c.Lock()
			var addEp []*endpoint

			delEpMap := make(map[string]*endpoint)
			for k, v := range nw.remoteEps {
				delEpMap[k] = v
			}

			for _, lEp := range epl {
				if _, ok := nw.localEps[lEp.ID()]; ok {
					continue
				}

				if _, ok := nw.remoteEps[lEp.ID()]; ok {
					delete(delEpMap, lEp.ID())
					continue
				}

				nw.remoteEps[lEp.ID()] = lEp
				addEp = append(addEp, lEp)

			}
			c.Unlock()

			for _, lEp := range addEp {
				ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), true)
			}

			for _, lEp := range delEpMap {
				ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), false)

			}
		}
	}
}

func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoint) {
	c.Lock()
	nw, ok := nmap[ep.getNetwork().ID()]
	c.Unlock()

	if ok {
		// Update the svc db for the local endpoint join right away
		ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)

		c.Lock()
		nw.localEps[ep.ID()] = ep
		c.Unlock()
		return
	}

	nw = &netWatch{
		localEps:  make(map[string]*endpoint),
		remoteEps: make(map[string]*endpoint),
	}

	// Update the svc db for the local endpoint join right away
	// Do this before adding this ep to localEps so that we don't
	// try to update this ep's container's svc records
	ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)

	c.Lock()
	nw.localEps[ep.ID()] = ep
	nmap[ep.getNetwork().ID()] = nw
	nw.stopCh = make(chan struct{})
	c.Unlock()

	store := c.getStore(ep.getNetwork().DataScope())
	if store == nil {
		return
	}

	if !store.Watchable() {
		return
	}

	ch, err := store.Watch(ep.getNetwork().getEpCnt(), nw.stopCh)
	if err != nil {
		log.Warnf("Error creating watch for network: %v", err)
		return
	}

	go c.networkWatchLoop(nw, ep, ch)
}

func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoint) {
	c.Lock()
	nw, ok := nmap[ep.getNetwork().ID()]

	if ok {
		delete(nw.localEps, ep.ID())
		c.Unlock()

		// Update the svc db about local endpoint leave right away
		// Do this after we remove this ep from localEps so that we
		// don't try to remove this svc record from this ep's container.
		ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), false)

		c.Lock()
		if len(nw.localEps) == 0 {
			close(nw.stopCh)
			delete(nmap, ep.getNetwork().ID())
		}
	}
	c.Unlock()
}

func (c *controller) watchLoop(nmap map[string]*netWatch) {
	for {
		select {
		case ep := <-c.watchCh:
			c.processEndpointCreate(nmap, ep)
		case ep := <-c.unWatchCh:
			c.processEndpointDelete(nmap, ep)
		}
	}
}

func (c *controller) startWatch() {
	c.watchCh = make(chan *endpoint)
	c.unWatchCh = make(chan *endpoint)
	nmap := make(map[string]*netWatch)

	go c.watchLoop(nmap)
}
<commit_msg>Dont fail the Get functions if there is an error in one of the stores<commit_after>package libnetwork

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/libnetwork/datastore"
)

func (c *controller) initStores() error {
	c.Lock()
	if c.cfg == nil {
		c.Unlock()
		return nil
	}
	scopeConfigs := c.cfg.Scopes
	c.Unlock()

	for scope, scfg := range scopeConfigs {
		store, err := datastore.NewDataStore(scope, scfg)
		if err != nil {
			return err
		}
		c.Lock()
		c.stores = append(c.stores, store)
		c.Unlock()
	}

	c.startWatch()
	return nil
}

func (c *controller) closeStores() {
	for _, store := range c.getStores() {
		store.Close()
	}
}

func (c *controller) getStore(scope string) datastore.DataStore {
	c.Lock()
	defer c.Unlock()

	for _, store := range c.stores {
		if store.Scope() == scope {
			return store
		}
	}

	return nil
}

func (c *controller) getStores() []datastore.DataStore {
	c.Lock()
	defer c.Unlock()

	return c.stores
}

func (c *controller) getNetworkFromStore(nid string) (*network, error) {
	for _, store := range c.getStores() {
		n := &network{id: nid, ctrlr: c}
		err := store.GetObject(datastore.Key(n.Key()...), n)
		// Continue searching in the next store if the key is not found in this store
		if err != nil {
			if err != datastore.ErrKeyNotFound {
				log.Debugf("could not find network %s: %v", nid, err)
			}
			continue
		}

		ec := &endpointCnt{n: n}
		err = store.GetObject(datastore.Key(ec.Key()...), ec)
		if err != nil {
			return nil, fmt.Errorf("could not find endpoint count for network %s: %v", n.Name(), err)
		}

		n.epCnt = ec
		return n, nil
	}

	return nil, fmt.Errorf("network %s not found", nid)
}

func (c *controller) getNetworksForScope(scope string) ([]*network, error) {
	var nl []*network

	store := c.getStore(scope)
	if store == nil {
		return nil, nil
	}

	kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix),
		&network{ctrlr: c})
	if err != nil && err != datastore.ErrKeyNotFound {
		return nil, fmt.Errorf("failed to get networks for scope %s: %v",
			scope, err)
	}

	for _, kvo := range kvol {
		n := kvo.(*network)
		n.ctrlr = c

		ec := &endpointCnt{n: n}
		err = store.GetObject(datastore.Key(ec.Key()...), ec)
		if err != nil {
			return nil, fmt.Errorf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
		}

		n.epCnt = ec
		nl = append(nl, n)
	}

	return nl, nil
}

func (c *controller) getNetworksFromStore() ([]*network, error) {
	var nl []*network

	for _, store := range c.getStores() {
		kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix),
			&network{ctrlr: c})
		// Continue searching in the next store if no keys found in this store
		if err != nil {
			if err != datastore.ErrKeyNotFound {
				log.Debugf("failed to get networks for scope %s: %v", store.Scope(), err)
			}
			continue
		}

		for _, kvo := range kvol {
			n := kvo.(*network)
			n.ctrlr = c

			ec := &endpointCnt{n: n}
			err = store.GetObject(datastore.Key(ec.Key()...), ec)
			if err != nil {
				return nil, fmt.Errorf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
			}

			n.epCnt = ec
			nl = append(nl, n)
		}
	}

	return nl, nil
}

func (n *network) getEndpointFromStore(eid string) (*endpoint, error) {
	store := n.ctrlr.getStore(n.Scope())
	if store == nil {
		return nil, fmt.Errorf("could not find endpoint %s: datastore not found for scope %s", eid, n.Scope())
	}

	ep := &endpoint{id: eid, network: n}
	err := store.GetObject(datastore.Key(ep.Key()...), ep)
	if err != nil {
		return nil, fmt.Errorf("could not find endpoint %s: %v", eid, err)
	}
	return ep, nil
}

func (n *network) getEndpointsFromStore() ([]*endpoint, error) {
	var epl []*endpoint

	tmp := endpoint{network: n}
	for _, store := range n.getController().getStores() {
		kvol, err := store.List(datastore.Key(tmp.KeyPrefix()...), &endpoint{network: n})
		// Continue searching in the next store if no keys found in this store
		if err != nil {
			if err != datastore.ErrKeyNotFound {
				log.Debugf("failed to get endpoints for network %s scope %s: %v",
					n.Name(), store.Scope(), err)
			}
			continue
		}

		for _, kvo := range kvol {
			ep := kvo.(*endpoint)
			ep.network = n
			epl = append(epl, ep)
		}
	}

	return epl, nil
}

func (c *controller) updateToStore(kvObject datastore.KVObject) error {
	cs := c.getStore(kvObject.DataScope())
	if cs == nil {
		log.Warnf("datastore for scope %s not initialized. kv object %s is not added to the store", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
		return nil
	}

	if err := cs.PutObjectAtomic(kvObject); err != nil {
		if err == datastore.ErrKeyModified {
			return err
		}
		return fmt.Errorf("failed to update store for object type %T: %v", kvObject, err)
	}

	return nil
}

func (c *controller) deleteFromStore(kvObject datastore.KVObject) error {
	cs := c.getStore(kvObject.DataScope())
	if cs == nil {
		log.Debugf("datastore for scope %s not initialized. kv object %s is not deleted from datastore", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
		return nil
	}

retry:
	if err := cs.DeleteObjectAtomic(kvObject); err != nil {
		if err == datastore.ErrKeyModified {
			if err := cs.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
				return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
			}
			goto retry
		}
		return err
	}

	return nil
}

type netWatch struct {
	localEps  map[string]*endpoint
	remoteEps map[string]*endpoint
	stopCh    chan struct{}
}

func (c *controller) getLocalEps(nw *netWatch) []*endpoint {
	c.Lock()
	defer c.Unlock()

	var epl []*endpoint
	for _, ep := range nw.localEps {
		epl = append(epl, ep)
	}

	return epl
}

func (c *controller) watchSvcRecord(ep *endpoint) {
	c.watchCh <- ep
}

func (c *controller) unWatchSvcRecord(ep *endpoint) {
	c.unWatchCh <- ep
}

func (c *controller) networkWatchLoop(nw *netWatch, ep *endpoint, ecCh <-chan datastore.KVObject) {
	for {
		select {
		case <-nw.stopCh:
			return
		case o := <-ecCh:
			ec := o.(*endpointCnt)

			epl, err := ec.n.getEndpointsFromStore()
			if err != nil {
				break
			}

			c.Lock()
			var addEp []*endpoint

			delEpMap := make(map[string]*endpoint)
			for k, v := range nw.remoteEps {
				delEpMap[k] = v
			}

			for _, lEp := range epl {
				if _, ok := nw.localEps[lEp.ID()]; ok {
					continue
				}

				if _, ok := nw.remoteEps[lEp.ID()]; ok {
					delete(delEpMap, lEp.ID())
					continue
				}

				nw.remoteEps[lEp.ID()] = lEp
				addEp = append(addEp, lEp)

			}
			c.Unlock()

			for _, lEp := range addEp {
				ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), true)
			}

			for _, lEp := range delEpMap {
				ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), false)

			}
		}
	}
}

func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoint) {
	c.Lock()
	nw, ok := nmap[ep.getNetwork().ID()]
	c.Unlock()

	if ok {
		// Update the svc db for the local endpoint join right away
		ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)

		c.Lock()
		nw.localEps[ep.ID()] = ep
		c.Unlock()
		return
	}

	nw = &netWatch{
		localEps:  make(map[string]*endpoint),
		remoteEps: make(map[string]*endpoint),
	}

	// Update the svc db for the local endpoint join right away
	// Do this before adding this ep to localEps so that we don't
	// try to update this ep's container's svc records
	ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)

	c.Lock()
	nw.localEps[ep.ID()] = ep
	nmap[ep.getNetwork().ID()] = nw
	nw.stopCh = make(chan struct{})
	c.Unlock()

	store := c.getStore(ep.getNetwork().DataScope())
	if store == nil {
		return
	}

	if !store.Watchable() {
		return
	}

	ch, err := store.Watch(ep.getNetwork().getEpCnt(), nw.stopCh)
	if err != nil {
		log.Warnf("Error creating watch for network: %v", err)
		return
	}

	go c.networkWatchLoop(nw, ep, ch)
}

func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoint) {
	c.Lock()
	nw, ok := nmap[ep.getNetwork().ID()]

	if ok {
		delete(nw.localEps, ep.ID())
		c.Unlock()

		// Update the svc db about local endpoint leave right away
		// Do this after we remove this ep from localEps so that we
		// don't try to remove this svc record from this ep's container.
		ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), false)

		c.Lock()
		if len(nw.localEps) == 0 {
			close(nw.stopCh)
			delete(nmap, ep.getNetwork().ID())
		}
	}
	c.Unlock()
}

func (c *controller) watchLoop(nmap map[string]*netWatch) {
	for {
		select {
		case ep := <-c.watchCh:
			c.processEndpointCreate(nmap, ep)
		case ep := <-c.unWatchCh:
			c.processEndpointDelete(nmap, ep)
		}
	}
}

func (c *controller) startWatch() {
	c.watchCh = make(chan *endpoint)
	c.unWatchCh = make(chan *endpoint)
	nmap := make(map[string]*netWatch)

	go c.watchLoop(nmap)
}
<|endoftext|>


<commit_before>package soy

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/slvmnd/soy/data"
	"github.com/slvmnd/soy/parse"
	"github.com/slvmnd/soy/parsepasses"
	"github.com/slvmnd/soy/soyhtml"
	"github.com/slvmnd/soy/template"
	"gopkg.in/fsnotify.v0"
)

// Logger is used to print notifications and compile errors when using the
// "WatchFiles" feature.
var Logger = log.New(os.Stderr, "[soy] ", 0)

type soyFile struct{ name, content string }

// Bundle is a collection of soy content (templates and globals).  It acts as
// input for the soy compiler.
type Bundle struct {
	files       []soyFile
	globals     data.Map
	err         error
	watcher     *fsnotify.Watcher
	Transformer func([]byte) ([]byte, error)
}

// NewBundle returns an empty bundle.
func NewBundle() *Bundle {
	return &Bundle{globals: make(data.Map)}
}

// WatchFiles tells soy to watch any template files added to this bundle,
// re-compile as necessary, and propagate the updates to your tofu.  It should
// be called once, before adding any files.
func (b *Bundle) WatchFiles(watch bool) *Bundle {
	if watch && b.err == nil && b.watcher == nil {
		b.watcher, b.err = fsnotify.NewWatcher()
	}
	return b
}

// AddTemplateDir adds all *.soy files found within the given directory
// (including sub-directories) to the bundle.
func (b *Bundle) AddTemplateDir(root string) *Bundle {
	var err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if !strings.HasSuffix(path, ".soy") {
			return nil
		}
		b.AddTemplateFile(path)
		return nil
	})
	if err != nil {
		b.err = err
	}
	return b
}

// AddTemplateFile adds the given soy template file text to this bundle.
// If WatchFiles is on, it will be subsequently watched for updates.
func (b *Bundle) AddTemplateFile(filename string) *Bundle {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		b.err = err
	}
	if b.err == nil && b.watcher != nil {
		b.err = b.watcher.Watch(filename)
	}
	if b.Transformer != nil {
		content, err = b.Transformer(content)
		if err != nil {
			b.err = fmt.Errorf("Error transforming file %s: %s", filename, err)
		}
	}
	return b.AddTemplateString(filename, string(content))
}

// AddTemplateString adds the given template to the bundle. The name is only
// used for error messages - it does not need to be provided nor does it need to
// be a real filename.
func (b *Bundle) AddTemplateString(filename, soyfile string) *Bundle {
	b.files = append(b.files, soyFile{filename, soyfile})
	return b
}

// AddGlobalsFile opens and parses the given filename for Soy globals, and adds
// the resulting data map to the bundle.
func (b *Bundle) AddGlobalsFile(filename string) *Bundle {
	var f, err = os.Open(filename)
	if err != nil {
		b.err = err
		return b
	}
	globals, err := ParseGlobals(f)
	if err != nil {
		b.err = err
	}
	return b.AddGlobalsMap(globals)
}

func (b *Bundle) AddGlobalsMap(globals data.Map) *Bundle {
	for k, v := range globals {
		if existing, ok := b.globals[k]; ok {
			b.err = fmt.Errorf("global %q already defined as %q", k, existing)
			return b
		}
		b.globals[k] = v
	}
	return b
}

// Compile parses all of the soy files in this bundle, verifies a number of
// rules about data references, and returns the completed template registry.
func (b *Bundle) Compile() (*template.Registry, error) {
	if b.err != nil {
		return nil, b.err
	}

	// Compile all the soy (globals are already parsed)
	var registry = template.Registry{}
	for _, soyfile := range b.files {
		var tree, err = parse.SoyFile(soyfile.name, soyfile.content, b.globals)
		if err != nil {
			return nil, err
		}
		if err = registry.Add(tree); err != nil {
			return nil, err
		}
	}

	// Apply the post-parse processing
	var err = parsepasses.CheckDataRefs(registry)
	if err != nil {
		return nil, err
	}

	if b.watcher != nil {
		go b.recompiler(&registry)
	}
	return &registry, nil
}

// CompileToTofu returns a soyhtml.Tofu object that allows you to render soy
// templates to HTML.
func (b *Bundle) CompileToTofu() (*soyhtml.Tofu, error) {
	var registry, err = b.Compile()
	// TODO: Verify all used funcs exist and have the right # args.
	return soyhtml.NewTofu(registry), err
}

func (b *Bundle) recompiler(reg *template.Registry) {
	for {
		select {
		case ev := <-b.watcher.Event:
			// If it's a rename, then fsnotify has removed the watch.
			// Add it back, after a delay.
			if ev.IsRename() || ev.IsDelete() {
				time.Sleep(10 * time.Millisecond)
				if err := b.watcher.Watch(ev.Name); err != nil {
					Logger.Println(err)
				}
			}

			// Recompile all the soy.
			var bundle = NewBundle().
				AddGlobalsMap(b.globals)
			bundle.Transformer = b.Transformer

			for _, soyfile := range b.files {
				bundle.AddTemplateFile(soyfile.name)
			}
			var registry, err = bundle.Compile()
			if err != nil {
				Logger.Println(err)
				continue
			}

			// update the existing template registry.
			// (this is not goroutine-safe, but that seems ok for a development aid,
			// as long as it works in practice)
			*reg = *registry
			Logger.Printf("update successful (%v)", ev)

		case err := <-b.watcher.Error:
			// Nothing to do with errors
			Logger.Println(err)
		}
	}
}
<commit_msg>update to newer fsnotify<commit_after>package soy

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/slvmnd/soy/data"
	"github.com/slvmnd/soy/parse"
	"github.com/slvmnd/soy/parsepasses"
	"github.com/slvmnd/soy/soyhtml"
	"github.com/slvmnd/soy/template"
)

// Logger is used to print notifications and compile errors when using the
// "WatchFiles" feature.
var Logger = log.New(os.Stderr, "[soy] ", 0)

type soyFile struct{ name, content string }

// Bundle is a collection of soy content (templates and globals).  It acts as
// input for the soy compiler.
type Bundle struct {
	files       []soyFile
	globals     data.Map
	err         error
	watcher     *fsnotify.Watcher
	Transformer func([]byte) ([]byte, error)
}

// NewBundle returns an empty bundle.
func NewBundle() *Bundle {
	return &Bundle{globals: make(data.Map)}
}

// WatchFiles tells soy to watch any template files added to this bundle,
// re-compile as necessary, and propagate the updates to your tofu.  It should
// be called once, before adding any files.
func (b *Bundle) WatchFiles(watch bool) *Bundle {
	if watch && b.err == nil && b.watcher == nil {
		b.watcher, b.err = fsnotify.NewWatcher()
	}
	return b
}

// AddTemplateDir adds all *.soy files found within the given directory
// (including sub-directories) to the bundle.
func (b *Bundle) AddTemplateDir(root string) *Bundle {
	var err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if !strings.HasSuffix(path, ".soy") {
			return nil
		}
		b.AddTemplateFile(path)
		return nil
	})
	if err != nil {
		b.err = err
	}
	return b
}

// AddTemplateFile adds the given soy template file text to this bundle.
// If WatchFiles is on, it will be subsequently watched for updates.
func (b *Bundle) AddTemplateFile(filename string) *Bundle {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		b.err = err
	}
	if b.err == nil && b.watcher != nil {
		b.err = b.watcher.Add(filename)
	}
	if b.Transformer != nil {
		content, err = b.Transformer(content)
		if err != nil {
			b.err = fmt.Errorf("Error transforming file %s: %s", filename, err)
		}
	}
	return b.AddTemplateString(filename, string(content))
}

// AddTemplateString adds the given template to the bundle. The name is only
// used for error messages - it does not need to be provided nor does it need to
// be a real filename.
func (b *Bundle) AddTemplateString(filename, soyfile string) *Bundle {
	b.files = append(b.files, soyFile{filename, soyfile})
	return b
}

// AddGlobalsFile opens and parses the given filename for Soy globals, and adds
// the resulting data map to the bundle.
func (b *Bundle) AddGlobalsFile(filename string) *Bundle {
	var f, err = os.Open(filename)
	if err != nil {
		b.err = err
		return b
	}
	globals, err := ParseGlobals(f)
	if err != nil {
		b.err = err
	}
	return b.AddGlobalsMap(globals)
}

func (b *Bundle) AddGlobalsMap(globals data.Map) *Bundle {
	for k, v := range globals {
		if existing, ok := b.globals[k]; ok {
			b.err = fmt.Errorf("global %q already defined as %q", k, existing)
			return b
		}
		b.globals[k] = v
	}
	return b
}

// Compile parses all of the soy files in this bundle, verifies a number of
// rules about data references, and returns the completed template registry.
func (b *Bundle) Compile() (*template.Registry, error) {
	if b.err != nil {
		return nil, b.err
	}

	// Compile all the soy (globals are already parsed)
	var registry = template.Registry{}
	for _, soyfile := range b.files {
		var tree, err = parse.SoyFile(soyfile.name, soyfile.content, b.globals)
		if err != nil {
			return nil, err
		}
		if err = registry.Add(tree); err != nil {
			return nil, err
		}
	}

	// Apply the post-parse processing
	var err = parsepasses.CheckDataRefs(registry)
	if err != nil {
		return nil, err
	}

	if b.watcher != nil {
		go b.recompiler(&registry)
	}
	return &registry, nil
}

// CompileToTofu returns a soyhtml.Tofu object that allows you to render soy
// templates to HTML.
func (b *Bundle) CompileToTofu() (*soyhtml.Tofu, error) {
	var registry, err = b.Compile()
	// TODO: Verify all used funcs exist and have the right # args.
	return soyhtml.NewTofu(registry), err
}

func (b *Bundle) recompiler(reg *template.Registry) {
	for {
		select {
		case ev := <-b.watcher.Events:
			// If it's a rename, then fsnotify has removed the watch.
			// Add it back, after a delay.
			if ev.Op == fsnotify.Rename || ev.Op == fsnotify.Remove {
				time.Sleep(10 * time.Millisecond)
				if err := b.watcher.Add(ev.Name); err != nil {
					Logger.Println(err)
				}
			}

			// Recompile all the soy.
			var bundle = NewBundle().
				AddGlobalsMap(b.globals)
			bundle.Transformer = b.Transformer

			for _, soyfile := range b.files {
				bundle.AddTemplateFile(soyfile.name)
			}
			var registry, err = bundle.Compile()
			if err != nil {
				Logger.Println(err)
				continue
			}

			// update the existing template registry.
			// (this is not goroutine-safe, but that seems ok for a development aid,
			// as long as it works in practice)
			*reg = *registry
			Logger.Printf("update successful (%v)", ev)

		case err := <-b.watcher.Errors:
			// Nothing to do with errors
			Logger.Println(err)
		}
	}
}
<|endoftext|>


<commit_before>package adyen

import "github.com/google/go-querystring/query"

// PaymentGateway - Adyen payment transaction logic
type PaymentGateway struct {
	*Adyen
}

// authoriseType - authorise type request, @TODO: move to enums
const authoriseType = "authorise"

// directoryLookupURL - version 2 url for Directory Lookup request
const directoryLookupURL = "directory/v2"

// skipHppUrl - SkipDetails request endpoint
const skipHppURL = "skipDetails"

// AuthoriseEncrypted - Perform authorise payment in Adyen
func (a *PaymentGateway) AuthoriseEncrypted(req *AuthoriseEncrypted) (*AuthoriseResponse, error) {
	resp, err := a.execute(PaymentService, authoriseType, req)

	if err != nil {
		return nil, err
	}

	return resp.authorize()
}

// Authorise - Perform authorise payment in Adyen
func (a *PaymentGateway) Authorise(req *Authorise) (*AuthoriseResponse, error) {
	resp, err := a.execute(PaymentService, authoriseType, req)

	if err != nil {
		return nil, err
	}

	return resp.authorize()
}

// DirectoryLookup - Execute directory lookup request
func (a *PaymentGateway) DirectoryLookup(req *DirectoryLookupRequest) (*DirectoryLookupResponse, error) {

	// Calculate HMAC signature to request
	err := req.CalculateSignature(a.Adyen)
	if err != nil {
		return nil, err
	}

	resp, err := a.executeHpp(directoryLookupURL, req)

	if err != nil {
		return nil, err
	}

	return resp.directoryLookup()
}

// GetHPPRedirectURL - Generates link, so customer could be redirected
// to perform Hosted Payment Page payments
func (a *PaymentGateway) GetHPPRedirectURL(req *SkipHppRequest) (string, error) {
	// Calculate HMAC signature to request
	err := req.CalculateSignature(a.Adyen)
	if err != nil {
		return "", err
	}

	url := a.createHPPUrl(skipHppURL)

	v, _ := query.Values(req)
	url = url + "?" + v.Encode()

	return url, nil
}
<commit_msg>Add recurring payment docs for gateway<commit_after>package adyen

import "github.com/google/go-querystring/query"

// PaymentGateway - Adyen payment transaction logic
type PaymentGateway struct {
	*Adyen
}

// authoriseType - authorise type request, @TODO: move to enums
const authoriseType = "authorise"

// directoryLookupURL - version 2 url for Directory Lookup request
const directoryLookupURL = "directory/v2"

// skipHppUrl - SkipDetails request endpoint
const skipHppURL = "skipDetails"

// AuthoriseEncrypted - Perform authorise payment in Adyen
//
// To perform recurring payment, AuthoriseEncrypted need to have contract specified and shopperReference
//
// Example:
//   &adyen.AuthoriseEncrypted{
//       Amount:           &adyen.Amount{Value: "2000", Currency: "EUR"},
//       MerchantAccount:  "merchant-account",
//       AdditionalData:   &adyen.AdditionalData{Content: r.Form.Get("adyen-encrypted-data")}, // encrypted CC data
//       ShopperReference: "unique-customer-reference",
//       Recurring:        &adyen.Recurring{Contract:adyen.RecurringPaymentRecurring}
//       Reference:        "some-merchant-reference",
//   }
//}
// adyen.Recurring{Contract:adyen.RecurringPaymentRecurring} as one of the contracts
func (a *PaymentGateway) AuthoriseEncrypted(req *AuthoriseEncrypted) (*AuthoriseResponse, error) {
	resp, err := a.execute(PaymentService, authoriseType, req)

	if err != nil {
		return nil, err
	}

	return resp.authorize()
}

// Authorise - Perform authorise payment in Adyen
//
// Used to perform authorisation transaction without credit card data encrypted
// NOTE: Due to PCI compliance, it's not recommended to send credit card data to server
// Please use AuthoriseEncrypted instead and adyen frontend encryption library
func (a *PaymentGateway) Authorise(req *Authorise) (*AuthoriseResponse, error) {
	resp, err := a.execute(PaymentService, authoriseType, req)

	if err != nil {
		return nil, err
	}

	return resp.authorize()
}

// DirectoryLookup - Execute directory lookup request
func (a *PaymentGateway) DirectoryLookup(req *DirectoryLookupRequest) (*DirectoryLookupResponse, error) {

	// Calculate HMAC signature to request
	err := req.CalculateSignature(a.Adyen)
	if err != nil {
		return nil, err
	}

	resp, err := a.executeHpp(directoryLookupURL, req)

	if err != nil {
		return nil, err
	}

	return resp.directoryLookup()
}

// GetHPPRedirectURL - Generates link, so customer could be redirected
// to perform Hosted Payment Page payments
func (a *PaymentGateway) GetHPPRedirectURL(req *SkipHppRequest) (string, error) {
	// Calculate HMAC signature to request
	err := req.CalculateSignature(a.Adyen)
	if err != nil {
		return "", err
	}

	url := a.createHPPUrl(skipHppURL)

	v, _ := query.Values(req)
	url = url + "?" + v.Encode()

	return url, nil
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"code.google.com/p/go.talks/pkg/present"
)

func init() {
	present.PlayEnabled = true
}

var tourContent []byte

// initTour loads tour.article and the relevant HTML templates from the given
// tour root, and renders the template to the tourContent global variable.
func initTour(root string) error {
	// Open and parse source file.
	source := filepath.Join(root, "tour.article")
	f, err := os.Open(source)
	if err != nil {
		return err
	}
	defer f.Close()
	doc, err := present.Parse(prepContent(f), source, 0)
	if err != nil {
		return err
	}

	// Set up templates.
	action := filepath.Join(root, "template", "action.tmpl")
	tour := filepath.Join(root, "template", "tour.tmpl")
	t := present.Template().Funcs(template.FuncMap{"nocode": nocode, "socketAddr": socketAddr})
	_, err = t.ParseFiles(action, tour)
	if err != nil {
		return err
	}

	// Render.
	buf := new(bytes.Buffer)
	if err := doc.Render(buf, t); err != nil {
		return err
	}
	tourContent = buf.Bytes()
	return nil
}

// renderTour writes the tour content to the provided Writer.
func renderTour(w io.Writer) error {
	if tourContent == nil {
		panic("renderTour called before successful initTour")
	}
	_, err := w.Write(tourContent)
	return err
}

// nocode returns true if the provided Section contains
// no Code elements with Play enabled.
func nocode(s present.Section) bool {
	for _, e := range s.Elem {
		if c, ok := e.(present.Code); ok && c.Play {
			return false
		}
	}
	return true
}

var commonScripts = []string{
	"jquery.js",
	"codemirror/lib/codemirror.js",
	"codemirror/lib/go.js",
	"lang.js",
}

// serveScripts registers an HTTP handler at /script.js that serves a
// concatenated set of all the scripts specified by path relative to root.
func serveScripts(root string, path ...string) error {
	modTime := time.Now()
	var buf bytes.Buffer
	scripts := append(commonScripts, path...)
	scripts = append(scripts, "tour.js")
	for _, p := range scripts {
		fn := filepath.Join(root, p)
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			return err
		}
		fmt.Fprintf(&buf, "\n\n// **** %s ****\n\n", filepath.Base(fn))
		buf.Write(b)
	}
	b := buf.Bytes()
	http.HandleFunc("/script.js", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-type", "application/javascript")
		http.ServeContent(w, r, "", modTime, bytes.NewReader(b))
	})
	return nil
}
<commit_msg>codereview.appspot.com/7409043<commit_after>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"code.google.com/p/go.talks/pkg/present"
)

var tourContent []byte

// initTour loads tour.article and the relevant HTML templates from the given
// tour root, and renders the template to the tourContent global variable.
func initTour(root string) error {
	// Make sure playground is enabled before rendering.
	present.PlayEnabled = true
	// Open and parse source file.
	source := filepath.Join(root, "tour.article")
	f, err := os.Open(source)
	if err != nil {
		return err
	}
	defer f.Close()
	doc, err := present.Parse(prepContent(f), source, 0)
	if err != nil {
		return err
	}

	// Set up templates.
	action := filepath.Join(root, "template", "action.tmpl")
	tour := filepath.Join(root, "template", "tour.tmpl")
	t := present.Template().Funcs(template.FuncMap{"nocode": nocode, "socketAddr": socketAddr})
	_, err = t.ParseFiles(action, tour)
	if err != nil {
		return err
	}

	// Render.
	buf := new(bytes.Buffer)
	if err := doc.Render(buf, t); err != nil {
		return err
	}
	tourContent = buf.Bytes()
	return nil
}

// renderTour writes the tour content to the provided Writer.
func renderTour(w io.Writer) error {
	if tourContent == nil {
		panic("renderTour called before successful initTour")
	}
	_, err := w.Write(tourContent)
	return err
}

// nocode returns true if the provided Section contains
// no Code elements with Play enabled.
func nocode(s present.Section) bool {
	for _, e := range s.Elem {
		if c, ok := e.(present.Code); ok && c.Play {
			return false
		}
	}
	return true
}

var commonScripts = []string{
	"jquery.js",
	"codemirror/lib/codemirror.js",
	"codemirror/lib/go.js",
	"lang.js",
}

// serveScripts registers an HTTP handler at /script.js that serves a
// concatenated set of all the scripts specified by path relative to root.
func serveScripts(root string, path ...string) error {
	modTime := time.Now()
	var buf bytes.Buffer
	scripts := append(commonScripts, path...)
	scripts = append(scripts, "tour.js")
	for _, p := range scripts {
		fn := filepath.Join(root, p)
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			return err
		}
		fmt.Fprintf(&buf, "\n\n// **** %s ****\n\n", filepath.Base(fn))
		buf.Write(b)
	}
	b := buf.Bytes()
	http.HandleFunc("/script.js", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-type", "application/javascript")
		http.ServeContent(w, r, "", modTime, bytes.NewReader(b))
	})
	return nil
}
<|endoftext|>


<commit_before>package main

//go:generate go-bindata -o modules/glue/generated_lua.go -pkg=glue -prefix "./builtin" ./builtin ./builtin/3rdparty ./builtin/libs ./builtin/libs/wrappers

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/DeedleFake/Go-PhysicsFS/physfs"
	"github.com/carbonsrv/carbon/modules/glue"
	"github.com/carbonsrv/carbon/modules/luaconf"
	"github.com/carbonsrv/carbon/modules/middleware"
	"github.com/carbonsrv/carbon/modules/scheduler"
	"github.com/carbonsrv/carbon/modules/static"
	"github.com/gin-gonic/gin"
	"github.com/namsral/flag"
	"github.com/pmylund/go-cache"
	"golang.org/x/net/http2"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"
)

// General
var jobs *int

// Cache
var cfe *cache.Cache
var kvstore *cache.Cache

func cacheRead(c *cache.Cache, file string) (string, error) {
	res := ""
	data_tmp, found := c.Get(file)
	if found == false {
		data, err := fileRead(file)
		if err != nil {
			return "", err
		}
		c.Set(file, data, cache.DefaultExpiration)
	} else {
		debug("Using cache for %s" + file)
		res = data_tmp.(string)
	}
	return res, nil
}

// File system functions
var filesystem http.FileSystem

func initPhysFS(path string) http.FileSystem {
	err := physfs.Init()
	if err != nil {
		panic(err)
	}
	err = physfs.Mount(path, "/", true)
	if err != nil {
		panic(err)
	}
	return physfs.FileSystem()
}

/*func fileExists(file string) bool {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		return false
	}
	return true
}*/
func fileRead(file string) (string, error) {
	if physfs.Exists(file) {
		f, err := filesystem.Open(file)
		defer f.Close()
		if err != nil {
			return "", err
		}
		fi, err := f.Stat()
		if err != nil {
			return "", err
		}
		r := bufio.NewReader(f)
		buf := make([]byte, fi.Size())
		_, err = r.Read(buf)
		if err != nil {
			return "", err
		}
		return string(buf), err
	}
	return "", errors.New("no such file or directory.")
}
func fileExists(file string) bool {
	return physfs.Exists(file)
}
func cacheFileExists(file string) bool {
	data_tmp, found := cfe.Get(file)
	if found == false {
		exists := fileExists(file)
		cfe.Set(file, exists, cache.DefaultExpiration)
		return exists
	} else {
		return data_tmp.(bool)
	}
}

// Logging
var doLog bool = false

func debug(str string) {
	if doLog {
		log.Print(str)
	}
}

// Server
func new_server() *gin.Engine {
	return gin.New()
}
func bootstrap(srv *gin.Engine, dir string, cfe *cache.Cache) {
	switcher := middleware.ExtRoute(middleware.Plan{
		".lua": middleware.Lua(),
		"***":  staticServe.ServeCached("", staticServe.PhysFS("", "", true, true), cfe),
	})
	/*srv.GET(`/:file`, switcher)
	srv.POST(`/:file`, switcher)*/
	srv.Use(switcher)
	/*st := staticServe.ServeCached("", staticServe.PhysFS("", true, true), cfe)
	lr := luaroute(dir)
	srv.Use(lr)
	srv.Use(st)*/
}

func serve(srv http.Handler, en_http bool, en_https bool, en_http2 bool, bind string, binds string, cert string, key string) {
	end := make(chan bool)
	if en_http {
		go serveHTTP(srv, bind, en_http2)
	}
	if en_https {
		cert, _ := filepath.Abs(cert)
		key, _ := filepath.Abs(key)
		go serveHTTPS(srv, binds, en_http2, cert, key)
	}
	<-end
}
func serveHTTP(srv http.Handler, bind string, en_http2 bool) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServe()
	if err != nil {
		panic(err)
	}
}
func serveHTTPS(srv http.Handler, bind string, en_http2 bool, cert string, key string) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServeTLS(cert, key)
	if err != nil {
		panic(err)
	}
}

func main() {
	cfe = cache.New(5*time.Minute, 30*time.Second) // File-Exists Cache
	kvstore = cache.New(-1, -1)                    // Key-Value Storage

	// Use config
	flag.String("config", "", "Parse Config File")
	var script_flag = flag.String("script", "", "Parse Lua Script as initialization")
	var run_repl = flag.Bool("repl", false, "Run REPL")
	var eval = flag.String("eval", "", "Eval Lua Code")
	var is_app = flag.Bool("app", false, "Script is bundle")
	var licenses = flag.Bool("licenses", false, "Show licenses")

	var host = flag.String("host", "", "IP of Host to bind the Webserver on")
	var port = flag.Int("port", 80, "Port to run Webserver on (HTTP)")
	var ports = flag.Int("ports", 443, "Port to run Webserver on (HTTPS)")
	var cert = flag.String("cert", "", "Certificate File for HTTPS")
	var key = flag.String("key", "", "Key File for HTTPS")
	var en_http = flag.Bool("http", true, "Listen HTTP")
	var en_https = flag.Bool("https", false, "Listen HTTPS")
	var en_http2 = flag.Bool("http2", false, "Enable HTTP/2")

	wrkrs := 2
	if runtime.NumCPU() > 2 {
		wrkrs = runtime.NumCPU()
	}
	jobs = flag.Int("states", wrkrs, "Number of Preinitialized Lua States")
	var workers = flag.Int("workers", wrkrs, "Number of Worker threads.")
	var webroot = flag.String("root", ".", "Path to Web Root")

	// Do debug!
	doDebug := flag.Bool("debug", false, "Show debug information")
	// Middleware options
	useRecovery := flag.Bool("recovery", false, "Recover from Panics")
	useLogger := flag.Bool("logger", true, "Log Request information")

	flag.Parse()

	if *en_https {
		if *key == "" || *cert == "" {
			panic("Need to have a Key and a Cert defined.")
		}
	}

	if *licenses {
		fmt.Println(glue.GetGlue("NOTICE.txt"))
		os.Exit(0)
	}

	var script string
	if *script_flag == "" {
		script = flag.Arg(0)
	} else {
		script = *script_flag
	}

	runtime.GOMAXPROCS(*workers)

	root, _ := filepath.Abs(*webroot)
	physroot_path := root
	if *is_app {
		physroot_path = script
	}
	filesystem = initPhysFS(physroot_path)

	defer physfs.Deinit()
	go scheduler.Run()                         // Run the scheduler.
	go middleware.Preloader()                  // Run the Preloader.
	middleware.Init(*jobs, cfe, kvstore, root) // Run init sequence.

	if *doDebug == false {
		gin.SetMode(gin.ReleaseMode)
	}

	args := flag.Args()

	if *eval != "" {
		err := luaconf.Eval(*eval, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		})
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	if script == "" {
		if *run_repl {
			err := luaconf.REPL(args, cfe, root, *useRecovery, false, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			err := luaconf.Eval(glue.GetGlue("bootscript.lua"), args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}
	} else {
		if *useLogger {
			doLog = true
		}

		if flag.Arg(1) == "" {
			args = make([]string, 0)
		} else {
			args = args[1:]
		}
		if *is_app {
			script_base := filepath.Base(script)
			script_name := script_base[:len(script_base)-len(filepath.Ext(script))]
			script_src, err := fileRead(script_name)
			if err != nil {
				script_src, err = fileRead("app.lua")
				if err != nil {
					script_src, err = fileRead("init.lua")
					if err != nil {
						fmt.Println("Error: App Bundle does not contain '" + script_name + "', 'app.lua' or 'init.lua'. No idea what to run. Aborting.")
						os.Exit(1)
					}
				}
			}
			err = luaconf.Eval(script_src, args, cfe, script, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			err := luaconf.Configure(script, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}
	}
}
<commit_msg>Small fixup and changes in app logic.<commit_after>package main

//go:generate go-bindata -o modules/glue/generated_lua.go -pkg=glue -prefix "./builtin" ./builtin ./builtin/3rdparty ./builtin/libs ./builtin/libs/wrappers

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/DeedleFake/Go-PhysicsFS/physfs"
	"github.com/carbonsrv/carbon/modules/glue"
	"github.com/carbonsrv/carbon/modules/luaconf"
	"github.com/carbonsrv/carbon/modules/middleware"
	"github.com/carbonsrv/carbon/modules/scheduler"
	"github.com/carbonsrv/carbon/modules/static"
	"github.com/gin-gonic/gin"
	"github.com/namsral/flag"
	"github.com/pmylund/go-cache"
	"golang.org/x/net/http2"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"
)

// General
var jobs *int

// Cache
var cfe *cache.Cache
var kvstore *cache.Cache

func cacheRead(c *cache.Cache, file string) (string, error) {
	res := ""
	data_tmp, found := c.Get(file)
	if found == false {
		data, err := fileRead(file)
		if err != nil {
			return "", err
		}
		c.Set(file, data, cache.DefaultExpiration)
	} else {
		debug("Using cache for %s" + file)
		res = data_tmp.(string)
	}
	return res, nil
}

// File system functions
var filesystem http.FileSystem

func initPhysFS(path string) http.FileSystem {
	err := physfs.Init()
	if err != nil {
		panic(err)
	}
	err = physfs.Mount(path, "/", true)
	if err != nil {
		panic(err)
	}
	return physfs.FileSystem()
}

/*func fileExists(file string) bool {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		return false
	}
	return true
}*/
func fileRead(file string) (string, error) {
	if physfs.Exists(file) {
		f, err := filesystem.Open(file)
		defer f.Close()
		if err != nil {
			return "", err
		}
		fi, err := f.Stat()
		if err != nil {
			return "", err
		}
		r := bufio.NewReader(f)
		buf := make([]byte, fi.Size())
		_, err = r.Read(buf)
		if err != nil {
			return "", err
		}
		return string(buf), err
	}
	return "", errors.New("no such file or directory.")
}
func fileExists(file string) bool {
	return physfs.Exists(file)
}
func cacheFileExists(file string) bool {
	data_tmp, found := cfe.Get(file)
	if found == false {
		exists := fileExists(file)
		cfe.Set(file, exists, cache.DefaultExpiration)
		return exists
	} else {
		return data_tmp.(bool)
	}
}

// Logging
var doLog bool = false

func debug(str string) {
	if doLog {
		log.Print(str)
	}
}

// Server
func new_server() *gin.Engine {
	return gin.New()
}
func bootstrap(srv *gin.Engine, dir string, cfe *cache.Cache) {
	switcher := middleware.ExtRoute(middleware.Plan{
		".lua": middleware.Lua(),
		"***":  staticServe.ServeCached("", staticServe.PhysFS("", "", true, true), cfe),
	})
	/*srv.GET(`/:file`, switcher)
	srv.POST(`/:file`, switcher)*/
	srv.Use(switcher)
	/*st := staticServe.ServeCached("", staticServe.PhysFS("", true, true), cfe)
	lr := luaroute(dir)
	srv.Use(lr)
	srv.Use(st)*/
}

func serve(srv http.Handler, en_http bool, en_https bool, en_http2 bool, bind string, binds string, cert string, key string) {
	end := make(chan bool)
	if en_http {
		go serveHTTP(srv, bind, en_http2)
	}
	if en_https {
		cert, _ := filepath.Abs(cert)
		key, _ := filepath.Abs(key)
		go serveHTTPS(srv, binds, en_http2, cert, key)
	}
	<-end
}
func serveHTTP(srv http.Handler, bind string, en_http2 bool) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServe()
	if err != nil {
		panic(err)
	}
}
func serveHTTPS(srv http.Handler, bind string, en_http2 bool, cert string, key string) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServeTLS(cert, key)
	if err != nil {
		panic(err)
	}
}

func main() {
	cfe = cache.New(5*time.Minute, 30*time.Second) // File-Exists Cache
	kvstore = cache.New(-1, -1)                    // Key-Value Storage

	// Use config
	flag.String("config", "", "Parse Config File")
	var script_flag = flag.String("script", "", "Parse Lua Script as initialization")
	var run_repl = flag.Bool("repl", false, "Run REPL")
	var eval = flag.String("eval", "", "Eval Lua Code")
	var is_app = flag.Bool("app", false, "Script is bundle")
	var licenses = flag.Bool("licenses", false, "Show licenses")

	var host = flag.String("host", "", "IP of Host to bind the Webserver on")
	var port = flag.Int("port", 80, "Port to run Webserver on (HTTP)")
	var ports = flag.Int("ports", 443, "Port to run Webserver on (HTTPS)")
	var cert = flag.String("cert", "", "Certificate File for HTTPS")
	var key = flag.String("key", "", "Key File for HTTPS")
	var en_http = flag.Bool("http", true, "Listen HTTP")
	var en_https = flag.Bool("https", false, "Listen HTTPS")
	var en_http2 = flag.Bool("http2", false, "Enable HTTP/2")

	wrkrs := 2
	if runtime.NumCPU() > 2 {
		wrkrs = runtime.NumCPU()
	}
	jobs = flag.Int("states", wrkrs, "Number of Preinitialized Lua States")
	var workers = flag.Int("workers", wrkrs, "Number of Worker threads.")
	var webroot = flag.String("root", ".", "Path to Web Root")

	// Do debug!
	doDebug := flag.Bool("debug", false, "Show debug information")
	// Middleware options
	useRecovery := flag.Bool("recovery", false, "Recover from Panics")
	useLogger := flag.Bool("logger", true, "Log Request information")

	flag.Parse()

	if *en_https {
		if *key == "" || *cert == "" {
			panic("Need to have a Key and a Cert defined.")
		}
	}

	if *licenses {
		fmt.Println(glue.GetGlue("NOTICE.txt"))
		os.Exit(0)
	}

	var script string
	if *script_flag == "" {
		script = flag.Arg(0)
	} else {
		script = *script_flag
	}

	runtime.GOMAXPROCS(*workers)

	root, _ := filepath.Abs(*webroot)
	physroot_path := root
	if *is_app {
		physroot_path = script
	}
	filesystem = initPhysFS(physroot_path)

	defer physfs.Deinit()
	go scheduler.Run()                         // Run the scheduler.
	go middleware.Preloader()                  // Run the Preloader.
	middleware.Init(*jobs, cfe, kvstore, root) // Run init sequence.

	if *doDebug == false {
		gin.SetMode(gin.ReleaseMode)
	}

	args := flag.Args()

	if *eval != "" {
		err := luaconf.Eval(*eval, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		})
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	if script == "" {
		if *run_repl {
			err := luaconf.REPL(args, cfe, root, *useRecovery, false, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			err := luaconf.Eval(glue.GetGlue("bootscript.lua"), args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}
	} else {
		if *useLogger {
			doLog = true
		}

		if flag.Arg(1) == "" {
			args = make([]string, 0)
		} else {
			args = args[1:]
		}
		if *is_app {
			script_src, err := fileRead("app.lua")
			if err != nil {
				script_base := filepath.Base(script)
				script_name := script_base[:len(script_base)-len(filepath.Ext(script))]
				script_src, err = fileRead(script_name + ".lua")
				if err != nil {
					script_src, err = fileRead("init.lua")
					if err != nil {
						fmt.Println("Error: App Bundle does not contain 'app.lua', '" + script_name + ".lua' or 'init.lua'. No idea what to run. Aborting.")
						os.Exit(1)
					}
				}
			}
			err = luaconf.Eval(script_src, args, cfe, script, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			err := luaconf.Configure(script, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

//go:generate go-bindata -o modules/glue/generated_lua.go -pkg=glue -prefix "./lua" ./lua ./lua/3rdparty ./lua/libs ./lua/libs/wrappers

import (
	"bufio"
	"fmt"
	"github.com/DeedleFake/Go-PhysicsFS/physfs"
	"github.com/bradfitz/http2"
	"github.com/carbonsrv/carbon/modules/luaconf"
	"github.com/carbonsrv/carbon/modules/middleware"
	"github.com/carbonsrv/carbon/modules/scheduler"
	"github.com/carbonsrv/carbon/modules/static"
	"github.com/gin-gonic/gin"
	"github.com/namsral/flag"
	"github.com/pmylund/go-cache"
	"github.com/vifino/contrib/gzip"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"
)

// General
var jobs *int

// Cache
var cfe *cache.Cache
var kvstore *cache.Cache

func cacheRead(c *cache.Cache, file string) (string, error) {
	res := ""
	data_tmp, found := c.Get(file)
	if found == false {
		data, err := fileRead(file)
		if err != nil {
			return "", err
		}
		c.Set(file, data, cache.DefaultExpiration)
	} else {
		debug("Using cache for %s" + file)
		res = data_tmp.(string)
	}
	return res, nil
}

// File sytem functions
var filesystem http.FileSystem

func initPhysFS(path string) http.FileSystem {
	err := physfs.Init()
	if err != nil {
		panic(err)
	}
	err = physfs.Mount(path, "/", true)
	if err != nil {
		panic(err)
	}
	return physfs.FileSystem()
}

/*func fileExists(file string) bool {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		return false
	}
	return true
}*/
func fileRead(file string) (string, error) {
	f, err := filesystem.Open(file)
	defer f.Close()
	if err != nil {
		return "", err
	}
	fi, err := f.Stat()
	if err != nil {
		return "", err
	}
	r := bufio.NewReader(f)
	buf := make([]byte, fi.Size())
	_, err = r.Read(buf)
	if err != nil {
		return "", err
	}
	return string(buf), err
}
func fileExists(file string) bool {
	return physfs.Exists(file)
}
func cacheFileExists(file string) bool {
	data_tmp, found := cfe.Get(file)
	if found == false {
		exists := fileExists(file)
		cfe.Set(file, exists, cache.DefaultExpiration)
		return exists
	} else {
		return data_tmp.(bool)
	}
}

// Logging
var doLog bool = false

func debug(str string) {
	if doLog {
		log.Print(str)
	}
}

// Server
func new_server() *gin.Engine {
	return gin.New()
}
func bootstrap(srv *gin.Engine, dir string, cfe *cache.Cache) {
	switcher := middleware.ExtRoute(middleware.Plan{
		".lua": middleware.Lua(),
		"***":  staticServe.ServeCached("", staticServe.PhysFS("", "", true, true), cfe),
	})
	/*srv.GET(`/:file`, switcher)
	srv.POST(`/:file`, switcher)*/
	srv.Use(switcher)
	/*st := staticServe.ServeCached("", staticServe.PhysFS("", true, true), cfe)
	lr := luaroute(dir)
	srv.Use(lr)
	srv.Use(st)*/
}

func serve(srv http.Handler, en_http bool, en_https bool, en_http2 bool, bind string, binds string, cert string, key string) {
	end := make(chan bool)
	if en_http {
		go serveHTTP(srv, bind, en_http2)
	}
	if en_https {
		go serveHTTPS(srv, binds, en_http2, cert, key)
	}
	<-end
}
func serveHTTP(srv http.Handler, bind string, en_http2 bool) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServe()
	if err != nil {
		panic(err)
	}
}
func serveHTTPS(srv http.Handler, bind string, en_http2 bool, cert string, key string) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServeTLS(cert, key)
	if err != nil {
		panic(err)
	}
}

func main() {
	cfe = cache.New(5*time.Minute, 30*time.Second) // File-Exists Cache
	kvstore = cache.New(-1, -1)                    // Key-Value Storage

	// Use config
	flag.String("config", "", "Parse Config File")
	var script_flag = flag.String("script", "", "Parse Lua Script as initialization")
	var run_repl = flag.Bool("repl", false, "Run REPL")
	var eval = flag.String("eval", "", "Eval Lua Code")

	var host = flag.String("host", "", "IP of Host to bind the Webserver on")
	var port = flag.Int("port", 8080, "Port to run Webserver on (HTTP)")
	var ports = flag.Int("ports", 8443, "Port to run Webserver on (HTTPS)")
	var cert = flag.String("cert", "", "Certificate File for HTTPS")
	var key = flag.String("key", "", "Key File for HTTPS")
	var en_http = flag.Bool("http", true, "Listen HTTP")
	var en_https = flag.Bool("https", false, "Listen HTTPS")
	var en_http2 = flag.Bool("http2", false, "Enable HTTP/2")

	wrkrs := 2
	if runtime.NumCPU() > 2 {
		wrkrs = runtime.NumCPU()
	}
	jobs = flag.Int("states", wrkrs, "Number of Preinitialized Lua States")
	var workers = flag.Int("workers", wrkrs, "Number of Worker threads.")
	var webroot = flag.String("root", ".", "Path to Web Root")

	// Do debug!
	doDebug := flag.Bool("debug", false, "Show debug information")
	// Middleware options
	useRecovery := flag.Bool("recovery", false, "Recover from Panics")
	useLogger := flag.Bool("logger", true, "Log Request information")
	useGzip := flag.Bool("gzip", false, "Use GZIP")

	flag.Parse()

	if *en_https {
		if *key == "" || *cert == "" {
			panic("Need to have a Key and a Cert defined.")
		}
	}

	runtime.GOMAXPROCS(*workers)

	root, _ := filepath.Abs(*webroot)
	filesystem = initPhysFS(root)
	defer physfs.Deinit()
	go scheduler.Run()                   // Run the scheduler.
	go middleware.Preloader()            // Run the Preloader.
	middleware.Init(*jobs, cfe, kvstore) // Run init sequence.

	var script string
	if *script_flag == "" {
		script = flag.Arg(0)
	} else {
		script = *script_flag
	}

	if *doDebug == false {
		gin.SetMode(gin.ReleaseMode)
	}

	args := flag.Args()

	if *eval != "" {
		err := luaconf.Eval(*eval, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		})
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	if script == "" {
		if *run_repl {
			err := luaconf.REPL(args, cfe, root, *useRecovery, false, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			srv := new_server()
			if *useLogger {
				doLog = true
				srv.Use(gin.Logger())
			}
			if *useRecovery {
				srv.Use(gin.Recovery())
			}
			if *useGzip {
				srv.Use(gzip.Gzip(gzip.DefaultCompression))
			}
			bootstrap(srv, "", cfe)
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		}
	} else {
		if *useLogger {
			doLog = true
		}

		if flag.Arg(1) == "" {
			args = make([]string)
		} else {
			args = args[1:]
		}
		err := luaconf.Configure(script, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		})
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
}
<commit_msg>Length.<commit_after>package main

//go:generate go-bindata -o modules/glue/generated_lua.go -pkg=glue -prefix "./lua" ./lua ./lua/3rdparty ./lua/libs ./lua/libs/wrappers

import (
	"bufio"
	"fmt"
	"github.com/DeedleFake/Go-PhysicsFS/physfs"
	"github.com/bradfitz/http2"
	"github.com/carbonsrv/carbon/modules/luaconf"
	"github.com/carbonsrv/carbon/modules/middleware"
	"github.com/carbonsrv/carbon/modules/scheduler"
	"github.com/carbonsrv/carbon/modules/static"
	"github.com/gin-gonic/gin"
	"github.com/namsral/flag"
	"github.com/pmylund/go-cache"
	"github.com/vifino/contrib/gzip"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"
)

// General
var jobs *int

// Cache
var cfe *cache.Cache
var kvstore *cache.Cache

func cacheRead(c *cache.Cache, file string) (string, error) {
	res := ""
	data_tmp, found := c.Get(file)
	if found == false {
		data, err := fileRead(file)
		if err != nil {
			return "", err
		}
		c.Set(file, data, cache.DefaultExpiration)
	} else {
		debug("Using cache for %s" + file)
		res = data_tmp.(string)
	}
	return res, nil
}

// File sytem functions
var filesystem http.FileSystem

func initPhysFS(path string) http.FileSystem {
	err := physfs.Init()
	if err != nil {
		panic(err)
	}
	err = physfs.Mount(path, "/", true)
	if err != nil {
		panic(err)
	}
	return physfs.FileSystem()
}

/*func fileExists(file string) bool {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		return false
	}
	return true
}*/
func fileRead(file string) (string, error) {
	f, err := filesystem.Open(file)
	defer f.Close()
	if err != nil {
		return "", err
	}
	fi, err := f.Stat()
	if err != nil {
		return "", err
	}
	r := bufio.NewReader(f)
	buf := make([]byte, fi.Size())
	_, err = r.Read(buf)
	if err != nil {
		return "", err
	}
	return string(buf), err
}
func fileExists(file string) bool {
	return physfs.Exists(file)
}
func cacheFileExists(file string) bool {
	data_tmp, found := cfe.Get(file)
	if found == false {
		exists := fileExists(file)
		cfe.Set(file, exists, cache.DefaultExpiration)
		return exists
	} else {
		return data_tmp.(bool)
	}
}

// Logging
var doLog bool = false

func debug(str string) {
	if doLog {
		log.Print(str)
	}
}

// Server
func new_server() *gin.Engine {
	return gin.New()
}
func bootstrap(srv *gin.Engine, dir string, cfe *cache.Cache) {
	switcher := middleware.ExtRoute(middleware.Plan{
		".lua": middleware.Lua(),
		"***":  staticServe.ServeCached("", staticServe.PhysFS("", "", true, true), cfe),
	})
	/*srv.GET(`/:file`, switcher)
	srv.POST(`/:file`, switcher)*/
	srv.Use(switcher)
	/*st := staticServe.ServeCached("", staticServe.PhysFS("", true, true), cfe)
	lr := luaroute(dir)
	srv.Use(lr)
	srv.Use(st)*/
}

func serve(srv http.Handler, en_http bool, en_https bool, en_http2 bool, bind string, binds string, cert string, key string) {
	end := make(chan bool)
	if en_http {
		go serveHTTP(srv, bind, en_http2)
	}
	if en_https {
		go serveHTTPS(srv, binds, en_http2, cert, key)
	}
	<-end
}
func serveHTTP(srv http.Handler, bind string, en_http2 bool) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServe()
	if err != nil {
		panic(err)
	}
}
func serveHTTPS(srv http.Handler, bind string, en_http2 bool, cert string, key string) {
	s := &http.Server{
		Addr:           bind,
		Handler:        srv,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	if en_http2 {
		http2.ConfigureServer(s, nil)
	}
	err := s.ListenAndServeTLS(cert, key)
	if err != nil {
		panic(err)
	}
}

func main() {
	cfe = cache.New(5*time.Minute, 30*time.Second) // File-Exists Cache
	kvstore = cache.New(-1, -1)                    // Key-Value Storage

	// Use config
	flag.String("config", "", "Parse Config File")
	var script_flag = flag.String("script", "", "Parse Lua Script as initialization")
	var run_repl = flag.Bool("repl", false, "Run REPL")
	var eval = flag.String("eval", "", "Eval Lua Code")

	var host = flag.String("host", "", "IP of Host to bind the Webserver on")
	var port = flag.Int("port", 8080, "Port to run Webserver on (HTTP)")
	var ports = flag.Int("ports", 8443, "Port to run Webserver on (HTTPS)")
	var cert = flag.String("cert", "", "Certificate File for HTTPS")
	var key = flag.String("key", "", "Key File for HTTPS")
	var en_http = flag.Bool("http", true, "Listen HTTP")
	var en_https = flag.Bool("https", false, "Listen HTTPS")
	var en_http2 = flag.Bool("http2", false, "Enable HTTP/2")

	wrkrs := 2
	if runtime.NumCPU() > 2 {
		wrkrs = runtime.NumCPU()
	}
	jobs = flag.Int("states", wrkrs, "Number of Preinitialized Lua States")
	var workers = flag.Int("workers", wrkrs, "Number of Worker threads.")
	var webroot = flag.String("root", ".", "Path to Web Root")

	// Do debug!
	doDebug := flag.Bool("debug", false, "Show debug information")
	// Middleware options
	useRecovery := flag.Bool("recovery", false, "Recover from Panics")
	useLogger := flag.Bool("logger", true, "Log Request information")
	useGzip := flag.Bool("gzip", false, "Use GZIP")

	flag.Parse()

	if *en_https {
		if *key == "" || *cert == "" {
			panic("Need to have a Key and a Cert defined.")
		}
	}

	runtime.GOMAXPROCS(*workers)

	root, _ := filepath.Abs(*webroot)
	filesystem = initPhysFS(root)
	defer physfs.Deinit()
	go scheduler.Run()                   // Run the scheduler.
	go middleware.Preloader()            // Run the Preloader.
	middleware.Init(*jobs, cfe, kvstore) // Run init sequence.

	var script string
	if *script_flag == "" {
		script = flag.Arg(0)
	} else {
		script = *script_flag
	}

	if *doDebug == false {
		gin.SetMode(gin.ReleaseMode)
	}

	args := flag.Args()

	if *eval != "" {
		err := luaconf.Eval(*eval, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		})
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	if script == "" {
		if *run_repl {
			err := luaconf.REPL(args, cfe, root, *useRecovery, false, func(srv *gin.Engine) {
				serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
			})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			srv := new_server()
			if *useLogger {
				doLog = true
				srv.Use(gin.Logger())
			}
			if *useRecovery {
				srv.Use(gin.Recovery())
			}
			if *useGzip {
				srv.Use(gzip.Gzip(gzip.DefaultCompression))
			}
			bootstrap(srv, "", cfe)
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		}
	} else {
		if *useLogger {
			doLog = true
		}

		if flag.Arg(1) == "" {
			args = make([]string, 0)
		} else {
			args = args[1:]
		}
		err := luaconf.Configure(script, args, cfe, root, *useRecovery, *useLogger, *run_repl, func(srv *gin.Engine) {
			serve(srv, *en_http, *en_https, *en_http2, *host+":"+strconv.Itoa(*port), *host+":"+strconv.Itoa(*ports), *cert, *key)
		})
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2016 VMware, Inc. All Rights Reserved.
   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 cache

import (
	"errors"
	"os"
	"time"

	"github.com/vmware/harbor/utils/log"
	"github.com/vmware/harbor/utils/registry"
	"github.com/vmware/harbor/utils/registry/auth"

	"github.com/astaxie/beego/cache"
)

var (
	// Cache is the global cache in system.
	Cache          cache.Cache
	endpoint       string
	insecure       bool
	username       string
	registryClient *registry.Registry
)

const catalogKey string = "catalog"

func init() {
	var err error
	Cache, err = cache.NewCache("memory", `{"interval":720}`)
	if err != nil {
		log.Errorf("Failed to initialize cache, error:%v", err)
	}

	endpoint = os.Getenv("REGISTRY_URL")
	// TODO read variable from config file
	insecure = true
	username = "admin"
	registryClient, err = NewRegistryClient(endpoint, insecure, username,
		"registry", "catalog", "*")
	if err != nil {
		log.Errorf("failed to create registry client: %v", err)
		return
	}
}

// RefreshCatalogCache calls registry's API to get repository list and write it to cache.
func RefreshCatalogCache() error {
	log.Debug("refreshing catalog cache...")

	if registryClient == nil {
		return errors.New("registry client is nil")
	}

	var err error
	rs, err := registryClient.Catalog()
	if err != nil {
		return err
	}

	repos := []string{}

	for _, repo := range rs {
		rc, err := NewRepositoryClient(endpoint, insecure, username,
			repo, "repository", repo, "pull", "push", "*")
		if err != nil {
			log.Errorf("error occurred while initializing repository client used by cache: %s %v", repo, err)
			continue
		}

		tags, err := rc.ListTag()
		if err != nil {
			log.Errorf("error occurred while list tag for %s: %v", repo, err)
			continue
		}

		if len(tags) != 0 {
			repos = append(repos, repo)
			log.Debugf("add %s to catalog cache", repo)
		}
	}

	Cache.Put(catalogKey, repos, 600*time.Second)
	return nil
}

// GetRepoFromCache get repository list from cache, it refreshes the cache if it's empty.
func GetRepoFromCache() ([]string, error) {

	result := Cache.Get(catalogKey)
	if result == nil {
		err := RefreshCatalogCache()
		if err != nil {
			return nil, err
		}
		cached := Cache.Get(catalogKey)
		if cached != nil {
			return cached.([]string), nil
		}
		return nil, nil
	}
	return result.([]string), nil
}

// NewRegistryClient ...
func NewRegistryClient(endpoint string, insecure bool, username, scopeType, scopeName string,
	scopeActions ...string) (*registry.Registry, error) {
	authorizer := auth.NewUsernameTokenAuthorizer(username, scopeType, scopeName, scopeActions...)

	store, err := auth.NewAuthorizerStore(endpoint, insecure, authorizer)
	if err != nil {
		return nil, err
	}

	client, err := registry.NewRegistryWithModifiers(endpoint, insecure, store)
	if err != nil {
		return nil, err
	}
	return client, nil
}

// NewRepositoryClient ...
func NewRepositoryClient(endpoint string, insecure bool, username, repository, scopeType, scopeName string,
	scopeActions ...string) (*registry.Repository, error) {

	authorizer := auth.NewUsernameTokenAuthorizer(username, scopeType, scopeName, scopeActions...)

	store, err := auth.NewAuthorizerStore(endpoint, insecure, authorizer)
	if err != nil {
		return nil, err
	}

	client, err := registry.NewRepositoryWithModifiers(repository, endpoint, insecure, store)
	if err != nil {
		return nil, err
	}
	return client, nil
}
<commit_msg>create a new registry client if it is nil in cache<commit_after>/*
   Copyright (c) 2016 VMware, Inc. All Rights Reserved.
   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 cache

import (
	"os"
	"time"

	"github.com/vmware/harbor/utils/log"
	"github.com/vmware/harbor/utils/registry"
	"github.com/vmware/harbor/utils/registry/auth"

	"github.com/astaxie/beego/cache"
)

var (
	// Cache is the global cache in system.
	Cache          cache.Cache
	endpoint       string
	insecure       bool
	username       string
	registryClient *registry.Registry
)

const catalogKey string = "catalog"

func init() {
	var err error
	Cache, err = cache.NewCache("memory", `{"interval":720}`)
	if err != nil {
		log.Errorf("Failed to initialize cache, error:%v", err)
	}

	endpoint = os.Getenv("REGISTRY_URL")
}

// RefreshCatalogCache calls registry's API to get repository list and write it to cache.
func RefreshCatalogCache() error {
	log.Debug("refreshing catalog cache...")

	var err error

	if registryClient == nil {

		registryClient, err = NewRegistryClient(endpoint, true, username,
			"registry", "catalog", "*")
		if err != nil {
			return err
		}
	}

	rs, err := registryClient.Catalog()
	if err != nil {
		return err
	}

	repos := []string{}

	for _, repo := range rs {
		rc, err := NewRepositoryClient(endpoint, insecure, username,
			repo, "repository", repo, "pull", "push", "*")
		if err != nil {
			log.Errorf("error occurred while initializing repository client used by cache: %s %v", repo, err)
			continue
		}

		tags, err := rc.ListTag()
		if err != nil {
			log.Errorf("error occurred while list tag for %s: %v", repo, err)
			continue
		}

		if len(tags) != 0 {
			repos = append(repos, repo)
			log.Debugf("add %s to catalog cache", repo)
		}
	}

	Cache.Put(catalogKey, repos, 600*time.Second)
	return nil
}

// GetRepoFromCache get repository list from cache, it refreshes the cache if it's empty.
func GetRepoFromCache() ([]string, error) {

	result := Cache.Get(catalogKey)
	if result == nil {
		err := RefreshCatalogCache()
		if err != nil {
			return nil, err
		}
		cached := Cache.Get(catalogKey)
		if cached != nil {
			return cached.([]string), nil
		}
		return nil, nil
	}
	return result.([]string), nil
}

// NewRegistryClient ...
func NewRegistryClient(endpoint string, insecure bool, username, scopeType, scopeName string,
	scopeActions ...string) (*registry.Registry, error) {
	authorizer := auth.NewUsernameTokenAuthorizer(username, scopeType, scopeName, scopeActions...)

	store, err := auth.NewAuthorizerStore(endpoint, insecure, authorizer)
	if err != nil {
		return nil, err
	}

	client, err := registry.NewRegistryWithModifiers(endpoint, insecure, store)
	if err != nil {
		return nil, err
	}
	return client, nil
}

// NewRepositoryClient ...
func NewRepositoryClient(endpoint string, insecure bool, username, repository, scopeType, scopeName string,
	scopeActions ...string) (*registry.Repository, error) {

	authorizer := auth.NewUsernameTokenAuthorizer(username, scopeType, scopeName, scopeActions...)

	store, err := auth.NewAuthorizerStore(endpoint, insecure, authorizer)
	if err != nil {
		return nil, err
	}

	client, err := registry.NewRepositoryWithModifiers(repository, endpoint, insecure, store)
	if err != nil {
		return nil, err
	}
	return client, nil
}
<|endoftext|>


<commit_before>// Copyright 2020 Jigsaw Operations 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
//
//     https://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 service

import (
	"bytes"
	"crypto"
	"crypto/hmac"
	"crypto/rand"
	"fmt"
	"io"

	ss "github.com/Jigsaw-Code/outline-ss-server/shadowsocks"
	"golang.org/x/crypto/hkdf"
)

// ServerSaltGenerator offers the ability to check if a salt was marked as
// server-originated.
type ServerSaltGenerator interface {
	ss.SaltGenerator
	// IsServerSalt returns true if the salt was created by this generator
	// and is marked as server-originated.
	IsServerSalt(salt []byte) bool
}

// randomSaltGenerator generates a new random salt.
type randomSaltGenerator struct{}

// GetSalt outputs a random salt.
func (randomSaltGenerator) GetSalt(salt []byte) error {
	_, err := rand.Read(salt)
	return err
}

func (randomSaltGenerator) IsServerSalt(salt []byte) bool {
	return false
}

// RandomServerSaltGenerator is a basic ServerSaltGenerator.
var RandomServerSaltGenerator ServerSaltGenerator = randomSaltGenerator{}

// serverSaltGenerator generates unique salts that are secretly marked.
type serverSaltGenerator struct {
	key []byte
}

// ServerSaltMarkLen is the number of bytes of salt to use as a marker.
// Increasing this value reduces the false positive rate, but increases
// the likelihood of salt collisions.
const ServerSaltMarkLen = 4 // Must be less than or equal to SHA1.Size()

// Constant to identify this marking scheme.
var serverSaltLabel = []byte("outline-server-salt")

// NewServerSaltGenerator returns a SaltGenerator whose output is apparently
// random, but is secretly marked as being issued by the server.
// This is useful to prevent the server from accepting its own output in a
// reflection attack.
func NewServerSaltGenerator(secret string) ServerSaltGenerator {
	// Shadowsocks already uses HKDF-SHA1 to derive the AEAD key, so we use
	// the same derivation with a different "info" to generate our HMAC key.
	keySource := hkdf.New(crypto.SHA1.New, []byte(secret), nil, serverSaltLabel)
	// The key can be any size, but matching the block size is most efficient.
	key := make([]byte, crypto.SHA1.Size())
	io.ReadFull(keySource, key)
	return serverSaltGenerator{key}
}

func (sg serverSaltGenerator) splitSalt(salt []byte) (prefix, mark []byte, err error) {
	prefixLen := len(salt) - ServerSaltMarkLen
	if prefixLen < 0 {
		return nil, nil, fmt.Errorf("Salt is too short: %d < %d", len(salt), ServerSaltMarkLen)
	}
	return salt[:prefixLen], salt[prefixLen:], nil
}

// getTag takes in a salt prefix and returns the tag.
func (sg serverSaltGenerator) getTag(prefix []byte) []byte {
	// Use HMAC-SHA1, even though SHA1 is broken, because HMAC-SHA1 is still
	// secure, and we're already using HKDF-SHA1.
	hmac := hmac.New(crypto.SHA1.New, sg.key)
	hmac.Write(prefix) // Hash.Write never returns an error.
	return hmac.Sum(nil)
}

// GetSalt returns an apparently random salt that can be identified
// as server-originated by anyone who knows the Shadowsocks key.
func (sg serverSaltGenerator) GetSalt(salt []byte) error {
	prefix, mark, err := sg.splitSalt(salt)
	if err != nil {
		return err
	}
	if _, err := rand.Read(prefix); err != nil {
		return err
	}
	tag := sg.getTag(prefix)
	copy(mark, tag)
	return nil
}

func (sg serverSaltGenerator) IsServerSalt(salt []byte) bool {
	prefix, mark, err := sg.splitSalt(salt)
	if err != nil {
		return false
	}
	tag := sg.getTag(prefix)
	return bytes.Equal(tag[:ServerSaltMarkLen], mark)
}
<commit_msg>Rename randomServerSaltGenerator<commit_after>// Copyright 2020 Jigsaw Operations 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
//
//     https://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 service

import (
	"bytes"
	"crypto"
	"crypto/hmac"
	"crypto/rand"
	"fmt"
	"io"

	ss "github.com/Jigsaw-Code/outline-ss-server/shadowsocks"
	"golang.org/x/crypto/hkdf"
)

// ServerSaltGenerator offers the ability to check if a salt was marked as
// server-originated.
type ServerSaltGenerator interface {
	ss.SaltGenerator
	// IsServerSalt returns true if the salt was created by this generator
	// and is marked as server-originated.
	IsServerSalt(salt []byte) bool
}

// randomServerSaltGenerator generates a new random salt.
type randomServerSaltGenerator struct{}

// GetSalt outputs a random salt.
func (randomServerSaltGenerator) GetSalt(salt []byte) error {
	_, err := rand.Read(salt)
	return err
}

func (randomServerSaltGenerator) IsServerSalt(salt []byte) bool {
	return false
}

// RandomServerSaltGenerator is a basic ServerSaltGenerator.
var RandomServerSaltGenerator ServerSaltGenerator = randomServerSaltGenerator{}

// serverSaltGenerator generates unique salts that are secretly marked.
type serverSaltGenerator struct {
	key []byte
}

// ServerSaltMarkLen is the number of bytes of salt to use as a marker.
// Increasing this value reduces the false positive rate, but increases
// the likelihood of salt collisions.
const ServerSaltMarkLen = 4 // Must be less than or equal to SHA1.Size()

// Constant to identify this marking scheme.
var serverSaltLabel = []byte("outline-server-salt")

// NewServerSaltGenerator returns a SaltGenerator whose output is apparently
// random, but is secretly marked as being issued by the server.
// This is useful to prevent the server from accepting its own output in a
// reflection attack.
func NewServerSaltGenerator(secret string) ServerSaltGenerator {
	// Shadowsocks already uses HKDF-SHA1 to derive the AEAD key, so we use
	// the same derivation with a different "info" to generate our HMAC key.
	keySource := hkdf.New(crypto.SHA1.New, []byte(secret), nil, serverSaltLabel)
	// The key can be any size, but matching the block size is most efficient.
	key := make([]byte, crypto.SHA1.Size())
	io.ReadFull(keySource, key)
	return serverSaltGenerator{key}
}

func (sg serverSaltGenerator) splitSalt(salt []byte) (prefix, mark []byte, err error) {
	prefixLen := len(salt) - ServerSaltMarkLen
	if prefixLen < 0 {
		return nil, nil, fmt.Errorf("Salt is too short: %d < %d", len(salt), ServerSaltMarkLen)
	}
	return salt[:prefixLen], salt[prefixLen:], nil
}

// getTag takes in a salt prefix and returns the tag.
func (sg serverSaltGenerator) getTag(prefix []byte) []byte {
	// Use HMAC-SHA1, even though SHA1 is broken, because HMAC-SHA1 is still
	// secure, and we're already using HKDF-SHA1.
	hmac := hmac.New(crypto.SHA1.New, sg.key)
	hmac.Write(prefix) // Hash.Write never returns an error.
	return hmac.Sum(nil)
}

// GetSalt returns an apparently random salt that can be identified
// as server-originated by anyone who knows the Shadowsocks key.
func (sg serverSaltGenerator) GetSalt(salt []byte) error {
	prefix, mark, err := sg.splitSalt(salt)
	if err != nil {
		return err
	}
	if _, err := rand.Read(prefix); err != nil {
		return err
	}
	tag := sg.getTag(prefix)
	copy(mark, tag)
	return nil
}

func (sg serverSaltGenerator) IsServerSalt(salt []byte) bool {
	prefix, mark, err := sg.splitSalt(salt)
	if err != nil {
		return false
	}
	tag := sg.getTag(prefix)
	return bytes.Equal(tag[:ServerSaltMarkLen], mark)
}
<|endoftext|>


<commit_before>package brain

import (
	"fmt"
	"io"
	"strings"

	"github.com/BytemarkHosting/bytemark-client/lib/prettyprint"
)

// IPRange is a representation of an IP range
type IPRange struct {
	ID        int      `json:"id"`
	Spec      string   `json:"spec"`
	VLANNum   int      `json:"vlan_num"`
	Zones     []string `json:"zones"`
	Available float64  `json:"available"` // Needs to be a float64, since the number could go past int64 size
}

// String serialises an IP range to easily be output
func (ipr IPRange) String() string {
	zones := ""
	if len(ipr.Zones) > 0 {
		pluralise := ""
		if len(ipr.Zones) > 1 {
			pluralise = "s"
		}
		zones = fmt.Sprintf(", in zone%s %s", pluralise, strings.Join(ipr.Zones, ","))
	}
	// Since `Available` is a float64 but won't have decimal points, we just format accordingly.
	return fmt.Sprintf("%s%s, %.0f IPs available.", ipr.Spec, zones, ipr.Available)
}

// PrettyPrint writes an overview of this IP range out to the given writer.
func (ipr IPRange) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const t = `
{{ define "ip_range_sgl" -}}
• IP range {{ .Spec }} (ID: {{ .ID }}), has {{ len .Zones }} zones and {{ printf "%.0f" .Available }} IPs available.
{{ end }}

{{ define "ip_range_full" -}}
{{ template "ip_range_sgl" . }}
{{ template "zones" . }}
{{- end }}

{{ define "zones"  }}
{{- if .Zones }}    zones:
{{- range .Zones }}
      • {{ . }}
{{- end }}

{{ end -}}
{{ end }}
`
	return prettyprint.Run(wr, t, "ip_range"+string(detail), ipr)
}
<commit_msg>Add IntAsFloat type to ensure Available IPs on IPRanges gets displayed as a whole number<commit_after>package brain

import (
	"fmt"
	"io"
	"strings"

	"github.com/BytemarkHosting/bytemark-client/lib/prettyprint"
)

type IntAsFloat float64

func (iaf IntAsFloat) String() string {
	return fmt.Sprintf("%0.f", iaf)
}

// IPRange is a representation of an IP range
type IPRange struct {
	ID        int        `json:"id"`
	Spec      string     `json:"spec"`
	VLANNum   int        `json:"vlan_num"`
	Zones     []string   `json:"zones"`
	Available IntAsFloat `json:"available"` // Needs to be a float64, since the number could go past int64 size
}

// String serialises an IP range to easily be output
func (ipr IPRange) String() string {
	zones := ""
	if len(ipr.Zones) > 0 {
		pluralise := ""
		if len(ipr.Zones) > 1 {
			pluralise = "s"
		}
		zones = fmt.Sprintf(", in zone%s %s", pluralise, strings.Join(ipr.Zones, ","))
	}
	// Since `Available` is a float64 but won't have decimal points, we just format accordingly.
	return fmt.Sprintf("%s%s, %.0f IPs available.", ipr.Spec, zones, ipr.Available)
}

// PrettyPrint writes an overview of this IP range out to the given writer.
func (ipr IPRange) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const t = `
{{ define "ip_range_sgl" -}}
• IP range {{ .Spec }} (ID: {{ .ID }}), has {{ len .Zones }} zones and {{ printf "%.0f" .Available }} IPs available.
{{ end }}

{{ define "ip_range_full" -}}
{{ template "ip_range_sgl" . }}
{{ template "zones" . }}
{{- end }}

{{ define "zones"  }}
{{- if .Zones }}    zones:
{{- range .Zones }}
      • {{ . }}
{{- end }}

{{ end -}}
{{ end }}
`
	return prettyprint.Run(wr, t, "ip_range"+string(detail), ipr)
}
<|endoftext|>


<commit_before>package qingcloud

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func modifyVxnetAttributes(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).vxnet
	input := new(qc.ModifyVxNetAttributesInput)
	input.VxNet = qc.String(d.Id())
	attributeUpdate := false
	if d.HasChange("description") {
		if d.Get("description").(string) != "" {
			input.Description = qc.String(d.Get("description").(string))
		} else {
			input.Description = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("name") && !d.IsNewResource() {
		if d.Get("name").(string) != "" {
			input.VxNetName = qc.String(d.Get("description").(string))
		} else {
			input.VxNetName = qc.String(" ")
		}
		attributeUpdate = true
	}
	if attributeUpdate {
		_, err := clt.ModifyVxNetAttributes(input)
		return err
	}
	return nil
}

func vxnetJoinRouter(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.JoinRouterInput)
	input.VxNet = qc.String(d.Id())
	input.Router = qc.String(d.Get("vpc_id").(string))
	input.IPNetwork = qc.String(d.Get("ip_network").(string))
	output, err := clt.JoinRouter(input)
	if err != nil {
		return fmt.Errorf("Error vxnet join router: %s", err)
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error vxnet join router: %s", *output.Message)
	}
	if _, err := RouterTransitionStateRefresh(meta.(*QingCloudClient).router, d.Get("vpc_id").(string)); err != nil {
		return err
	}
	return nil
}

func vxnetLeaverRouter(d *schema.ResourceData, meta interface{}) error {
	oldVPC, _ := d.GetChange("vpc_id")
	clt := meta.(*QingCloudClient).router
	input := new(qc.LeaveRouterInput)
	input.VxNets = []*string{qc.String(d.Id())}
	input.Router = qc.String(oldVPC.(string))
	output, err := clt.LeaveRouter(input)
	if err != nil {
		return fmt.Errorf("Error vxnet leave router: %s", err)
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error vxnet leave router: %s", *output.Message)
	}
	if _, err := VxnetLeaveRouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return err
	}
	if _, err := RouterTransitionStateRefresh(meta.(*QingCloudClient).router, d.Get("vpc_id").(string)); err != nil {
		return err
	}
	return nil
}
<commit_msg>fix typo error<commit_after>package qingcloud

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func modifyVxnetAttributes(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).vxnet
	input := new(qc.ModifyVxNetAttributesInput)
	input.VxNet = qc.String(d.Id())
	attributeUpdate := false
	if d.HasChange("description") {
		if d.Get("description").(string) != "" {
			input.Description = qc.String(d.Get("description").(string))
		} else {
			input.Description = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("name") && !d.IsNewResource() {
		if d.Get("name").(string) != "" {
			input.VxNetName = qc.String(d.Get("description").(string))
		} else {
			input.VxNetName = qc.String(" ")
		}
		attributeUpdate = true
	}
	if attributeUpdate {
		_, err := clt.ModifyVxNetAttributes(input)
		return err
	}
	return nil
}

func vxnetJoinRouter(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.JoinRouterInput)
	input.VxNet = qc.String(d.Id())
	input.Router = qc.String(d.Get("vpc_id").(string))
	input.IPNetwork = qc.String(d.Get("ip_network").(string))
	output, err := clt.JoinRouter(input)
	if err != nil {
		return fmt.Errorf("Error vxnet join router: %s", err)
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error vxnet join router: %s", *output.Message)
	}
	if _, err := RouterTransitionStateRefresh(meta.(*QingCloudClient).router, d.Get("vpc_id").(string)); err != nil {
		return err
	}
	return nil
}

func vxnetLeaverRouter(d *schema.ResourceData, meta interface{}) error {
	oldVPC, _ := d.GetChange("vpc_id")
	clt := meta.(*QingCloudClient).router
	input := new(qc.LeaveRouterInput)
	input.VxNets = []*string{qc.String(d.Id())}
	input.Router = qc.String(oldVPC.(string))
	output, err := clt.LeaveRouter(input)
	if err != nil {
		return fmt.Errorf("Error vxnet leave router: %s", err)
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error vxnet leave router: %s", *output.Message)
	}
	if _, err := VxnetLeaveRouterTransitionStateRefresh(meta.(*QingCloudClient).vxnet, d.Id()); err != nil {
		return err
	}
	if _, err := RouterTransitionStateRefresh(meta.(*QingCloudClient).router, d.Get("vpc_id").(string)); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package qingcloud

import (
	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func modifyVxnetAttributes(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).vxnet
	input := new(qc.ModifyVxNetAttributesInput)
	input.VxNet = qc.String(d.Id())
	attributeUpdate := false

	if d.HasChange("description") {
		if d.Get("description").(string) != "" {
			input.Description = qc.String(d.Get("description").(string))
		} else {
			input.Description = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("name") && !d.IsNewResource() {
		if d.Get("name").(string) != "" {
			input.VxNetName = qc.String(d.Get("description").(string))
		} else {
			input.VxNetName = qc.String(" ")
		}
		attributeUpdate = true
	}
	if attributeUpdate {
		_, err := clt.ModifyVxNetAttributes(input)
		return err
	}

	return nil
}
<commit_msg>add vxnet join router 、vxnet leave router func<commit_after>package qingcloud

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func modifyVxnetAttributes(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).vxnet
	input := new(qc.ModifyVxNetAttributesInput)
	input.VxNet = qc.String(d.Id())
	attributeUpdate := false
	if d.HasChange("description") {
		if d.Get("description").(string) != "" {
			input.Description = qc.String(d.Get("description").(string))
		} else {
			input.Description = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("name") && !d.IsNewResource() {
		if d.Get("name").(string) != "" {
			input.VxNetName = qc.String(d.Get("description").(string))
		} else {
			input.VxNetName = qc.String(" ")
		}
		attributeUpdate = true
	}
	if attributeUpdate {
		_, err := clt.ModifyVxNetAttributes(input)
		return err
	}
	return nil
}

func vxnetJoinRouter(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.JoinRouterInput)
	input.VxNet = qc.String(d.Id())
	input.Router = qc.String(d.Get("vpc_id").(string))
	input.IPNetwork = qc.String(d.Get("ip_network").(string))
	output, err := clt.JoinRouter(input)
	if err != nil {
		return fmt.Errorf("Error vxnet join router: %s", err)
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error vxnet join router: %s", *output.Message)
	}
	if _, err := RouterTransitionStateRefresh(meta.(*QingCloudClient).router, d.Get("vpc_id").(string)); err != nil {
		return err
	}
	return nil
}

func vxnetLeaverRouter(d *schema.ResourceData, meta interface{}) error {
	oldVPC, _ := d.GetChange("vpc_id")
	clt := meta.(*QingCloudClient).router
	input := new(qc.LeaveRouterInput)
	input.VxNets = []*string{qc.String(d.Id())}
	input.Router = qc.String(oldVPC.(string))
	output, err := clt.LeaveRouter(input)
	if err != nil {
		return fmt.Errorf("Error vxnet leave router: %s", err)
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error vxnet leave router: %s", *output.Message)
	}
	if _, err := RouterTransitionStateRefresh(meta.(*QingCloudClient).router, d.Get("vpc_id").(string)); err != nil {
		return err
	}
	return nil
}
<|endoftext|>