<commit_before>package clusterapi

import (
	"github.com/docker/swarm-v2/api"
	"github.com/docker/swarm-v2/state"
	"golang.org/x/net/context"
)

// ListNodes returns a list of all nodes.
func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (*api.ListNodesResponse, error) {
	var nodes []*api.Node
	err := s.store.View(func(tx state.ReadTx) error {
		var err error

		nodes, err = tx.Nodes().Find(state.All)
		return err
	})
	if err != nil {
		return nil, err
	}
	return &api.ListNodesResponse{
		Nodes: nodes,
	}, nil
}
<commit_msg>clusterapi: Implement `UpdateNode`<commit_after>package clusterapi

import (
	"github.com/docker/swarm-v2/api"
	"github.com/docker/swarm-v2/state"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

// UpdateNode updates a Node referenced by NodeID with the given NodeSpec.
// TODO(aluzzardi): Not implemented.
func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest) (*api.UpdateNodeResponse, error) {
	return nil, grpc.Errorf(codes.Unimplemented, errNotImplemented.Error())
}

// ListNodes returns a list of all nodes.
func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (*api.ListNodesResponse, error) {
	var nodes []*api.Node
	err := s.store.View(func(tx state.ReadTx) error {
		var err error

		nodes, err = tx.Nodes().Find(state.All)
		return err
	})
	if err != nil {
		return nil, err
	}
	return &api.ListNodesResponse{
		Nodes: nodes,
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"strings"
)

var (
	mode       = flag.String("mode", "broadcast", "chan/broadcast . chan means using channel to dispatch ,must handshake. direct means broadcast to all other directly, handshake not need.")
	listenAddr = flag.String("listenAddr", ":8601", "listen address")
	hsPwd      = flag.String("handshakePwd", "", "encryption password for handshaking process. empty means no encryption")
)

type ConnInfo struct {
	conn    net.Conn // 客户端tcp连接
	chid    string   // 客户端的 channel id
	timeout uint32   // 客户端连接的心跳超时
	recvers []string // 接收者的chids
}

type SendQEle struct {
	chid string        // 发送者的 channel id
	data *bytes.Buffer // 发送的数据
}

var cmdQ = make(chan string)           // gorouting 控制命令
var sendQ = make(chan SendQEle)        // 要发送的数据发给 Dispatcher
var createConnQ = make(chan *ConnInfo) // 客户端连接创建
var removeConnQ = make(chan string)    // 客户端连接关闭

func main() {
	flag.Parse()
	log.Printf("-- Main started. Listen addr:%s, handshake password:%s, mode:%s \n", *listenAddr, *hsPwd, *mode)

	go Dispatcher()
	go Accepter(*listenAddr, *hsPwd, *mode)

	select {
	case cmd := <-cmdQ: // 收到控制指令
		if strings.EqualFold(cmd, "quit") {
			log.Println("quit")
			break
		}
	}
}

// 管理所有客户端连接信息； 发送数据
func Dispatcher() {
	connMap := make(map[string]*ConnInfo)
	for {
		select {
		case cmd := <-cmdQ:
			if strings.EqualFold(cmd, "quit") {
				break
			}

		case sendQEle := <-sendQ: // 从发送队列取出 chid->bytes ，找出接收者，然后发送出去。
			senderInfo, found := connMap[sendQEle.chid]
			if !found {
				continue
			}
			if senderInfo.recvers != nil && len(senderInfo.recvers) > 0 {
				for _, recvChid := range senderInfo.recvers {
					recverInfo, found := connMap[recvChid]
					if !found {
						continue
					}
					recverInfo.conn.Write(sendQEle.data.Bytes())
				}
			} else {
				for senderChid, v := range connMap {
					if senderChid != sendQEle.chid { // 不发给自己.
						v.conn.Write(sendQEle.data.Bytes())
					}
				}
			}

		case connInfo := <-createConnQ: // 接收到连接创建通知时，创建连接信息。
			connMap[connInfo.chid] = connInfo
			log.Println("接收到连接创建通知时，创建连接信息 ", connInfo)

		case chid := <-removeConnQ: // 接收到连接关闭通知时，移除连接信息。
			delete(connMap, chid)
			log.Println("接收到连接关闭通知时，移除连接信息 ", chid)
		}
	}
}

// 创建连接; 创建 Handler
func Accepter(listenAddr string, hsPwd string, mode string) {

	listener, err := net.Listen("tcp", listenAddr)
	if err != nil {
		log.Fatal(err)
		cmdQ <- "quit"
		return
	}

	chIdx := 1000
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
			continue
		}

		inputChid := ""
		if mode == "broadcast" {
			inputChid = fmt.Sprintf("%d", chIdx)
			chIdx++
		}

		log.Println("Accepter, inputChid=", inputChid)
		go Handler(conn, hsPwd, inputChid)
	}

}

// 连接建立之后的握手过程
func HandShake(conn net.Conn, hsPwd string) (chid string, recvers []string, err error) {
	err = nil
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		log.Println(scanner.Text()) // Println will add back the final '\n'

		var hsMap map[string]interface{}
		err = json.Unmarshal([]byte(scanner.Text()), &hsMap)
		if err != nil {
			return
		}

		if hsMap["req"] == "hs1" {
			if hsMap["chid"] == nil {
				continue
			}

			if len(hsMap["chid"].(string)) > 0 {
				chid = hsMap["chid"].(string)
			} else {
				// chid =uuid // TODO
			}

			hs2 := map[string]string{"rsp": "hs2", "chid": chid}
			enc := json.NewEncoder(conn)
			enc.Encode(hs2)

		} else if hsMap["req"] == "hs3" {
			if hsMap["recvers"] != nil {
				r := hsMap["recvers"].([]interface{})
				for _, v := range r {
					recvers = append(recvers, v.(string))
				}
			}

			hs4 := map[string]string{"rsp": "hs4", "result": "OK"}
			enc := json.NewEncoder(conn)
			enc.Encode(hs4)
			break
		}
	}
	if err = scanner.Err(); err != nil {
		log.Println("HandShake scanner:", err)
	}
	return
}

// 客户端连接的处理逻辑。 首先握手，握手失败关闭连接；然后读数据，写入 Dispatcher 的处理队列。
func Handler(conn net.Conn, hsPwd string, inputChid string) {
	defer conn.Close()

	chid := ""
	if len(inputChid) < 1 {
		ch, recvers, err := HandShake(conn, hsPwd)
		if err != nil {
			return
		}
		chid = ch
		createConnQ <- &ConnInfo{conn, chid, 600, recvers}
	} else {
		chid = inputChid
		createConnQ <- &ConnInfo{conn, chid, 0, nil}
	}

	for {
		data := make([]byte, 1048576)
		n, err := conn.Read(data) // 读出数据，放入 Dispatcher 的发送队列
		if err != nil {           // 关闭时给 Dispatcher 发送通知
			if err == io.EOF {
				log.Println("Connection closed!")
			} else {
				log.Println("Read error: ", err)
			}
			removeConnQ <- chid
			break
		}
		log.Println("Read data:", string(data[:n]))
		sendQ <- SendQEle{chid, bytes.NewBuffer(data[:n])}
	}
}
<commit_msg>add timeout to forwarding_server<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"strings"
	"time"
)

var (
	mode       = flag.String("mode", "broadcast", "chan/broadcast . chan means using channel to dispatch ,must handshake. direct means broadcast to all other directly, handshake not need.")
	listenAddr = flag.String("listenAddr", ":8601", "listen address")
	hsPwd      = flag.String("handshakePwd", "", "encryption password for handshaking process. empty means no encryption")
)

type ConnInfo struct {
	conn    net.Conn // 客户端tcp连接
	chid    string   // 客户端的 channel id
	timeout uint32   // 客户端连接的心跳超时
	recvers []string // 接收者的chids
}

type SendQEle struct {
	chid string        // 发送者的 channel id
	data *bytes.Buffer // 发送的数据
}

var cmdQ = make(chan string)           // gorouting 控制命令
var sendQ = make(chan SendQEle)        // 要发送的数据发给 Dispatcher
var createConnQ = make(chan *ConnInfo) // 客户端连接创建
var removeConnQ = make(chan string)    // 客户端连接关闭

func main() {
	flag.Parse()
	log.Printf("-- Main started. Listen addr:%s, handshake password:%s, mode:%s \n", *listenAddr, *hsPwd, *mode)

	go Dispatcher()
	go Accepter(*listenAddr, *hsPwd, *mode)

	select {
	case cmd := <-cmdQ: // 收到控制指令
		if strings.EqualFold(cmd, "quit") {
			log.Println("quit")
			break
		}
	}
}

// 管理所有客户端连接信息； 发送数据
func Dispatcher() {
	connMap := make(map[string]*ConnInfo)
	for {
		select {
		case cmd := <-cmdQ:
			if strings.EqualFold(cmd, "quit") {
				break
			}

		case sendQEle := <-sendQ: // 从发送队列取出 chid->bytes ，找出接收者，然后发送出去。
			senderInfo, found := connMap[sendQEle.chid]
			if !found {
				continue
			}
			if senderInfo.recvers != nil && len(senderInfo.recvers) > 0 {
				for _, recvChid := range senderInfo.recvers {
					recverInfo, found := connMap[recvChid]
					if !found {
						continue
					}
					recverInfo.conn.Write(sendQEle.data.Bytes())
				}
			} else {
				for senderChid, v := range connMap {
					if senderChid != sendQEle.chid { // 不发给自己.
						v.conn.Write(sendQEle.data.Bytes())
					}
				}
			}

		case connInfo := <-createConnQ: // 接收到连接创建通知时，创建连接信息。
			connMap[connInfo.chid] = connInfo
			log.Println("接收到连接创建通知时，创建连接信息 ", connInfo)

		case chid := <-removeConnQ: // 接收到连接关闭通知时，移除连接信息。
			delete(connMap, chid)
			log.Println("接收到连接关闭通知时，移除连接信息 ", chid)
		}
	}
}

// 创建连接; 创建 Handler
func Accepter(listenAddr string, hsPwd string, mode string) {

	listener, err := net.Listen("tcp", listenAddr)
	if err != nil {
		log.Fatal(err)
		cmdQ <- "quit"
		return
	}

	chIdx := 1000
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
			continue
		}
		conn.SetDeadline(time.Now().Add(time.Duration(30) * time.Second))

		inputChid := ""
		if mode == "broadcast" {
			inputChid = fmt.Sprintf("%d", chIdx)
			chIdx++
		}

		log.Println("Accepter, inputChid=", inputChid)
		go Handler(conn, hsPwd, inputChid)
	}

}

// 连接建立之后的握手过程
func HandShake(conn net.Conn, hsPwd string) (chid string, recvers []string, err error) {
	err = nil
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		log.Println(scanner.Text()) // Println will add back the final '\n'

		var hsMap map[string]interface{}
		err = json.Unmarshal([]byte(scanner.Text()), &hsMap)
		if err != nil {
			return
		}

		if hsMap["req"] == "hs1" {
			if hsMap["chid"] == nil {
				continue
			}

			if len(hsMap["chid"].(string)) > 0 {
				chid = hsMap["chid"].(string)
			} else {
				// chid =uuid // TODO
			}

			hs2 := map[string]string{"rsp": "hs2", "chid": chid}
			enc := json.NewEncoder(conn)
			enc.Encode(hs2)

		} else if hsMap["req"] == "hs3" {
			if hsMap["recvers"] != nil {
				r := hsMap["recvers"].([]interface{})
				for _, v := range r {
					recvers = append(recvers, v.(string))
				}
			}

			hs4 := map[string]string{"rsp": "hs4", "result": "OK"}
			enc := json.NewEncoder(conn)
			enc.Encode(hs4)
			break
		}
	}
	if err = scanner.Err(); err != nil {
		log.Println("HandShake scanner:", err)
	}
	return
}

// 客户端连接的处理逻辑。 首先握手，握手失败关闭连接；然后读数据，写入 Dispatcher 的处理队列。
func Handler(conn net.Conn, hsPwd string, inputChid string) {
	defer conn.Close()

	chid := ""
	if len(inputChid) < 1 {
		ch, recvers, err := HandShake(conn, hsPwd)
		if err != nil {
			return
		}
		chid = ch
		createConnQ <- &ConnInfo{conn, chid, 600, recvers}
	} else {
		chid = inputChid
		createConnQ <- &ConnInfo{conn, chid, 0, nil}
	}

	for {
		data := make([]byte, 1048576)
		n, err := conn.Read(data) // 读出数据，放入 Dispatcher 的发送队列
		if err != nil {           // 关闭时给 Dispatcher 发送通知
			if err == io.EOF {
				log.Println("Connection closed!")
			} else {
				log.Println("Read error: ", err)
			}
			removeConnQ <- chid
			break
		}
		conn.SetDeadline(time.Now().Add(time.Duration(120) * time.Second))
		log.Println("Read data:", string(data[:n]))
		sendQ <- SendQEle{chid, bytes.NewBuffer(data[:n])}
	}
}
<|endoftext|>


