<commit_before>/*

   Copyright 2013 Niklas Voss

   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 golem

import (
	"errors"
	"github.com/garyburd/go-websocket/websocket"
	"log"
	"net/http"
	"reflect"
)

// Router handles multiplexing of incoming messenges by typenames/events.
// Initially a router uses heartbeats and the default protocol.
type Router struct {
	// Map of callbacks for event types.
	callbacks map[string]func(*Connection, interface{})
	// Protocol extensions
	extensions map[reflect.Type]reflect.Value
	// Function being called if connection is closed.
	closeFunc func(*Connection)
	// Function verifying handshake.
	handshakeFunc func(http.ResponseWriter, *http.Request) bool
	// Active protocol
	protocol Protocol
	// Flag to enable or disable heartbeats
	useHeartbeats bool
	//
	connExtensionConstructor reflect.Value
}

// NewRouter intialises a new instance and returns the pointer.
func NewRouter() *Router {
	// Tries to run hub, if already running nothing will happen.
	hub.run()
	// Returns pointer to instance.
	return &Router{
		callbacks:                make(map[string]func(*Connection, interface{})),
		extensions:               make(map[reflect.Type]reflect.Value),
		closeFunc:                func(*Connection) {},                                          // Empty placeholder close function.
		handshakeFunc:            func(http.ResponseWriter, *http.Request) bool { return true }, // Handshake always allowed.
		protocol:                 initialProtocol,
		useHeartbeats:            true,
		connExtensionConstructor: defaultConnectionExtension,
	}
}

// Handler creates a handler function for this router, that can be used with the
// http-package to handle WebSocket-Connections.
func (router *Router) Handler() func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		// Check if method used was GET.
		if r.Method != "GET" {
			http.Error(w, "Method not allowed", 405)
			return
		}
		// Disallow cross-origin connections.
		if r.Header.Get("Origin") != "http://"+r.Host {
			http.Error(w, "Origin not allowed", 403)
			return
		}
		// Check if handshake callback verifies upgrade.
		if !router.handshakeFunc(w, r) {
			http.Error(w, "Authorization failed", 403)
			return
		}
		// Upgrade websocket connection.
		socket, err := websocket.Upgrade(w, r.Header, nil, 1024, 1024)
		// Check if handshake was successful
		if _, ok := err.(websocket.HandshakeError); ok {
			http.Error(w, "Not a websocket handshake", 400)
			return
		} else if err != nil {
			log.Println(err)
			return
		}

		// Create the connection.
		conn := newConnection(socket, router)
		//
		if router.connExtensionConstructor.IsValid() {
			conn.extend(router.connExtensionConstructor.Call([]reflect.Value{reflect.ValueOf(conn)})[0].Interface())
		}
		// And start reading and writing routines.
		conn.run()
	}
}

// The On-function adds callbacks by name of the event, that should be handled.
// For type T the callback would be of type:
//     func (*golem.Connection, *T)
// Type T can be any type. By default golem tries to unmarshal json into the
// specified type. If a custom protocol is used, it will be used instead to process the data.
// If type T is registered to use a protocol extension, it will be used instead.
// If type T is interface{} the interstage data of the active protocol will be directly forwarded!
// (Note: the golem wiki has a whole page about this function)
func (router *Router) On(name string, callback interface{}) {

	callbackValue := reflect.ValueOf(callback)
	callbackType := reflect.TypeOf(callback)
	if router.connExtensionConstructor.IsValid() {
		extType := router.connExtensionConstructor.Type().Out(0)
		if callbackType.In(0) == extType {
			// EXTENSION TYPE

			// NO DATA
			if callbackType.NumIn() == 1 {
				router.callbacks[name] = func(conn *Connection, data interface{}) {
					args := []reflect.Value{reflect.ValueOf(conn.extension)}
					callbackValue.Call(args)
				}
				return
			}

			// INTERFACE
			if callbackType.In(1).Kind() == reflect.Interface {
				router.callbacks[name] = func(conn *Connection, data interface{}) {
					args := []reflect.Value{reflect.ValueOf(conn.extension), reflect.ValueOf(data)}
					callbackValue.Call(args)
				}
				return
			}

			// PROTOCOL EXTENSION
			if parser, ok := router.extensions[callbackType.In(1)]; ok {
				router.callbacks[name] = func(conn *Connection, data interface{}) {
					if result := parser.Call([]reflect.Value{reflect.ValueOf(data)}); result[1].Bool() {
						args := []reflect.Value{reflect.ValueOf(conn.extension), result[0]}
						callbackValue.Call(args)
					}
				}
				return
			}

			// PROTOCOL
			callbackDataElem := callbackType.In(1).Elem()
			router.callbacks[name] = func(conn *Connection, data interface{}) {
				result := reflect.New(callbackDataElem)

				err := router.protocol.Unmarshal(data, result.Interface())
				if err == nil {
					args := []reflect.Value{reflect.ValueOf(conn.extension), result}
					callbackValue.Call(args)
				} else {
					// TODO: Proper debug output!
				}
			}
			return
		}
	} else {
		// DEFAULT TYPE

		// NO DATA
		if reflect.TypeOf(callback).NumIn() == 1 {
			router.callbacks[name] = func(conn *Connection, data interface{}) {
				callback.(func(*Connection))(conn)
			}
			return
		}

		// INTERFACE
		if cb, ok := callback.(func(*Connection, interface{})); ok {
			router.callbacks[name] = cb
			return
		}

		// PROTOCOL EXTENSION
		if parser, ok := router.extensions[callbackType.In(1)]; ok {
			router.callbacks[name] = func(conn *Connection, data interface{}) {
				if result := parser.Call([]reflect.Value{reflect.ValueOf(data)}); result[1].Bool() {
					args := []reflect.Value{reflect.ValueOf(conn), result[0]}
					callbackValue.Call(args)
				}
			}
			return
		}

		// PROTOCOL
		callbackDataElem := callbackType.In(1).Elem()
		router.callbacks[name] = func(conn *Connection, data interface{}) {
			result := reflect.New(callbackDataElem)

			err := router.protocol.Unmarshal(data, result.Interface())
			if err == nil {
				args := []reflect.Value{reflect.ValueOf(conn), result}
				callbackValue.Call(args)
			} else {
				// TODO: Proper debug output!
			}
		}
		return
	}
}

// Unpacks incoming data and forwards it to callback.
func (router *Router) processMessage(conn *Connection, in []byte) {
	if name, data, err := router.protocol.Unpack(in); err == nil {
		if callback, ok := router.callbacks[name]; ok {
			callback(conn, data)
		}
	} // TODO: else error logging?

	defer recover()
}

// OnClose sets the callback, that is called when the connection is closed.
// It accept function of the type func(*Connection) by default or functions
// taking extended connection types if previously registered.
func (router *Router) OnClose(callback interface{}) error { //func(*Connection)) {
	if cb, ok := callback.(func(*Connection)); ok {
		router.closeFunc = cb
	} else {
		if router.connExtensionConstructor.IsValid() {
			callbackValue := reflect.ValueOf(callback)
			extType := router.connExtensionConstructor.Type().Out(0)
			if reflect.TypeOf(callback).In(0) == extType {
				router.closeFunc = func(conn *Connection) {
					callbackValue.Call([]reflect.Value{reflect.ValueOf(conn.extension)})
				}
			} else {
				return errors.New("OnClose cannot accept a callback of the type " + reflect.TypeOf(callback).String() + ".")
			}
		} else {
			return errors.New("OnClose can only accept functions of the type func(*Connection), if no extension is registered.")
		}
	}
	return nil
}

// OnHandshake sets the callback for handshake verfication.
// If the handshake function returns false the request will not be upgraded.
func (router *Router) OnHandshake(callback func(http.ResponseWriter, *http.Request) bool) {
	router.handshakeFunc = callback
}

// The AddProtocolExtension-function allows adding of custom parsers for custom types. For any Type T
// the parser function would look like this:
//      func (interface{}) (T, bool)
// The interface's type is depending on the interstage product of the active protocol, by default
// for the JSON-based protocol it is []byte and therefore the function could be simplified to:
//      func ([]byte) (T, bool)
// Or in general if P is the interstage product:
//      func (*P) (T, bool)
// The boolean return value is necessary to verify if parsing was successful.
// All On-handling function accepting T as input data will now automatically use the custom
// extension. For an example see the example_data.go file in the example repository.
func (router *Router) AddProtocolExtension(extensionFunc interface{}) error {
	extensionValue := reflect.ValueOf(extensionFunc)
	extensionType := extensionValue.Type()

	if extensionType.NumIn() != 1 {
		return errors.New("Cannot add function(" + extensionType.String() + ") as parser: To many arguments!")
	}
	if extensionType.NumOut() != 2 {
		return errors.New("Cannot add function(" + extensionType.String() + ") as parser: Wrong number of return values!")
	}
	if extensionType.Out(1).Kind() != reflect.Bool {
		return errors.New("Cannot add function(" + extensionType.String() + ") as parser: Second return value is not Bool!")
	}

	router.extensions[extensionType.Out(0)] = extensionValue

	return nil
}

// SetConnectionExtension sets the extension for this router. A connection extension is an extended connection structure, that afterwards can be
// used by On-handlers as well (use-cases: add persistent storage to connection, additional methods et cetera).
// The SetConnectionExtension function takes the constructor of the custom format to be able to use and create it on
// connection to the router.
// For type E the constructor needs to fulfil the following requirements:
//     func NewE(conn *Connection) *E
// Afterwards On-handler can us this extended type:
//     router.On(func (extendedConn E, data Datatype) { ... })
// For an example have a look at the example repository and have a look at the 'example_connection_extension.go'.
func (router *Router) SetConnectionExtension(constructor interface{}) {
	router.connExtensionConstructor = reflect.ValueOf(constructor)
}

// SetProtocol sets the protocol of the router to the supplied implementation of the Protocol interface.
func (router *Router) SetProtocol(protocol Protocol) {
	router.protocol = protocol
}

//

// SetHeartbeat activates or deactivates the heartbeat depending on the flag parameter. By default heartbeats are activated.
func (router *Router) SetHeartbeat(flag bool) {
	router.useHeartbeats = flag
}
<commit_msg>OnConnection callback added to router.<commit_after>/*

   Copyright 2013 Niklas Voss

   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 golem

import (
	"errors"
	"github.com/garyburd/go-websocket/websocket"
	"log"
	"net/http"
	"reflect"
)

// Router handles multiplexing of incoming messenges by typenames/events.
// Initially a router uses heartbeats and the default protocol.
type Router struct {
	// Map of callbacks for event types.
	callbacks map[string]func(*Connection, interface{})
	// Protocol extensions
	extensions map[reflect.Type]reflect.Value
	// Function being called if connection is closed.
	closeFunc func(*Connection)
    // Function called after handshake when a WebSocket connection
    // was succesfully established.
    connectionFunc func(*Connection)
	// Function verifying handshake.
	handshakeFunc func(http.ResponseWriter, *http.Request) bool
	// Active protocol
	protocol Protocol
	// Flag to enable or disable heartbeats
	useHeartbeats bool
	//
	connExtensionConstructor reflect.Value
}

// NewRouter intialises a new instance and returns the pointer.
func NewRouter() *Router {
	// Tries to run hub, if already running nothing will happen.
	hub.run()
	// Returns pointer to instance.
	return &Router{
		callbacks:                make(map[string]func(*Connection, interface{})),
		extensions:               make(map[reflect.Type]reflect.Value),
		closeFunc:                func(*Connection) {},                                          // Empty placeholder close function.
        connectionFunc: func(*Connection) {},
		handshakeFunc:            func(http.ResponseWriter, *http.Request) bool { return true }, // Handshake always allowed.
		protocol:                 initialProtocol,
		useHeartbeats:            true,
		connExtensionConstructor: defaultConnectionExtension,
	}
}

// Handler creates a handler function for this router, that can be used with the
// http-package to handle WebSocket-Connections.
func (router *Router) Handler() func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		// Check if method used was GET.
		if r.Method != "GET" {
			http.Error(w, "Method not allowed", 405)
			return
		}
		// Disallow cross-origin connections.
		if r.Header.Get("Origin") != "http://"+r.Host {
			http.Error(w, "Origin not allowed", 403)
			return
		}
		// Check if handshake callback verifies upgrade.
		if !router.handshakeFunc(w, r) {
			http.Error(w, "Authorization failed", 403)
			return
		}
		// Upgrade websocket connection.
		socket, err := websocket.Upgrade(w, r.Header, nil, 1024, 1024)
		// Check if handshake was successful
		if _, ok := err.(websocket.HandshakeError); ok {
			http.Error(w, "Not a websocket handshake", 400)
			return
		} else if err != nil {
			log.Println(err)
			return
		}

		// Create the connection.
		conn := newConnection(socket, router)
		//
		if router.connExtensionConstructor.IsValid() {
			conn.extend(router.connExtensionConstructor.Call([]reflect.Value{reflect.ValueOf(conn)})[0].Interface())
		}

        // Connection established with possible extension, so callback
        router.connectionFunc(conn)

        // And start reading and writing routines.
		conn.run()
	}
}

// The On-function adds callbacks by name of the event, that should be handled.
// For type T the callback would be of type:
//     func (*golem.Connection, *T)
// Type T can be any type. By default golem tries to unmarshal json into the
// specified type. If a custom protocol is used, it will be used instead to process the data.
// If type T is registered to use a protocol extension, it will be used instead.
// If type T is interface{} the interstage data of the active protocol will be directly forwarded!
// (Note: the golem wiki has a whole page about this function)
func (router *Router) On(name string, callback interface{}) {

	callbackValue := reflect.ValueOf(callback)
	callbackType := reflect.TypeOf(callback)
	if router.connExtensionConstructor.IsValid() {
		extType := router.connExtensionConstructor.Type().Out(0)
		if callbackType.In(0) == extType {
			// EXTENSION TYPE

			// NO DATA
			if callbackType.NumIn() == 1 {
				router.callbacks[name] = func(conn *Connection, data interface{}) {
					args := []reflect.Value{reflect.ValueOf(conn.extension)}
					callbackValue.Call(args)
				}
				return
			}

			// INTERFACE
			if callbackType.In(1).Kind() == reflect.Interface {
				router.callbacks[name] = func(conn *Connection, data interface{}) {
					args := []reflect.Value{reflect.ValueOf(conn.extension), reflect.ValueOf(data)}
					callbackValue.Call(args)
				}
				return
			}

			// PROTOCOL EXTENSION
			if parser, ok := router.extensions[callbackType.In(1)]; ok {
				router.callbacks[name] = func(conn *Connection, data interface{}) {
					if result := parser.Call([]reflect.Value{reflect.ValueOf(data)}); result[1].Bool() {
						args := []reflect.Value{reflect.ValueOf(conn.extension), result[0]}
						callbackValue.Call(args)
					}
				}
				return
			}

			// PROTOCOL
			callbackDataElem := callbackType.In(1).Elem()
			router.callbacks[name] = func(conn *Connection, data interface{}) {
				result := reflect.New(callbackDataElem)

				err := router.protocol.Unmarshal(data, result.Interface())
				if err == nil {
					args := []reflect.Value{reflect.ValueOf(conn.extension), result}
					callbackValue.Call(args)
				} else {
					// TODO: Proper debug output!
				}
			}
			return
		}
	} else {
		// DEFAULT TYPE

		// NO DATA
		if reflect.TypeOf(callback).NumIn() == 1 {
			router.callbacks[name] = func(conn *Connection, data interface{}) {
				callback.(func(*Connection))(conn)
			}
			return
		}

		// INTERFACE
		if cb, ok := callback.(func(*Connection, interface{})); ok {
			router.callbacks[name] = cb
			return
		}

		// PROTOCOL EXTENSION
		if parser, ok := router.extensions[callbackType.In(1)]; ok {
			router.callbacks[name] = func(conn *Connection, data interface{}) {
				if result := parser.Call([]reflect.Value{reflect.ValueOf(data)}); result[1].Bool() {
					args := []reflect.Value{reflect.ValueOf(conn), result[0]}
					callbackValue.Call(args)
				}
			}
			return
		}

		// PROTOCOL
		callbackDataElem := callbackType.In(1).Elem()
		router.callbacks[name] = func(conn *Connection, data interface{}) {
			result := reflect.New(callbackDataElem)

			err := router.protocol.Unmarshal(data, result.Interface())
			if err == nil {
				args := []reflect.Value{reflect.ValueOf(conn), result}
				callbackValue.Call(args)
			} else {
				// TODO: Proper debug output!
			}
		}
		return
	}
}

// Unpacks incoming data and forwards it to callback.
func (router *Router) processMessage(conn *Connection, in []byte) {
	if name, data, err := router.protocol.Unpack(in); err == nil {
		if callback, ok := router.callbacks[name]; ok {
			callback(conn, data)
		}
	} // TODO: else error logging?

	defer recover()
}

// OnClose sets the callback, that is called when the connection is closed.
// It accept function of the type func(*Connection) by default or functions
// taking extended connection types if previously registered.
func (router *Router) OnClose(callback interface{}) error { //func(*Connection)) {
	if cb, ok := callback.(func(*Connection)); ok {
		router.closeFunc = cb
	} else {
		if router.connExtensionConstructor.IsValid() {
			callbackValue := reflect.ValueOf(callback)
			extType := router.connExtensionConstructor.Type().Out(0)
			if reflect.TypeOf(callback).In(0) == extType {
				router.closeFunc = func(conn *Connection) {
					callbackValue.Call([]reflect.Value{reflect.ValueOf(conn.extension)})
				}
			} else {
				return errors.New("OnClose cannot accept a callback of the type " + reflect.TypeOf(callback).String() + ".")
			}
		} else {
			return errors.New("OnClose can only accept functions of the type func(*Connection), if no extension is registered.")
		}
	}
	return nil
}

// OnConnection sets the callback, that is called when a websocket connection
// was successfully established, it is therefore called after the handshake.
// It accept function of the type func(*Connection) by default or functions
// taking extended connection types if previously registered.
func (router *Router) OnConnection(callback interface{}) error { //func(*Connection)) {
	if cb, ok := callback.(func(*Connection)); ok {
		router.connectionFunc = cb
	} else {
		if router.connExtensionConstructor.IsValid() {
			callbackValue := reflect.ValueOf(callback)
			extType := router.connExtensionConstructor.Type().Out(0)
			if reflect.TypeOf(callback).In(0) == extType {
				router.connectionFunc = func(conn *Connection) {
					callbackValue.Call([]reflect.Value{reflect.ValueOf(conn.extension)})
				}
			} else {
				return errors.New("OnConnection cannot accept a callback of the type " + reflect.TypeOf(callback).String() + ".")
			}
		} else {
			return errors.New("OnConnection can only accept functions of the type func(*Connection), if no extension is registered.")
		}
	}
	return nil
}

// OnHandshake sets the callback for handshake verfication.
// If the handshake function returns false the request will not be upgraded.
func (router *Router) OnHandshake(callback func(http.ResponseWriter, *http.Request) bool) {
	router.handshakeFunc = callback
}

// The AddProtocolExtension-function allows adding of custom parsers for custom types. For any Type T
// the parser function would look like this:
//      func (interface{}) (T, bool)
// The interface's type is depending on the interstage product of the active protocol, by default
// for the JSON-based protocol it is []byte and therefore the function could be simplified to:
//      func ([]byte) (T, bool)
// Or in general if P is the interstage product:
//      func (*P) (T, bool)
// The boolean return value is necessary to verify if parsing was successful.
// All On-handling function accepting T as input data will now automatically use the custom
// extension. For an example see the example_data.go file in the example repository.
func (router *Router) AddProtocolExtension(extensionFunc interface{}) error {
	extensionValue := reflect.ValueOf(extensionFunc)
	extensionType := extensionValue.Type()

	if extensionType.NumIn() != 1 {
		return errors.New("Cannot add function(" + extensionType.String() + ") as parser: To many arguments!")
	}
	if extensionType.NumOut() != 2 {
		return errors.New("Cannot add function(" + extensionType.String() + ") as parser: Wrong number of return values!")
	}
	if extensionType.Out(1).Kind() != reflect.Bool {
		return errors.New("Cannot add function(" + extensionType.String() + ") as parser: Second return value is not Bool!")
	}

	router.extensions[extensionType.Out(0)] = extensionValue

	return nil
}

// SetConnectionExtension sets the extension for this router. A connection extension is an extended connection structure, that afterwards can be
// used by On-handlers as well (use-cases: add persistent storage to connection, additional methods et cetera).
// The SetConnectionExtension function takes the constructor of the custom format to be able to use and create it on
// connection to the router.
// For type E the constructor needs to fulfil the following requirements:
//     func NewE(conn *Connection) *E
// Afterwards On-handler can us this extended type:
//     router.On(func (extendedConn E, data Datatype) { ... })
// For an example have a look at the example repository and have a look at the 'example_connection_extension.go'.
func (router *Router) SetConnectionExtension(constructor interface{}) {
	router.connExtensionConstructor = reflect.ValueOf(constructor)
}

// SetProtocol sets the protocol of the router to the supplied implementation of the Protocol interface.
func (router *Router) SetProtocol(protocol Protocol) {
	router.protocol = protocol
}

//

// SetHeartbeat activates or deactivates the heartbeat depending on the flag parameter. By default heartbeats are activated.
func (router *Router) SetHeartbeat(flag bool) {
	router.useHeartbeats = flag
}
<|endoftext|>


<commit_before>package main

import (
  "github.com/ricallinson/forgery"
  "github.com/spacedock-io/index/common"
)

func Routes(server *f.Server) {
  /*
    Stuff needed for private index
   */
  server.Get("/v1/_ping", func(req *f.Request, res *f.Response, next func()) {
    res.SetHeader("X-Docker-Registry-Standalone", "False")
    res.Send("true")
  })

  /*
    Library repository routes
   */
  server.Put("/v1/repositories/:repo/auth/", common.TokenAuth, LibraryAuth)
  server.Put("/v1/repositories/:repo/", common.BasicAuth, CreateLibrary)
  server.Delete("/v1/repositories/:repo/", DeleteLibrary)
  server.Put("/v1/repositories/:repo/images/", UpdateLibraryImage)
  server.Get("/v1/repositories/:repo/images/", GetLibraryImage)

  /*
    User routes
   */
  server.Get("/v1/users/", common.BasicAuth, Login)
  server.Post("/v1/users/", CreateUser)
  server.Put("/v1/users/:username/", common.BasicAuth, UpdateUser)

  /*
    User repository routes
   */
  server.Put("/v1/repositories/:namespace/:repo/auth/", common.TokenAuth, RepoAuth)
  server.Put("/v1/repositories/:namespace/:repo/", common.BasicAuth, CreateRepo)
  server.Delete("/v1/repositories/:namespace/:repo/", common.BasicAuth, DeleteRepo)
  server.Put("/v1/repositories/:namespace/:repo/images/", common.BasicAuth, UpdateUserImage)
  server.Get("/v1/repositories/:namespace/:repo/images/", GetUserImage)

  // Search route
  server.Get("/v1/search/", Search)
}
<commit_msg>Add common.BasicAuth to a few routes<commit_after>package main