<commit_before>package HotPotatoFS

import (
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"github.com/golang/groupcache"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"syscall"
)

var filecache *groupcache.Group

func ServeDir(mountpoint string, target string, peerlist []string) {
	// me := "http://localhost"
	// peers := groupcache.NewHTTPPool(me)

	// Whenever peers change:
	//peers.Set("http://10.0.0.1", "http://10.0.0.2", "http://10.0.0.3")

	fuse.Debugf = log.Printf

	filecache = groupcache.NewGroup("filecache", 64<<20, groupcache.GetterFunc(
		func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
			contents, err := ioutil.ReadFile(key)
			dest.SetBytes(contents)
			return err
		}))

	c, err := fuse.Mount(mountpoint)
	if err != nil {
		log.Fatal(err)
	}

	fs.Serve(c, TargetDir{target})

}

type TargetDir struct {
	Path string
}

func (nf TargetDir) Root() (fs.Node, fuse.Error) {
	return Dir{Node{Path: nf.Path}}, nil
}

type Node struct {
	Path string
}

func (n Node) Attr() fuse.Attr {
	s, err := os.Stat(n.Path)
	if err != nil {
		log.Print(err)
		return fuse.Attr{}
	}

	return fuse.Attr{Size: uint64(s.Size()), Mtime: s.ModTime(), Mode: s.Mode()}
}

type Dir struct {
	Node
}

func (d Dir) Lookup(name string, intr fs.Intr) (fs fs.Node, error fuse.Error) {

	path := filepath.Join(d.Path, name)
	s, err := os.Stat(path)
	if err != nil {
		log.Print(err)
		return nil, fuse.ENOENT
	}
	node := Node{path}
	switch {
	case s.IsDir():
		fs = Dir{node}
	case s.Mode().IsRegular():
		fs = File{node}
	default:
		fs = node
	}

	return
}

func (d Dir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
	var out []fuse.Dirent
	files, err := ioutil.ReadDir(d.Path)
	if err != nil {
		log.Print(err)
		return nil, fuse.Errno(err.(syscall.Errno))
	}
	for _, d := range files {
		de := fuse.Dirent{Name: d.Name()}
		if d.IsDir() {
			de.Type = fuse.DT_Dir
		}
		if d.Mode().IsRegular() {
			de.Type = fuse.DT_File
		}
		out = append(out, de)
	}

	return out, nil
}

type File struct {
	Node
}

// func (f File) ReadAll(intr fs.Intr) ([]byte, fuse.Error) {
// 	var contents []byte
// 	err := filecache.Get(nil, f.Path, groupcache.AllocatingByteSliceSink(&contents))
// 	if err != nil {
// 		log.Print(err)
// 		return nil, fuse.ENOENT
// 	}
// 	return contents, nil
// }

// func (f File) Read(req *fuse.ReadRequest, resp *fuse.ReadResponse, intr fs.Intr) fuse.Error {
// 	//log.Print("Read Called: ", req, resp, intr)
// 	//fuse.Debugf = log.Printf
// 	var dst groupcache.ByteView
// 	err := filecache.Get(nil, f.Path, groupcache.ByteViewSink(&dst))
// 	if err != nil {
// 		log.Print(err)
// 		return fuse.ENOENT
// 	}

// 	resp = &fuse.ReadResponse{Data: dst.Slice(int(req.Offset), int(req.Offset)+req.Size).ByteSlice()}

// 	return nil
// }
<commit_msg>still not workign on os x<commit_after>package HotPotatoFS

import (
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"github.com/golang/groupcache"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"syscall"
)

var filecache *groupcache.Group

func ServeDir(mountpoint string, target string, peerlist []string) {
	// me := "http://localhost"
	// peers := groupcache.NewHTTPPool(me)

	// Whenever peers change:
	//peers.Set("http://10.0.0.1", "http://10.0.0.2", "http://10.0.0.3")

	//fuse.Debugf = log.Printf

	filecache = groupcache.NewGroup("filecache", 64<<20, groupcache.GetterFunc(
		func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
			contents, err := ioutil.ReadFile(key)
			dest.SetBytes(contents)
			return err
		}))

	c, err := fuse.Mount(mountpoint)
	if err != nil {
		log.Fatal(err)
	}

	fs.Serve(c, TargetDir{target})

}

type TargetDir struct {
	Path string
}

func (nf TargetDir) Root() (fs.Node, fuse.Error) {
	return Dir{Node{Path: nf.Path}}, nil
}

type Node struct {
	Path string
}

func (n Node) Attr() fuse.Attr {
	s, err := os.Stat(n.Path)
	if err != nil {
		log.Print(err)
		return fuse.Attr{}
	}

	return fuse.Attr{Size: uint64(s.Size()), Mtime: s.ModTime(), Mode: s.Mode()}
}

type Dir struct {
	Node
}

func (d Dir) Lookup(name string, intr fs.Intr) (fs fs.Node, error fuse.Error) {

	path := filepath.Join(d.Path, name)
	s, err := os.Stat(path)
	if err != nil {
		log.Print(err)
		return nil, fuse.ENOENT
	}
	node := Node{path}
	switch {
	case s.IsDir():
		fs = Dir{node}
	case s.Mode().IsRegular():
		fs = File{node}
	default:
		fs = node
	}

	return
}

func (d Dir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
	var out []fuse.Dirent
	files, err := ioutil.ReadDir(d.Path)
	if err != nil {
		log.Print(err)
		return nil, fuse.Errno(err.(syscall.Errno))
	}
	for _, d := range files {
		de := fuse.Dirent{Name: d.Name()}
		if d.IsDir() {
			de.Type = fuse.DT_Dir
		}
		if d.Mode().IsRegular() {
			de.Type = fuse.DT_File
		}
		out = append(out, de)
	}

	return out, nil
}

type File struct {
	Node
}

// func (f File) ReadAll(intr fs.Intr) ([]byte, fuse.Error) {
// 	var contents []byte
// 	err := filecache.Get(nil, f.Path, groupcache.AllocatingByteSliceSink(&contents))
// 	if err != nil {
// 		log.Print(err)
// 		return nil, fuse.ENOENT
// 	}
// 	return contents, nil
// }

// func (f File) Read(req *fuse.ReadRequest, resp *fuse.ReadResponse, intr fs.Intr) fuse.Error {
// 	//log.Print("Read Called: ", req, resp, intr)
// 	//fuse.Debugf = log.Printf
// 	var dst groupcache.ByteView
// 	err := filecache.Get(nil, f.Path, groupcache.ByteViewSink(&dst))
// 	if err != nil {
// 		log.Print(err)
// 		return fuse.ENOENT
// 	}

// 	resp = &fuse.ReadResponse{Data: dst.Slice(int(req.Offset), int(req.Offset)+req.Size).ByteSlice()}

// 	return nil
// }
<|endoftext|>


<commit_before>package masterapi

import (
	"fmt"
	"github.com/KIT-MAMID/mamid/master"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jinzhu/gorm"
	"net/http"
)

var masterapiLog = logrus.WithField("module", "masterapi")

type MasterAPI struct {
	DB               *model.DB
	ClusterAllocator *master.ClusterAllocator
	Router           *mux.Router
}

func (m *MasterAPI) Setup() {

	m.Router.Methods("GET").Path("/slaves").Name("SlaveIndex").HandlerFunc(m.SlaveIndex)
	m.Router.Methods("GET").Path("/slaves/{slaveId}").Name("SlaveById").HandlerFunc(m.SlaveById)
	m.Router.Methods("PUT").Path("/slaves").Name("SlavePut").HandlerFunc(m.SlavePut)
	m.Router.Methods("POST").Path("/slaves/{slaveId}").Name("SlaveUpdate").HandlerFunc(m.SlaveUpdate)
	m.Router.Methods("DELETE").Path("/slaves/{slaveId}").Name("SlaveDelete").HandlerFunc(m.SlaveDelete)

	m.Router.Methods("GET").Path("/replicasets").Name("ReplicaSetIndex").HandlerFunc(m.ReplicaSetIndex)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}").Name("ReplicaSetById").HandlerFunc(m.ReplicaSetById)
	m.Router.Methods("PUT").Path("/replicasets").Name("ReplicaSetPut").HandlerFunc(m.ReplicaSetPut)
	m.Router.Methods("POST").Path("/replicasets/{replicasetId}").Name("ReplicaSetUpdate").HandlerFunc(m.ReplicaSetUpdate)
	m.Router.Methods("DELETE").Path("/replicasets/{replicasetId}").Name("ReplicaSetDelete").HandlerFunc(m.ReplicaSetDelete)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}/slaves").Name("ReplicaSetGetSlaves").HandlerFunc(m.ReplicaSetGetSlaves)

	m.Router.Methods("GET").Path("/riskgroups").Name("RiskGroupIndex").HandlerFunc(m.RiskGroupIndex)
	m.Router.Methods("GET").Path("/riskgroups/{riskgroupId}").Name("RiskGroupById").HandlerFunc(m.RiskGroupById)
	m.Router.Methods("PUT").Path("/riskgroups").Name("RiskGroupPut").HandlerFunc(m.RiskGroupPut)
	m.Router.Methods("POST").Path("/riskgroups/{riskgroupId}").Name("RiskGroupUpdate").HandlerFunc(m.RiskGroupUpdate)
	m.Router.Methods("DELETE").Path("/riskgroups/{riskgroupId}").Name("RiskGroupDelete").HandlerFunc(m.RiskGroupDelete)
	m.Router.Methods("GET").Path("/riskgroups/{riskgroupId}/slaves").Name("RiskGroupGetSlaves").HandlerFunc(m.RiskGroupGetSlaves)
	m.Router.Methods("PUT").Path("/riskgroups/{riskgroupId}/slaves/{slaveId}").Name("RiskGroupAssignSlave").HandlerFunc(m.RiskGroupAssignSlave)
	m.Router.Methods("DELETE").Path("/riskgroups/{riskgroupId}/slaves/{slaveId}").Name("RiskGroupRemoveSlave").HandlerFunc(m.RiskGroupRemoveSlave)

	m.Router.Methods("GET").Path("/problems").Name("ProblemIndex").HandlerFunc(m.ProblemIndex)
	m.Router.Methods("GET").Path("/problems/{problemId}").Name("ProblemById").HandlerFunc(m.ProblemById)
	m.Router.Methods("GET").Path("/slaves/{slaveId}/problems").Name("ProblemBySlave").HandlerFunc(m.ProblemBySlave)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}/problems").Name("ProblemByReplicaSet").HandlerFunc(m.ProblemByReplicaSet)

	m.Router.Methods("GET").Path("/slaves/{slaveId}/mongods").Name("MongodsBySlave").HandlerFunc(m.MongodsBySlave)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}/mongods").Name("MongodsByReplicaSet").HandlerFunc(m.MongodsByReplicaSet)

	m.Router.Methods("GET").Path("/system/keyfile").Name("KeyfileGet").HandlerFunc(m.KeyfileGet)
	m.Router.Methods("GET").Path("/system/managementuser").Name("ManagementUserGet").HandlerFunc(m.ManagementUserGet)

}

func (m *MasterAPI) attemptClusterAllocator(tx *gorm.DB, w http.ResponseWriter) (err error) {
	err = m.ClusterAllocator.CompileMongodLayout(tx)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "cluster allocator failure: %s\n", err)
		if err = tx.Rollback().Error; err != nil {
			fmt.Fprintf(w, "cluster allocator rollback failure: %s\n", err)
		}
	}
	return err
}

func (m *MasterAPI) attemptCommit(tx *gorm.DB, w http.ResponseWriter) (err error) {
	err = tx.Commit().Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	}
	return err
}
<commit_msg>FIX: masterapi: return commit error to client<commit_after>package masterapi

import (
	"fmt"
	"github.com/KIT-MAMID/mamid/master"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jinzhu/gorm"
	"net/http"
)

var masterapiLog = logrus.WithField("module", "masterapi")

type MasterAPI struct {
	DB               *model.DB
	ClusterAllocator *master.ClusterAllocator
	Router           *mux.Router
}