import (
  "github.com/ricallinson/forgery"
  "github.com/spacedock-io/index/common"
)

func Routes(server *f.Server) {
  /*
    Stuff needed for private index
   */
  server.Get("/v1/_ping", func(req *f.Request, res *f.Response, next func()) {
    res.SetHeader("X-Docker-Registry-Standalone", "False")
    res.Send("true")
  })

  /*
    Library repository routes
   */
  server.Put("/v1/repositories/:repo/auth/", common.TokenAuth, LibraryAuth)
  server.Put("/v1/repositories/:repo/", common.BasicAuth, CreateLibrary)
  server.Delete("/v1/repositories/:repo/", common.BasicAuth, DeleteLibrary)
  server.Put("/v1/repositories/:repo/images/", common.BasicAuth, UpdateLibraryImage)
  server.Get("/v1/repositories/:repo/images/", common.BasicAuth, GetLibraryImage)

  /*
    User routes
   */
  server.Get("/v1/users/", common.BasicAuth, Login)
  server.Post("/v1/users/", CreateUser)
  server.Put("/v1/users/:username/", common.BasicAuth, UpdateUser)

  /*
    User repository routes
   */
  server.Put("/v1/repositories/:namespace/:repo/auth/", common.TokenAuth, RepoAuth)
  server.Put("/v1/repositories/:namespace/:repo/", common.BasicAuth, CreateRepo)
  server.Delete("/v1/repositories/:namespace/:repo/", common.BasicAuth, DeleteRepo)
  server.Put("/v1/repositories/:namespace/:repo/images/", common.BasicAuth, UpdateUserImage)
  server.Get("/v1/repositories/:namespace/:repo/images/", common.BasicAuth, GetUserImage)

  // Search route
  server.Get("/v1/search/", Search)
}
<|endoftext|>


<commit_before>package topology

import (
	"errors"
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/storage"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/storage/super_block"
)

// mapping from volume to its locations, inverted from server to volume
type VolumeLayout struct {
	rp               *super_block.ReplicaPlacement
	ttl              *needle.TTL
	vid2location     map[needle.VolumeId]*VolumeLocationList
	writables        []needle.VolumeId        // transient array of writable volume id
	readonlyVolumes  map[needle.VolumeId]bool // transient set of readonly volumes
	oversizedVolumes map[needle.VolumeId]bool // set of oversized volumes
	volumeSizeLimit  uint64
	accessLock       sync.RWMutex
}

type VolumeLayoutStats struct {
	TotalSize uint64
	UsedSize  uint64
	FileCount uint64
}

func NewVolumeLayout(rp *super_block.ReplicaPlacement, ttl *needle.TTL, volumeSizeLimit uint64) *VolumeLayout {
	return &VolumeLayout{
		rp:               rp,
		ttl:              ttl,
		vid2location:     make(map[needle.VolumeId]*VolumeLocationList),
		writables:        *new([]needle.VolumeId),
		readonlyVolumes:  make(map[needle.VolumeId]bool),
		oversizedVolumes: make(map[needle.VolumeId]bool),
		volumeSizeLimit:  volumeSizeLimit,
	}
}

func (vl *VolumeLayout) String() string {
	return fmt.Sprintf("rp:%v, ttl:%v, vid2location:%v, writables:%v, volumeSizeLimit:%v", vl.rp, vl.ttl, vl.vid2location, vl.writables, vl.volumeSizeLimit)
}

func (vl *VolumeLayout) RegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	defer vl.ensureCorrectWritables(v)
	defer vl.rememberOversizedVolume(v)

	if _, ok := vl.vid2location[v.Id]; !ok {
		vl.vid2location[v.Id] = NewVolumeLocationList()
	}
	vl.vid2location[v.Id].Set(dn)
	// glog.V(4).Infof("volume %d added to %s len %d copy %d", v.Id, dn.Id(), vl.vid2location[v.Id].Length(), v.ReplicaPlacement.GetCopyCount())
	for _, dn := range vl.vid2location[v.Id].list {
		if vInfo, err := dn.GetVolumesById(v.Id); err == nil {
			if vInfo.ReadOnly {
				glog.V(1).Infof("vid %d removed from writable", v.Id)
				vl.removeFromWritable(v.Id)
				vl.readonlyVolumes[v.Id] = true
				return
			} else {
				delete(vl.readonlyVolumes, v.Id)
			}
		} else {
			glog.V(1).Infof("vid %d removed from writable", v.Id)
			vl.removeFromWritable(v.Id)
			delete(vl.readonlyVolumes, v.Id)
			return
		}
	}

}

func (vl *VolumeLayout) rememberOversizedVolume(v *storage.VolumeInfo) {
	if vl.isOversized(v) {
		vl.oversizedVolumes[v.Id] = true
	}
}

func (vl *VolumeLayout) UnRegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	// remove from vid2location map
	location, ok := vl.vid2location[v.Id]
	if !ok {
		return
	}

	if location.Remove(dn) {

		vl.ensureCorrectWritables(v)

		if location.Length() == 0 {
			delete(vl.vid2location, v.Id)
		}

	}
}

func (vl *VolumeLayout) ensureCorrectWritables(v *storage.VolumeInfo) {
	if vl.vid2location[v.Id].Length() == vl.rp.GetCopyCount() && vl.isWritable(v) {
		if _, ok := vl.oversizedVolumes[v.Id]; !ok {
			vl.setVolumeWritable(v.Id)
		}
	} else {
		vl.removeFromWritable(v.Id)
	}
}

func (vl *VolumeLayout) isOversized(v *storage.VolumeInfo) bool {
	return uint64(v.Size) >= vl.volumeSizeLimit
}

func (vl *VolumeLayout) isWritable(v *storage.VolumeInfo) bool {
	return !vl.isOversized(v) &&
		v.Version == needle.CurrentVersion &&
		!v.ReadOnly
}

func (vl *VolumeLayout) isEmpty() bool {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	return len(vl.vid2location) == 0
}

func (vl *VolumeLayout) Lookup(vid needle.VolumeId) []*DataNode {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if location := vl.vid2location[vid]; location != nil {
		return location.list
	}
	return nil
}

func (vl *VolumeLayout) ListVolumeServers() (nodes []*DataNode) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	for _, location := range vl.vid2location {
		nodes = append(nodes, location.list...)
	}
	return
}