func (m *MasterAPI) Setup() {

	m.Router.Methods("GET").Path("/slaves").Name("SlaveIndex").HandlerFunc(m.SlaveIndex)
	m.Router.Methods("GET").Path("/slaves/{slaveId}").Name("SlaveById").HandlerFunc(m.SlaveById)
	m.Router.Methods("PUT").Path("/slaves").Name("SlavePut").HandlerFunc(m.SlavePut)
	m.Router.Methods("POST").Path("/slaves/{slaveId}").Name("SlaveUpdate").HandlerFunc(m.SlaveUpdate)
	m.Router.Methods("DELETE").Path("/slaves/{slaveId}").Name("SlaveDelete").HandlerFunc(m.SlaveDelete)

	m.Router.Methods("GET").Path("/replicasets").Name("ReplicaSetIndex").HandlerFunc(m.ReplicaSetIndex)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}").Name("ReplicaSetById").HandlerFunc(m.ReplicaSetById)
	m.Router.Methods("PUT").Path("/replicasets").Name("ReplicaSetPut").HandlerFunc(m.ReplicaSetPut)
	m.Router.Methods("POST").Path("/replicasets/{replicasetId}").Name("ReplicaSetUpdate").HandlerFunc(m.ReplicaSetUpdate)
	m.Router.Methods("DELETE").Path("/replicasets/{replicasetId}").Name("ReplicaSetDelete").HandlerFunc(m.ReplicaSetDelete)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}/slaves").Name("ReplicaSetGetSlaves").HandlerFunc(m.ReplicaSetGetSlaves)

	m.Router.Methods("GET").Path("/riskgroups").Name("RiskGroupIndex").HandlerFunc(m.RiskGroupIndex)
	m.Router.Methods("GET").Path("/riskgroups/{riskgroupId}").Name("RiskGroupById").HandlerFunc(m.RiskGroupById)
	m.Router.Methods("PUT").Path("/riskgroups").Name("RiskGroupPut").HandlerFunc(m.RiskGroupPut)
	m.Router.Methods("POST").Path("/riskgroups/{riskgroupId}").Name("RiskGroupUpdate").HandlerFunc(m.RiskGroupUpdate)
	m.Router.Methods("DELETE").Path("/riskgroups/{riskgroupId}").Name("RiskGroupDelete").HandlerFunc(m.RiskGroupDelete)
	m.Router.Methods("GET").Path("/riskgroups/{riskgroupId}/slaves").Name("RiskGroupGetSlaves").HandlerFunc(m.RiskGroupGetSlaves)
	m.Router.Methods("PUT").Path("/riskgroups/{riskgroupId}/slaves/{slaveId}").Name("RiskGroupAssignSlave").HandlerFunc(m.RiskGroupAssignSlave)
	m.Router.Methods("DELETE").Path("/riskgroups/{riskgroupId}/slaves/{slaveId}").Name("RiskGroupRemoveSlave").HandlerFunc(m.RiskGroupRemoveSlave)

	m.Router.Methods("GET").Path("/problems").Name("ProblemIndex").HandlerFunc(m.ProblemIndex)
	m.Router.Methods("GET").Path("/problems/{problemId}").Name("ProblemById").HandlerFunc(m.ProblemById)
	m.Router.Methods("GET").Path("/slaves/{slaveId}/problems").Name("ProblemBySlave").HandlerFunc(m.ProblemBySlave)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}/problems").Name("ProblemByReplicaSet").HandlerFunc(m.ProblemByReplicaSet)

	m.Router.Methods("GET").Path("/slaves/{slaveId}/mongods").Name("MongodsBySlave").HandlerFunc(m.MongodsBySlave)
	m.Router.Methods("GET").Path("/replicasets/{replicasetId}/mongods").Name("MongodsByReplicaSet").HandlerFunc(m.MongodsByReplicaSet)

	m.Router.Methods("GET").Path("/system/keyfile").Name("KeyfileGet").HandlerFunc(m.KeyfileGet)
	m.Router.Methods("GET").Path("/system/managementuser").Name("ManagementUserGet").HandlerFunc(m.ManagementUserGet)

}

func (m *MasterAPI) attemptClusterAllocator(tx *gorm.DB, w http.ResponseWriter) (err error) {
	err = m.ClusterAllocator.CompileMongodLayout(tx)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "cluster allocator failure: %s\n", err)
		if err = tx.Rollback().Error; err != nil {
			fmt.Fprintf(w, "cluster allocator rollback failure: %s\n", err)
		}
	}
	return err
}

func (m *MasterAPI) attemptCommit(tx *gorm.DB, w http.ResponseWriter) (err error) {
	err = tx.Commit().Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "commit failed with error %s\n", err)
		masterapiLog.WithError(err).Errorf("commit failed")
	}
	return err
}
<|endoftext|>


<commit_before>package masterapi

import (
	"encoding/json"
	"fmt"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"strconv"
)

type Slave struct {
	ID                   uint   `json:"id"`
	Hostname             string `json:"hostname"`
	Port                 uint   `json:"slave_port"`
	MongodPortRangeBegin uint   `json:"mongod_port_range_begin"` //inclusive
	MongodPortRangeEnd   uint   `json:"mongod_port_range_end"`   //exclusive
	PersistentStorage    bool   `json:"persistent_storage"`
	ConfiguredState      string `json:"configured_state"`
}

func (m *MasterAPI) SlaveIndex(w http.ResponseWriter, r *http.Request) {

	var slaves []*model.Slave
	err := m.DB.Order("id", false).Find(&slaves).Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	out := make([]*Slave, len(slaves))
	for i, v := range slaves {
		out[i] = ProjectModelSlaveToSlave(v)
	}
	json.NewEncoder(w).Encode(out)
}

func (m *MasterAPI) SlaveById(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["slaveId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	var slaves []model.Slave
	err = m.DB.Find(&slaves, &model.Slave{ID: id}).Error

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}
	if len(slaves) == 0 { // Not found?
		w.WriteHeader(http.StatusNotFound)
		return
	}

	if len(slaves) > 1 {
		log.Printf("inconsistency: multiple slaves for slave.ID = %d found in database", len(slaves))
	}
	json.NewEncoder(w).Encode(ProjectModelSlaveToSlave(&slaves[0]))
	return
}

func (m *MasterAPI) SlavePut(w http.ResponseWriter, r *http.Request) {
	var postSlave Slave
	err := json.NewDecoder(r.Body).Decode(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postSlave.ID != 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not change the slave ID in PUT request")
		return
	}

	modelSlave, err := ProjectSlaveToModelSlave(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, err.Error())
		return
	}

	// Persist to database

	err = m.DB.Create(&modelSlave).Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	// Return created slave

	json.NewEncoder(w).Encode(ProjectModelSlaveToSlave(modelSlave))

	return
}

func (m *MasterAPI) SlaveUpdate(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["slaveId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	var postSlave Slave
	err = json.NewDecoder(r.Body).Decode(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postSlave.ID != id {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not change the id of an object")
		return
	}

	if err = postSlave.assertNoZeroFieldsSet(); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not POST JSON with zero values in any field: %s", err.Error())
		return
	}

	// Only allow changes to both observed and desired disabled slaves

	var modelSlave model.Slave
	if err = m.DB.First(&modelSlave, id).Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	if modelSlave.ConfiguredState != model.SlaveStateDisabled {
		w.WriteHeader(http.StatusForbidden)
		fmt.Fprintf(w, "slave's desired state must be = disabled")
		return
	}

	if err = m.DB.Model(&modelSlave).Related(&modelSlave.Mongods, "Mongods").Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	if len(modelSlave.Mongods) != 0 {
		w.WriteHeader(http.StatusForbidden)
		fmt.Fprintf(w, "slave has active Mongods")
		return
	}

	// Allow update

	save, err := ProjectSlaveToModelSlave(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, err)
		return
	}

	// Persist to database

	m.DB.Model(&modelSlave).Updates(&save)
}

func (m *MasterAPI) SlaveDelete(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["slaveId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	s := m.DB.Delete(&model.Slave{ID: id})
	if s.Error != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}
	if s.RowsAffected == 0 {
		w.WriteHeader(http.StatusNotFound)
	}

	if s.RowsAffected > 1 {
		log.Printf("inconsistency: slave DELETE affected more than one row. Slave.ID = %v", id)
	}
}
<commit_msg>ADD: masterapi: slaves: check for disabled state.<commit_after>package masterapi

import (
	"encoding/json"
	"fmt"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/gorilla/mux"
	"github.com/jinzhu/gorm"
	"log"
	"net/http"
	"strconv"
)

type Slave struct {
	ID                   uint   `json:"id"`
	Hostname             string `json:"hostname"`
	Port                 uint   `json:"slave_port"`
	MongodPortRangeBegin uint   `json:"mongod_port_range_begin"` //inclusive
	MongodPortRangeEnd   uint   `json:"mongod_port_range_end"`   //exclusive
	PersistentStorage    bool   `json:"persistent_storage"`
	ConfiguredState      string `json:"configured_state"`
}

func (m *MasterAPI) SlaveIndex(w http.ResponseWriter, r *http.Request) {

	var slaves []*model.Slave
	err := m.DB.Order("id", false).Find(&slaves).Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	out := make([]*Slave, len(slaves))
	for i, v := range slaves {
		out[i] = ProjectModelSlaveToSlave(v)
	}
	json.NewEncoder(w).Encode(out)
}

func (m *MasterAPI) SlaveById(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["slaveId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	var slaves []model.Slave
	err = m.DB.Find(&slaves, &model.Slave{ID: id}).Error

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}
	if len(slaves) == 0 { // Not found?
		w.WriteHeader(http.StatusNotFound)
		return
	}

	if len(slaves) > 1 {
		log.Printf("inconsistency: multiple slaves for slave.ID = %d found in database", len(slaves))
	}
	json.NewEncoder(w).Encode(ProjectModelSlaveToSlave(&slaves[0]))
	return
}

func (m *MasterAPI) SlavePut(w http.ResponseWriter, r *http.Request) {
	var postSlave Slave
	err := json.NewDecoder(r.Body).Decode(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postSlave.ID != 0 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not specify the slave ID in PUT request")
		return
	}

	modelSlave, err := ProjectSlaveToModelSlave(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, err.Error())
		return
	}

	// Persist to database

	err = m.DB.Create(&modelSlave).Error
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	// Return created slave

	json.NewEncoder(w).Encode(ProjectModelSlaveToSlave(modelSlave))

	return
}

func (m *MasterAPI) SlaveUpdate(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["slaveId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	var postSlave Slave
	err = json.NewDecoder(r.Body).Decode(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot parse object (%s)", err.Error())
		return
	}

	// Validation

	if postSlave.ID != id {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not change the id of an object")
		return
	}

	if err = postSlave.assertNoZeroFieldsSet(); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "must not POST JSON with zero values in any field: %s", err.Error())
		return
	}

	// Only allow changes to both observed and desired disabled slaves

	var modelSlave model.Slave
	if err = m.DB.First(&modelSlave, id).Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	permissionError, dbError := changeToSlaveAllowed(m.DB, &modelSlave, postSlave)
	if dbError != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, dbError)
		return
	}
	if permissionError != nil {
		w.WriteHeader(http.StatusForbidden)
		fmt.Fprint(w, permissionError)
		return
	}

	// Allow update

	save, err := ProjectSlaveToModelSlave(&postSlave)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, err)
		return
	}

	// Persist to database

	m.DB.Model(&modelSlave).Updates(&save)
}

func (m *MasterAPI) SlaveDelete(w http.ResponseWriter, r *http.Request) {
	idStr := mux.Vars(r)["slaveId"]
	id64, err := strconv.ParseUint(idStr, 10, 0)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id := uint(id64)

	// Can only delete disabled slaves
	var currentSlave model.Slave
	if err = m.DB.First(&currentSlave, id).Related(&currentSlave.Mongods, "Mongods").Error; err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}

	if len(currentSlave.Mongods) != 0 {
		w.WriteHeader(http.StatusForbidden)
		fmt.Fprintf(w, "slave with id %d has active Mongods", currentSlave.ID)
		return
	}

	// Allow delete

	s := m.DB.Delete(&model.Slave{ID: id})
	if s.Error != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, err.Error())
		return
	}
	if s.RowsAffected == 0 {
		w.WriteHeader(http.StatusNotFound)
	}

	if s.RowsAffected > 1 {
		log.Printf("inconsistency: slave DELETE affected more than one row. Slave.ID = %v", id)
	}
}

func changeToSlaveAllowed(db *gorm.DB, currentSlave *model.Slave, updatedSlave Slave) (permissionError, dbError error) {

	if currentSlave.ConfiguredState != model.SlaveStateDisabled {
		return fmt.Errorf("slave's desired state must be = disabled"), nil
	}

	if err := db.Model(&currentSlave).Related(&currentSlave.Mongods, "Mongods").Error; err != nil {
		return nil, err
	}

	if len(currentSlave.Mongods) != 0 {
		return fmt.Errorf("slave has active Mongods"), nil
	}

	return nil, nil

}
<|endoftext|>


<commit_before>package kite

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

	"github.com/koding/kite/dnode"
	"github.com/koding/kite/protocol"
)

type kontrolFunc func(*Client) error

// kontrolFunc setups and prepares a kontrol instance. It connects to
// kontrol and providers a way to call the given function in that connected
// kontrol environment. This method is called internally whenever a kontrol
// client specific action is taking (getKites, getToken, register). The main
// reason for having this is doing the call and close the connection
// immediately, so there will be no persistent connection.
func (k *Kite) kontrolFunc(fn kontrolFunc) error {
	if k.Config.KontrolURL == "" {
		return errors.New("no kontrol URL given in config")
	}

	client := k.NewClient(k.Config.KontrolURL)

	client.Kite = protocol.Kite{Name: "kontrol"} // for logging purposes
	client.Auth = &Auth{
		Type: "kiteKey",
		Key:  k.Config.KiteKey,
	}

	if err := client.Dial(); err != nil {
		return err
	}
	defer client.Close()

	return fn(client)
}

// RegisterHTTPForever is just like RegisterHTTP however it first tries to
// register forever until a response from kontrol is received. It's useful to
// use it during app initializations. After the registration a reconnect is
// automatically handled inside the RegisterHTTP method.
func (k *Kite) RegisterHTTPForever(kiteURL *url.URL) {
	interval := time.NewTicker(kontrolRetryDuration)
	defer interval.Stop()

	_, err := k.RegisterHTTP(kiteURL)
	if err == nil {
		return
	}

	for _ = range interval.C {
		_, err := k.RegisterHTTP(kiteURL)
		if err == nil {
			return
		}

		k.Log.Error("Cannot register to Kontrol: %s Will retry after %d seconds",
			err, kontrolRetryDuration/time.Second)

	}
}

// RegisterHTTP registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() or WatchKites() method. It registers again if
// connection to kontrol is lost.
func (k *Kite) RegisterHTTP(kiteURL *url.URL) (*registerResult, error) {
	var response *dnode.Partial

	registerFunc := func(kontrol *Client) error {
		args := protocol.RegisterArgs{
			URL: kiteURL.String(),
		}

		k.Log.Info("Registering to kontrol with URL (via HTTP): %s", kiteURL.String())
		var err error
		response, err = kontrol.TellWithTimeout("registerHTTP", 4*time.Second, args)
		return err
	}

	if err := k.kontrolFunc(registerFunc); err != nil {
		return nil, err
	}

	var rr protocol.RegisterResult
	if err := response.Unmarshal(&rr); err != nil {
		return nil, err
	}

	parsed, err := url.Parse(rr.URL)
	if err != nil {
		k.Log.Error("Cannot parse registered URL: %s", err.Error())
	}

	heartbeat := time.Duration(rr.HeartbeatInterval) * time.Second

	k.Log.Info("Registered (via HTTP) with URL: '%s' and HeartBeat interval: '%s'",
		rr.URL, heartbeat)

	go k.sendHeartbeats(heartbeat, kiteURL)

	return &registerResult{parsed}, nil
}

func (k *Kite) sendHeartbeats(interval time.Duration, kiteURL *url.URL) {
	tick := time.NewTicker(interval)

	var heartbeatURL string
	if strings.HasSuffix(k.Config.KontrolURL, "/kite") {
		heartbeatURL = strings.TrimSuffix(k.Config.KontrolURL, "/kite") + "/heartbeat"
	} else {
		heartbeatURL = k.Config.KontrolURL + "/heartbeat"
	}

	u, err := url.Parse(heartbeatURL)
	if err != nil {
		k.Log.Fatal("HeartbeatURL is malformed: %s", err)
	}

	q := u.Query()
	q.Set("id", k.Id)
	u.RawQuery = q.Encode()

	errRegisterAgain := errors.New("register again")

	heartbeatFunc := func() error {
		k.Log.Info("Sending heartbeat to %s", u.String())

		resp, err := http.Get(u.String())
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// we are just receving small size strings such as "pong",
		// "registeragain" so it's totally normal to consume the whole response
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		k.Log.Info("Heartbeat response received '%s'", string(body))

		switch string(body) {
		case "pong":
			return nil
		case "registeragain":
			tick.Stop()
			k.RegisterHTTP(kiteURL)
			return errRegisterAgain
		}

		return fmt.Errorf("malformed heartbeat response %v", string(body))
	}

	for _ = range tick.C {
		err := heartbeatFunc()
		if err == errRegisterAgain {
			return // return so we don't run forever
		}

		if err != nil {
			k.Log.Error("couldn't sent hearbeat: %s", err)
		}
	}
}
<commit_msg>heartbeat: don't use info for those<commit_after>package kite

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

	"github.com/koding/kite/dnode"
	"github.com/koding/kite/protocol"
)

type kontrolFunc func(*Client) error

// kontrolFunc setups and prepares a kontrol instance. It connects to
// kontrol and providers a way to call the given function in that connected
// kontrol environment. This method is called internally whenever a kontrol
// client specific action is taking (getKites, getToken, register). The main
// reason for having this is doing the call and close the connection
// immediately, so there will be no persistent connection.
func (k *Kite) kontrolFunc(fn kontrolFunc) error {
	if k.Config.KontrolURL == "" {
		return errors.New("no kontrol URL given in config")
	}

	client := k.NewClient(k.Config.KontrolURL)

	client.Kite = protocol.Kite{Name: "kontrol"} // for logging purposes
	client.Auth = &Auth{
		Type: "kiteKey",
		Key:  k.Config.KiteKey,
	}

	if err := client.Dial(); err != nil {
		return err
	}
	defer client.Close()

	return fn(client)
}

// RegisterHTTPForever is just like RegisterHTTP however it first tries to
// register forever until a response from kontrol is received. It's useful to
// use it during app initializations. After the registration a reconnect is
// automatically handled inside the RegisterHTTP method.
func (k *Kite) RegisterHTTPForever(kiteURL *url.URL) {
	interval := time.NewTicker(kontrolRetryDuration)
	defer interval.Stop()

	_, err := k.RegisterHTTP(kiteURL)
	if err == nil {
		return
	}

	for _ = range interval.C {
		_, err := k.RegisterHTTP(kiteURL)
		if err == nil {
			return
		}

		k.Log.Error("Cannot register to Kontrol: %s Will retry after %d seconds",
			err, kontrolRetryDuration/time.Second)

	}
}

// RegisterHTTP registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() or WatchKites() method. It registers again if
// connection to kontrol is lost.
func (k *Kite) RegisterHTTP(kiteURL *url.URL) (*registerResult, error) {
	var response *dnode.Partial

	registerFunc := func(kontrol *Client) error {
		args := protocol.RegisterArgs{
			URL: kiteURL.String(),
		}

		k.Log.Info("Registering to kontrol with URL (via HTTP): %s", kiteURL.String())
		var err error
		response, err = kontrol.TellWithTimeout("registerHTTP", 4*time.Second, args)
		return err
	}

	if err := k.kontrolFunc(registerFunc); err != nil {
		return nil, err
	}

	var rr protocol.RegisterResult
	if err := response.Unmarshal(&rr); err != nil {
		return nil, err
	}

	parsed, err := url.Parse(rr.URL)
	if err != nil {
		k.Log.Error("Cannot parse registered URL: %s", err.Error())
	}

	heartbeat := time.Duration(rr.HeartbeatInterval) * time.Second

	k.Log.Info("Registered (via HTTP) with URL: '%s' and HeartBeat interval: '%s'",
		rr.URL, heartbeat)

	go k.sendHeartbeats(heartbeat, kiteURL)

	return &registerResult{parsed}, nil
}

func (k *Kite) sendHeartbeats(interval time.Duration, kiteURL *url.URL) {
	tick := time.NewTicker(interval)

	var heartbeatURL string
	if strings.HasSuffix(k.Config.KontrolURL, "/kite") {
		heartbeatURL = strings.TrimSuffix(k.Config.KontrolURL, "/kite") + "/heartbeat"
	} else {
		heartbeatURL = k.Config.KontrolURL + "/heartbeat"
	}

	u, err := url.Parse(heartbeatURL)
	if err != nil {
		k.Log.Fatal("HeartbeatURL is malformed: %s", err)
	}

	q := u.Query()
	q.Set("id", k.Id)
	u.RawQuery = q.Encode()

	errRegisterAgain := errors.New("register again")

	heartbeatFunc := func() error {
		k.Log.Debug("Sending heartbeat to %s", u.String())

		resp, err := http.Get(u.String())
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// we are just receving small size strings such as "pong",
		// "registeragain" so it's totally normal to consume the whole response
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		k.Log.Debug("Heartbeat response received '%s'", string(body))

		switch string(body) {
		case "pong":
			return nil
		case "registeragain":
			tick.Stop()
			k.RegisterHTTP(kiteURL)
			return errRegisterAgain
		}

		return fmt.Errorf("malformed heartbeat response %v", string(body))
	}

	for _ = range tick.C {
		err := heartbeatFunc()
		if err == errRegisterAgain {
			return // return so we don't run forever
		}

		if err != nil {
			k.Log.Error("couldn't sent hearbeat: %s", err)
		}
	}
}
<|endoftext|>


<commit_before>package state

import (
	"encoding/gob"
	"fmt"
	"log"
	"math"
	"math/rand"
	"os"
	"os/signal"
	"sort"
	"strings"
	"time"
)

func (g *Game) write(fn string) {
	g.Lock()
	defer g.Unlock()

	new := fn + ".new"
	old := fn + ".old"
	f, err := os.OpenFile(fn+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		log.Fatal(err)
	}
	err = gob.NewEncoder(f).Encode(&g.g)
	if err != nil {
		log.Fatal(err)
	}
	f.Sync()
	f.Close()

	os.Rename(fn, old)
	err = os.Rename(new, fn)
	if err != nil {
		log.Fatal(err)
	}
	os.Remove(old)
}

func (g *Game) nextTurn() <-chan time.Time {
	g.Lock()
	defer g.Unlock()

	now := time.Now().UTC()
	prev := g.g.Previous

	if prev.Day() != now.Day() {
		return time.After(1)
	}

	tomorrow := now.Add(time.Hour * 23)
	for tomorrow.Day() == now.Day() {
		tomorrow = tomorrow.Add(time.Hour)
	}
	next := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 0, 0, 0, 0, time.UTC)
	return time.After(next.Sub(now))
}

func (g *Game) newDay() {
	const rounds = 15
	const (
		up = iota
		down
		dividend
	)

	g.Lock()
	defer g.Unlock()

	now := time.Now().UTC()
	defer func() { g.g.Previous = now }()

	before := g.g.Stock
	var divpaid [stockTypes]uint64
	news := make([]string, 0, stockTypes)

	for i := 0; i < rounds; i++ {
		adjust := uint64(math.Pow(rand.Float64()*.8+1.2, 5.0))
		stock := rand.Intn(stockTypes)
		switch rand.Intn(3) {
		case up:
			g.g.Stock[stock].Value += adjust
			if g.g.Stock[stock].Value >= splitValue {
				news = append(news, g.g.Stock[stock].Name+" split 2 for 1")
				g.g.Stock[stock].Value = (g.g.Stock[stock].Value + 1) / 2
				before[stock].Value = (before[stock].Value + 1) / 2
				for _, p := range g.g.Player {
					p.Shares[stock] *= 2
				}
			}
		case down:
			if g.g.Stock[stock].Value <= adjust {
				news = append(news, g.g.Stock[stock].Name+" went bankrupt, and was removed from the market")
				for _, p := range g.g.Player {
					p.Shares[stock] = 0
				}
				g.g.Stock[stock].Value = startingValue
				before[stock].Value = startingValue
				newname := g.g.pickName()
				news = append(news, newname+" was added to the market")
				g.g.Stock[stock].Name = newname
			} else {
				g.g.Stock[stock].Value -= adjust
			}
		case dividend:
			if g.g.Stock[stock].Value >= startingValue {
				divpaid[stock] += adjust
				for _, p := range g.g.Player {
					p.Cash += adjust * p.Shares[stock]
				}
			}
		}
	}

	for k, v := range g.g.Stock {
		var item string
		switch {
		case v.Value == before[k].Value:
			item = v.Name + " did not change price"
		case v.Value < before[k].Value:
			item = fmt.Sprintf("%s fell %.1f%%", v.Name, float64(before[k].Value-v.Value)/float64(before[k].Value)*100)
		default: // case v.Value > before[k].Value:
			item = fmt.Sprintf("%s rose %.1f%%", v.Name, float64(v.Value-before[k].Value)/float64(before[k].Value)*100)
		}
		if divpaid[k] > 0 {
			item = fmt.Sprintf("%s, and paid $%d in dividends", item, divpaid[k])
		}
		news = append(news, item)
	}
	g.g.News = news

	if now.Month() != g.g.Previous.Month() {
		leader := g.g.Leaders()
		sort.Sort(LeaderSort(leader))
		announce := fmt.Sprintf("The winner of the %s %d season was %s, with a net worth of $%d",
			g.g.Previous.Month().String(), g.g.Previous.Year(), leader[0].Name, leader[0].Worth)
		g.g.News = append(g.g.News, announce)
		g.g.History = append([]string{announce}, g.g.History...)
		if len(leader) > 1 {
			rup := []string{}
			for i := 1; i < len(leader); i++ {
				rup = append(rup, fmt.Sprintf("%s had $%d", leader[i].Name, leader[i].Worth))
			}
			g.g.News = append(g.g.News,
				fmt.Sprintf("(%s)", strings.Join(rup, ", ")))
		}
		g.g.reset()
	}
}