func (vl *VolumeLayout) PickForWrite(count uint64, option *VolumeGrowOption) (*needle.VolumeId, uint64, *VolumeLocationList, error) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	lenWriters := len(vl.writables)
	if lenWriters <= 0 {
		glog.V(0).Infoln("No more writable volumes!")
		return nil, 0, nil, errors.New("No more writable volumes!")
	}
	if option.DataCenter == "" {
		vid := vl.writables[rand.Intn(lenWriters)]
		locationList := vl.vid2location[vid]
		if locationList != nil {
			return &vid, count, locationList, nil
		}
		return nil, 0, nil, errors.New("Strangely vid " + vid.String() + " is on no machine!")
	}
	var vid needle.VolumeId
	var locationList *VolumeLocationList
	counter := 0
	for _, v := range vl.writables {
		volumeLocationList := vl.vid2location[v]
		for _, dn := range volumeLocationList.list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
				if rand.Intn(counter) < 1 {
					vid, locationList = v, volumeLocationList
				}
			}
		}
	}
	return &vid, count, locationList, nil
}

func (vl *VolumeLayout) GetActiveVolumeCount(option *VolumeGrowOption) int {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if option.DataCenter == "" {
		return len(vl.writables)
	}
	counter := 0
	for _, v := range vl.writables {
		for _, dn := range vl.vid2location[v].list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
			}
		}
	}
	return counter
}

func (vl *VolumeLayout) removeFromWritable(vid needle.VolumeId) bool {
	toDeleteIndex := -1
	for k, id := range vl.writables {
		if id == vid {
			toDeleteIndex = k
			break
		}
	}
	if toDeleteIndex >= 0 {
		glog.V(0).Infoln("Volume", vid, "becomes unwritable")
		vl.writables = append(vl.writables[0:toDeleteIndex], vl.writables[toDeleteIndex+1:]...)
		return true
	}
	return false
}
func (vl *VolumeLayout) setVolumeWritable(vid needle.VolumeId) bool {
	for _, v := range vl.writables {
		if v == vid {
			return false
		}
	}
	glog.V(0).Infoln("Volume", vid, "becomes writable")
	vl.writables = append(vl.writables, vid)
	return true
}

func (vl *VolumeLayout) SetVolumeUnavailable(dn *DataNode, vid needle.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	if location, ok := vl.vid2location[vid]; ok {
		if location.Remove(dn) {
			if location.Length() < vl.rp.GetCopyCount() {
				glog.V(0).Infoln("Volume", vid, "has", location.Length(), "replica, less than required", vl.rp.GetCopyCount())
				return vl.removeFromWritable(vid)
			}
		}
	}
	return false
}
func (vl *VolumeLayout) SetVolumeAvailable(dn *DataNode, vid needle.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	vInfo, err := dn.GetVolumesById(v.Id)
	if err != nil {
		return false
	}

	vl.vid2location[vid].Set(dn)

	if vInfo.ReadOnly {
		return false
	}

	if vl.vid2location[vid].Length() == vl.rp.GetCopyCount() {
		return vl.setVolumeWritable(vid)
	}
	return false
}

func (vl *VolumeLayout) SetVolumeCapacityFull(vid needle.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	// glog.V(0).Infoln("Volume", vid, "reaches full capacity.")
	return vl.removeFromWritable(vid)
}

func (vl *VolumeLayout) ToMap() map[string]interface{} {
	m := make(map[string]interface{})
	m["replication"] = vl.rp.String()
	m["ttl"] = vl.ttl.String()
	m["writables"] = vl.writables
	//m["locations"] = vl.vid2location
	return m
}

func (vl *VolumeLayout) Stats() *VolumeLayoutStats {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	ret := &VolumeLayoutStats{}

	freshThreshold := time.Now().Unix() - 60

	for vid, vll := range vl.vid2location {
		size, fileCount := vll.Stats(vid, freshThreshold)
		ret.FileCount += uint64(fileCount)
		ret.UsedSize += size
		if vl.readonlyVolumes[vid] {
			ret.TotalSize += size
		} else {
			ret.TotalSize += vl.volumeSizeLimit
		}
	}

	return ret
}
<commit_msg>fix compilation error<commit_after>package topology

import (
	"errors"
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/storage"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/storage/super_block"
)

// mapping from volume to its locations, inverted from server to volume
type VolumeLayout struct {
	rp               *super_block.ReplicaPlacement
	ttl              *needle.TTL
	vid2location     map[needle.VolumeId]*VolumeLocationList
	writables        []needle.VolumeId        // transient array of writable volume id
	readonlyVolumes  map[needle.VolumeId]bool // transient set of readonly volumes
	oversizedVolumes map[needle.VolumeId]bool // set of oversized volumes
	volumeSizeLimit  uint64
	accessLock       sync.RWMutex
}

type VolumeLayoutStats struct {
	TotalSize uint64
	UsedSize  uint64
	FileCount uint64
}

func NewVolumeLayout(rp *super_block.ReplicaPlacement, ttl *needle.TTL, volumeSizeLimit uint64) *VolumeLayout {
	return &VolumeLayout{
		rp:               rp,
		ttl:              ttl,
		vid2location:     make(map[needle.VolumeId]*VolumeLocationList),
		writables:        *new([]needle.VolumeId),
		readonlyVolumes:  make(map[needle.VolumeId]bool),
		oversizedVolumes: make(map[needle.VolumeId]bool),
		volumeSizeLimit:  volumeSizeLimit,
	}
}

func (vl *VolumeLayout) String() string {
	return fmt.Sprintf("rp:%v, ttl:%v, vid2location:%v, writables:%v, volumeSizeLimit:%v", vl.rp, vl.ttl, vl.vid2location, vl.writables, vl.volumeSizeLimit)
}

func (vl *VolumeLayout) RegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	defer vl.ensureCorrectWritables(v)
	defer vl.rememberOversizedVolume(v)

	if _, ok := vl.vid2location[v.Id]; !ok {
		vl.vid2location[v.Id] = NewVolumeLocationList()
	}
	vl.vid2location[v.Id].Set(dn)
	// glog.V(4).Infof("volume %d added to %s len %d copy %d", v.Id, dn.Id(), vl.vid2location[v.Id].Length(), v.ReplicaPlacement.GetCopyCount())
	for _, dn := range vl.vid2location[v.Id].list {
		if vInfo, err := dn.GetVolumesById(v.Id); err == nil {
			if vInfo.ReadOnly {
				glog.V(1).Infof("vid %d removed from writable", v.Id)
				vl.removeFromWritable(v.Id)
				vl.readonlyVolumes[v.Id] = true
				return
			} else {
				delete(vl.readonlyVolumes, v.Id)
			}
		} else {
			glog.V(1).Infof("vid %d removed from writable", v.Id)
			vl.removeFromWritable(v.Id)
			delete(vl.readonlyVolumes, v.Id)
			return
		}
	}

}

func (vl *VolumeLayout) rememberOversizedVolume(v *storage.VolumeInfo) {
	if vl.isOversized(v) {
		vl.oversizedVolumes[v.Id] = true
	}
}

func (vl *VolumeLayout) UnRegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	// remove from vid2location map
	location, ok := vl.vid2location[v.Id]
	if !ok {
		return
	}

	if location.Remove(dn) {

		vl.ensureCorrectWritables(v)

		if location.Length() == 0 {
			delete(vl.vid2location, v.Id)
		}

	}
}

func (vl *VolumeLayout) ensureCorrectWritables(v *storage.VolumeInfo) {
	if vl.vid2location[v.Id].Length() == vl.rp.GetCopyCount() && vl.isWritable(v) {
		if _, ok := vl.oversizedVolumes[v.Id]; !ok {
			vl.setVolumeWritable(v.Id)
		}
	} else {
		vl.removeFromWritable(v.Id)
	}
}

func (vl *VolumeLayout) isOversized(v *storage.VolumeInfo) bool {
	return uint64(v.Size) >= vl.volumeSizeLimit
}

func (vl *VolumeLayout) isWritable(v *storage.VolumeInfo) bool {
	return !vl.isOversized(v) &&
		v.Version == needle.CurrentVersion &&
		!v.ReadOnly
}

func (vl *VolumeLayout) isEmpty() bool {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	return len(vl.vid2location) == 0
}

func (vl *VolumeLayout) Lookup(vid needle.VolumeId) []*DataNode {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if location := vl.vid2location[vid]; location != nil {
		return location.list
	}
	return nil
}

func (vl *VolumeLayout) ListVolumeServers() (nodes []*DataNode) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	for _, location := range vl.vid2location {
		nodes = append(nodes, location.list...)
	}
	return
}

func (vl *VolumeLayout) PickForWrite(count uint64, option *VolumeGrowOption) (*needle.VolumeId, uint64, *VolumeLocationList, error) {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	lenWriters := len(vl.writables)
	if lenWriters <= 0 {
		glog.V(0).Infoln("No more writable volumes!")
		return nil, 0, nil, errors.New("No more writable volumes!")
	}
	if option.DataCenter == "" {
		vid := vl.writables[rand.Intn(lenWriters)]
		locationList := vl.vid2location[vid]
		if locationList != nil {
			return &vid, count, locationList, nil
		}
		return nil, 0, nil, errors.New("Strangely vid " + vid.String() + " is on no machine!")
	}
	var vid needle.VolumeId
	var locationList *VolumeLocationList
	counter := 0
	for _, v := range vl.writables {
		volumeLocationList := vl.vid2location[v]
		for _, dn := range volumeLocationList.list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
				if rand.Intn(counter) < 1 {
					vid, locationList = v, volumeLocationList
				}
			}
		}
	}
	return &vid, count, locationList, nil
}

func (vl *VolumeLayout) GetActiveVolumeCount(option *VolumeGrowOption) int {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	if option.DataCenter == "" {
		return len(vl.writables)
	}
	counter := 0
	for _, v := range vl.writables {
		for _, dn := range vl.vid2location[v].list {
			if dn.GetDataCenter().Id() == NodeId(option.DataCenter) {
				if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
					continue
				}
				if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
					continue
				}
				counter++
			}
		}
	}
	return counter
}

func (vl *VolumeLayout) removeFromWritable(vid needle.VolumeId) bool {
	toDeleteIndex := -1
	for k, id := range vl.writables {
		if id == vid {
			toDeleteIndex = k
			break
		}
	}
	if toDeleteIndex >= 0 {
		glog.V(0).Infoln("Volume", vid, "becomes unwritable")
		vl.writables = append(vl.writables[0:toDeleteIndex], vl.writables[toDeleteIndex+1:]...)
		return true
	}
	return false
}
func (vl *VolumeLayout) setVolumeWritable(vid needle.VolumeId) bool {
	for _, v := range vl.writables {
		if v == vid {
			return false
		}
	}
	glog.V(0).Infoln("Volume", vid, "becomes writable")
	vl.writables = append(vl.writables, vid)
	return true
}

func (vl *VolumeLayout) SetVolumeUnavailable(dn *DataNode, vid needle.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	if location, ok := vl.vid2location[vid]; ok {
		if location.Remove(dn) {
			if location.Length() < vl.rp.GetCopyCount() {
				glog.V(0).Infoln("Volume", vid, "has", location.Length(), "replica, less than required", vl.rp.GetCopyCount())
				return vl.removeFromWritable(vid)
			}
		}
	}
	return false
}
func (vl *VolumeLayout) SetVolumeAvailable(dn *DataNode, vid needle.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	vInfo, err := dn.GetVolumesById(vid)
	if err != nil {
		return false
	}

	vl.vid2location[vid].Set(dn)

	if vInfo.ReadOnly {
		return false
	}

	if vl.vid2location[vid].Length() == vl.rp.GetCopyCount() {
		return vl.setVolumeWritable(vid)
	}
	return false
}

func (vl *VolumeLayout) SetVolumeCapacityFull(vid needle.VolumeId) bool {
	vl.accessLock.Lock()
	defer vl.accessLock.Unlock()

	// glog.V(0).Infoln("Volume", vid, "reaches full capacity.")
	return vl.removeFromWritable(vid)
}

func (vl *VolumeLayout) ToMap() map[string]interface{} {
	m := make(map[string]interface{})
	m["replication"] = vl.rp.String()
	m["ttl"] = vl.ttl.String()
	m["writables"] = vl.writables
	//m["locations"] = vl.vid2location
	return m
}

func (vl *VolumeLayout) Stats() *VolumeLayoutStats {
	vl.accessLock.RLock()
	defer vl.accessLock.RUnlock()

	ret := &VolumeLayoutStats{}

	freshThreshold := time.Now().Unix() - 60

	for vid, vll := range vl.vid2location {
		size, fileCount := vll.Stats(vid, freshThreshold)
		ret.FileCount += uint64(fileCount)
		ret.UsedSize += size
		if vl.readonlyVolumes[vid] {
			ret.TotalSize += size
		} else {
			ret.TotalSize += vl.volumeSizeLimit
		}
	}

	return ret
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Clever/go-bench/slowhttp"
	"fmt"
)

func main() {
	server, err := slowhttp.StartServer()
	if (err != nil) {
		fmt.Println(err)
	}

	// continue running until user input given
	var input string
    _, err2 := fmt.Scanf("%s", &input)
	if (err != nil) {
		fmt.Println(err2)
	}
	fmt.Println("Exiting.")
	server.Close()
}<commit_msg>Fixes start_server error handling, indentation, and trailing newline<commit_after>package main

import (
	"github.com/Clever/go-bench/slowhttp"
	"fmt"
)

func main() {
	server, err := slowhttp.StartServer()
	if (err != nil) {
		panic(err)
	}
	defer server.Close()

	// continue running until user input given
	var input string
	_, err2 := fmt.Scanf("%s", &input)
	if (err != nil) {
		fmt.Println(err2)
	}
	fmt.Println("Exiting.")
	server.Close()
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"time"

	"github.com/juju/errors"
	jujutxn "github.com/juju/txn"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2/txn"

	"github.com/juju/juju/leadership"
	"github.com/juju/juju/mongo"
)

// statusDoc represents a entity status in Mongodb.  The implicit
// _id field is explicitly set to the global key of the associated
// entity in the document's creation transaction, but omitted to allow
// direct use of the document in both create and update transactions.
type statusDoc struct {
	EnvUUID    string                 `bson:"env-uuid"`
	Status     Status                 `bson:"status"`
	StatusInfo string                 `bson:"statusinfo"`
	StatusData map[string]interface{} `bson:"statusdata"`

	// Updated used to be a *time.Time that was not present on statuses dating
	// from older versions of juju so this might be 0 for those cases.
	Updated int64 `bson:"updated"`

	// TODO(fwereade/wallyworld): lp:1479278
	// NeverSet is a short-term hack to work around a misfeature in service
	// status. To maintain current behaviour, we create service status docs
	// (and only service status documents) with NeverSet true; and then, when
	// reading them, if NeverSet is still true, we aggregate status from the
	// units instead.
	NeverSet bool `bson:"neverset"`
}

func unixNanoToTime(i int64) *time.Time {
	t := time.Unix(0, i)
	return &t
}

// mapKeys returns a copy of the supplied map, with all nested map[string]interface{}
// keys transformed by f. All other types are ignored.
func mapKeys(f func(string) string, input map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for key, value := range input {
		if submap, ok := value.(map[string]interface{}); ok {
			value = mapKeys(f, submap)
		}
		result[f(key)] = value
	}
	return result
}

// escapeKeys is used to escape bad keys in StatusData. A statusDoc without
// escaped keys is broken.
func escapeKeys(input map[string]interface{}) map[string]interface{} {
	return mapKeys(escapeReplacer.Replace, input)
}

// unescapeKeys is used to restore escaped keys from StatusData to their
// original values.
func unescapeKeys(input map[string]interface{}) map[string]interface{} {
	return mapKeys(unescapeReplacer.Replace, input)
}

// getStatus retrieves the status document associated with the given
// globalKey and converts it to a StatusInfo. If the status document
// is not found, a NotFoundError referencing badge will be returned.
func getStatus(st *State, globalKey, badge string) (_ StatusInfo, err error) {
	defer errors.DeferredAnnotatef(&err, "cannot get status")
	statuses, closer := st.getCollection(statusesC)
	defer closer()

	var doc statusDoc
	err = statuses.FindId(globalKey).One(&doc)
	if err == mgo.ErrNotFound {
		return StatusInfo{}, errors.NotFoundf(badge)
	} else if err != nil {
		return StatusInfo{}, errors.Trace(err)
	}

	return StatusInfo{
		Status:  doc.Status,
		Message: doc.StatusInfo,
		Data:    unescapeKeys(doc.StatusData),
		Since:   unixNanoToTime(doc.Updated),
	}, nil
}

// setStatusParams configures a setStatus call. All parameters are presumed to
// be set to valid values unless otherwise noted.
type setStatusParams struct {

	// badge is used to specialize any NotFound error emitted.
	badge string

	// globalKey uniquely identifies the entity to which the
	globalKey string

	// status is the status value.
	status Status

	// message is an optional string elaborating upon the status.
	message string

	// rawData is a map of arbitrary data elaborating upon the status and
	// message. Its keys are assumed not to have been escaped.
	rawData map[string]interface{}

	// token, if present, must accept an *[]txn.Op passed to its Check method,
	// and will prevent any change if it becomes invalid.
	token leadership.Token
}

// setStatus inteprets the supplied params as documented on the type.
func setStatus(st *State, params setStatusParams) (err error) {
	defer errors.DeferredAnnotatef(&err, "cannot set status")

	// TODO(fwereade): this can/should probably be recording the time the
	// status was *set*, not the time it happened to arrive in state.
	// We should almost certainly be accepting StatusInfo in the exposed
	// SetStatus methods, for symetry with the Status methods.
	now := time.Now().UnixNano()
	doc := statusDoc{
		Status:     params.status,
		StatusInfo: params.message,
		StatusData: escapeKeys(params.rawData),
		Updated:    now,
	}
	probablyUpdateStatusHistory(st, params.globalKey, doc)

	// Set the authoritative status document, or fail trying.
	buildTxn := updateStatusSource(st, params.globalKey, doc)
	if params.token != nil {
		buildTxn = buildTxnWithLeadership(buildTxn, params.token)
	}
	err = st.run(buildTxn)
	if cause := errors.Cause(err); cause == mgo.ErrNotFound {
		return errors.NotFoundf(params.badge)
	}
	return errors.Trace(err)
}

// updateStatusSource returns a transaction source that builds the operations
// necessary to set the supplied status (and to fail safely if leaked and
// executed late, so as not to overwrite more recent documents).
func updateStatusSource(st *State, globalKey string, doc statusDoc) jujutxn.TransactionSource {
	update := bson.D{{"$set", &doc}}
	return func(_ int) ([]txn.Op, error) {
		txnRevno, err := st.readTxnRevno(statusesC, globalKey)
		if err != nil {
			return nil, errors.Trace(err)
		}
		assert := bson.D{{"txn-revno", txnRevno}}
		return []txn.Op{{
			C:      statusesC,
			Id:     globalKey,
			Assert: assert,
			Update: update,
		}}, nil
	}
}

// createStatusOp returns the operation needed to create the given status
// document associated with the given globalKey.
func createStatusOp(st *State, globalKey string, doc statusDoc) txn.Op {
	return txn.Op{
		C:      statusesC,
		Id:     st.docID(globalKey),
		Assert: txn.DocMissing,
		Insert: &doc,
	}
}

// removeStatusOp returns the operation needed to remove the status
// document associated with the given globalKey.
func removeStatusOp(st *State, globalKey string) txn.Op {
	return txn.Op{
		C:      statusesC,
		Id:     st.docID(globalKey),
		Remove: true,
	}
}

type historicalStatusDoc struct {
	EnvUUID    string                 `bson:"env-uuid"`
	GlobalKey  string                 `bson:"globalkey"`
	Status     Status                 `bson:"status"`
	StatusInfo string                 `bson:"statusinfo"`
	StatusData map[string]interface{} `bson:"statusdata"`

	// Updated might not be present on statuses copied by old versions of juju
	// from yet older versions of juju. Do not dereference without checking.
	// Updated *time.Time `bson:"updated"`
	Updated int64 `bson:"updated"`
}