func watcher(g *Game, filename string, changed chan struct{}) {
	var tick <-chan time.Time
	tock := g.nextTurn()

	sigint := make(chan os.Signal, 1)
	signal.Notify(sigint, os.Interrupt, os.Kill)

	for {
		select {
		case <-changed:
			if tick == nil {
				tick = time.After(5 * time.Minute)
			}
		case <-tick:
			tick = nil
			g.write(filename)
		case <-tock:
			g.newDay()
			g.write(filename)
			tock = g.nextTurn()
		case <-sigint:
			if tick != nil {
				g.write(filename)
			}
			log.Println("Exiting")
			os.Exit(0)
		}
	}
}
<commit_msg>Fix crash at end of month if there are no players<commit_after>package state

import (
	"encoding/gob"
	"fmt"
	"log"
	"math"
	"math/rand"
	"os"
	"os/signal"
	"sort"
	"strings"
	"time"
)

func (g *Game) write(fn string) {
	g.Lock()
	defer g.Unlock()

	new := fn + ".new"
	old := fn + ".old"
	f, err := os.OpenFile(fn+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		log.Fatal(err)
	}
	err = gob.NewEncoder(f).Encode(&g.g)
	if err != nil {
		log.Fatal(err)
	}
	f.Sync()
	f.Close()

	os.Rename(fn, old)
	err = os.Rename(new, fn)
	if err != nil {
		log.Fatal(err)
	}
	os.Remove(old)
}

func (g *Game) nextTurn() <-chan time.Time {
	g.Lock()
	defer g.Unlock()

	now := time.Now().UTC()
	prev := g.g.Previous

	if prev.Day() != now.Day() {
		return time.After(1)
	}

	tomorrow := now.Add(time.Hour * 23)
	for tomorrow.Day() == now.Day() {
		tomorrow = tomorrow.Add(time.Hour)
	}
	next := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 0, 0, 0, 0, time.UTC)
	return time.After(next.Sub(now))
}

func (g *Game) newDay() {
	const rounds = 15
	const (
		up = iota
		down
		dividend
	)

	g.Lock()
	defer g.Unlock()

	now := time.Now().UTC()
	defer func() { g.g.Previous = now }()

	before := g.g.Stock
	var divpaid [stockTypes]uint64
	news := make([]string, 0, stockTypes)

	for i := 0; i < rounds; i++ {
		adjust := uint64(math.Pow(rand.Float64()*.8+1.2, 5.0))
		stock := rand.Intn(stockTypes)
		switch rand.Intn(3) {
		case up:
			g.g.Stock[stock].Value += adjust
			if g.g.Stock[stock].Value >= splitValue {
				news = append(news, g.g.Stock[stock].Name+" split 2 for 1")
				g.g.Stock[stock].Value = (g.g.Stock[stock].Value + 1) / 2
				before[stock].Value = (before[stock].Value + 1) / 2
				for _, p := range g.g.Player {
					p.Shares[stock] *= 2
				}
			}
		case down:
			if g.g.Stock[stock].Value <= adjust {
				news = append(news, g.g.Stock[stock].Name+" went bankrupt, and was removed from the market")
				for _, p := range g.g.Player {
					p.Shares[stock] = 0
				}
				g.g.Stock[stock].Value = startingValue
				before[stock].Value = startingValue
				newname := g.g.pickName()
				news = append(news, newname+" was added to the market")
				g.g.Stock[stock].Name = newname
			} else {
				g.g.Stock[stock].Value -= adjust
			}
		case dividend:
			if g.g.Stock[stock].Value >= startingValue {
				divpaid[stock] += adjust
				for _, p := range g.g.Player {
					p.Cash += adjust * p.Shares[stock]
				}
			}
		}
	}

	for k, v := range g.g.Stock {
		var item string
		switch {
		case v.Value == before[k].Value:
			item = v.Name + " did not change price"
		case v.Value < before[k].Value:
			item = fmt.Sprintf("%s fell %.1f%%", v.Name, float64(before[k].Value-v.Value)/float64(before[k].Value)*100)
		default: // case v.Value > before[k].Value:
			item = fmt.Sprintf("%s rose %.1f%%", v.Name, float64(v.Value-before[k].Value)/float64(before[k].Value)*100)
		}
		if divpaid[k] > 0 {
			item = fmt.Sprintf("%s, and paid $%d in dividends", item, divpaid[k])
		}
		news = append(news, item)
	}
	g.g.News = news

	if now.Month() != g.g.Previous.Month() {
		leader := g.g.Leaders()
		if len(leader) > 0 {
			sort.Sort(LeaderSort(leader))
			announce := fmt.Sprintf("The winner of the %s %d season was %s, with a net worth of $%d",
				g.g.Previous.Month().String(), g.g.Previous.Year(), leader[0].Name, leader[0].Worth)
			g.g.News = append(g.g.News, announce)
			g.g.History = append([]string{announce}, g.g.History...)
		}
		if len(leader) > 1 {
			rup := []string{}
			for i := 1; i < len(leader); i++ {
				rup = append(rup, fmt.Sprintf("%s had $%d", leader[i].Name, leader[i].Worth))
			}
			g.g.News = append(g.g.News,
				fmt.Sprintf("(%s)", strings.Join(rup, ", ")))
		}
		g.g.reset()
	}
}

func watcher(g *Game, filename string, changed chan struct{}) {
	var tick <-chan time.Time
	tock := g.nextTurn()

	sigint := make(chan os.Signal, 1)
	signal.Notify(sigint, os.Interrupt, os.Kill)

	for {
		select {
		case <-changed:
			if tick == nil {
				tick = time.After(5 * time.Minute)
			}
		case <-tick:
			tick = nil
			g.write(filename)
		case <-tock:
			g.newDay()
			g.write(filename)
			tock = g.nextTurn()
		case <-sigint:
			if tick != nil {
				g.write(filename)
			}
			log.Println("Exiting")
			os.Exit(0)
		}
	}
}
<|endoftext|>


<commit_before>package otp

import "strings"

func newKey(method, label, secret, issuer string, algo Hash, digits, period, counter int) (*Key, error) {

	k := Key{
		Method:   method,
		Label:    label,
		Secret32: strings.ToUpper(secret),
		Issuer:   issuer,
		Algo:     algo,
		Digits:   digits,
		Period:   period,
		Counter:  counter,
	}

	if err := k.Validate(); err != nil {
		return &k, err
	}

	return &k, nil
}

// NewTOTPKey returns a totp key struct.
func NewTOTPKey(
	label,
	secret32,
	issuer string,
	algo Hash,
	digits,
	period int) (*Key, error) {
	k, err := newKey("totp", label, secret32, issuer, algo, digits, period, 0)
	return k, err
}

// NewHOTPKey returns a hotp key struct.
func NewHOTPKey(label, secret32, issuer string, algo Hash, digits, counter int) (*Key, error) {
	k, err := newKey("hotp", label, secret32, issuer, algo, digits, 0, counter)
	return k, err
}

// NewKey returns a new Key from an otpauth URI.
func NewKey(uri string) (*Key, error) {
	k := Key{}
	if err := k.FromURI(uri); err != nil {
		return &k, err
	}

	if err := k.Validate(); err != nil {
		return &k, err
	}

	return &k, nil
}
<commit_msg>long view<commit_after>package otp

import "strings"

func newKey(method, label, secret, issuer string, algo Hash, digits, period, counter int) (*Key, error) {

	k := Key{
		Method:   method,
		Label:    label,
		Secret32: strings.ToUpper(secret),
		Issuer:   issuer,
		Algo:     algo,
		Digits:   digits,
		Period:   period,
		Counter:  counter,
	}

	if err := k.Validate(); err != nil {
		return &k, err
	}

	return &k, nil
}

// NewTOTPKey returns a totp key struct.
func NewTOTPKey(
	label,
	secret32,
	issuer string,
	algo Hash,
	digits,
	period int) (*Key, error) {
	k, err := newKey("totp", label, secret32, issuer, algo, digits, period, 0)
	return k, err
}

// NewHOTPKey returns a hotp key struct.
func NewHOTPKey(
	label,
	secret32,
	issuer string,
	algo Hash,
	digits,
	counter int) (*Key, error) {
	k, err := newKey("hotp", label, secret32, issuer, algo, digits, 0, counter)
	return k, err
}

// NewKey returns a key from an otpauth URI.
func NewKey(uri string) (*Key, error) {
	k := Key{}
	if err := k.FromURI(uri); err != nil {
		return &k, err
	}

	if err := k.Validate(); err != nil {
		return &k, err
	}

	return &k, nil
}
<|endoftext|>


<commit_before>package columnize

import (
	"fmt"
	"strings"
)

type Config struct {
	// The string by which the lines of input will be split.
	Delim string

	// The string by which columns of output will be separated.
	Glue string
}

// Returns a Config with default values.
func DefaultConfig() *Config {
	return &Config{
		Delim: "|",
		Glue:  "  ",
	}
}

// Returns a list of elements, each representing a single item which will
// belong to a column of output.
func getElementsFromLine(line string, delim string) []interface{} {
	elements := make([]interface{}, 0)
	for _, field := range strings.Split(line, delim) {
		elements = append(elements, strings.TrimSpace(field))
	}
	return elements
}

// Examines a list of strings and determines how wide each column should be
// considering all of the elements that need to be printed within it.
func getWidthsFromLines(lines []string, delim string) []int {
	var widths []int

	for _, line := range lines {
		elems := getElementsFromLine(line, delim)
		for i := 0; i < len(elems); i++ {
			if len(widths) <= i {
				widths = append(widths, len(elems[i].(string)))
			} else if widths[i] < len(elems[i].(string)) {
				widths[i] = len(elems[i].(string))
			}
		}
	}
	return widths
}

// Given a set of column widths and the number of columns in the current line,
// returns a sprintf-style format string which can be used to print output
// aligned properly with other lines using the same widths set.
func getStringFormat(widths []int, columns int, space string) string {
	var stringfmt string

	// Create the format string from the discovered widths
	for i := 0; i < columns && i < len(widths); i++ {
		if i == columns-1 {
			stringfmt += "%s\n"
		} else {
			stringfmt += fmt.Sprintf("%%-%ds%s", widths[i], space)
		}
	}
	return stringfmt
}

// Format is the public-facing interface that takes either a plain string
// or a list of strings, plus a delimiter, and returns nicely aligned output.
func Format(input interface{}, config *Config) (string, error) {
	var result string
	var lines []string

	switch in := input.(type) {
	case string:
		for _, line := range strings.Split(in, "\n") {
			lines = append(lines, line)
		}

	case []string:
		lines = in

	default:
		return "", fmt.Errorf("columnize: Expected string or []string")
	}

	widths := getWidthsFromLines(lines, config.Delim)

	// Create the formatted output using the format string
	for _, line := range lines {
		elems := getElementsFromLine(line, config.Delim)
		stringfmt := getStringFormat(widths, len(elems), config.Glue)
		result += fmt.Sprintf(stringfmt, elems...)
	}

	// Remove trailing newline without removing leading/trailing space
	if n := len(result); result[n-1] == '\n' {
		result = result[:n-1]
	}

	return result, nil
}

// Convenience function for using Columnize as easy as possible.
func SimpleFormat(input interface{}) (string, error) {
	config := DefaultConfig()
	return Format(input, config)
}
<commit_msg>Don't try indexing backward in strings if they are 0-length<commit_after>package columnize

import (
	"fmt"
	"strings"
)

type Config struct {
	// The string by which the lines of input will be split.
	Delim string

	// The string by which columns of output will be separated.
	Glue string
}