func probablyUpdateStatusHistory(st *State, globalKey string, doc statusDoc) {
	historyDoc := &historicalStatusDoc{
		// We can't guarantee that the statusDoc we're dealing with has the
		// env-uuid filled in; and envStateCollection does not trap inserts.
		// Good to be explicit; better to fix leaky abstraction.
		EnvUUID:    st.EnvironUUID(),
		Status:     doc.Status,
		StatusInfo: doc.StatusInfo,
		StatusData: doc.StatusData, // coming from a statusDoc, already escaped
		Updated:    doc.Updated,
		GlobalKey:  globalKey,
	}
	history, closer := st.getCollection(statusesHistoryC)
	defer closer()
	historyW := history.Writeable()
	if err := historyW.Insert(historyDoc); err != nil {
		logger.Errorf("failed to write status history: %v", err)
	}
}

func statusHistory(st *State, globalKey string, size int) ([]StatusInfo, error) {
	statusHistory, closer := st.getCollection(statusesHistoryC)
	defer closer()

	var docs []historicalStatusDoc
	query := statusHistory.Find(bson.D{{"globalkey", globalKey}})
	err := query.Sort("-updated").Limit(size).All(&docs)
	if err == mgo.ErrNotFound {
		return []StatusInfo{}, errors.NotFoundf("status history")
	} else if err != nil {
		return []StatusInfo{}, errors.Annotatef(err, "cannot get status history")
	}

	results := make([]StatusInfo, len(docs))
	for i, doc := range docs {
		results[i] = StatusInfo{
			Status:  doc.Status,
			Message: doc.StatusInfo,
			Data:    unescapeKeys(doc.StatusData),
			Since:   unixNanoToTime(doc.Updated),
		}
	}
	return results, nil
}