// Returns a Config with default values.
func DefaultConfig() *Config {
	return &Config{
		Delim: "|",
		Glue:  "  ",
	}
}

// Returns a list of elements, each representing a single item which will
// belong to a column of output.
func getElementsFromLine(line string, delim string) []interface{} {
	elements := make([]interface{}, 0)
	for _, field := range strings.Split(line, delim) {
		elements = append(elements, strings.TrimSpace(field))
	}
	return elements
}

// Examines a list of strings and determines how wide each column should be
// considering all of the elements that need to be printed within it.
func getWidthsFromLines(lines []string, delim string) []int {
	var widths []int

	for _, line := range lines {
		elems := getElementsFromLine(line, delim)
		for i := 0; i < len(elems); i++ {
			if len(widths) <= i {
				widths = append(widths, len(elems[i].(string)))
			} else if widths[i] < len(elems[i].(string)) {
				widths[i] = len(elems[i].(string))
			}
		}
	}
	return widths
}

// Given a set of column widths and the number of columns in the current line,
// returns a sprintf-style format string which can be used to print output
// aligned properly with other lines using the same widths set.
func getStringFormat(widths []int, columns int, space string) string {
	var stringfmt string

	// Create the format string from the discovered widths
	for i := 0; i < columns && i < len(widths); i++ {
		if i == columns-1 {
			stringfmt += "%s\n"
		} else {
			stringfmt += fmt.Sprintf("%%-%ds%s", widths[i], space)
		}
	}
	return stringfmt
}

// Format is the public-facing interface that takes either a plain string
// or a list of strings, plus a delimiter, and returns nicely aligned output.
func Format(input interface{}, config *Config) (string, error) {
	var result string
	var lines []string

	switch in := input.(type) {
	case string:
		for _, line := range strings.Split(in, "\n") {
			lines = append(lines, line)
		}

	case []string:
		lines = in

	default:
		return "", fmt.Errorf("columnize: Expected string or []string")
	}

	widths := getWidthsFromLines(lines, config.Delim)

	// Create the formatted output using the format string
	for _, line := range lines {
		elems := getElementsFromLine(line, config.Delim)
		stringfmt := getStringFormat(widths, len(elems), config.Glue)
		result += fmt.Sprintf(stringfmt, elems...)
	}

	// Remove trailing newline without removing leading/trailing space
	if n := len(result); n > 0 && result[n-1] == '\n' {
		result = result[:n-1]
	}

	return result, nil
}

// Convenience function for using Columnize as easy as possible.
func SimpleFormat(input interface{}) (string, error) {
	config := DefaultConfig()
	return Format(input, config)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/pilu/traffic"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/memcache"
	"google.golang.org/appengine/user"
)

type StatsData struct {
	Posts        int
	WordsPerPost float64
	PostsPerDay  float64
	WordsPerDay  float64
	DaysSince    float64
	IsAdmin      bool
	LinksPerPost float64
	LinksPerDay  float64
	Years        []string
	YearData     map[string][]float64
}

func StatsWorkHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)

	var data *StatsData
	entries, err := AllPosts(c)
	if err != nil {
		log.Errorf(c, "Error loading posts: %+v", err)
		http.Error(w, err.Error(), 500)
		return
	}

	postCount := len(*entries)
	oldestPost := (*entries)[postCount-1]
	dayCount := time.Since(oldestPost.Datetime).Hours() / 24.0

	years := []string{}
	yearData := make(map[string][]float64)
	for i := time.Now().Year(); i >= oldestPost.Datetime.Year(); i-- {
		years = append(years, strconv.Itoa(i))
		yearData[strconv.Itoa(i)] = []float64{0.0, 0.0, 0.0}
	}

	words := 0
	for _, p := range *entries {
		words += len(strings.Fields(p.Content))
		words += len(strings.Fields(p.Title))
		yearData[strconv.Itoa(p.Datetime.Year())][0] += 1
	}

	for _, y := range years {
		yearData[y][1] = yearData[y][0] / 52.0
	}

	readLinks := 0
	q := LinkQuery(c, -1, true)
	for t := q.Run(c); ; {
		var l Link
		_, err := t.Next(&l)
		if err == datastore.Done {
			break
		}
		if err != nil {
			log.Errorf(c, "Error loading link: %+v", err)
		} else {
			readLinks += 1
			yearPosted := strconv.Itoa(l.Posted.Year())
			// Don't want to record stats for years we don't have posts.
			if yearPosted >= oldestPost.Datetime.Year() {
				yearData[yearPosted][2] += 1
			}
		}
	}

	data = &StatsData{
		Posts:        postCount,
		PostsPerDay:  float64(postCount) / dayCount,
		WordsPerPost: float64(words) / float64(postCount),
		WordsPerDay:  float64(words) / dayCount,
		DaysSince:    dayCount,
		LinksPerDay:  float64(readLinks) / dayCount,
		Years:        years,
		YearData:     yearData,
	}

	b, err := json.Marshal(data)
	if err != nil {
		log.Errorf(c, err.Error())
		http.Error(w, err.Error(), 500)
		return
	}
	item := &memcache.Item{
		Key:   "stats-data",
		Value: b,
	}

	// Set the item, unconditionally
	if err := memcache.Set(c, item); err != nil {
		log.Errorf(c, "error setting item: %v", err)
	}
}

func StatsHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)

	data := &StatsData{}
	if json_data, err := memcache.Get(c, "stats-data"); err == memcache.ErrCacheMiss {
		log.Errorf(c, "stats-data is empty")
	} else if err != nil {
		log.Errorf(c, "error getting item: %v", err)
	} else {
		err := json.Unmarshal(json_data.Value, &data)
		if err != nil {
			log.Errorf(c, err.Error())
			http.Error(w, err.Error(), 500)
			return
		}
	}

	data.IsAdmin = user.IsAdmin(c)
	w.Render("stats", data)
}

func StatsHistoryJsonHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	entries, err := AllPosts(c)
	if err != nil {
		log.Errorf(c, "Error loading posts: %+v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.WriteJSON(entries)
}
<commit_msg>types<commit_after>package main

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/pilu/traffic"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/memcache"
	"google.golang.org/appengine/user"
)

type StatsData struct {
	Posts        int
	WordsPerPost float64
	PostsPerDay  float64
	WordsPerDay  float64
	DaysSince    float64
	IsAdmin      bool
	LinksPerPost float64
	LinksPerDay  float64
	Years        []string
	YearData     map[string][]float64
}

func StatsWorkHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)

	var data *StatsData
	entries, err := AllPosts(c)
	if err != nil {
		log.Errorf(c, "Error loading posts: %+v", err)
		http.Error(w, err.Error(), 500)
		return
	}

	postCount := len(*entries)
	oldestPost := (*entries)[postCount-1]
	dayCount := time.Since(oldestPost.Datetime).Hours() / 24.0
	oldestYear := oldestPost.Datetime.Year()

	years := []string{}
	yearData := make(map[string][]float64)
	for i := time.Now().Year(); i >= oldestYear; i-- {
		years = append(years, strconv.Itoa(i))
		yearData[strconv.Itoa(i)] = []float64{0.0, 0.0, 0.0}
	}

	words := 0
	for _, p := range *entries {
		words += len(strings.Fields(p.Content))
		words += len(strings.Fields(p.Title))
		yearData[strconv.Itoa(p.Datetime.Year())][0] += 1
	}

	for _, y := range years {
		yearData[y][1] = yearData[y][0] / 52.0
	}

	readLinks := 0
	q := LinkQuery(c, -1, true)
	for t := q.Run(c); ; {
		var l Link
		_, err := t.Next(&l)
		if err == datastore.Done {
			break
		}
		if err != nil {
			log.Errorf(c, "Error loading link: %+v", err)
		} else {
			readLinks += 1
			yearPosted := l.Posted.Year()
			// Don't want to record stats for years we don't have posts.
			if yearPosted >= oldestYear {
				yearData[strconv.Itoa(yearPosted)][2] += 1
			}
		}
	}

	data = &StatsData{
		Posts:        postCount,
		PostsPerDay:  float64(postCount) / dayCount,
		WordsPerPost: float64(words) / float64(postCount),
		WordsPerDay:  float64(words) / dayCount,
		DaysSince:    dayCount,
		LinksPerDay:  float64(readLinks) / dayCount,
		Years:        years,
		YearData:     yearData,
	}

	b, err := json.Marshal(data)
	if err != nil {
		log.Errorf(c, err.Error())
		http.Error(w, err.Error(), 500)
		return
	}
	item := &memcache.Item{
		Key:   "stats-data",
		Value: b,
	}

	// Set the item, unconditionally
	if err := memcache.Set(c, item); err != nil {
		log.Errorf(c, "error setting item: %v", err)
	}
}

func StatsHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)

	data := &StatsData{}
	if json_data, err := memcache.Get(c, "stats-data"); err == memcache.ErrCacheMiss {
		log.Errorf(c, "stats-data is empty")
	} else if err != nil {
		log.Errorf(c, "error getting item: %v", err)
	} else {
		err := json.Unmarshal(json_data.Value, &data)
		if err != nil {
			log.Errorf(c, err.Error())
			http.Error(w, err.Error(), 500)
			return
		}
	}

	data.IsAdmin = user.IsAdmin(c)
	w.Render("stats", data)
}

func StatsHistoryJsonHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	entries, err := AllPosts(c)
	if err != nil {
		log.Errorf(c, "Error loading posts: %+v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.WriteJSON(entries)
}
<|endoftext|>


<commit_before>package status

import (
	"github.com/byuoitav/configuration-database-microservice/accessors"
)

type PowerStatus struct {
	Power string `json:"power"`
}

type BlankedStatus struct {
	Blanked bool `json:"blanked"`
}

type MuteStatus struct {
	Muted bool `json:"muted"`
}

type Input struct {
	Input string `json:"input,omitempty"`
}

type AudioList struct {
	Inputs []Input `json"inputs"`
}

type VideoList struct {
	Inputs []Input `json:"inputs"`
}

type Volume struct {
	Volume int `json:"volume"`
}

//represents output from a device, use Error field to flag errors
type Status struct {
	Status            map[string]interface{} `json:"status"`
	DestinationDevice DestinationDevice      `json:"destination_device"`
}

//represents a status response, including the generator that created the command that returned the status
type StatusResponse struct {
	SourceDevice      accessors.Device       `json:"source_device"`
	DestinationDevice DestinationDevice      `json:"destination_device"`
	Generator         string                 `json:"generator"`
	Status            map[string]interface{} `json:"status"`
	ErrorMessage      *string                `json:"error"`
}

//StatusCommand contains information to issue a status command against a device
type StatusCommand struct {
	Action            accessors.Command `json:"action"`
	Device            accessors.Device  `json:"device"`
	Generator         string            `json:"generator"`
	DestinationDevice DestinationDevice `json:"destination"`
	Parameters        map[string]string `json:"parameters"`
}

//DestinationDevice represents the device whose status is being queried by user
type DestinationDevice struct {
	accessors.Device
	AudioDevice bool `json:"audio"`
	Display     bool `json:"video"`
}

type StatusEvaluator interface {

	//Identifies relevant devices
	GetDevices(room accessors.Room) ([]accessors.Device, error)

	//Generates action list
	GenerateCommands(devices []accessors.Device) ([]StatusCommand, error)

	//Evaluate Response
	EvaluateResponse(label string, value interface{}, Source accessors.Device, Destination DestinationDevice) (string, interface{}, error)
}

const FLAG = "STATUS"

//TODO: we shoud grab the keys from constants in the evaluators themselves
var STATUS_EVALUATORS = map[string]StatusEvaluator{
	"STATUS_PowerDefault":       &PowerDefault{},
	"STATUS_BlankedDefault":     &BlankedDefault{},
	"STATUS_MutedDefault":       &MutedDefault{},
	"STATUS_InputDefault":       &InputDefault{},
	"STATUS_VolumeDefault":      &VolumeDefault{},
	"STATUS_InputVideoSwitcher": &InputVideoSwitcher{},
	"STATUS_InputDSP":           &InputDSP{},
	"STATUS_MutedDSP":           &MutedDSP{},
	"STATUS_VolumeDSP":          &VolumeDSP{},
}
<commit_msg>I have a bad feeling about this<commit_after>package status

import (
	"github.com/byuoitav/configuration-database-microservice/accessors"
)

type PowerStatus struct {
	Power string `json:"power"`
}

type BlankedStatus struct {
	Blanked bool `json:"blanked"`
}

type MuteStatus struct {
	Muted bool `json:"muted"`
}

type Input struct {
	Input string `json:"input,omitempty"`
}

type AudioList struct {
	Inputs []Input `json"inputs"`
}

type VideoList struct {
	Inputs []Input `json:"inputs"`
}

type Volume struct {
	Volume int `json:"volume"`
}

type Battery struct {
	Battery int `json:"battery"`
}

//represents output from a device, use Error field to flag errors
type Status struct {
	Status            map[string]interface{} `json:"status"`
	DestinationDevice DestinationDevice      `json:"destination_device"`
}

//represents a status response, including the generator that created the command that returned the status
type StatusResponse struct {
	SourceDevice      accessors.Device       `json:"source_device"`
	DestinationDevice DestinationDevice      `json:"destination_device"`
	Generator         string                 `json:"generator"`
	Status            map[string]interface{} `json:"status"`
	ErrorMessage      *string                `json:"error"`
}

//StatusCommand contains information to issue a status command against a device
type StatusCommand struct {
	Action            accessors.Command `json:"action"`
	Device            accessors.Device  `json:"device"`
	Generator         string            `json:"generator"`
	DestinationDevice DestinationDevice `json:"destination"`
	Parameters        map[string]string `json:"parameters"`
}

//DestinationDevice represents the device whose status is being queried by user
type DestinationDevice struct {
	accessors.Device
	AudioDevice bool `json:"audio"`
	Display     bool `json:"video"`
}

type StatusEvaluator interface {

	//Identifies relevant devices
	GetDevices(room accessors.Room) ([]accessors.Device, error)

	//Generates action list
	GenerateCommands(devices []accessors.Device) ([]StatusCommand, error)

	//Evaluate Response
	EvaluateResponse(label string, value interface{}, Source accessors.Device, Destination DestinationDevice) (string, interface{}, error)
}

const FLAG = "STATUS"

//TODO: we shoud grab the keys from constants in the evaluators themselves
var STATUS_EVALUATORS = map[string]StatusEvaluator{
	"STATUS_PowerDefault":       &PowerDefault{},
	"STATUS_BlankedDefault":     &BlankedDefault{},
	"STATUS_MutedDefault":       &MutedDefault{},
	"STATUS_InputDefault":       &InputDefault{},
	"STATUS_VolumeDefault":      &VolumeDefault{},
	"STATUS_InputVideoSwitcher": &InputVideoSwitcher{},
	"STATUS_InputDSP":           &InputDSP{},
	"STATUS_MutedDSP":           &MutedDSP{},
	"STATUS_VolumeDSP":          &VolumeDSP{},
}
<|endoftext|>


<commit_before>package step
import (
	"github.com/LastCallMedia/vagabond/config"
	"os/exec"
	"fmt"
	"errors"
	"bytes"
)

var ServicesStep = ConfigStep{
	Name: "service containers",
	NeedsRun: func(envt *config.Environment) bool {
		out, err := dockerCommand(envt, "inspect vagabond_proxy").Output()
		if err != nil || bytes.Contains(out, []byte("running")) {
			return true
		}
		out, err = dockerCommand(envt, "inspect vagabond_dnsmasq").Output()
		return err != nil || !bytes.Contains(out, []byte("running"))
	},
	Run: func(envt *config.Environment) error {
		dockerCommand(envt, "stop vagabond_proxy vagabond_dnsmasq").Run()
		dockerCommand(envt, "rm vagabond_proxy vagabond_dnsmasq").Run()
		cmd := dockerCommand(envt, "run --name vagabond_proxy -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy")
		if out, err := cmd.CombinedOutput(); err != nil {
			return errors.New(string(out))
		}
		cmd = dockerCommand(envt, fmt.Sprintf("run --name vagabond_dnsmasq -d -p 53:53/udp -p 53:53/tcp --cap-add NET_ADMIN andyshinn/dnsmasq --address=/docker/%s", envt.DockerDaemonIp))
		if out, err := cmd.CombinedOutput(); err != nil {
			return errors.New(string(out))
		}
		return nil
	},
}

func dockerCommand(envt *config.Environment, command string) (cmd *exec.Cmd) {
	if envt.RequiresMachine() {
		cmd = exec.Command("bash", "-c", fmt.Sprintf("docker `docker-machine config %s` %s", envt.MachineName, command))
	} else {
		cmd = exec.Command("bash", "-c", fmt.Sprintf("docker %s", command))
	}
	return
}

<commit_msg>Fix service containers always restarting<commit_after>package step
import (
	"github.com/LastCallMedia/vagabond/config"
	"os/exec"
	"fmt"
	"errors"
	"bytes"
)

var ServicesStep = ConfigStep{
	Name: "service containers",
	NeedsRun: func(envt *config.Environment) bool {
		out, err := dockerCommand(envt, "inspect -f {{.State.Status}} vagabond_proxy").Output()
		if err != nil || !bytes.Contains(out, []byte("running")) {
			return true
		}
		out, err = dockerCommand(envt, "inspect -f {{.State.Status}} vagabond_dnsmasq").Output()
		return err != nil || !bytes.Contains(out, []byte("running"))
	},
	Run: func(envt *config.Environment) error {
		dockerCommand(envt, "stop vagabond_proxy vagabond_dnsmasq").Run()
		dockerCommand(envt, "rm vagabond_proxy vagabond_dnsmasq").Run()
		cmd := dockerCommand(envt, "run --name vagabond_proxy -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy")
		if out, err := cmd.CombinedOutput(); err != nil {
			return errors.New(string(out))
		}
		cmd = dockerCommand(envt, fmt.Sprintf("run --name vagabond_dnsmasq -d -p 53:53/udp -p 53:53/tcp --cap-add NET_ADMIN andyshinn/dnsmasq --address=/docker/%s", envt.DockerDaemonIp))
		if out, err := cmd.CombinedOutput(); err != nil {
			return errors.New(string(out))
		}
		return nil
	},
}

func dockerCommand(envt *config.Environment, command string) (cmd *exec.Cmd) {
	if envt.RequiresMachine() {
		cmd = exec.Command("bash", "-c", fmt.Sprintf("docker `docker-machine config %s` %s", envt.MachineName, command))
	} else {
		cmd = exec.Command("bash", "-c", fmt.Sprintf("docker %s", command))
	}
	return
}

<|endoftext|>


<commit_before>package stick

import "reflect"

// Unwrap will unwrap pointers and return the underlying value.
func Unwrap(v interface{}) interface{} {
	// get value
	val := reflect.ValueOf(v)

	// unwrap pointers
	for val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	return val.Interface()
}

// IsNil returns whether the provided value is nil while correctly handling typed
// nils.
func IsNil(v interface{}) bool {
	// check plain nil
	if v == nil {
		return true
	}

	// check typed nils
	value := reflect.ValueOf(v)
	switch value.Kind() {
	case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice:
		return value.IsNil()
	}

	return false
}

// GetInt will attempt to get an int64 from the provided value.
func GetInt(v interface{}) (int64, bool) {
	switch v := v.(type) {
	case int:
		return int64(v), true
	case int8:
		return int64(v), true
	case int16:
		return int64(v), true
	case int32:
		return int64(v), true
	case int64:
		return v, true
	default:
		return 0, false
	}
}

// GetUint will attempt to get an uint64 from the provided value.
func GetUint(v interface{}) (uint64, bool) {
	switch v := v.(type) {
	case uint:
		return uint64(v), true
	case uint8:
		return uint64(v), true
	case uint16:
		return uint64(v), true
	case uint32:
		return uint64(v), true
	case uint64:
		return v, true
	default:
		return 0, false
	}
}

// GetFloat will attempt to get a float from the provided value.
func GetFloat(v interface{}) (float64, bool) {
	switch v := v.(type) {
	case float32:
		return float64(v), true
	case float64:
		return v, true
	default:
		return 0, false
	}
}
<commit_msg>stick: fix nil check<commit_after>package stick

import "reflect"

// Unwrap will unwrap pointers and return the underlying value.
func Unwrap(v interface{}) interface{} {
	// get value
	val := reflect.ValueOf(v)

	// unwrap pointers
	for val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	return val.Interface()
}

// IsNil returns whether the provided value is nil while correctly handling typed
// nils.
func IsNil(v interface{}) bool {
	// check plain nil
	if v == nil {
		return true
	}

	// check typed nils
	value := reflect.ValueOf(v)
	switch value.Kind() {
	case reflect.Ptr, reflect.Slice, reflect.Map:
		return value.IsNil()
	}

	return false
}

// GetInt will attempt to get an int64 from the provided value.
func GetInt(v interface{}) (int64, bool) {
	switch v := v.(type) {
	case int:
		return int64(v), true
	case int8:
		return int64(v), true
	case int16:
		return int64(v), true
	case int32:
		return int64(v), true
	case int64:
		return v, true
	default:
		return 0, false
	}
}

// GetUint will attempt to get an uint64 from the provided value.
func GetUint(v interface{}) (uint64, bool) {
	switch v := v.(type) {
	case uint:
		return uint64(v), true
	case uint8:
		return uint64(v), true
	case uint16:
		return uint64(v), true
	case uint32:
		return uint64(v), true
	case uint64:
		return v, true
	default:
		return 0, false
	}
}

// GetFloat will attempt to get a float from the provided value.
func GetFloat(v interface{}) (float64, bool) {
	switch v := v.(type) {
	case float32:
		return float64(v), true
	case float64:
		return v, true
	default:
		return 0, false
	}
}
<|endoftext|>


<commit_before>package util

import (
	"github.com/gin-gonic/gin"
)

func CORS() gin.HandlerFunc {
	return func(c *gin.Context) {
		resp := c.Writer
		resp.Header().Set("Access-Control-Allow-Origin", "*")
		resp.Header().Set("Access-Control-Allow-Credentials", "true")
		resp.Header().Set("Access-Control-Allow-Headers", "Content-Type,Content-Encoding,Cache-Control,Content-Length,Accept-Encoding ")
	}
}
<commit_msg>更新CORS<commit_after>package util

import (
	"github.com/gin-gonic/gin"
)

func CORS() gin.HandlerFunc {
	return func(c *gin.Context) {
		resp := c.Writer
		resp.Header().Set("Access-Control-Allow-Methods", "GET, POST")
		resp.Header().Set("Access-Control-Allow-Origin", "*")
		resp.Header().Set("Access-Control-Allow-Credentials", "true")
		resp.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Encoding, Cache-Control, Content-Length, Accept-Encoding, Authorization, Origin, X-Requested-With, Accept")
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package set

// StringSet is a string set.
type StringSet map[string]struct{}

// NewStringSet builds a float64 set.
func NewStringSet(ss ...string) StringSet {
	set := make(StringSet)
	for _, s := range ss {
		set.Insert(s)
	}
	return set
}

// Exist checks whether `val` exists in `s`.
func (s StringSet) Exist(val string) bool {
	_, ok := s[val]
	return ok
}

// Insert inserts `val` into `s`.
func (s StringSet) Insert(val string) {
	s[val] = struct{}{}
}

// Intersection returns the intersection of two sets
func (s StringSet) Intersection(rhs StringSet) StringSet {
	newSet := NewStringSet()
	for elt := range s {
		if rhs.Exist(elt) {
			newSet.Insert(elt)
		}
	}
	return newSet
}
<commit_msg>util/set: fix wrong comment (#14799)<commit_after>// Copyright 2018 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package set

// StringSet is a string set.
type StringSet map[string]struct{}

// NewStringSet builds a string set.
func NewStringSet(ss ...string) StringSet {
	set := make(StringSet)
	for _, s := range ss {
		set.Insert(s)
	}
	return set
}

// Exist checks whether `val` exists in `s`.
func (s StringSet) Exist(val string) bool {
	_, ok := s[val]
	return ok
}

// Insert inserts `val` into `s`.
func (s StringSet) Insert(val string) {
	s[val] = struct{}{}
}

// Intersection returns the intersection of two sets
func (s StringSet) Intersection(rhs StringSet) StringSet {
	newSet := NewStringSet()
	for elt := range s {
		if rhs.Exist(elt) {
			newSet.Insert(elt)
		}
	}
	return newSet
}
<|endoftext|>


<commit_before>// In this example HTTP traffic is inspected by introspecting on an underlying
// TCP acceptor. By injecting callbacks on Accept, Read, Write and Close we can
// track stats for each individual connection as it changes state.
//
// This is only one possible use case of the connxray library.
package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/golang/glog"
	xray "github.com/marcinwyszynski/connxray"
)

var (
	port = flag.Int("port", 1983, "HTTP port")
)

type stats struct {
	bytesRead    int
	bytesWritten int
	startTime    time.Time
	guard        sync.Mutex
}

func newStats() *stats {
	return &stats{startTime: time.Now()}
}

type statsTracker struct {
	data      map[net.Conn]*stats
	dataGuard sync.Mutex
}

func newTracker() *statsTracker {
	return &statsTracker{data: make(map[net.Conn]*stats)}
}

func (s *statsTracker) onAccept(_ net.Listener, conn *xray.Conn, err error) {
	if err != nil {
		glog.Errorf("Error establishing connection: %v", err)
		return
	}
	glog.Infof("%s <-> %s started", conn.LocalAddr(), conn.RemoteAddr())
	s.dataGuard.Lock()
	defer s.dataGuard.Unlock()
	s.data[conn.NetConn] = newStats()
}

func (s *statsTracker) onRead(conn net.Conn, _ []byte, n int, err error) {
	if err != nil {
		glog.Errorf("Error reading from connection %#v %v", conn, err)
	}
	data, exists := s.data[conn]
	if !exists {
		glog.Errorf("Connection not tracked: %#v", conn)
		return
	}
	data.guard.Lock()
	defer data.guard.Unlock()
	data.bytesRead += n
}

func (s *statsTracker) onWrite(conn net.Conn, _ []byte, n int, err error) {
	if err != nil {
		glog.Errorf("Error writing to connection %#v %v", conn, err)
	}
	data, exists := s.data[conn]
	if !exists {
		glog.Errorf("Connection not tracked: %#v", conn)
		return
	}
	data.guard.Lock()
	defer data.guard.Unlock()
	data.bytesWritten += n
}

func (s *statsTracker) onClose(conn net.Conn, err error) {
	if err != nil {
		glog.Errorf("Error closing connection %#v %v", conn, err)
	}
	data, exists := s.data[conn]
	if !exists {
		glog.Errorf("Connection not tracked: %#v", conn)
		return
	}
	glog.Infof(
		"%s <-> %s closed: %d bytes read, %d bytes written in %d ms",
		conn.LocalAddr(),
		conn.RemoteAddr(),
		data.bytesRead,
		data.bytesWritten,
		time.Since(data.startTime)/1e6,
	)
	data.guard.Lock()
	defer data.guard.Unlock()
	delete(s.data, conn)
}

func main() {
	flag.Parse()
	addr := net.TCPAddr{Port: *port}
	tcpLisetner, err := net.ListenTCP("tcp", &addr)
	if err != nil {
		glog.Fatalf("Error creating a TCP listener: %v", err)
	}
	tracker := newTracker()
	introspectedListener := &xray.Listener{
		NetListener:       tcpLisetner,
		AcceptCallback:    tracker.onAccept,
		ConnReadCallback:  tracker.onRead,
		ConnWriteCallback: tracker.onWrite,
		ConnCloseCallback: tracker.onClose,
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello world!")
	})
	glog.Infof("About to start serving on %s", addr.String())
	glog.Fatal(http.Serve(introspectedListener, nil))
}
<commit_msg>fix example to fit the new API<commit_after>// In this example HTTP traffic is inspected by introspecting on an underlying
// TCP acceptor. By injecting callbacks on Accept, Read, Write and Close we can
// track stats for each individual connection as it changes state.
//
// This is only one possible use case of the connxray library.
package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/golang/glog"
	xray "github.com/marcinwyszynski/connxray"
)

var (
	port = flag.Int("port", 1983, "HTTP port")
)

type stats struct {
	bytesRead    int
	bytesWritten int
	startTime    time.Time
	guard        sync.Mutex
}

func newStats() *stats {
	return &stats{startTime: time.Now()}
}

type statsTracker struct {
	data      map[net.Conn]*stats
	dataGuard sync.Mutex
}

func newTracker() *statsTracker {
	return &statsTracker{data: make(map[net.Conn]*stats)}
}

func (s *statsTracker) onAccept(_ *xray.Listener, conn *xray.Conn, err error) {
	conn.AfterRead = s.onRead
	conn.AfterWrite = s.onWrite
	conn.AfterClose = s.onClose
	if err != nil {
		glog.Errorf("Error establishing connection: %v", err)
		return
	}
	glog.Infof("%s <-> %s started", conn.LocalAddr(), conn.RemoteAddr())
	s.dataGuard.Lock()
	defer s.dataGuard.Unlock()
	s.data[conn.Base] = newStats()
}

func (s *statsTracker) onRead(conn *xray.Conn, _ []byte, n int, err error) {
	if err != nil {
		glog.Errorf(
			"Error reading from connection with %s: %v",
			conn.RemoteAddr(),
			err,
		)
	}
	data, exists := s.data[conn.Base]
	if !exists {
		glog.Errorf("Connection not tracked: %#v", conn)
		return
	}
	data.guard.Lock()
	defer data.guard.Unlock()
	data.bytesRead += n
}

func (s *statsTracker) onWrite(conn *xray.Conn, _ []byte, n int, err error) {
	if err != nil {
		glog.Errorf(
			"Error writing to connection with %s: %v",
			conn.RemoteAddr(),
			err,
		)
	}
	data, exists := s.data[conn.Base]
	if !exists {
		glog.Errorf("Connection not tracked: %#v", conn)
		return
	}
	data.guard.Lock()
	defer data.guard.Unlock()
	data.bytesWritten += n
}

func (s *statsTracker) onClose(conn *xray.Conn, err error) {
	if err != nil {
		glog.Errorf(
			"Error closing connection with %s: %v",
			conn.RemoteAddr(),
			err,
		)
	}
	data, exists := s.data[conn.Base]
	if !exists {
		glog.Errorf("Connection not tracked: %#v", conn)
		return
	}
	glog.Infof(
		"%s <-> %s closed: %d bytes read, %d bytes written in %d ms",
		conn.LocalAddr(),
		conn.RemoteAddr(),
		data.bytesRead,
		data.bytesWritten,
		time.Since(data.startTime)/1e6,
	)
	data.guard.Lock()
	defer data.guard.Unlock()
	delete(s.data, conn)
}

func main() {
	flag.Parse()
	addr := net.TCPAddr{Port: *port}
	tcpLisetner, err := net.ListenTCP("tcp", &addr)
	if err != nil {
		glog.Fatalf("Error creating a TCP listener: %v", err)
	}
	tracker := newTracker()
	introspectedListener := &xray.Listener{
		Base:        tcpLisetner,
		AfterAccept: tracker.onAccept,
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello world!")
	})
	glog.Infof("About to start serving on %s", addr.String())
	glog.Fatal(http.Serve(introspectedListener, nil))
}
<|endoftext|>