// PruneStatusHistory removes status history entries until
// only the maxLogsPerEntity newest records per unit remain.
func PruneStatusHistory(st *State, maxLogsPerEntity int) error {
	history, closer := st.getCollection(statusesHistoryC)
	defer closer()

	historyW := history.Writeable()

	// TODO(fwereade): This is a very strange implementation.
	//
	// It goes to a lot of effort to keep a *different* span of history for
	// each entity -- which effectively hides interaction history older than
	// the recorded span of the most-frequently-updated object.
	//
	// It would be much less surprising -- and much more efficient -- to keep
	// either a fixed total number of records, or a fixed total span of history,
	// -- but either way we should be deleting only the oldest records at any
	// given time.
	globalKeys, err := getEntitiesWithStatuses(historyW)
	if err != nil {
		return errors.Trace(err)
	}
	for _, globalKey := range globalKeys {
		keepUpTo, ok, err := getOldestTimeToKeep(historyW, globalKey, maxLogsPerEntity)
		if err != nil {
			return errors.Trace(err)
		}
		if !ok {
			continue
		}
		_, err = historyW.RemoveAll(bson.D{
			{"globalkey", globalKey},
			{"updated", bson.M{"$lt": keepUpTo}},
		})
		if err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

// getOldestTimeToKeep returns the create time for the oldest
// status log to be kept.
func getOldestTimeToKeep(coll mongo.Collection, globalKey string, size int) (int64, bool, error) {
	result := historicalStatusDoc{}
	err := coll.Find(bson.D{{"globalkey", globalKey}}).Sort("-updated").Skip(size - 1).One(&result)
	if err == mgo.ErrNotFound {
		return -1, false, nil
	}
	if err != nil {
		return -1, false, errors.Trace(err)
	}
	return result.Updated, true, nil

}

// getEntitiesWithStatuses returns the ids for all entities that
// have history entries
func getEntitiesWithStatuses(coll mongo.Collection) ([]string, error) {
	var globalKeys []string
	err := coll.Find(nil).Distinct("globalkey", &globalKeys)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return globalKeys, nil
}
<commit_msg>state: status history inserts no longer need to include EnvUUID<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"time"

	"github.com/juju/errors"
	jujutxn "github.com/juju/txn"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2/txn"

	"github.com/juju/juju/leadership"
	"github.com/juju/juju/mongo"
)

// statusDoc represents a entity status in Mongodb.  The implicit
// _id field is explicitly set to the global key of the associated
// entity in the document's creation transaction, but omitted to allow
// direct use of the document in both create and update transactions.
type statusDoc struct {
	EnvUUID    string                 `bson:"env-uuid"`
	Status     Status                 `bson:"status"`
	StatusInfo string                 `bson:"statusinfo"`
	StatusData map[string]interface{} `bson:"statusdata"`

	// Updated used to be a *time.Time that was not present on statuses dating
	// from older versions of juju so this might be 0 for those cases.
	Updated int64 `bson:"updated"`

	// TODO(fwereade/wallyworld): lp:1479278
	// NeverSet is a short-term hack to work around a misfeature in service
	// status. To maintain current behaviour, we create service status docs
	// (and only service status documents) with NeverSet true; and then, when
	// reading them, if NeverSet is still true, we aggregate status from the
	// units instead.
	NeverSet bool `bson:"neverset"`
}

func unixNanoToTime(i int64) *time.Time {
	t := time.Unix(0, i)
	return &t
}

// mapKeys returns a copy of the supplied map, with all nested map[string]interface{}
// keys transformed by f. All other types are ignored.
func mapKeys(f func(string) string, input map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for key, value := range input {
		if submap, ok := value.(map[string]interface{}); ok {
			value = mapKeys(f, submap)
		}
		result[f(key)] = value
	}
	return result
}

// escapeKeys is used to escape bad keys in StatusData. A statusDoc without
// escaped keys is broken.
func escapeKeys(input map[string]interface{}) map[string]interface{} {
	return mapKeys(escapeReplacer.Replace, input)
}

// unescapeKeys is used to restore escaped keys from StatusData to their
// original values.
func unescapeKeys(input map[string]interface{}) map[string]interface{} {
	return mapKeys(unescapeReplacer.Replace, input)
}

// getStatus retrieves the status document associated with the given
// globalKey and converts it to a StatusInfo. If the status document
// is not found, a NotFoundError referencing badge will be returned.
func getStatus(st *State, globalKey, badge string) (_ StatusInfo, err error) {
	defer errors.DeferredAnnotatef(&err, "cannot get status")
	statuses, closer := st.getCollection(statusesC)
	defer closer()

	var doc statusDoc
	err = statuses.FindId(globalKey).One(&doc)
	if err == mgo.ErrNotFound {
		return StatusInfo{}, errors.NotFoundf(badge)
	} else if err != nil {
		return StatusInfo{}, errors.Trace(err)
	}

	return StatusInfo{
		Status:  doc.Status,
		Message: doc.StatusInfo,
		Data:    unescapeKeys(doc.StatusData),
		Since:   unixNanoToTime(doc.Updated),
	}, nil
}

// setStatusParams configures a setStatus call. All parameters are presumed to
// be set to valid values unless otherwise noted.
type setStatusParams struct {

	// badge is used to specialize any NotFound error emitted.
	badge string

	// globalKey uniquely identifies the entity to which the
	globalKey string

	// status is the status value.
	status Status

	// message is an optional string elaborating upon the status.
	message string

	// rawData is a map of arbitrary data elaborating upon the status and
	// message. Its keys are assumed not to have been escaped.
	rawData map[string]interface{}

	// token, if present, must accept an *[]txn.Op passed to its Check method,
	// and will prevent any change if it becomes invalid.
	token leadership.Token
}

// setStatus inteprets the supplied params as documented on the type.
func setStatus(st *State, params setStatusParams) (err error) {
	defer errors.DeferredAnnotatef(&err, "cannot set status")

	// TODO(fwereade): this can/should probably be recording the time the
	// status was *set*, not the time it happened to arrive in state.
	// We should almost certainly be accepting StatusInfo in the exposed
	// SetStatus methods, for symetry with the Status methods.
	now := time.Now().UnixNano()
	doc := statusDoc{
		Status:     params.status,
		StatusInfo: params.message,
		StatusData: escapeKeys(params.rawData),
		Updated:    now,
	}
	probablyUpdateStatusHistory(st, params.globalKey, doc)

	// Set the authoritative status document, or fail trying.
	buildTxn := updateStatusSource(st, params.globalKey, doc)
	if params.token != nil {
		buildTxn = buildTxnWithLeadership(buildTxn, params.token)
	}
	err = st.run(buildTxn)
	if cause := errors.Cause(err); cause == mgo.ErrNotFound {
		return errors.NotFoundf(params.badge)
	}
	return errors.Trace(err)
}

// updateStatusSource returns a transaction source that builds the operations
// necessary to set the supplied status (and to fail safely if leaked and
// executed late, so as not to overwrite more recent documents).
func updateStatusSource(st *State, globalKey string, doc statusDoc) jujutxn.TransactionSource {
	update := bson.D{{"$set", &doc}}
	return func(_ int) ([]txn.Op, error) {
		txnRevno, err := st.readTxnRevno(statusesC, globalKey)
		if err != nil {
			return nil, errors.Trace(err)
		}
		assert := bson.D{{"txn-revno", txnRevno}}
		return []txn.Op{{
			C:      statusesC,
			Id:     globalKey,
			Assert: assert,
			Update: update,
		}}, nil
	}
}

// createStatusOp returns the operation needed to create the given status
// document associated with the given globalKey.
func createStatusOp(st *State, globalKey string, doc statusDoc) txn.Op {
	return txn.Op{
		C:      statusesC,
		Id:     st.docID(globalKey),
		Assert: txn.DocMissing,
		Insert: &doc,
	}
}

// removeStatusOp returns the operation needed to remove the status
// document associated with the given globalKey.
func removeStatusOp(st *State, globalKey string) txn.Op {
	return txn.Op{
		C:      statusesC,
		Id:     st.docID(globalKey),
		Remove: true,
	}
}

type historicalStatusDoc struct {
	EnvUUID    string                 `bson:"env-uuid"`
	GlobalKey  string                 `bson:"globalkey"`
	Status     Status                 `bson:"status"`
	StatusInfo string                 `bson:"statusinfo"`
	StatusData map[string]interface{} `bson:"statusdata"`

	// Updated might not be present on statuses copied by old versions of juju
	// from yet older versions of juju. Do not dereference without checking.
	// Updated *time.Time `bson:"updated"`
	Updated int64 `bson:"updated"`
}

func probablyUpdateStatusHistory(st *State, globalKey string, doc statusDoc) {
	historyDoc := &historicalStatusDoc{
		Status:     doc.Status,
		StatusInfo: doc.StatusInfo,
		StatusData: doc.StatusData, // coming from a statusDoc, already escaped
		Updated:    doc.Updated,
		GlobalKey:  globalKey,
	}
	history, closer := st.getCollection(statusesHistoryC)
	defer closer()
	historyW := history.Writeable()
	if err := historyW.Insert(historyDoc); err != nil {
		logger.Errorf("failed to write status history: %v", err)
	}
}

func statusHistory(st *State, globalKey string, size int) ([]StatusInfo, error) {
	statusHistory, closer := st.getCollection(statusesHistoryC)
	defer closer()

	var docs []historicalStatusDoc
	query := statusHistory.Find(bson.D{{"globalkey", globalKey}})
	err := query.Sort("-updated").Limit(size).All(&docs)
	if err == mgo.ErrNotFound {
		return []StatusInfo{}, errors.NotFoundf("status history")
	} else if err != nil {
		return []StatusInfo{}, errors.Annotatef(err, "cannot get status history")
	}

	results := make([]StatusInfo, len(docs))
	for i, doc := range docs {
		results[i] = StatusInfo{
			Status:  doc.Status,
			Message: doc.StatusInfo,
			Data:    unescapeKeys(doc.StatusData),
			Since:   unixNanoToTime(doc.Updated),
		}
	}
	return results, nil
}

// PruneStatusHistory removes status history entries until
// only the maxLogsPerEntity newest records per unit remain.
func PruneStatusHistory(st *State, maxLogsPerEntity int) error {
	history, closer := st.getCollection(statusesHistoryC)
	defer closer()

	historyW := history.Writeable()

	// TODO(fwereade): This is a very strange implementation.
	//
	// It goes to a lot of effort to keep a *different* span of history for
	// each entity -- which effectively hides interaction history older than
	// the recorded span of the most-frequently-updated object.
	//
	// It would be much less surprising -- and much more efficient -- to keep
	// either a fixed total number of records, or a fixed total span of history,
	// -- but either way we should be deleting only the oldest records at any
	// given time.
	globalKeys, err := getEntitiesWithStatuses(historyW)
	if err != nil {
		return errors.Trace(err)
	}
	for _, globalKey := range globalKeys {
		keepUpTo, ok, err := getOldestTimeToKeep(historyW, globalKey, maxLogsPerEntity)
		if err != nil {
			return errors.Trace(err)
		}
		if !ok {
			continue
		}
		_, err = historyW.RemoveAll(bson.D{
			{"globalkey", globalKey},
			{"updated", bson.M{"$lt": keepUpTo}},
		})
		if err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

// getOldestTimeToKeep returns the create time for the oldest
// status log to be kept.
func getOldestTimeToKeep(coll mongo.Collection, globalKey string, size int) (int64, bool, error) {
	result := historicalStatusDoc{}
	err := coll.Find(bson.D{{"globalkey", globalKey}}).Sort("-updated").Skip(size - 1).One(&result)
	if err == mgo.ErrNotFound {
		return -1, false, nil
	}
	if err != nil {
		return -1, false, errors.Trace(err)
	}
	return result.Updated, true, nil

}

// getEntitiesWithStatuses returns the ids for all entities that
// have history entries
func getEntitiesWithStatuses(coll mongo.Collection) ([]string, error) {
	var globalKeys []string
	err := coll.Find(nil).Distinct("globalkey", &globalKeys)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return globalKeys, nil
}
<|endoftext|>


<commit_before>package main

import (
	"strconv"

	"github.com/shirou/gopsutil/process"
)

// procinfo represent the processes informations
type procinfo struct {
	total   string
	running string
	//TODO add zombies threads ?
}

// Get informations about the processes
func getProcinfo() procinfo {
	ret := procinfo{}

	pids, err := processPids() //TODO replace by something like psutil.process_iter() if available in gopsutils
	if err == nil {
		run := 0
		for i := range pids {
			proc, err := process.NewProcess(pids[i])
			if err == nil { //TODO rename `err` variables names to avoid confusion ?
				status, err := procStatus(proc)
				if err == nil {
					if status == "R" { // "R" for running process
						run++
					}
				}
			}
		}
		ret.total = strconv.Itoa(len(pids))
		ret.running = strconv.Itoa(run)
	}
	return ret
}

// wrap `process.Pids()` in an unexported variable for testability
var processPids = func() ([]int32, error) {
	return process.Pids()
}

// wrap `process.Status()` in an unexported variable for testability
var procStatus = func(proc *process.Process) (string, error) {
	return proc.Status()
}
<commit_msg>Typos<commit_after>package main

import (
	"strconv"

	"github.com/shirou/gopsutil/process"
)

// procinfo represent the processes informations
type procinfo struct {
	total   string
	running string
	//TODO add zombies threads ?
}

// Get informations about the processes
func getProcinfo() procinfo {
	ret := procinfo{}

	pids, err := processPids() //TODO replace by something like psutil.process_iter() if available in gopsutils
	if err == nil {
		run := 0
		for i := range pids {
			proc, err := process.NewProcess(pids[i])
			if err == nil { //TODO rename `err` variables names to avoid confusion ?
				status, err := procStatus(proc)
				if err == nil {
					if status == "R" { // "R" for running process
						run++
					}
				}
			}
		}
		ret.total = strconv.Itoa(len(pids))
		ret.running = strconv.Itoa(run)
	}
	return ret
}

// wrap `process.Pids()` in an unexported variable for testability
var processPids = func() ([]int32, error) {
	return process.Pids()
}

// wrap `Process.Status()` in an unexported variable for testability
var procStatus = func(proc *process.Process) (string, error) {
	return proc.Status()
}
<|endoftext|>


<commit_before>// Copyright 2015 Blackhawk Network, Inc.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package chimpmail

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
)

type GlobalMergeVars struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

type To struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

type Message struct {
	Subject         string            `json:"subject"`
	FromEmail       string            `json:"from_email"`
	To              []To              `json:"to"`
	Important       bool              `json:"important"`
	GlobalMergeVars []GlobalMergeVars `json:"global_merge_vars"`
}

type SendTemplateRequest struct {
	Key             string            `json:"key"`
	TemplateName    string            `json:"template_name"`
	Message         Message           `json:"message"`
	TemplateContent []GlobalMergeVars `json:"template_content"`
}

func SendTemplate(senderMessage string, eGiftId string, toEmail string, partner string) (err error) {
	g := make([]GlobalMergeVars, 3)

	g[0] = GlobalMergeVars{
		Name:    "SENDER_MESSAGE",
		Content: senderMessage,
	}

	g[1] = GlobalMergeVars{
		Name:    "EGIFT_ID",
		Content: eGiftId,
	}

	g[2] = GlobalMergeVars{
		Name:    "PARTNER",
		Content: partner,
	}

	t := make([]To, 3)

	t[0] = To{
		Email: toEmail,
		Name:  toEmail,
	}

	t[1] = To{
		Email: "rdabas@nexient.com",
		Name:  "Rahul Dabas",
	}

	t[2] = To{
		Email: "dougbusley@gmail.com",
		Name:  "Doug Busley",
	}

	m := Message{
		Subject:         senderMessage,
		FromEmail:       "craig.thomas@bhnetwork.com",
		To:              t,
		Important:       true,
		GlobalMergeVars: g,
	}

	r := SendTemplateRequest{
		Key:          "53yx5-nHBEYqKlyf8zfk8g",
		Message:      m,
		TemplateName: "transactional-notification",
	}
	log.Print(r)

	buf, err := json.Marshal(r)

	if err != nil {
		log.Fatal(err)
	}
	log.Print(string(buf))

	b := bytes.NewBuffer(buf)
	resp, err := http.Post("https://mandrillapp.com/api/1.0/messages/send-template.json", "text/json", b)

	log.Print(resp.StatusCode)

	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	log.Print(body)

	s := string(body)
	log.Print(s)

	return err
}
<commit_msg>Update mandrillclient.go<commit_after>// Copyright 2015 Blackhawk Network, Inc.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package chimpmail

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
)

type GlobalMergeVars struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

type To struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

type Message struct {
	Subject         string            `json:"subject"`
	FromEmail       string            `json:"from_email"`
	To              []To              `json:"to"`
	Important       bool              `json:"important"`
	GlobalMergeVars []GlobalMergeVars `json:"global_merge_vars"`
}

type SendTemplateRequest struct {
	Key             string            `json:"key"`
	TemplateName    string            `json:"template_name"`
	Message         Message           `json:"message"`
	TemplateContent []GlobalMergeVars `json:"template_content"`
}

func SendTemplate(senderMessage string, eGiftId string, toEmail string, partner string) (err error) {
	g := make([]GlobalMergeVars, 3)

	g[0] = GlobalMergeVars{
		Name:    "SENDER_MESSAGE",
		Content: senderMessage,
	}

	g[1] = GlobalMergeVars{
		Name:    "EGIFT_ID",
		Content: eGiftId,
	}

	g[2] = GlobalMergeVars{
		Name:    "PARTNER",
		Content: partner,
	}

	t := make([]To, 3)

	t[0] = To{
		Email: toEmail,
		Name:  toEmail,
	}

	t[1] = To{
		Email: "rdabas@nexient.com",
		Name:  "Rahul Dabas",
	}

	t[2] = To{
		Email: "dougbusley@gmail.com",
		Name:  "Doug Busley",
	}

	m := Message{
		Subject:         senderMessage,
		FromEmail:       "craig.thomas@bhnetwork.com",
		To:              t,
		Important:       true,
		GlobalMergeVars: g,
	}

	r := SendTemplateRequest{
		Key:          "put-your-own-key-here",
		Message:      m,
		TemplateName: "transactional-notification",
	}
	log.Print(r)

	buf, err := json.Marshal(r)

	if err != nil {
		log.Fatal(err)
	}
	log.Print(string(buf))

	b := bytes.NewBuffer(buf)
	resp, err := http.Post("https://mandrillapp.com/api/1.0/messages/send-template.json", "text/json", b)

	log.Print(resp.StatusCode)

	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	log.Print(body)

	s := string(body)
	log.Print(s)

	return err
}
<|endoftext|>


<commit_before>package app

import (
	"os"

	"strings"

	"path"
	"path/filepath"

	"os/user"
)

const (
	// Version of the application
	Version = "banksaurus 1.2.0" // TODO: define this automagically on make build
)

// New creates an instance of App.
//
// An app needs a configuration file.
// The path to the configuration file can be defined by:
// 1) passing by argument to the new function;
// 2) Defining the BANKSAURUS_CONFIG environment variable
// Both ways should receive the full path to the configuration file.
//
// If a configuration file path is not defined,
// the default value is $HOME/.bank/config.json
//
func New(configurationFilePath string) (*App, error) {

	var projectPath string

	// Environment variable has priority above others
	configPath := os.Getenv("BANKSAURUS_CONFIG")
	if configPath != "" {
		configurationFilePath = configPath
	}

	// Assume defaults
	if configurationFilePath == "" {
		projectPath = path.Join(ConfigHome(), "config.json")
	}

	if configurationFilePath != "" {
		err := ValidatePath(configurationFilePath)
		if err != nil {
			return &App{}, err
		}

		projectPath, err = buildProjectPath(filepath.Dir(configurationFilePath))
		if err != nil {
			return &App{}, err
		}
	}

	application := &App{projectPath}
	err := application.Init()
	if err != nil {
		return &App{}, err
	}

	return application, nil
}

// A project must have in the project path
// - /configurations
// - /cmd
// - /infrastructure
func buildProjectPath(pth string) (string, error) {

	p := path.Join(pth, "..")

	err := ValidatePath(path.Join(p, "/configurations"))
	if err != nil {
		return "", ErrInvalidAppStructure
	}

	err = ValidatePath(path.Join(p, "/cmd"))
	if err != nil {
		return "", ErrInvalidAppStructure
	}

	err = ValidatePath(path.Join(p, "/infrastructure"))
	if err != nil {
		return "", ErrInvalidAppStructure
	}

	return p, nil
}

// App represents an application
type App struct {
	ProjectPath string
}

// ValidatePath checks if a path is valid
// A path is considered valid if:
// a) the path exists
// b) it's not a file
// If a path is valid the return is nil
func ValidatePath(path string) error {

	if !strings.HasPrefix(path, "/") {
		return ErrMalformedPath
	}

	_, err := os.Stat(path)
	if err != nil && os.IsNotExist(err) {
		return ErrPathDoesNotExist
	}
	if err != nil {
		return err
	}

	//if !fileInfo.IsDir() {
	//	return ErrPathIsFile
	//}

	return nil
}

// Init initializes the application
func (a *App) Init() error {

	if IsDev() {
		return nil
	}

	// Create home dir if not exists
	_, err := os.Stat(ConfigHome())
	if err != nil {
		if os.IsNotExist(err) {
			err = os.Mkdir(ConfigHome(), 0700)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	// TODO: Must create the configuration file here
	// touch applicationpath/config.json

	return nil
}

// ConfigHome defines the base directory relative to which
// user specific configuration files should be stored.
func ConfigHome() string {
	usr, err := user.Current()
	if err != nil {
		panic(err)
	}
	return path.Join(usr.HomeDir, ".bank")
}

// DatabasePath returns the path and name for the database
// taking into account the type of environment
func DatabasePath() (string, string) {
	dbName := "bank"
	if IsDev() {
		return dbName, os.TempDir()
	}

	return dbName, ConfigHome()
}

// IsDev returns if in dev environment or not
func IsDev() bool {
	if os.Getenv("BANKSAURUS_ENV") == "dev" {
		return true
	}
	return false
}
<commit_msg>ValidatePath ignores if it is file or directory<commit_after>package app

import (
	"os"

	"strings"

	"path"
	"path/filepath"

	"os/user"
)

const (
	// Version of the application
	Version = "banksaurus 1.2.0" // TODO: define this automagically on make build
)

// New creates an instance of App.
//
// An app needs a configuration file.
// The path to the configuration file can be defined by:
// 1) passing by argument to the new function;
// 2) Defining the BANKSAURUS_CONFIG environment variable
// Both ways should receive the full path to the configuration file.
//
// If a configuration file path is not defined,
// the default value is $HOME/.bank/config.json
//
func New(configurationFilePath string) (*App, error) {

	var projectPath string

	// Environment variable has priority above others
	configPath := os.Getenv("BANKSAURUS_CONFIG")
	if configPath != "" {
		configurationFilePath = configPath
	}

	// Assume defaults
	if configurationFilePath == "" {
		projectPath = path.Join(ConfigHome(), "config.json")
	}

	if configurationFilePath != "" {
		err := ValidatePath(configurationFilePath)
		if err != nil {
			return &App{}, err
		}

		projectPath, err = buildProjectPath(filepath.Dir(configurationFilePath))
		if err != nil {
			return &App{}, err
		}
	}

	application := &App{projectPath}
	err := application.Init()
	if err != nil {
		return &App{}, err
	}

	return application, nil
}

// A project must have in the project path
// - /configurations
// - /cmd
// - /infrastructure
func buildProjectPath(pth string) (string, error) {

	p := path.Join(pth, "..")

	err := ValidatePath(path.Join(p, "/configurations"))
	if err != nil {
		return "", ErrInvalidAppStructure
	}

	err = ValidatePath(path.Join(p, "/cmd"))
	if err != nil {
		return "", ErrInvalidAppStructure
	}

	err = ValidatePath(path.Join(p, "/infrastructure"))
	if err != nil {
		return "", ErrInvalidAppStructure
	}

	return p, nil
}

// App represents an application
type App struct {
	ProjectPath string
}

// ValidatePath checks if a path is valid
// A path is considered valid if exists.
func ValidatePath(path string) error {

	if !strings.HasPrefix(path, "/") {
		return ErrMalformedPath
	}

	_, err := os.Stat(path)
	if err != nil && os.IsNotExist(err) {
		return ErrPathDoesNotExist
	}
	if err != nil {
		return err
	}

	return nil
}

// Init initializes the application
func (a *App) Init() error {

	if IsDev() {
		return nil
	}

	// Create home dir if not exists
	_, err := os.Stat(ConfigHome())
	if err != nil {
		if os.IsNotExist(err) {
			err = os.Mkdir(ConfigHome(), 0700)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	// TODO: Must create the configuration file here
	// touch applicationpath/config.json

	return nil
}

// ConfigHome defines the base directory relative to which
// user specific configuration files should be stored.
func ConfigHome() string {
	usr, err := user.Current()
	if err != nil {
		panic(err)
	}
	return path.Join(usr.HomeDir, ".bank")
}

// DatabasePath returns the path and name for the database
// taking into account the type of environment
func DatabasePath() (string, string) {
	dbName := "bank"
	if IsDev() {
		return dbName, os.TempDir()
	}

	return dbName, ConfigHome()
}

// IsDev returns if in dev environment or not
func IsDev() bool {
	if os.Getenv("BANKSAURUS_ENV") == "dev" {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// 256 color terminal printing in Go.
package golor

import (
	"fmt"
)

// 16-colors
var RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, BLACK, WHITE int
var R, G, C, M, Y, W int

func Colorize(s string, fg int, bg int) string {
	if fg > 255 || bg > 255 {
		panic("invalid color index")
	}
	color := ""
	if fg > -1 {
		color += fmt.Sprintf("\033[38;5;%dm", fg)
	}
	if bg > -1 {
		color += fmt.Sprintf("\033[48;5;%dm", bg)
	}
	reset := "\033[0m"
	return color + s + reset
}

// RGB returns the color code corresponding a RGB value set. Arguments
// must range from 0 to 5.
func RGB(red, green, blue int) int {
	return 16 + (red * 36) + (green * 6) + blue
}

func init() {
	RED = RGB(5, 0, 0)
	GREEN = RGB(0, 5, 0)
	BLUE = RGB(0, 0, 0)
	CYAN = RGB(0, 5, 5)
	MAGENTA = RGB(5, 0, 5)
	YELLOW = RGB(5, 5, 0)
	BLACK = 0
	WHITE = RGB(5, 5, 5)

	R = RED
	G = GREEN
	C = CYAN
	M = MAGENTA
	Y = YELLOW
	W = WHITE
}
<commit_msg>forgot to restore color in event stream<commit_after>// 256 color terminal printing in Go.
package golor

import (
	"fmt"
)

// 16-colors
var RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, BLACK, WHITE int
var R, G, C, M, Y, W int

func Colorize(s string, fg int, bg int) string {
	if fg > 255 || bg > 255 {
		panic("invalid color index")
	}
	color := ""
	if fg > -1 {
		color += fmt.Sprintf("\033[38;5;%dm", fg)
	}
	if bg > -1 {
		color += fmt.Sprintf("\033[48;5;%dm", bg)
	}
	reset := "\033[0m"
	return color + s + reset
}

// RGB returns the color code corresponding a RGB value set. Arguments
// must range from 0 to 5.
func RGB(red, green, blue int) int {
	return 16 + (red * 36) + (green * 6) + blue
}

func init() {
	RED = RGB(5, 0, 0)
	GREEN = RGB(0, 5, 0)
	BLUE = RGB(0, 0, 5)
	CYAN = RGB(0, 5, 5)
	MAGENTA = RGB(5, 0, 5)
	YELLOW = RGB(5, 5, 0)
	BLACK = 0
	WHITE = RGB(5, 5, 5)

	R = RED
	G = GREEN
	C = CYAN
	M = MAGENTA
	Y = YELLOW
	W = WHITE
}
<|endoftext|>