<commit_before>package stream

import (
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/bahadley/ssim/generator"
	"github.com/bahadley/ssim/log"
)

var (
	send bool

	wg sync.WaitGroup
)

func Transmit(tuples []*generator.SensorTuple) {
	addrs := DstAddr()

	// Make a slice of channels and initialize them.
	chans := make([]chan *generator.SensorTuple, len(addrs))
	for i := 0; i < len(chans); i++ {
		chans[i] = make(chan *generator.SensorTuple, ChannelBufSz())
	}

	// Counting semaphore set to the number of channels.
	wg.Add(len(chans))

	// Launch all threads.  Each thread has a different destination.
	for idx, pipe := range chans {
		go egress(addrs[idx], pipe)
	}

	delayInt := DelayInterval()

	// Send all the tuples by randomly selecting channels.
	for _, tuple := range tuples {
		chans[rand.Intn(len(chans))] <- tuple
		time.Sleep(delayInt * time.Millisecond)
	}

	// Send a poison pill into the channels to shut down the threads.
	for _, pipe := range chans {
		pipe <- nil
	}

	// Wait for the threads to finish any queued work.
	wg.Wait()
}

func egress(addr string, pipe chan *generator.SensorTuple) {
	dstAddr, err := net.ResolveUDPAddr("udp",
		addr+":"+DstPort())
	if err != nil {
		log.Error.Fatal(err.Error())
	}

	srcAddr, err := net.ResolveUDPAddr("udp",
		Addr()+":0")
	if err != nil {
		log.Error.Fatal(err.Error())
	}

	conn, err := net.DialUDP("udp", srcAddr, dstAddr)
	if err != nil {
		log.Error.Fatal(err.Error())
	}

	defer conn.Close()
	defer wg.Done()

	for {
		tuple := <-pipe
		if tuple == nil {
			// Poison pill found.
			return
		}

		msg, err := generator.Marshal(tuple)
		if err != nil {
			continue
		}

		log.Trace.Printf("Tx(%s): %s", dstAddr, msg)

		if !send {
			continue
		}

		_, err = conn.Write([]byte(msg))
		if err != nil {
			log.Warning.Println(err.Error())
		}
	}
}

func init() {
	send = Send()
}
<commit_msg>Removed an unnecessary conversion to []byte<commit_after>package stream

import (
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/bahadley/ssim/generator"
	"github.com/bahadley/ssim/log"
)

var (
	send bool

	wg sync.WaitGroup
)

func Transmit(tuples []*generator.SensorTuple) {
	addrs := DstAddr()

	// Make a slice of channels and initialize them.
	chans := make([]chan *generator.SensorTuple, len(addrs))
	for i := 0; i < len(chans); i++ {
		chans[i] = make(chan *generator.SensorTuple, ChannelBufSz())
	}

	// Counting semaphore set to the number of channels.
	wg.Add(len(chans))

	// Launch all threads.  Each thread has a different destination.
	for idx, pipe := range chans {
		go egress(addrs[idx], pipe)
	}

	delayInt := DelayInterval()

	// Send all the tuples by randomly selecting channels.
	for _, tuple := range tuples {
		chans[rand.Intn(len(chans))] <- tuple
		time.Sleep(delayInt * time.Millisecond)
	}

	// Send a poison pill into the channels to shut down the threads.
	for _, pipe := range chans {
		pipe <- nil
	}

	// Wait for the threads to finish any queued work.
	wg.Wait()
}

func egress(addr string, pipe chan *generator.SensorTuple) {
	dstAddr, err := net.ResolveUDPAddr("udp",
		addr+":"+DstPort())
	if err != nil {
		log.Error.Fatal(err.Error())
	}

	srcAddr, err := net.ResolveUDPAddr("udp",
		Addr()+":0")
	if err != nil {
		log.Error.Fatal(err.Error())
	}

	conn, err := net.DialUDP("udp", srcAddr, dstAddr)
	if err != nil {
		log.Error.Fatal(err.Error())
	}

	defer conn.Close()
	defer wg.Done()

	for {
		tuple := <-pipe
		if tuple == nil {
			// Poison pill found.
			return
		}

		msg, err := generator.Marshal(tuple)
		if err != nil {
			continue
		}

		log.Trace.Printf("Tx(%s): %s", dstAddr, msg)

		if !send {
			continue
		}

		_, err = conn.Write(msg)
		if err != nil {
			log.Warning.Println(err.Error())
		}
	}
}

func init() {
	send = Send()
}
<|endoftext|>


<commit_before>// A packege for manipulating streams of events, which are basically any pieces of data.
package stream

import (
	"errors"
)

// Event interface represents just about anything you want.
// It only exists for type safety.
type Event interface{}

// An error that represents the end of iteration.
var EOI error = errors.New("End of iteration")

/*
A Stream is an interface for any stream of data.

It has only one method for geting next event or an error.
An error might be EOI in which case you just need to stop iteration, or any other.

Calling the Next method on a Stream after it already returned an error is unspecified and may be unsafe.

Calling the Next method on a Stream from multiple goroutines at once is unspecified and may be unsafe.

Typical iteration over the steam looks like this:

	func iter(s Stream, callback func(Event)) error {
		for {
			evt, err := s.Next()
			if err == EOI {
				break
			}
			if err != nil {
				return err
			}

			callback(evt)
		}
		return nil
	}
*/
type Stream interface {
	Next() (Event, error)
}
<commit_msg>docs fix<commit_after>// A package for manipulating streams of events, which are basically any pieces of data.
package stream

import (
	"errors"
)

// Event interface represents just about anything you want.
// It only exists for type safety.
type Event interface{}

// An error that represents the end of iteration.
var EOI error = errors.New("End of iteration")

/*
A Stream is an interface for any stream of data.

It has only one method for geting next event or an error.
An error might be EOI in which case you just need to stop iteration, or any other.

Calling the Next method on a Stream after it already returned an error is unspecified and may be unsafe.

Calling the Next method on a Stream from multiple goroutines at once is unspecified and may be unsafe.

Typical iteration over the steam looks like this:

	func iter(s Stream, callback func(Event)) error {
		for {
			evt, err := s.Next()
			if err == EOI {
				break
			}
			if err != nil {
				return err
			}

			callback(evt)
		}
		return nil
	}
*/
type Stream interface {
	Next() (Event, error)
}
<|endoftext|>