<commit_before>package openzwave

//
// Provides a facade for the C++ API that exposes just enough of the underlying C++
// API to be useful to implementing the Ninja Zwave driver
//
// The functions in this module are responsible for marshalling to and from the C functions
// declared in api.hpp and api.cpp.
//

//
// The following #cgo directives assumed that 'go' is a symbolic link that references the gopath that contains the current directory, e.g. ../../../..
//
// All 'go' packages that have this package as a dependency should include such a go link and will then inherit the library built in this package.
//

// #cgo LDFLAGS: -lopenzwave -Lgo/src/github.com/ninjasphere/go-openzwave/openzwave
// #cgo CPPFLAGS: -Iopenzwave/cpp/src/platform -Iopenzwave/cpp/src -Iopenzwave/cpp/src/value_classes
//
// #include "api.h"
import "C"

import "fmt"
import "os"
import "os/signal"
import "unsafe"

import "github.com/ninjasphere/go-openzwave/NT"
import "github.com/ninjasphere/go-openzwave/VT"
import "github.com/ninjasphere/go-openzwave/CODE"

type api struct {
	options       C.Options // an opaque reference to C++ Options object
	notifications chan Notification
	device        string
}

//
// The Phase0 -> Phase2 interface represent 3 different states in the evolution of the api from
// creation, through configuration, through use.
//
// Each phase includes at least one method that allows transition to the next phase.
//
// Use of strong typing like this helps guide the consumer of the api package
// to construct a valid build sequence.
//

type Phase0 interface {
	AddIntOption(option string, value int) Phase0
	AddBoolOption(option string, value bool) Phase0
	SetDriver(device string) Phase0
	Run(loop EventLoop) int
}

type EventLoop func (chan Notification);

type Notification struct {
	notification *C.Notification
}

func (self Notification) String() string {
	return fmt.Sprintf(
		"Notification[\n"+
			"notificationType=%s,\n"+
			"notificationCode=%s,\n"+
			"homeId=0x%08x,\n"+
			"nodeId=0x%02x,\n"+
			"valueType=%s,\n"+
			"valueId=0x%08x]\n",
		NT.ToEnum(int(self.notification.notificationType)),
		CODE.ToEnum(int(self.notification.notificationCode)),
		self.notification.nodeId.homeId,
		self.notification.nodeId.nodeId,
		VT.ToEnum(int(self.notification.valueId.valueType)),
		self.notification.valueId.valueId)
}

// allocate the control block used to track the state of the API
func API(configPath string, userPath string, overrides string) Phase0 {
	var (
		cConfigPath *C.char = C.CString(configPath)
		cUserPath *C.char = C.CString(userPath)
		cOverrides *C.char = C.CString(overrides)
	)
	//defer C.free(unsafe.Pointer(cConfigPath))
	//defer C.free(unsafe.Pointer(cUserPath))
	//defer C.free(unsafe.Pointer(cOverrides))
	return api{
	       C.startOptions(cConfigPath, cUserPath, cOverrides),
	       make(chan Notification),
	       defaultDriverName}
}

// configure the C++ Options object with an integer value
func (self api) AddIntOption(option string, value int) Phase0 {
	var cOption *C.char = C.CString(option)
	//defer C.free(unsafe.Pointer(cOption))

	C.addIntOption(self.options, cOption, C.int(value))
	return self
}

// configure the C++ Options object with a boolean value
func (self api) AddBoolOption(option string, value bool) Phase0 {
	var cOption *C.char = C.CString(option)

	//defer C.free(unsafe.Pointer(cOption))
	C.addBoolOption(self.options, cOption, C._Bool(value))
	return self
}

// add a driver.
func (self api) SetDriver(device string) Phase0 {
	if self.device != "" {
	       self.device = device
	}
	return self
}

// start the manager
func (self api) startManager() C.Manager {
	var cDevice *C.char = C.CString(self.device)
	//defer C.free(unsafe.Pointer(cDevice))
	return C.startManager(cDevice, unsafe.Pointer(&self));
}

func (self api) Run(loop EventLoop) int {

	C.endOptions(self.options)

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

	self.startManager()

	go loop(self.notifications);

	// Block until a signal is received.
	signal := <-signals
	fmt.Printf("received signal: %v", signal)
	return 1
}

//export OnNotificationWrapper
func OnNotificationWrapper(notification *C.Notification, context unsafe.Pointer) {
	(*api)(context).notifications <- Notification{notification}
}
<commit_msg>fix: check the parameter, not the internal thing.<commit_after>package openzwave

//
// Provides a facade for the C++ API that exposes just enough of the underlying C++
// API to be useful to implementing the Ninja Zwave driver
//
// The functions in this module are responsible for marshalling to and from the C functions
// declared in api.hpp and api.cpp.
//

//
// The following #cgo directives assumed that 'go' is a symbolic link that references the gopath that contains the current directory, e.g. ../../../..
//
// All 'go' packages that have this package as a dependency should include such a go link and will then inherit the library built in this package.
//

// #cgo LDFLAGS: -lopenzwave -Lgo/src/github.com/ninjasphere/go-openzwave/openzwave
// #cgo CPPFLAGS: -Iopenzwave/cpp/src/platform -Iopenzwave/cpp/src -Iopenzwave/cpp/src/value_classes
//
// #include "api.h"
import "C"

import "fmt"
import "os"
import "os/signal"
import "unsafe"

import "github.com/ninjasphere/go-openzwave/NT"
import "github.com/ninjasphere/go-openzwave/VT"
import "github.com/ninjasphere/go-openzwave/CODE"

type api struct {
	options       C.Options // an opaque reference to C++ Options object
	notifications chan Notification
	device        string
}

//
// The Phase0 -> Phase2 interface represent 3 different states in the evolution of the api from
// creation, through configuration, through use.
//
// Each phase includes at least one method that allows transition to the next phase.
//
// Use of strong typing like this helps guide the consumer of the api package
// to construct a valid build sequence.
//

type Phase0 interface {
	AddIntOption(option string, value int) Phase0
	AddBoolOption(option string, value bool) Phase0
	SetDriver(device string) Phase0
	Run(loop EventLoop) int
}

type EventLoop func (chan Notification);

type Notification struct {
	notification *C.Notification
}

func (self Notification) String() string {
	return fmt.Sprintf(
		"Notification[\n"+
			"notificationType=%s,\n"+
			"notificationCode=%s,\n"+
			"homeId=0x%08x,\n"+
			"nodeId=0x%02x,\n"+
			"valueType=%s,\n"+
			"valueId=0x%08x]\n",
		NT.ToEnum(int(self.notification.notificationType)),
		CODE.ToEnum(int(self.notification.notificationCode)),
		self.notification.nodeId.homeId,
		self.notification.nodeId.nodeId,
		VT.ToEnum(int(self.notification.valueId.valueType)),
		self.notification.valueId.valueId)
}

// allocate the control block used to track the state of the API
func API(configPath string, userPath string, overrides string) Phase0 {
	var (
		cConfigPath *C.char = C.CString(configPath)
		cUserPath *C.char = C.CString(userPath)
		cOverrides *C.char = C.CString(overrides)
	)
	//defer C.free(unsafe.Pointer(cConfigPath))
	//defer C.free(unsafe.Pointer(cUserPath))
	//defer C.free(unsafe.Pointer(cOverrides))
	return api{
	       C.startOptions(cConfigPath, cUserPath, cOverrides),
	       make(chan Notification),
	       defaultDriverName}
}

// configure the C++ Options object with an integer value
func (self api) AddIntOption(option string, value int) Phase0 {
	var cOption *C.char = C.CString(option)
	//defer C.free(unsafe.Pointer(cOption))

	C.addIntOption(self.options, cOption, C.int(value))
	return self
}

// configure the C++ Options object with a boolean value
func (self api) AddBoolOption(option string, value bool) Phase0 {
	var cOption *C.char = C.CString(option)

	//defer C.free(unsafe.Pointer(cOption))
	C.addBoolOption(self.options, cOption, C._Bool(value))
	return self
}

// add a driver.
func (self api) SetDriver(device string) Phase0 {
	if device != "" {
	       self.device = device
	}
	return self
}

// start the manager
func (self api) startManager() C.Manager {
	var cDevice *C.char = C.CString(self.device)
	//defer C.free(unsafe.Pointer(cDevice))
	return C.startManager(cDevice, unsafe.Pointer(&self));
}

func (self api) Run(loop EventLoop) int {

	C.endOptions(self.options)

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

	self.startManager()

	go loop(self.notifications);

	// Block until a signal is received.
	signal := <-signals
	fmt.Printf("received signal: %v", signal)
	return 1
}

//export OnNotificationWrapper
func OnNotificationWrapper(notification *C.Notification, context unsafe.Pointer) {
	(*api)(context).notifications <- Notification{notification}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"net/http"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/blevesearch/bleve"
)

// ErrorResponse Error response structure
type ErrorResponse struct {
	Message string `json:"message"`
}

// SeachResultItem is a response structure for search result item
type SeachResultItem struct {
	ID     string      `json:"id"`
	Score  float64     `json:"score"`
	Fields interface{} `json:"fields"`
}

// SearchResultsResponse is a response structure for final search results
type SearchResultsResponse struct {
	TotalResults uint64            `json:"total_results"`
	MoreResults  bool              `json:"more_results"`
	Page         int               `json:"page"`
	Time         string            `json:"took"`
	Results      []SeachResultItem `json:"results"`
}

// Adapter type
type Adapter func(http.Handler) http.Handler

// Adapt wraps http handlers with middlewares
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
	for _, adapter := range adapters {
		h = adapter(h)
	}

	return h
}

// Log all requests
func HttpLogger() Adapter {
	return func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			defer log.Infof("%s %s", r.Method, r.RequestURI)
			h.ServeHTTP(w, r)
		})
	}
}

// Write response as a JSON formt
func writeJSONResponse(w http.ResponseWriter, i interface{}, status int) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)

	if err := json.NewEncoder(w).Encode(i); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// Validate search query
func validateSearchQuery(query string) (string, error) {
	if len(query) < 3 {
		return query, errors.New("Search query should be of minimum 3 characters")
	}

	return query, nil
}

// Index page handler
func indexHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello from Bankr!"))
}

// Query search handler
func searchHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query().Get("q")
	page := r.URL.Query().Get("p")

	var (
		errorRespose         ErrorResponse
		searchResults        *bleve.SearchResult
		searchResultItems    []SeachResultItem
		resultsSize          = 10
		pageNumber           = 1
		moreResultsAvailable = false
	)

	// Validate search query
	query, err := validateSearchQuery(query)
	if err != nil {
		errorRespose.Message = err.Error()
		writeJSONResponse(w, errorRespose, http.StatusBadRequest)
		return
	}

	// Validate page number
	if page == "" {
		pageNumber = 1
	} else {
		pageNumber, err = strconv.Atoi(page)
		errorRespose.Message = "Invalid page number."
		writeJSONResponse(w, errorRespose, http.StatusBadRequest)
		return
	}

	// Search for give query and result size (startIndex + size). Start index is (pageNum - 1)
	searchResults, err = querySearch(query, resultsSize, pageNumber)
	if err != nil {
		log.Errorf("Error while searching query: %v", err)
		errorRespose.Message = "Something went wrong. Please report to admin."
		writeJSONResponse(w, errorRespose, http.StatusInternalServerError)
		return
	}

	// Create list for search items response
	for _, result := range searchResults.Hits {
		searchResultItems = append(searchResultItems, SeachResultItem{
			ID:     result.ID,
			Score:  result.Score,
			Fields: result.Fields,
		})
	}

	// Check if more available
	if searchResults.Total > uint64(pageNumber+resultsSize) {
		moreResultsAvailable = true
	}

	// Final search response
	searchResultsResponse := SearchResultsResponse{
		TotalResults: searchResults.Total,
		MoreResults:  moreResultsAvailable,
		Page:         pageNumber,
		Time:         searchResults.Took.String(),
		Results:      searchResultItems,
	}

	// Write the output
	writeJSONResponse(w, searchResultsResponse, http.StatusOK)
}

func initServer(address string) {
	http.Handle("/", Adapt(http.HandlerFunc(indexHandler)))

	// API handlers
	http.Handle("/api/search", Adapt(http.HandlerFunc(searchHandler), HttpLogger()))

	// Start the server
	log.Infof("Starting server: http://%s", address)
	if err := http.ListenAndServe(address, nil); err != nil {
		log.Error("Error starting the server: ", err)
	}
}
<commit_msg>Fixed lowercase bug with search queries<commit_after>package main

import (
	"encoding/json"
	"errors"
	"net/http"
	"strconv"

	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/blevesearch/bleve"
)

// ErrorResponse Error response structure
type ErrorResponse struct {
	Message string `json:"message"`
}

// SeachResultItem is a response structure for search result item
type SeachResultItem struct {
	ID     string      `json:"id"`
	Score  float64     `json:"score"`
	Fields interface{} `json:"fields"`
}

// SearchResultsResponse is a response structure for final search results
type SearchResultsResponse struct {
	TotalResultsPages uint64            `json:"total_results_pages"`
	MoreResults       bool              `json:"more_results"`
	Page              int               `json:"page"`
	Time              string            `json:"took"`
	Results           []SeachResultItem `json:"results"`
}

// Adapter type
type Adapter func(http.Handler) http.Handler

// Adapt wraps http handlers with middlewares
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
	for _, adapter := range adapters {
		h = adapter(h)
	}

	return h
}

// Log all requests
func HttpLogger() Adapter {
	return func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			defer log.Infof("%s %s", r.Method, r.RequestURI)
			h.ServeHTTP(w, r)
		})
	}
}

// Write response as a JSON formt
func writeJSONResponse(w http.ResponseWriter, i interface{}, status int) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)

	if err := json.NewEncoder(w).Encode(i); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// Validate search query
func sanatizeSearchQuery(query string) (string, error) {
	if len(query) < 3 {
		return query, errors.New("Search query should be of minimum 3 characters")
	}

	return strings.ToLower(query), nil
}

// Index page handler
func indexHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello from Bankr!"))
}

// Query search handler
func searchHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query().Get("q")
	page := r.URL.Query().Get("p")

	var (
		errorRespose         ErrorResponse
		searchResults        *bleve.SearchResult
		searchResultItems    []SeachResultItem
		resultsSize          = 10
		pageNumber           = 1
		moreResultsAvailable = false
	)

	// Validate search query
	query, err := sanatizeSearchQuery(query)
	if err != nil {
		errorRespose.Message = err.Error()
		writeJSONResponse(w, errorRespose, http.StatusBadRequest)
		return
	}

	// Validate page number
	if page == "" {
		pageNumber = 1
	} else {
		pageNumber, err = strconv.Atoi(page)
		if err != nil {
			errorRespose.Message = "Invalid page number."
			writeJSONResponse(w, errorRespose, http.StatusBadRequest)
			return
		}
	}

	// Search for give query and result size (startIndex + size). Start index is (pageNum - 1)
	searchResults, err = querySearch(query, resultsSize, pageNumber)
	if err != nil {
		log.Errorf("Error while searching query: %v", err)
		errorRespose.Message = "Something went wrong. Please report to admin."
		writeJSONResponse(w, errorRespose, http.StatusInternalServerError)
		return
	}

	// Create list for search items response
	for _, result := range searchResults.Hits {
		searchResultItems = append(searchResultItems, SeachResultItem{
			ID:     result.ID,
			Score:  result.Score,
			Fields: result.Fields,
		})
	}

	// Check if more available
	if searchResults.Total > uint64(pageNumber+resultsSize) {
		moreResultsAvailable = true
	}

	// Final search response
	searchResultsResponse := SearchResultsResponse{
		TotalResultsPages: searchResults.Total - 1,
		MoreResults:       moreResultsAvailable,
		Page:              pageNumber,
		Time:              searchResults.Took.String(),
		Results:           searchResultItems,
	}

	// Write the output
	writeJSONResponse(w, searchResultsResponse, http.StatusOK)
}

func initServer(address string) {
	http.Handle("/", Adapt(http.HandlerFunc(indexHandler)))

	// API handlers
	http.Handle("/api/search", Adapt(http.HandlerFunc(searchHandler), HttpLogger()))

	// Start the server
	log.Infof("Starting server: http://%s", address)
	if err := http.ListenAndServe(address, nil); err != nil {
		log.Error("Error starting the server: ", err)
	}
}
<|endoftext|>


<commit_before>package app

import (
	"errors"
	"fmt"
	"irken/client/msg"
	"os"
)

func initHandlers(ia *IrkenApp) {
	ia.handlers["CCONNECT"] = func(l *msg.Line) {
		if ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("Disconnect first to connect to a new server", "")
			handleFatalErr(err)
		}

		addr := l.Args()[len(l.Args())-1]
		err := ia.cs.Connect(addr)
		if err != nil {
			errMsg := fmt.Sprintf("Couldn't connect to %s\n, error: %v",
				addr, err)
			err = ia.gui.WriteToChannel(errMsg, "")
			handleFatalErr(err)
		}
	}

	ia.handlers["CHAN"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("Error: Must be connected to chat",
				l.Context())
			handleFatalErr(err)
			return
		}

		err := ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)

	}

	// ia.handlers["CDISCONNECT"] = func(l *msg.Line) {
	// 	if !ia.cs.IsConnected() {
	// 		err := ia.gui.WriteToChannel("You are not connected to any server", "")
	// 		handleFatalErr(err)
	// 	}

	// 	for context, _ := range ia.listeners {
	// 		if context != "" {
	// 			ia.cs.DeleteChannel(context)
	// 			ia.gui.DeleteCurrentWindow
	// 		}
	// 		ia.cs.CloseConnection()
	// 	}

	// }

	ia.handlers["CJOIN"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/join: Not connected to any server",
				"")
			handleFatalErr(err)
			return
		}

		if l.Context() == "" {
			err := ia.gui.WriteToChannel(l.Output(), l.Context())
			handleFatalErr(err)
			return

		}

		if ia.cs.ChannelExist(l.Context()) {
			err := ia.gui.WriteToChannel("/join: You have already joined "+
				l.Context(), "")
			handleFatalErr(err)
			return
		}

		ia.AddChatWindow(l.Context())
	}

	ia.handlers["CPART"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/part: Not in any channel", "")
			handleFatalErr(err)
			return
		}

		if l.Context() == "" {
			err := ia.gui.WriteToChannel("/part: You can't \"part\" from the server",
				l.Context())
			handleFatalErr(err)
			return
		}

		ia.DeleteChatWindow(l.Context())
	}

	ia.handlers["CQUIT"] = func(l *msg.Line) {
		// TODO: Clean up, at least check that the server has disconnected
		os.Exit(0)
	}

	ia.handlers["353"] = func(l *msg.Line) { // nick list
		channel, ok := ia.cs.IrcChannels[l.Context()]
		if !ok {
			handleFatalErr(errors.New("353 Nicklist: Channel, " + l.Context() + ", doesn't exist. Raw: " + l.Raw()))
			return
		}
		channel.AddNicks(l.OutputMsg())
	}

	ia.handlers["366"] = func(l *msg.Line) { // end of nick list
		channel, ok := ia.cs.IrcChannels[l.Context()]
		if !ok {
			handleFatalErr(errors.New("366 Nicklist: Channel, " + l.Context() + ", doesn't exist. Raw: " + l.Raw()))
			return
		}
		ia.updateNicks(channel.Nicks, l.Context())
	}

	ia.handlers["JOIN"] = func(l *msg.Line) {
		channel, ok := ia.cs.IrcChannels[l.Context()]
		if !ok {
			handleFatalErr(errors.New("366 Nicklist: Channel, " + l.Context() + ", doesn't exist. Raw: " + l.Raw()))
			return
		}
		channel.AddNick(l.Nick(), "")
		ia.updateNicks(channel.Nicks, l.Context())
		ia.gui.WriteToChannel(l.Output(), l.Context())
	}

	ia.handlers["NICK"] = func(l *msg.Line) {
		prevNick := l.Nick()
		if prevNick == ia.cs.GetNick() {
			ia.cs.ChangeNick(l.Args()[0])
		}

		for context, channel := range ia.cs.IrcChannels {
			if context != "" {
				channel.ChangeNick(prevNick, l.Args()[0])
				ia.updateNicks(channel.Nicks, context)
				fmt.Println(channel.Nicks)
			}
			ia.gui.WriteToChannel(l.Output(), context)
		}
	}

	ia.handlers["QUIT"] = func(l *msg.Line) {
		for context, channel := range ia.cs.IrcChannels {
			if context != "" {
				channel.RemoveNick(l.Nick())
				ia.updateNicks(channel.Nicks, context)
				ia.gui.WriteToChannel(l.Output(), context)
			}
		}
	}

	ia.handlers["PART"] = func(l *msg.Line) {
		ia.handlers["QUIT"](l)
	}

	ia.handlers["PING"] = func(l *msg.Line) {
		// TODO: Handle different for server and IRC users
		if len(l.Args()) > 0 {
			ia.cs.Send("/silentpong "+l.Args()[len(l.Args())-1], "")
		} else {
			ia.cs.Send("/silentpong", "")
		}
		ia.cs.ResetPing()
	}

	ia.handlers["P2PMSG"] = func(l *msg.Line) {
		if ia.cs.ChannelExist(l.Context()) {
			// just write to correct window
			err := ia.gui.WriteToChannel(l.Output(), l.Context())
			handleFatalErr(err)
			return
		}

		ia.AddChatWindow(l.Context())
		err := ia.gui.WriteToChannel("Beginning conversation with "+
			l.Context(), l.Context())
		handleFatalErr(err)

		err = ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)

	}

	ia.handlers["CMSG"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/msg: Not connected to any server",
				"")
			handleFatalErr(err)
			return
		}

		if ia.cs.ChannelExist(l.Context()) {
			err := ia.gui.WriteToChannel(l.Output(), l.Context())
			handleFatalErr(err)
			return
		}

		ia.AddChatWindow(l.Context())
		err := ia.gui.WriteToChannel("Beginning conversation with "+
			l.Context(), l.Context())
		handleFatalErr(err)

		err = ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)
	}

	ia.handlers["401"] = func(l *msg.Line) {
		// should not close window automatically on
		// disconnect, just tell that the user has disconnected
		prevCmd, ok := ia.prevCmd[l.Context()]
		if ok && prevCmd == "CHAN" {
			err := ia.gui.WriteToChannel(l.Context()+" has disconnected, either /part or wait for him/her to come online",
				l.Context())
			handleFatalErr(err)
			return
		}

		ia.DeleteChatWindow(l.Context())
		err := ia.gui.WriteToChannel(l.Output(), "")
		handleFatalErr(err)
	}

	ia.handlers["470"] = func(l *msg.Line) {
		ia.DeleteChatWindow(l.Args()[1])
		ia.AddChatWindow(l.Context())
		err := ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)
	}

	ia.handlers["CRAW"] = func(l *msg.Line) {
		if !ia.cs.IsDebugging() {
			err := ia.gui.WriteToChannel("/raw: Only available in debug mode",
				l.Context())
			handleFatalErr(err)
			return
		}

		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/raw: Can only send when connected",
				l.Context())
			handleFatalErr(err)
			return

		}

		ia.cs.SendRaw(l.OutputMsg())
		err := ia.gui.WriteToChannel(l.Output(),
			l.Context())
		handleFatalErr(err)

	}
}

func (ia *IrkenApp) AddChatWindow(context string) {
	ia.cs.NewChannel(context)

	ia.gui.CreateChannelWindow(context, func() {
		text, err := ia.gui.GetEntryText(context)
		if err != nil {
			err := ia.gui.WriteToChannel("Couldn't get input", context)
			handleFatalErr(err)
		}
		err = ia.cs.Send(text, context)
		if err != nil {
			err := ia.gui.WriteToChannel("Couldn't parse input", context)
			handleFatalErr(err)
		}
		ia.gui.EmptyEntryText(context)
	})
	ia.BeginInput(context)
	ia.gui.Notebook().NextPage()
}

func (ia *IrkenApp) DeleteChatWindow(context string) {
	ia.cs.DeleteChannel(context)
	ia.EndInput(context)
	ia.gui.DeleteChannelWindow(context)
}
<commit_msg>Nick now doesn't write to server window<commit_after>package app

import (
	"errors"
	"fmt"
	"irken/client/msg"
	"os"
)

func initHandlers(ia *IrkenApp) {
	ia.handlers["CCONNECT"] = func(l *msg.Line) {
		if ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("Disconnect first to connect to a new server", "")
			handleFatalErr(err)
		}

		addr := l.Args()[len(l.Args())-1]
		err := ia.cs.Connect(addr)
		if err != nil {
			errMsg := fmt.Sprintf("Couldn't connect to %s\n, error: %v",
				addr, err)
			err = ia.gui.WriteToChannel(errMsg, "")
			handleFatalErr(err)
		}
	}

	ia.handlers["CHAN"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("Error: Must be connected to chat",
				l.Context())
			handleFatalErr(err)
			return
		}

		err := ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)

	}

	// ia.handlers["CDISCONNECT"] = func(l *msg.Line) {
	// 	if !ia.cs.IsConnected() {
	// 		err := ia.gui.WriteToChannel("You are not connected to any server", "")
	// 		handleFatalErr(err)
	// 	}

	// 	for context, _ := range ia.listeners {
	// 		if context != "" {
	// 			ia.cs.DeleteChannel(context)
	// 			ia.gui.DeleteCurrentWindow
	// 		}
	// 		ia.cs.CloseConnection()
	// 	}

	// }

	ia.handlers["CJOIN"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/join: Not connected to any server",
				"")
			handleFatalErr(err)
			return
		}

		if l.Context() == "" {
			err := ia.gui.WriteToChannel(l.Output(), l.Context())
			handleFatalErr(err)
			return

		}

		if ia.cs.ChannelExist(l.Context()) {
			err := ia.gui.WriteToChannel("/join: You have already joined "+
				l.Context(), "")
			handleFatalErr(err)
			return
		}

		ia.AddChatWindow(l.Context())
	}

	ia.handlers["CPART"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/part: Not in any channel", "")
			handleFatalErr(err)
			return
		}

		if l.Context() == "" {
			err := ia.gui.WriteToChannel("/part: You can't \"part\" from the server",
				l.Context())
			handleFatalErr(err)
			return
		}

		ia.DeleteChatWindow(l.Context())
	}

	ia.handlers["CQUIT"] = func(l *msg.Line) {
		// TODO: Clean up, at least check that the server has disconnected
		os.Exit(0)
	}

	ia.handlers["353"] = func(l *msg.Line) { // nick list
		channel, ok := ia.cs.IrcChannels[l.Context()]
		if !ok {
			handleFatalErr(errors.New("353 Nicklist: Channel, " + l.Context() + ", doesn't exist. Raw: " + l.Raw()))
			return
		}
		channel.AddNicks(l.OutputMsg())
	}

	ia.handlers["366"] = func(l *msg.Line) { // end of nick list
		channel, ok := ia.cs.IrcChannels[l.Context()]
		if !ok {
			handleFatalErr(errors.New("366 Nicklist: Channel, " + l.Context() + ", doesn't exist. Raw: " + l.Raw()))
			return
		}
		ia.updateNicks(channel.Nicks, l.Context())
	}

	ia.handlers["JOIN"] = func(l *msg.Line) {
		channel, ok := ia.cs.IrcChannels[l.Context()]
		if !ok {
			handleFatalErr(errors.New("366 Nicklist: Channel, " + l.Context() + ", doesn't exist. Raw: " + l.Raw()))
			return
		}
		channel.AddNick(l.Nick(), "")
		ia.updateNicks(channel.Nicks, l.Context())
		ia.gui.WriteToChannel(l.Output(), l.Context())
	}

	ia.handlers["NICK"] = func(l *msg.Line) {
		prevNick := l.Nick()
		if prevNick == ia.cs.GetNick() {
			ia.cs.ChangeNick(l.Args()[0])
		}

		for context, channel := range ia.cs.IrcChannels {
			if context != "" {
				channel.ChangeNick(prevNick, l.Args()[0])
				ia.updateNicks(channel.Nicks, context)
				fmt.Println(channel.Nicks)
				ia.gui.WriteToChannel(l.Output(), context)
			}
		}
	}

	ia.handlers["QUIT"] = func(l *msg.Line) {
		for context, channel := range ia.cs.IrcChannels {
			if context != "" {
				channel.RemoveNick(l.Nick())
				ia.updateNicks(channel.Nicks, context)
				ia.gui.WriteToChannel(l.Output(), context)
			}
		}
	}

	ia.handlers["PART"] = func(l *msg.Line) {
		ia.handlers["QUIT"](l)
	}

	ia.handlers["PING"] = func(l *msg.Line) {
		// TODO: Handle different for server and IRC users
		if len(l.Args()) > 0 {
			ia.cs.Send("/silentpong "+l.Args()[len(l.Args())-1], "")
		} else {
			ia.cs.Send("/silentpong", "")
		}
		ia.cs.ResetPing()
	}

	ia.handlers["P2PMSG"] = func(l *msg.Line) {
		if ia.cs.ChannelExist(l.Context()) {
			// just write to correct window
			err := ia.gui.WriteToChannel(l.Output(), l.Context())
			handleFatalErr(err)
			return
		}

		ia.AddChatWindow(l.Context())
		err := ia.gui.WriteToChannel("Beginning conversation with "+
			l.Context(), l.Context())
		handleFatalErr(err)

		err = ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)

	}

	ia.handlers["CMSG"] = func(l *msg.Line) {
		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/msg: Not connected to any server",
				"")
			handleFatalErr(err)
			return
		}

		if ia.cs.ChannelExist(l.Context()) {
			err := ia.gui.WriteToChannel(l.Output(), l.Context())
			handleFatalErr(err)
			return
		}

		ia.AddChatWindow(l.Context())
		err := ia.gui.WriteToChannel("Beginning conversation with "+
			l.Context(), l.Context())
		handleFatalErr(err)

		err = ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)
	}

	ia.handlers["401"] = func(l *msg.Line) {
		// should not close window automatically on
		// disconnect, just tell that the user has disconnected
		prevCmd, ok := ia.prevCmd[l.Context()]
		if ok && prevCmd == "CHAN" {
			err := ia.gui.WriteToChannel(l.Context()+" has disconnected, either /part or wait for him/her to come online",
				l.Context())
			handleFatalErr(err)
			return
		}

		ia.DeleteChatWindow(l.Context())
		err := ia.gui.WriteToChannel(l.Output(), "")
		handleFatalErr(err)
	}

	ia.handlers["470"] = func(l *msg.Line) {
		ia.DeleteChatWindow(l.Args()[1])
		ia.AddChatWindow(l.Context())
		err := ia.gui.WriteToChannel(l.Output(), l.Context())
		handleFatalErr(err)
	}

	ia.handlers["CRAW"] = func(l *msg.Line) {
		if !ia.cs.IsDebugging() {
			err := ia.gui.WriteToChannel("/raw: Only available in debug mode",
				l.Context())
			handleFatalErr(err)
			return
		}

		if !ia.cs.IsConnected() {
			err := ia.gui.WriteToChannel("/raw: Can only send when connected",
				l.Context())
			handleFatalErr(err)
			return

		}

		ia.cs.SendRaw(l.OutputMsg())
		err := ia.gui.WriteToChannel(l.Output(),
			l.Context())
		handleFatalErr(err)

	}
}

func (ia *IrkenApp) AddChatWindow(context string) {
	ia.cs.NewChannel(context)

	ia.gui.CreateChannelWindow(context, func() {
		text, err := ia.gui.GetEntryText(context)
		if err != nil {
			err := ia.gui.WriteToChannel("Couldn't get input", context)
			handleFatalErr(err)
		}
		err = ia.cs.Send(text, context)
		if err != nil {
			err := ia.gui.WriteToChannel("Couldn't parse input", context)
			handleFatalErr(err)
		}
		ia.gui.EmptyEntryText(context)
	})
	ia.BeginInput(context)
	ia.gui.Notebook().NextPage()
}

func (ia *IrkenApp) DeleteChatWindow(context string) {
	ia.cs.DeleteChannel(context)
	ia.EndInput(context)
	ia.gui.DeleteChannelWindow(context)
}
<|endoftext|>


<commit_before>package twitter

import (
	"net/http"

	"github.com/dghubble/sling"
)

const twitterAPI = "https://api.twitter.com/1.1/"

// Client is a Twitter client for making Twitter API requests.
type Client struct {
	sling *sling.Sling
	// Twitter API Services
	Accounts       *AccountService
	Statuses       *StatusService
	Timelines      *TimelineService
	Users          *UserService
	Favorites      *FavoriteService
	Followers      *FollowerService
	Friends        *FriendService
	DirectMessages *DirectMessageService
	Streams        *StreamService
	Friendships	   *FriendshipService
}

// NewClient returns a new Client.
func NewClient(httpClient *http.Client) *Client {
	base := sling.New().Client(httpClient).Base(twitterAPI)
	return &Client{
		sling:          base,
		Accounts:       newAccountService(base.New()),
		Statuses:       newStatusService(base.New()),
		Timelines:      newTimelineService(base.New()),
		Users:          newUserService(base.New()),
		Favorites:      newFavoriteService(base.New()),
		Followers:      newFollowerService(base.New()),
		Friends:        newFriendService(base.New()),
		DirectMessages: newDirectMessageService(base.New()),
		Streams:        newStreamService(httpClient, base.New()),
		Friendships: 	newFriendshipService(base.New()),
	}
}

// Bool returns a new pointer to the given bool value.
func Bool(v bool) *bool {
	ptr := new(bool)
	*ptr = v
	return ptr
}

// Float returns a new pointer to the given float64 value.
func Float(v float64) *float64 {
	ptr := new(float64)
	*ptr = v
	return ptr
}
<commit_msg>gofmt style updates<commit_after>package twitter

import (
	"net/http"

	"github.com/dghubble/sling"
)

const twitterAPI = "https://api.twitter.com/1.1/"

// Client is a Twitter client for making Twitter API requests.
type Client struct {
	sling *sling.Sling
	// Twitter API Services
	Accounts       *AccountService
	Statuses       *StatusService
	Timelines      *TimelineService
	Users          *UserService
	Favorites      *FavoriteService
	Followers      *FollowerService
	Friends        *FriendService
	DirectMessages *DirectMessageService
	Streams        *StreamService
	Friendships    *FriendshipService
}

// NewClient returns a new Client.
func NewClient(httpClient *http.Client) *Client {
	base := sling.New().Client(httpClient).Base(twitterAPI)
	return &Client{
		sling:          base,
		Accounts:       newAccountService(base.New()),
		Statuses:       newStatusService(base.New()),
		Timelines:      newTimelineService(base.New()),
		Users:          newUserService(base.New()),
		Favorites:      newFavoriteService(base.New()),
		Followers:      newFollowerService(base.New()),
		Friends:        newFriendService(base.New()),
		DirectMessages: newDirectMessageService(base.New()),
		Streams:        newStreamService(httpClient, base.New()),
		Friendships:    newFriendshipService(base.New()),
	}
}

// Bool returns a new pointer to the given bool value.
func Bool(v bool) *bool {
	ptr := new(bool)
	*ptr = v
	return ptr
}

// Float returns a new pointer to the given float64 value.
func Float(v float64) *float64 {
	ptr := new(float64)
	*ptr = v
	return ptr
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/gopass"
	"flag"
	"fmt"
	"github.com/moraes/config"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"tmux"
)

func init() {
}

type tmugsCfg struct {
	*config.Config
	*tmux.Session
	name string
	root string
}

func main() {
	flag.Parse()
	args := flag.Args()
	processArgs(args)
}

func usage() {
	msg := []string{
		"usage: %s",
		" start CFG1 [CFG2 CFG3 ...] - start sessions with configurations",
		" ls - list sessions",
		" ls CFG - list windows in session",
		" a CFG WINDOW - attach to specified window in session",
		" kill CFG1 [CFG2 CFG3 ...] - kill specified sessions",
		"\n",
	}
	fmt.Fprintf(os.Stderr, strings.Join(msg, "\n"), os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

func processArgs(args []string) {
	if len(args) == 0 {
		usage()
	}
	switch args[0] {
	case "start":
		if len(args) > 1 {
			startSessions(args[1:])
		} else {
			usage()
		}
	case "ls":
		switch len(args) {
		case 1:
			listSessions()
		case 2:
			listWindows(args[1])
		default:
			usage()
		}
	case "a":
		if len(args) == 3 {
			attachWindow(args[1], args[2])
		} else {
			usage()
		}
	case "kill":
		if len(args) > 1 {
			killSessions(args[1:])
		} else {
			usage()
		}
	default:
		usage()
	}
}

func startSessions(sessions []string) {
	for _, filename := range sessions {
		c := getCfg(filename)
		c.processTabs()
	}
}

func killSessions(sessions []string) {
	for _, sessionname := range sessions {
		tmux.KillSession(sessionname)
	}
}

func listSessions() {
	sessions, _ := tmux.ListSessions()
	fmt.Printf("%v\n", strings.Join(sessions, "\n"))
	return
}

func listWindows(session string) {
	windows, _ := tmux.ListWindowsIdx(session)
	fmt.Printf("%v\n", strings.Join(windows, "\n"))
	return
}

func attachWindow(session string, window string) {
	tmux.SelectWindow(session, window)
}

func getCfg(filename string) (c *tmugsCfg) {
	cfg, err := config.ParseYamlFile(filename)
	if err != nil {
		log.Panic(err)
	}

	bn := filepath.Base(filename)
	pn := strings.Split(bn, ".")[0]

	proot, err := cfg.String("root")
	if err != nil {
		proot, err = os.Getwd()
		if err != nil {
			proot = "~/"
		}
	}

	_, err = cfg.String("sudo")
	if err != nil {
		log.Printf("No SUDO")
	} else {
		log.Printf("SUDO")
		getSudoPass()
	}

	sessEx, err := tmux.ListSessions()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Sessions: %#v", sessEx)

	var ts *tmux.Session
	if isMember(pn, sessEx) {
		ts = tmux.CreateSession(pn)
	} else {
		ts, err = tmux.NewSession(pn)
		if err != nil {
			log.Fatal(err)
		}
	}
	c = &tmugsCfg{
		Config:  cfg,
		Session: ts,
		name:    pn,
		root:    proot,
	}
	return
}

var SUDOPASS string
var isSudoValid = false

func getSudoPass() {
	for !isSudoValid {
		pass, err := gopass.GetPass("Enter SUDO password: ")
		if err != nil {
			log.Panic(err)
		}
		cmd := exec.Command("sudo", "-k", "-S", "whoami")
		if err != nil {
			log.Panic(err)
		}
		stdin, err := cmd.StdinPipe()
		if err != nil {
			log.Panic(err)
		}

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Panic(err)
		}

		err = cmd.Start()
		if err != nil {
			log.Panic(err)
		}
		_, err = io.WriteString(stdin, pass+"\n")

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

		_, err = ioutil.ReadAll(stdout)

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

		err = cmd.Wait()

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

		SUDOPASS = pass
		isSudoValid = true
	}
}

func (c *tmugsCfg) tabs() (ts []interface{}) {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	log.Printf("Tabs: %#v", ts)
	return
}

func (c *tmugsCfg) processTabs() {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	for _, tab := range ts {
		c.newWindow(tab.(map[string]interface{}))
	}
}

func sleep(s int) {
	time.Sleep(time.Duration(s) * time.Second)
}

func (c *tmugsCfg) newWindow(tab map[string]interface{}) {
	log.Printf("Tab: %#v", tab)
	if 1 != len(tab) {
		log.Printf("ERROR: Bad tab: %#v", tab)
		return
	}
	for k, v := range tab {
		sleepS, ok := v.(map[string]interface{})["sleep"].(int)
		if !ok {
			sleepS = 0
		}
		cd, ok := v.(map[string]interface{})["cd"].(string)
		if !ok {
			cd = "."
		}
		dir := filepath.Join(c.root, cd)
		winsExists, err := tmux.ListWindows(c.name)
		if err != nil {
			log.Printf("Error: %v", err)
			continue
		}
		log.Printf("Windows Exists in %s: %#v", c.name, winsExists)

		if isMember(k, winsExists) {
			log.Printf("Window %s already exists", k)
			continue
		}

		_, err = c.NewWindow(k, dir)
		if err != nil {
			log.Printf("Error: %v", err)
			continue
		}
		command, ok := v.(map[string]interface{})["run"]
		if ok {
			sleep(sleepS)
			switch command := command.(type) {
			case string:
				log.Printf("Exec: %s", command)
				c.SendCommand(command)
			case []interface{}:
				for _, rv := range command {
					switch rv := rv.(type) {
					case string:
						log.Printf("Exec: %s", rv)
						c.SendCommand(rv)
					case map[string]interface{}:
						if len(rv) == 1 {
							// Take name of the key
							var rkey string
							for rkey, _ = range rv {
								break
							}

							switch rkey {
							case "sudo":
								log.Printf("Run with SUDO: %#v", rv[rkey])
								c.SendCommand("sudo " + rv[rkey].(string))
								// wait for prompt
								// TODO: rewrite with async
								sleep(2)
								c.SendCommand(SUDOPASS)
							default:
								log.Printf("ERR: Unknown type of run: %#v", rkey)
							}
						} else {
							log.Printf("ERR: bad command: %#v", rv)
						}
					default:
						log.Printf("ERR: Bad command: %#v", rv)
					}
					sleep(sleepS)
				}
			default:
				log.Printf("ERR: Unknown type of run: %#v", command)
			}
		}
	}
}

func isMember(el string, els []string) (member bool) {
	member = false
	for _, v := range els {
		if el == v {
			member = true
			return
		}
	}
	return
}
<commit_msg>Add more diagnostic<commit_after>package main

import (
	"code.google.com/p/gopass"
	"flag"
	"fmt"
	"github.com/moraes/config"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"tmux"
)

func init() {
}

type tmugsCfg struct {
	*config.Config
	*tmux.Session
	name string
	root string
}

func main() {
	flag.Parse()
	args := flag.Args()
	processArgs(args)
}

func usage() {
	msg := []string{
		"usage: %s",
		" start CFG1 [CFG2 CFG3 ...] - start sessions with configurations",
		" ls - list sessions",
		" ls CFG - list windows in session",
		" a CFG WINDOW - attach to specified window in session",
		" kill CFG1 [CFG2 CFG3 ...] - kill specified sessions",
		"\n",
	}
	fmt.Fprintf(os.Stderr, strings.Join(msg, "\n"), os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

func processArgs(args []string) {
	if len(args) == 0 {
		usage()
	}
	switch args[0] {
	case "start":
		if len(args) > 1 {
			startSessions(args[1:])
		} else {
			usage()
		}
	case "ls":
		switch len(args) {
		case 1:
			listSessions()
		case 2:
			listWindows(args[1])
		default:
			usage()
		}
	case "a":
		if len(args) == 3 {
			attachWindow(args[1], args[2])
		} else {
			usage()
		}
	case "kill":
		if len(args) > 1 {
			killSessions(args[1:])
		} else {
			usage()
		}
	default:
		usage()
	}
}

func startSessions(sessions []string) {
	for _, filename := range sessions {
		c := getCfg(filename)
		c.processTabs()
	}
}

func killSessions(sessions []string) {
	for _, sessionname := range sessions {
		tmux.KillSession(sessionname)
	}
}

func listSessions() {
	sessions, _ := tmux.ListSessions()
	fmt.Printf("%v\n", strings.Join(sessions, "\n"))
	return
}

func listWindows(session string) {
	windows, _ := tmux.ListWindowsIdx(session)
	fmt.Printf("%v\n", strings.Join(windows, "\n"))
	return
}

func attachWindow(session string, window string) {
	tmux.SelectWindow(session, window)
}

func getCfg(filename string) (c *tmugsCfg) {
	cfg, err := config.ParseYamlFile(filename)
	if err != nil {
		log.Panic(err)
	}

	bn := filepath.Base(filename)
	pn := strings.Split(bn, ".")[0]

	proot, err := cfg.String("root")
	if err != nil {
		proot, err = os.Getwd()
		if err != nil {
			proot = "~/"
		}
	}

	_, err = cfg.String("sudo")
	if err != nil {
		log.Printf("No SUDO")
	} else {
		log.Printf("SUDO")
		getSudoPass()
	}

	sessEx, err := tmux.ListSessions()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Sessions: %#v", sessEx)

	var ts *tmux.Session
	if isMember(pn, sessEx) {
		ts = tmux.CreateSession(pn)
	} else {
		ts, err = tmux.NewSession(pn)
		if err != nil {
			log.Printf("Cannot create new session")
			log.Fatal(err)
		}
	}
	c = &tmugsCfg{
		Config:  cfg,
		Session: ts,
		name:    pn,
		root:    proot,
	}
	return
}

var SUDOPASS string
var isSudoValid = false

func getSudoPass() {
	for !isSudoValid {
		pass, err := gopass.GetPass("Enter SUDO password: ")
		if err != nil {
			log.Panic(err)
		}
		cmd := exec.Command("sudo", "-k", "-S", "whoami")
		if err != nil {
			log.Panic(err)
		}
		stdin, err := cmd.StdinPipe()
		if err != nil {
			log.Panic(err)
		}

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Panic(err)
		}

		err = cmd.Start()
		if err != nil {
			log.Panic(err)
		}
		_, err = io.WriteString(stdin, pass+"\n")

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

		_, err = ioutil.ReadAll(stdout)

		if err != nil {
			log.Printf("Cannot read from stdout")
			log.Panic(err)
		}

		err = cmd.Wait()

		if err != nil {
			log.Printf("Cannot wait for sudo")
			log.Panic(err)
		}

		SUDOPASS = pass
		isSudoValid = true
	}
}

func (c *tmugsCfg) tabs() (ts []interface{}) {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	log.Printf("Tabs: %#v", ts)
	return
}

func (c *tmugsCfg) processTabs() {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	for _, tab := range ts {
		c.newWindow(tab.(map[string]interface{}))
	}
}

func sleep(s int) {
	time.Sleep(time.Duration(s) * time.Second)
}

func (c *tmugsCfg) newWindow(tab map[string]interface{}) {
	log.Printf("Tab: %#v", tab)
	if 1 != len(tab) {
		log.Printf("ERROR: Bad tab: %#v", tab)
		return
	}
	for k, v := range tab {
		sleepS, ok := v.(map[string]interface{})["sleep"].(int)
		if !ok {
			sleepS = 0
		}
		cd, ok := v.(map[string]interface{})["cd"].(string)
		if !ok {
			cd = "."
		}
		dir := filepath.Join(c.root, cd)
		winsExists, err := tmux.ListWindows(c.name)
		if err != nil {
			log.Printf("Error: %v", err)
			continue
		}
		log.Printf("Windows Exists in %s: %#v", c.name, winsExists)

		if isMember(k, winsExists) {
			log.Printf("Window %s already exists", k)
			continue
		}

		_, err = c.NewWindow(k, dir)
		if err != nil {
			log.Printf("Error: %v", err)
			continue
		}
		command, ok := v.(map[string]interface{})["run"]
		if ok {
			sleep(sleepS)
			switch command := command.(type) {
			case string:
				log.Printf("Exec: %s", command)
				c.SendCommand(command)
			case []interface{}:
				for _, rv := range command {
					switch rv := rv.(type) {
					case string:
						log.Printf("Exec: %s", rv)
						c.SendCommand(rv)
					case map[string]interface{}:
						if len(rv) == 1 {
							// Take name of the key
							var rkey string
							for rkey, _ = range rv {
								break
							}

							switch rkey {
							case "sudo":
								log.Printf("Run with SUDO: %#v", rv[rkey])
								c.SendCommand("sudo " + rv[rkey].(string))
								// wait for prompt
								// TODO: rewrite with async
								sleep(2)
								c.SendCommand(SUDOPASS)
							default:
								log.Printf("ERR: Unknown type of run: %#v", rkey)
							}
						} else {
							log.Printf("ERR: bad command: %#v", rv)
						}
					default:
						log.Printf("ERR: Bad command: %#v", rv)
					}
					sleep(sleepS)
				}
			default:
				log.Printf("ERR: Unknown type of run: %#v", command)
			}
		}
	}
}

func isMember(el string, els []string) (member bool) {
	member = false
	for _, v := range els {
		if el == v {
			member = true
			return
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/gopass"
	"flag"
	"fmt"
	"github.com/moraes/config"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"tmux"
)

func init() {
}

type tmugsCfg struct {
	*config.Config
	*tmux.Session
	name string
	root string
}

func main() {
	flag.Parse()
	args := flag.Args()
	processArgs(args)
}

func usage() {
	msg := []string{
		"usage: %s",
		" start CFG1 [CFG2 CFG3 ...] - start sessions with configurations",
		" ls - list sessions",
		" ls CFG - list windows in session",
		" a CFG WINDOW - attach to specified window in session",
		" kill CFG1 [CFG2 CFG3 ...] - kill specified sessions",
		"\n",
	}
	fmt.Fprintf(os.Stderr, strings.Join(msg, "\n"), os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

func processArgs(args []string) {
	if len(args) == 0 {
		usage()
	}
	switch args[0] {
	case "start":
		if len(args) > 1 {
			startSessions(args[1:])
		} else {
			usage()
		}
	case "ls":
		switch len(args) {
		case 1:
			listSessions()
		case 2:
			listWindows(args[1])
		default:
			usage()
		}
	case "a":
		if len(args) == 3 {
			attachWindow(args[1], args[2])
		} else {
			usage()
		}
	case "kill":
		if len(args) > 1 {
			killSessions(args[1:])
		} else {
			usage()
		}
	default:
		usage()
	}
}

func startSessions(sessions []string) {
	for _, filename := range sessions {
		c := getCfg(filename)
		c.processTabs()
	}
}

func killSessions(sessions []string) {
	for _, sessionname := range sessions {
		tmux.KillSession(sessionname)
	}
}

func listSessions() {
	sessions, _ := tmux.ListSessions()
	fmt.Printf("%v\n", strings.Join(sessions, "\n"))
	return
}

func listWindows(session string) {
	windows, _ := tmux.ListWindows(session)
	fmt.Printf("%v\n", strings.Join(windows, "\n"))
	return
}

func attachWindow(session string, window string) {
	tmux.SelectWindow(session, window)
}

func getCfg(filename string) (c *tmugsCfg) {
	cfg, err := config.ParseYamlFile(filename)
	if err != nil {
		log.Panic(err)
	}

	bn := filepath.Base(filename)
	pn := strings.Split(bn, ".")[0]

	proot, err := cfg.String("root")
	if err != nil {
		proot, err = os.Getwd()
		if err != nil {
			proot = "~/"
		}
	}

	_, err = cfg.String("sudo")
	if err != nil {
		log.Printf("No SUDO")
	} else {
		log.Printf("SUDO")
		getSudoPass()
	}

	ts, err := tmux.NewSession(pn)
	if err != nil {
		log.Fatal(err)
	}
	c = &tmugsCfg{
		Config:  cfg,
		Session: ts,
		name:    pn,
		root:    proot,
	}
	return
}

var SUDOPASS string
var isSudoValid = false

func getSudoPass() {
	for !isSudoValid {
		pass, err := gopass.GetPass("Enter SUDO password: ")
		if err != nil {
			log.Panic(err)
		}
		cmd := exec.Command("sudo", "-k", "-S", "whoami")
		if err != nil {
			log.Panic(err)
		}
		stdin, err := cmd.StdinPipe()
		if err != nil {
			log.Panic(err)
		}

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Panic(err)
		}

		err = cmd.Start()
		if err != nil {
			log.Panic(err)
		}
		n, err := io.WriteString(stdin, pass+"\n")

		if err != nil {
			log.Panic(err)
		} else {
			log.Printf("Write %d bytes", n)
		}

		outB, err := ioutil.ReadAll(stdout)

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

		log.Printf("Out: %#v", string(outB))
		err = cmd.Wait()

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

		SUDOPASS = pass
		isSudoValid = true
	}
}

func (c *tmugsCfg) tabs() (ts []interface{}) {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	log.Printf("Tabs: %#v", ts)
	return
}

func (c *tmugsCfg) processTabs() {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	for _, tab := range ts {
		c.newWindow(tab.(map[string]interface{}))
	}
}

func sleep(s int) {
	time.Sleep(time.Duration(s) * time.Second)
}

func (c *tmugsCfg) newWindow(tab map[string]interface{}) {
	log.Printf("Tab: %#v", tab)
	if 1 != len(tab) {
		log.Printf("ERROR: Bad tab: %#v", tab)
		return
	}
	for k, v := range tab {
		sleepS, ok := v.(map[string]interface{})["sleep"].(int)
		if !ok {
			sleepS = 0
		}
		sleep(sleepS)
		cd, ok := v.(map[string]interface{})["cd"].(string)
		if !ok {
			cd = "."
		}
		dir := filepath.Join(c.root, cd)
		_, err := c.NewWindow(k, dir)
		if err != nil {
			log.Printf("Error: %v", err)
			continue
		}
		command, ok := v.(map[string]interface{})["run"]
		if ok {
			switch command := command.(type) {
			case string:
				log.Printf("Exec: %s", command)
				c.SendCommand(command)
			case []interface{}:
				for _, rv := range command {
					switch rv := rv.(type) {
					case string:
						log.Printf("Exec: %s", rv)
						c.SendCommand(rv)
					case map[string]interface{}:
						if len(rv) == 1 {
							// Take name of the key
							var rkey string
							for rkey, _ = range rv {
								break
							}

							switch rkey {
							case "sudo":
								log.Printf("Run with SUDO: %#v", rv[rkey])
								c.SendCommand("sudo " + rv[rkey].(string))
								// wait for prompt
								// TODO: rewrite with async
								sleep(2)
								c.SendCommand(SUDOPASS)
							default:
								log.Printf("ERR: Unknown type of run: %#v", rkey)
							}
						} else {
							log.Printf("ERR: bad command: %#v", rv)
						}
					default:
						log.Printf("ERR: Bad command: %#v", rv)
					}
					sleep(sleepS)
				}
			default:
				log.Printf("ERR: Unknown type of run: %#v", command)
			}
		}
	}
}
<commit_msg>Run new windows in old sessions<commit_after>package main

import (
	"code.google.com/p/gopass"
	"flag"
	"fmt"
	"github.com/moraes/config"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"tmux"
)

func init() {
}

type tmugsCfg struct {
	*config.Config
	*tmux.Session
	name string
	root string
}

func main() {
	flag.Parse()
	args := flag.Args()
	processArgs(args)
}

func usage() {
	msg := []string{
		"usage: %s",
		" start CFG1 [CFG2 CFG3 ...] - start sessions with configurations",
		" ls - list sessions",
		" ls CFG - list windows in session",
		" a CFG WINDOW - attach to specified window in session",
		" kill CFG1 [CFG2 CFG3 ...] - kill specified sessions",
		"\n",
	}
	fmt.Fprintf(os.Stderr, strings.Join(msg, "\n"), os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

func processArgs(args []string) {
	if len(args) == 0 {
		usage()
	}
	switch args[0] {
	case "start":
		if len(args) > 1 {
			startSessions(args[1:])
		} else {
			usage()
		}
	case "ls":
		switch len(args) {
		case 1:
			listSessions()
		case 2:
			listWindows(args[1])
		default:
			usage()
		}
	case "a":
		if len(args) == 3 {
			attachWindow(args[1], args[2])
		} else {
			usage()
		}
	case "kill":
		if len(args) > 1 {
			killSessions(args[1:])
		} else {
			usage()
		}
	default:
		usage()
	}
}

func startSessions(sessions []string) {
	for _, filename := range sessions {
		c := getCfg(filename)
		c.processTabs()
	}
}

func killSessions(sessions []string) {
	for _, sessionname := range sessions {
		tmux.KillSession(sessionname)
	}
}

func listSessions() {
	sessions, _ := tmux.ListSessions()
	fmt.Printf("%v\n", strings.Join(sessions, "\n"))
	return
}

func listWindows(session string) {
	windows, _ := tmux.ListWindowsIdx(session)
	fmt.Printf("%v\n", strings.Join(windows, "\n"))
	return
}

func attachWindow(session string, window string) {
	tmux.SelectWindow(session, window)
}

func getCfg(filename string) (c *tmugsCfg) {
	cfg, err := config.ParseYamlFile(filename)
	if err != nil {
		log.Panic(err)
	}

	bn := filepath.Base(filename)
	pn := strings.Split(bn, ".")[0]

	proot, err := cfg.String("root")
	if err != nil {
		proot, err = os.Getwd()
		if err != nil {
			proot = "~/"
		}
	}

	_, err = cfg.String("sudo")
	if err != nil {
		log.Printf("No SUDO")
	} else {
		log.Printf("SUDO")
		getSudoPass()
	}

	sessEx, err := tmux.ListSessions()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Sessions: %#v", sessEx)

	var ts *tmux.Session
	if isMember(pn, sessEx) {
		ts = tmux.CreateSession(pn)
	} else {
		ts, err = tmux.NewSession(pn)
		if err != nil {
			log.Fatal(err)
		}
	}
	c = &tmugsCfg{
		Config:  cfg,
		Session: ts,
		name:    pn,
		root:    proot,
	}
	return
}

var SUDOPASS string
var isSudoValid = false

func getSudoPass() {
	for !isSudoValid {
		pass, err := gopass.GetPass("Enter SUDO password: ")
		if err != nil {
			log.Panic(err)
		}
		cmd := exec.Command("sudo", "-k", "-S", "whoami")
		if err != nil {
			log.Panic(err)
		}
		stdin, err := cmd.StdinPipe()
		if err != nil {
			log.Panic(err)
		}

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Panic(err)
		}

		err = cmd.Start()
		if err != nil {
			log.Panic(err)
		}
		_, err = io.WriteString(stdin, pass+"\n")

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

		_, err = ioutil.ReadAll(stdout)

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

		err = cmd.Wait()

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

		SUDOPASS = pass
		isSudoValid = true
	}
}

func (c *tmugsCfg) tabs() (ts []interface{}) {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	log.Printf("Tabs: %#v", ts)
	return
}

func (c *tmugsCfg) processTabs() {
	ts, err := c.List("tabs")
	if err != nil {
		log.Panic(err)
	}
	for _, tab := range ts {
		c.newWindow(tab.(map[string]interface{}))
	}
}

func sleep(s int) {
	time.Sleep(time.Duration(s) * time.Second)
}

func (c *tmugsCfg) newWindow(tab map[string]interface{}) {
	log.Printf("Tab: %#v", tab)
	if 1 != len(tab) {
		log.Printf("ERROR: Bad tab: %#v", tab)
		return
	}
	for k, v := range tab {
		sleepS, ok := v.(map[string]interface{})["sleep"].(int)
		if !ok {
			sleepS = 0
		}
		cd, ok := v.(map[string]interface{})["cd"].(string)
		if !ok {
			cd = "."
		}
		dir := filepath.Join(c.root, cd)
		winsExists, err := tmux.ListWindows(c.name)
		if err != nil {
			log.Printf("Error: %v", err)
			continue
		}
		log.Printf("Windows Exists in %s: %#v", c.name, winsExists)

		if isMember(k, winsExists) {
			log.Printf("Window %s already exists", k)
			continue
		}

		_, err = c.NewWindow(k, dir)
		if err != nil {
			log.Printf("Error: %v", err)
			continue
		}
		command, ok := v.(map[string]interface{})["run"]
		if ok {
			sleep(sleepS)
			switch command := command.(type) {
			case string:
				log.Printf("Exec: %s", command)
				c.SendCommand(command)
			case []interface{}:
				for _, rv := range command {
					switch rv := rv.(type) {
					case string:
						log.Printf("Exec: %s", rv)
						c.SendCommand(rv)
					case map[string]interface{}:
						if len(rv) == 1 {
							// Take name of the key
							var rkey string
							for rkey, _ = range rv {
								break
							}

							switch rkey {
							case "sudo":
								log.Printf("Run with SUDO: %#v", rv[rkey])
								c.SendCommand("sudo " + rv[rkey].(string))
								// wait for prompt
								// TODO: rewrite with async
								sleep(2)
								c.SendCommand(SUDOPASS)
							default:
								log.Printf("ERR: Unknown type of run: %#v", rkey)
							}
						} else {
							log.Printf("ERR: bad command: %#v", rv)
						}
					default:
						log.Printf("ERR: Bad command: %#v", rv)
					}
					sleep(sleepS)
				}
			default:
				log.Printf("ERR: Unknown type of run: %#v", command)
			}
		}
	}
}

func isMember(el string, els []string) (member bool) {
	member = false
	for _, v := range els {
		if el == v {
			member = true
			return
		}
	}
	return
}
<|endoftext|>


<commit_before>// +build ignore+
package solver
<commit_msg>Fix invalid build comment.<commit_after>// +build ignore+

package solver
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"html/template"
	"log"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/nlopes/slack"
)

const (
	MessageGroupDisplayTimestampFormat = "3:04pm"
	MessageTextBlockquotePrefix1       = ">"
	MessageTextBlockquotePrefix2       = ">>>"
	MessageTextControlRegexp           = "<(.*?)>"
	MessageTextEmojiRegexp             = ":([a-z_]+):"
)

func textToHtml(text string, truncate bool, slackClient *slack.Client) template.HTML {
	if truncate && len(text) > 700 {
		text = fmt.Sprintf("%s...", text[:700])
	}
	lines := strings.Split(text, "\n")
	if truncate && len(lines) > 5 {
		lines = append(lines[:5], "...")
	}
	htmlPieces := []string{}
	controlRegexp := regexp.MustCompile(MessageTextControlRegexp)
	emojiRegexp := regexp.MustCompile(MessageTextEmojiRegexp)
	for i, line := range lines {
		linePrefix := ""
		lineSuffix := ""
		if strings.HasPrefix(line, MessageTextBlockquotePrefix1) ||
			strings.HasPrefix(line, MessageTextBlockquotePrefix2) {
			line = strings.TrimPrefix(line, MessageTextBlockquotePrefix1)
			line = strings.TrimPrefix(line, MessageTextBlockquotePrefix2)
			if line == "" {
				// Ensure that even empty blockquote lines get rendered.
				line = "\u200b"
			}
			linePrefix = fmt.Sprintf("
",
				Style("message.blockquote"))
			lineSuffix = "
"
		} else {
			if i != 0 {
				lineSuffix = "
"
			}
		}
		line = controlRegexp.ReplaceAllStringFunc(line, func(control string) string {
			control = control[1 : len(control)-1]
			anchorText := ""
			pipeIndex := strings.LastIndex(control, "|")
			if pipeIndex != -1 {
				anchorText = control[pipeIndex+1:]
				control = control[:pipeIndex]
			}
			if strings.HasPrefix(control, "@U") {
				userId := strings.TrimPrefix(control, "@")
				userLookup, err := newUserLookup(slackClient)
				if err == nil {
					user, err := userLookup.GetUser(userId)
					if err == nil {
						anchorText = fmt.Sprintf("@%s", user.Name)
						authTest, err := slackClient.AuthTest()
						if err == nil {
							control = fmt.Sprintf("%s/team/%s", authTest.URL, user.Name)
						} else {
							log.Printf("Could get team URL: %s", err)
						}
					} else {
						log.Printf("Could not render user mention: %s", err)
					}
				} else {
					log.Printf("Could not render user mention: %s", err)
				}
			} else if strings.HasPrefix(control, "#C") {
				channelId := strings.TrimPrefix(control, "#")
				channel, err := slackClient.GetChannelInfo(channelId)
				if err == nil {
					anchorText = fmt.Sprintf("#%s", channel.Name)
					authTest, err := slackClient.AuthTest()
					if err == nil {
						control = fmt.Sprintf("%s/team/%s", authTest.URL, channel.Name)
					} else {
						log.Printf("Could get team URL: %s", err)
					}
				} else {
					log.Printf("Could not render channel mention: %s", err)
				}
			} else if strings.HasPrefix(control, "!") {
				command := strings.TrimPrefix(control, "!")
				return fmt.Sprintf("@%s", command)
			}
			if anchorText == "" {
				anchorText = control
			}
			return fmt.Sprintf("%s",
				control, Style("message.link"), anchorText)
		})
		line = emojiRegexp.ReplaceAllStringFunc(line, func(emojiString string) string {
			shortName := emojiString[1 : len(emojiString)-1]
			if emojiHtml, err := getEmojiHtml(shortName, slackClient); err == nil {
				return fmt.Sprintf("%s", emojiString, emojiHtml)
			}
			return emojiString
		})

		htmlPieces = append(htmlPieces, linePrefix)
		// Slack's API claims that all HTML is already escaped
		htmlPieces = append(htmlPieces, line)
		htmlPieces = append(htmlPieces, lineSuffix)
	}
	return template.HTML(strings.Join(htmlPieces, ""))
}

type Message struct {
	*slack.Message
	slackClient *slack.Client
	account     *Account
}

func (m *Message) TimestampTime() time.Time {
	floatTimestamp, err := strconv.ParseFloat(m.Timestamp, 64)
	if err != nil {
		log.Println("Could not parse timestamp \"%s\".", m.Timestamp, err)
		return time.Time{}
	}
	return time.Unix(int64(floatTimestamp), 0).In(m.account.TimezoneLocation)
}

func (m *Message) TextHtml() template.HTML {
	return textToHtml(m.Text, false, m.slackClient)
}

func (m *Message) StylePath() string {
	if strings.HasPrefix(m.SubType, "channel_") || strings.HasPrefix(m.SubType, "group_") {
		return "message.automated"
	}
	if m.SubType == "me_message" {
		return "message.me"
	}
	return ""
}

func (m *Message) MessageAttachments() []*MessageAttachment {
	attachments := make([]*MessageAttachment, 0, len(m.Attachments))
	for i := range m.Attachments {
		attachments = append(
			attachments, &MessageAttachment{&m.Attachments[i], m.slackClient})
	}
	return attachments
}

func (m *Message) MessageFile() *MessageFile {
	if m.File == nil {
		return nil
	}
	return &MessageFile{m.File, m.slackClient, m.account}
}

func (m *Message) MessageReactions() []*MessageReaction {
	reactions := make([]*MessageReaction, 0, len(m.Reactions))
	for i := range m.Reactions {
		reactions = append(
			reactions, &MessageReaction{&m.Reactions[i], m.slackClient})
	}
	return reactions
}

type MessageAttachment struct {
	*slack.Attachment
	slackClient *slack.Client
}

func (a *MessageAttachment) TitleHtml() template.HTML {
	return textToHtml(a.Title, false, a.slackClient)
}

func (a *MessageAttachment) TextHtml() template.HTML {
	return textToHtml(a.Text, true, a.slackClient)
}

func (a *MessageAttachment) FieldsHtml() template.HTML {
	htmlPieces := []string{}
	inTable := false
	currentRowCellCount := 0
	for _, field := range a.Fields {
		fieldHtml := fmt.Sprintf(
			"
%s

%s
",
			Style("message.attachment.field.title"),
			textToHtml(field.Title, false, a.slackClient),
			textToHtml(field.Value, false, a.slackClient))
		if field.Short {
			if !inTable {
				htmlPieces = append(htmlPieces, fmt.Sprintf(
					"

",
					Style("message.attachment.field.table")))
				inTable = true
				currentRowCellCount = 0
			}
			if currentRowCellCount == 2 {
				htmlPieces = append(htmlPieces, "

")
				currentRowCellCount = 0
			}
			htmlPieces = append(htmlPieces, "")
			htmlPieces = append(htmlPieces, fieldHtml)
			htmlPieces = append(htmlPieces, "	")
			currentRowCellCount += 1
		} else {
			if inTable {
				htmlPieces = append(htmlPieces, "

")
				inTable = false
			}
			htmlPieces = append(htmlPieces, fieldHtml)
		}
	}
	if inTable {
		htmlPieces = append(htmlPieces, "

")
	}
	return template.HTML(strings.Join(htmlPieces, ""))
}

type MessageFile struct {
	*slack.File
	slackClient *slack.Client
	account     *Account
}

func (f *MessageFile) ThumbnailUrl() (string, error) {
	ref := FileUrlRef{f.ID, f.account.SlackUserId}
	encodedRef, err := ref.Encode()
	if err != nil {
		return "", err
	}
	return AbsoluteRouteUrl("archive-file-thumbnail", "ref", encodedRef)
}

func (f *MessageFile) ThumbnailWidth() int {
	return f.Thumb360W
}

func (f *MessageFile) ThumbnailHeight() int {
	return f.Thumb360H
}

type MessageReaction struct {
	*slack.ItemReaction
	slackClient *slack.Client
}

func (r *MessageReaction) Emoji() template.HTML {
	if emojiHtml, err := getEmojiHtml(r.Name, r.slackClient); err == nil {
		return template.HTML(emojiHtml)
	}
	return template.HTML(r.Name)
}

func (r *MessageReaction) Summary() (string, error) {
	userLookup, err := newUserLookup(r.slackClient)
	if err != nil {
		return "", err
	}
	names := make([]string, len(r.Users))
	for i := range r.Users {
		if user, err := userLookup.GetUser(r.Users[i]); err == nil {
			names[i] = user.Name
		} else {
			names[i] = r.Users[i]
		}
	}
	return fmt.Sprintf("%s reacted with :%s:",
		strings.Join(names, ", "), r.Name), nil
}

type MessageGroup struct {
	Messages []*Message
	Author   *slack.User
}

func safeFormattedDate(date string) string {
	// Insert zero-width spaces every few characters so that Apple Data
	// Detectors and Gmail's calendar event dection don't pick up on these
	// dates.
	var buffer bytes.Buffer
	dateLength := len(date)
	for i := 0; i < dateLength; i += 2 {
		if i == dateLength-1 {
			buffer.WriteString(date[i : i+1])
		} else {
			buffer.WriteString(date[i : i+2])
			if date[i] != ' ' && date[i+1] != ' ' && i < dateLength-2 {
				buffer.WriteString("\u200b")
			}
		}
	}
	return buffer.String()
}

func (mg *MessageGroup) shouldContainMessage(message *Message, messageAuthor *slack.User) bool {
	if messageAuthor.ID != mg.Author.ID {
		return false
	}
	lastMessage := mg.Messages[len(mg.Messages)-1]
	timestampDelta := message.TimestampTime().Sub(lastMessage.TimestampTime())
	if timestampDelta > time.Minute*10 {
		return false
	}
	return true
}

func (mg *MessageGroup) FromBot() bool {
	return mg.Messages[0].SubType == "bot_message"
}

func (mg *MessageGroup) DisplayTimestamp() string {
	return safeFormattedDate(mg.Messages[0].TimestampTime().Format(
		MessageGroupDisplayTimestampFormat))
}

func groupMessages(messages []*slack.Message, slackClient *slack.Client, account *Account) ([]*MessageGroup, error) {
	var currentGroup *MessageGroup = nil
	groups := make([]*MessageGroup, 0)
	userLookup, err := newUserLookup(slackClient)
	if err != nil {
		return nil, err
	}
	for i := range messages {
		message := &Message{messages[i], slackClient, account}
		if message.Hidden {
			continue
		}
		messageAuthor, _ := userLookup.GetUserForMessage(messages[i])
		if messageAuthor == nil {
			log.Printf("Could not determine author for message type %s "+
				"(subtype %s), skipping", message.Type, message.SubType)
			continue
		}
		if currentGroup == nil || !currentGroup.shouldContainMessage(message, messageAuthor) {
			currentGroup = &MessageGroup{
				Messages: make([]*Message, 0),
				Author:   messageAuthor,
			}
			groups = append(groups, currentGroup)
		}
		currentGroup.Messages = append(currentGroup.Messages, message)
	}
	return groups, nil
}
<commit_msg>Broaden emoji regexp to handle more emoji shortnames.<commit_after>package main

import (
	"bytes"
	"fmt"
	"html/template"
	"log"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/nlopes/slack"
)

const (
	MessageGroupDisplayTimestampFormat = "3:04pm"
	MessageTextBlockquotePrefix1       = ">"
	MessageTextBlockquotePrefix2       = ">>>"
	MessageTextControlRegexp           = "<(.*?)>"
	MessageTextEmojiRegexp             = ":([a-z0-9_\\-+]+):"
)

func textToHtml(text string, truncate bool, slackClient *slack.Client) template.HTML {
	if truncate && len(text) > 700 {
		text = fmt.Sprintf("%s...", text[:700])
	}
	lines := strings.Split(text, "\n")
	if truncate && len(lines) > 5 {
		lines = append(lines[:5], "...")
	}
	htmlPieces := []string{}
	controlRegexp := regexp.MustCompile(MessageTextControlRegexp)
	emojiRegexp := regexp.MustCompile(MessageTextEmojiRegexp)
	for i, line := range lines {
		linePrefix := ""
		lineSuffix := ""
		if strings.HasPrefix(line, MessageTextBlockquotePrefix1) ||
			strings.HasPrefix(line, MessageTextBlockquotePrefix2) {
			line = strings.TrimPrefix(line, MessageTextBlockquotePrefix1)
			line = strings.TrimPrefix(line, MessageTextBlockquotePrefix2)
			if line == "" {
				// Ensure that even empty blockquote lines get rendered.
				line = "\u200b"
			}
			linePrefix = fmt.Sprintf("
",
				Style("message.blockquote"))
			lineSuffix = "
"
		} else {
			if i != 0 {
				lineSuffix = "
"
			}
		}
		line = controlRegexp.ReplaceAllStringFunc(line, func(control string) string {
			control = control[1 : len(control)-1]
			anchorText := ""
			pipeIndex := strings.LastIndex(control, "|")
			if pipeIndex != -1 {
				anchorText = control[pipeIndex+1:]
				control = control[:pipeIndex]
			}
			if strings.HasPrefix(control, "@U") {
				userId := strings.TrimPrefix(control, "@")
				userLookup, err := newUserLookup(slackClient)
				if err == nil {
					user, err := userLookup.GetUser(userId)
					if err == nil {
						anchorText = fmt.Sprintf("@%s", user.Name)
						authTest, err := slackClient.AuthTest()
						if err == nil {
							control = fmt.Sprintf("%s/team/%s", authTest.URL, user.Name)
						} else {
							log.Printf("Could get team URL: %s", err)
						}
					} else {
						log.Printf("Could not render user mention: %s", err)
					}
				} else {
					log.Printf("Could not render user mention: %s", err)
				}
			} else if strings.HasPrefix(control, "#C") {
				channelId := strings.TrimPrefix(control, "#")
				channel, err := slackClient.GetChannelInfo(channelId)
				if err == nil {
					anchorText = fmt.Sprintf("#%s", channel.Name)
					authTest, err := slackClient.AuthTest()
					if err == nil {
						control = fmt.Sprintf("%s/team/%s", authTest.URL, channel.Name)
					} else {
						log.Printf("Could get team URL: %s", err)
					}
				} else {
					log.Printf("Could not render channel mention: %s", err)
				}
			} else if strings.HasPrefix(control, "!") {
				command := strings.TrimPrefix(control, "!")
				return fmt.Sprintf("@%s", command)
			}
			if anchorText == "" {
				anchorText = control
			}
			return fmt.Sprintf("%s",
				control, Style("message.link"), anchorText)
		})
		line = emojiRegexp.ReplaceAllStringFunc(line, func(emojiString string) string {
			shortName := emojiString[1 : len(emojiString)-1]
			if emojiHtml, err := getEmojiHtml(shortName, slackClient); err == nil {
				return fmt.Sprintf("%s", emojiString, emojiHtml)
			}
			return emojiString
		})

		htmlPieces = append(htmlPieces, linePrefix)
		// Slack's API claims that all HTML is already escaped
		htmlPieces = append(htmlPieces, line)
		htmlPieces = append(htmlPieces, lineSuffix)
	}
	return template.HTML(strings.Join(htmlPieces, ""))
}

type Message struct {
	*slack.Message
	slackClient *slack.Client
	account     *Account
}

func (m *Message) TimestampTime() time.Time {
	floatTimestamp, err := strconv.ParseFloat(m.Timestamp, 64)
	if err != nil {
		log.Println("Could not parse timestamp \"%s\".", m.Timestamp, err)
		return time.Time{}
	}
	return time.Unix(int64(floatTimestamp), 0).In(m.account.TimezoneLocation)
}

func (m *Message) TextHtml() template.HTML {
	return textToHtml(m.Text, false, m.slackClient)
}

func (m *Message) StylePath() string {
	if strings.HasPrefix(m.SubType, "channel_") || strings.HasPrefix(m.SubType, "group_") {
		return "message.automated"
	}
	if m.SubType == "me_message" {
		return "message.me"
	}
	return ""
}

func (m *Message) MessageAttachments() []*MessageAttachment {
	attachments := make([]*MessageAttachment, 0, len(m.Attachments))
	for i := range m.Attachments {
		attachments = append(
			attachments, &MessageAttachment{&m.Attachments[i], m.slackClient})
	}
	return attachments
}

func (m *Message) MessageFile() *MessageFile {
	if m.File == nil {
		return nil
	}
	return &MessageFile{m.File, m.slackClient, m.account}
}

func (m *Message) MessageReactions() []*MessageReaction {
	reactions := make([]*MessageReaction, 0, len(m.Reactions))
	for i := range m.Reactions {
		reactions = append(
			reactions, &MessageReaction{&m.Reactions[i], m.slackClient})
	}
	return reactions
}

type MessageAttachment struct {
	*slack.Attachment
	slackClient *slack.Client
}

func (a *MessageAttachment) TitleHtml() template.HTML {
	return textToHtml(a.Title, false, a.slackClient)
}

func (a *MessageAttachment) TextHtml() template.HTML {
	return textToHtml(a.Text, true, a.slackClient)
}

func (a *MessageAttachment) FieldsHtml() template.HTML {
	htmlPieces := []string{}
	inTable := false
	currentRowCellCount := 0
	for _, field := range a.Fields {
		fieldHtml := fmt.Sprintf(
			"
%s

%s
",
			Style("message.attachment.field.title"),
			textToHtml(field.Title, false, a.slackClient),
			textToHtml(field.Value, false, a.slackClient))
		if field.Short {
			if !inTable {
				htmlPieces = append(htmlPieces, fmt.Sprintf(
					"

",
					Style("message.attachment.field.table")))
				inTable = true
				currentRowCellCount = 0
			}
			if currentRowCellCount == 2 {
				htmlPieces = append(htmlPieces, "

")
				currentRowCellCount = 0
			}
			htmlPieces = append(htmlPieces, "")
			htmlPieces = append(htmlPieces, fieldHtml)
			htmlPieces = append(htmlPieces, "	")
			currentRowCellCount += 1
		} else {
			if inTable {
				htmlPieces = append(htmlPieces, "

")
				inTable = false
			}
			htmlPieces = append(htmlPieces, fieldHtml)
		}
	}
	if inTable {
		htmlPieces = append(htmlPieces, "

")
	}
	return template.HTML(strings.Join(htmlPieces, ""))
}

type MessageFile struct {
	*slack.File
	slackClient *slack.Client
	account     *Account
}

func (f *MessageFile) ThumbnailUrl() (string, error) {
	ref := FileUrlRef{f.ID, f.account.SlackUserId}
	encodedRef, err := ref.Encode()
	if err != nil {
		return "", err
	}
	return AbsoluteRouteUrl("archive-file-thumbnail", "ref", encodedRef)
}

func (f *MessageFile) ThumbnailWidth() int {
	return f.Thumb360W
}

func (f *MessageFile) ThumbnailHeight() int {
	return f.Thumb360H
}

type MessageReaction struct {
	*slack.ItemReaction
	slackClient *slack.Client
}

func (r *MessageReaction) Emoji() template.HTML {
	if emojiHtml, err := getEmojiHtml(r.Name, r.slackClient); err == nil {
		return template.HTML(emojiHtml)
	}
	return template.HTML(r.Name)
}

func (r *MessageReaction) Summary() (string, error) {
	userLookup, err := newUserLookup(r.slackClient)
	if err != nil {
		return "", err
	}
	names := make([]string, len(r.Users))
	for i := range r.Users {
		if user, err := userLookup.GetUser(r.Users[i]); err == nil {
			names[i] = user.Name
		} else {
			names[i] = r.Users[i]
		}
	}
	return fmt.Sprintf("%s reacted with :%s:",
		strings.Join(names, ", "), r.Name), nil
}

type MessageGroup struct {
	Messages []*Message
	Author   *slack.User
}

func safeFormattedDate(date string) string {
	// Insert zero-width spaces every few characters so that Apple Data
	// Detectors and Gmail's calendar event dection don't pick up on these
	// dates.
	var buffer bytes.Buffer
	dateLength := len(date)
	for i := 0; i < dateLength; i += 2 {
		if i == dateLength-1 {
			buffer.WriteString(date[i : i+1])
		} else {
			buffer.WriteString(date[i : i+2])
			if date[i] != ' ' && date[i+1] != ' ' && i < dateLength-2 {
				buffer.WriteString("\u200b")
			}
		}
	}
	return buffer.String()
}

func (mg *MessageGroup) shouldContainMessage(message *Message, messageAuthor *slack.User) bool {
	if messageAuthor.ID != mg.Author.ID {
		return false
	}
	lastMessage := mg.Messages[len(mg.Messages)-1]
	timestampDelta := message.TimestampTime().Sub(lastMessage.TimestampTime())
	if timestampDelta > time.Minute*10 {
		return false
	}
	return true
}

func (mg *MessageGroup) FromBot() bool {
	return mg.Messages[0].SubType == "bot_message"
}

func (mg *MessageGroup) DisplayTimestamp() string {
	return safeFormattedDate(mg.Messages[0].TimestampTime().Format(
		MessageGroupDisplayTimestampFormat))
}

func groupMessages(messages []*slack.Message, slackClient *slack.Client, account *Account) ([]*MessageGroup, error) {
	var currentGroup *MessageGroup = nil
	groups := make([]*MessageGroup, 0)
	userLookup, err := newUserLookup(slackClient)
	if err != nil {
		return nil, err
	}
	for i := range messages {
		message := &Message{messages[i], slackClient, account}
		if message.Hidden {
			continue
		}
		messageAuthor, _ := userLookup.GetUserForMessage(messages[i])
		if messageAuthor == nil {
			log.Printf("Could not determine author for message type %s "+
				"(subtype %s), skipping", message.Type, message.SubType)
			continue
		}
		if currentGroup == nil || !currentGroup.shouldContainMessage(message, messageAuthor) {
			currentGroup = &MessageGroup{
				Messages: make([]*Message, 0),
				Author:   messageAuthor,
			}
			groups = append(groups, currentGroup)
		}
		currentGroup.Messages = append(currentGroup.Messages, message)
	}
	return groups, nil
}
<|endoftext|>


<commit_before>package http

import (
	"bytes"
	"common"
	"coordinator"
	"encoding/json"
	"fmt"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"net"
	libhttp "net/http"
	"net/url"
	"parser"
	"protocol"
	"testing"
	"time"
)

// Hook up gocheck into the gotest runner.
func Test(t *testing.T) {
	TestingT(t)
}

type ApiSuite struct {
	listener    net.Listener
	server      *HttpServer
	coordinator *MockCoordinator
}

var _ = Suite(&ApiSuite{})

type MockEngine struct{}

func (self *MockEngine) RunQuery(_ string, query string, yield func(*protocol.Series) error) error {
	series, err := common.StringToSeriesArray(`
[
  {
    "points": [
      {
        "values": [
				  { "string_value": "some_value"},{"int64_value": 1}
        ],
        "timestamp": 1381346631000000,
        "sequence_number": 1
      },
      {
        "values": [
				  {"string_value": "some_value"},{"int64_value": 2}
				],
        "timestamp": 1381346632000000,
        "sequence_number": 2
      }
    ],
    "name": "foo",
    "fields": [{"type": "STRING","name": "column_one"},{"type": "INT64","name": "column_two"}]
  },
  {
    "points": [
      {
        "values": [
				  { "string_value": "some_value"},{"int64_value": 3}
        ],
        "timestamp": 1381346633000000,
        "sequence_number": 1
      },
      {
        "values": [
				  {"string_value": "some_value"},{"int64_value": 4}
				],
        "timestamp": 1381346634000000,
        "sequence_number": 2
      }
    ],
    "name": "foo",
    "fields": [{"type": "STRING","name": "column_one"},{"type": "INT64","name": "column_two"}]
  }
]
`)
	if err != nil {
		return err
	}
	if err := yield(series[0]); err != nil {
		return err
	}
	return yield(series[1])
}

type MockCoordinator struct {
	series           []*protocol.Series
	db               string
	initialApiKey    string
	requestingApiKey string
}

func (self *MockCoordinator) DistributeQuery(db string, query *parser.Query, yield func(*protocol.Series) error) error {
	return nil
}
func (self *MockCoordinator) WriteSeriesData(db string, series *protocol.Series) error {
	self.series = append(self.series, series)
	return nil
}
func (self *MockCoordinator) CreateDatabase(db, initialApiKey, requestingApiKey string) error {
	self.db = db
	self.initialApiKey = initialApiKey
	self.requestingApiKey = requestingApiKey
	return nil
}

func (self *MockCoordinator) GetUser(username, password string) (*coordinator.User, error) {
	return nil, nil
}
func (self *MockCoordinator) GetUserWithoutPassword(username string) *coordinator.User { return nil }
func (self *MockCoordinator) SaveUser(user *coordinator.User) error                    { return nil }

func (self *ApiSuite) SetUpSuite(c *C) {
	self.coordinator = &MockCoordinator{}
	self.server = NewHttpServer("", &MockEngine{}, self.coordinator)
	var err error
	self.listener, err = net.Listen("tcp4", ":8081")
	c.Assert(err, IsNil)
	go func() {
		self.server.Serve(self.listener)
	}()
	time.Sleep(1 * time.Second)
}

func (self *ApiSuite) TearDownSuite(c *C) {
	self.server.Close()
}

func (self *ApiSuite) SetUpTest(c *C) {
	self.coordinator.series = nil
}

func (self *ApiSuite) TestQueryWithSecondsPrecision(c *C) {
	port := self.listener.Addr().(*net.TCPAddr).Port
	query := "select * from foo where column_one == 'some_value';"
	query = url.QueryEscape(query)
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?q=%s&time_precision=s", port, query)
	resp, err := libhttp.Get(addr)
	c.Assert(err, IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	data, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	series := []SerializedSeries{}
	err = json.Unmarshal(data, &series)
	c.Assert(err, IsNil)
	c.Assert(series, HasLen, 1)
	c.Assert(series[0].Name, Equals, "foo")
	// time, seq, column_one, column_two
	c.Assert(series[0].Columns, HasLen, 4)
	c.Assert(series[0].Points, HasLen, 4)
	c.Assert(int(series[0].Points[0][0].(float64)), Equals, 1381346631)
}

func (self *ApiSuite) TestNotChunkedQuery(c *C) {
	port := self.listener.Addr().(*net.TCPAddr).Port
	query := "select * from foo where column_one == 'some_value';"
	query = url.QueryEscape(query)
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?q=%s", port, query)
	resp, err := libhttp.Get(addr)
	c.Assert(err, IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	data, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	series := []SerializedSeries{}
	err = json.Unmarshal(data, &series)
	c.Assert(err, IsNil)
	c.Assert(series, HasLen, 1)
	c.Assert(series[0].Name, Equals, "foo")
	// time, seq, column_one, column_two
	c.Assert(series[0].Columns, HasLen, 4)
	c.Assert(series[0].Points, HasLen, 4)
	// timestamp precision is milliseconds by default
	c.Assert(int(series[0].Points[0][0].(float64)), Equals, 1381346631000)
}

func (self *ApiSuite) TestChunkedQuery(c *C) {
	port := self.listener.Addr().(*net.TCPAddr).Port
	query := "select * from foo where column_one == 'some_value';"
	query = url.QueryEscape(query)
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?q=%s&chunked=true", port, query)
	resp, err := libhttp.Get(addr)
	c.Assert(err, IsNil)
	defer resp.Body.Close()

	for i := 0; i < 2; i++ {
		chunk := make([]byte, 2048, 2048)
		n, err := resp.Body.Read(chunk)
		c.Assert(err, IsNil)

		series := SerializedSeries{}
		err = json.Unmarshal(chunk[0:n], &series)
		c.Assert(err, IsNil)
		c.Assert(series.Name, Equals, "foo")
		// time, seq, column_one, column_two
		c.Assert(series.Columns, HasLen, 4)
		// each chunk should have 2 points
		c.Assert(series.Points, HasLen, 2)
	}
}

func (self *ApiSuite) TestWriteDataWithTimeInSeconds(c *C) {
	data := `
[
  {
    "points": [
				[1382131686, "1"]
    ],
    "name": "foo",
    "columns": ["time", "column_one"]
  }
]
`

	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?time_precision=s", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	fmt.Printf("body: %s\n", string(body))
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	c.Assert(self.coordinator.series, HasLen, 1)
	series := self.coordinator.series[0]

	// check the types
	c.Assert(series.Fields, HasLen, 1)
	c.Assert(*series.Fields[0].Name, Equals, "column_one")
	c.Assert(*series.Fields[0].Type, Equals, protocol.FieldDefinition_STRING)

	// check the values
	c.Assert(series.Points, HasLen, 1)
	c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
	c.Assert(*series.Points[0].GetTimestampInMicroseconds(), Equals, int64(1382131686000000))
}

func (self *ApiSuite) TestWriteDataWithTime(c *C) {
	data := `
[
  {
    "points": [
				[1382131686000, "1"]
    ],
    "name": "foo",
    "columns": ["time", "column_one"]
  }
]
`

	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	fmt.Printf("body: %s\n", string(body))
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	c.Assert(self.coordinator.series, HasLen, 1)
	series := self.coordinator.series[0]

	// check the types
	c.Assert(series.Fields, HasLen, 1)
	c.Assert(*series.Fields[0].Name, Equals, "column_one")
	c.Assert(*series.Fields[0].Type, Equals, protocol.FieldDefinition_STRING)

	// check the values
	c.Assert(series.Points, HasLen, 1)
	c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
	c.Assert(*series.Points[0].GetTimestampInMicroseconds(), Equals, int64(1382131686000000))
}

func (self *ApiSuite) TestWriteData(c *C) {
	data := `
[
  {
    "points": [
				["1", 1, 1.0, true],
				["2", 2, 2.0, false],
				["3", 3, 3.0, true]
    ],
    "name": "foo",
    "integer_columns": [1],
    "columns": ["column_one", "column_two", "column_three", "column_four"]
  }
]
`

	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	fmt.Printf("body: %s\n", string(body))
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	c.Assert(self.coordinator.series, HasLen, 1)
	series := self.coordinator.series[0]
	c.Assert(series.Fields, HasLen, 4)

	// check the types
	c.Assert(*series.Fields[0].Name, Equals, "column_one")
	c.Assert(*series.Fields[0].Type, Equals, protocol.FieldDefinition_STRING)
	c.Assert(*series.Fields[1].Name, Equals, "column_two")
	c.Assert(*series.Fields[1].Type, Equals, protocol.FieldDefinition_INT64)
	c.Assert(*series.Fields[2].Name, Equals, "column_three")
	c.Assert(*series.Fields[2].Type, Equals, protocol.FieldDefinition_DOUBLE)
	c.Assert(*series.Fields[3].Name, Equals, "column_four")
	c.Assert(*series.Fields[3].Type, Equals, protocol.FieldDefinition_BOOL)

	// check the values
	c.Assert(series.Points, HasLen, 3)
	c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
	c.Assert(*series.Points[0].Values[1].Int64Value, Equals, int64(1))
	c.Assert(*series.Points[0].Values[2].DoubleValue, Equals, 1.0)
	c.Assert(*series.Points[0].Values[3].BoolValue, Equals, true)
}

func (self *ApiSuite) TestCreateDatabase(c *C) {
	data := `{"name": "foo", "apiKey": "bar"}`
	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db?api_key=asdf", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	_, err = ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	c.Assert(resp.StatusCode, Equals, libhttp.StatusCreated)
	c.Assert(self.coordinator.db, Equals, "foo")
	c.Assert(self.coordinator.initialApiKey, Equals, "bar")
	c.Assert(self.coordinator.requestingApiKey, Equals, "asdf")
}
<commit_msg>remove a printf.<commit_after>package http

import (
	"bytes"
	"common"
	"coordinator"
	"encoding/json"
	"fmt"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"net"
	libhttp "net/http"
	"net/url"
	"parser"
	"protocol"
	"testing"
	"time"
)

// Hook up gocheck into the gotest runner.
func Test(t *testing.T) {
	TestingT(t)
}

type ApiSuite struct {
	listener    net.Listener
	server      *HttpServer
	coordinator *MockCoordinator
}

var _ = Suite(&ApiSuite{})

type MockEngine struct{}

func (self *MockEngine) RunQuery(_ string, query string, yield func(*protocol.Series) error) error {
	series, err := common.StringToSeriesArray(`
[
  {
    "points": [
      {
        "values": [
				  { "string_value": "some_value"},{"int64_value": 1}
        ],
        "timestamp": 1381346631000000,
        "sequence_number": 1
      },
      {
        "values": [
				  {"string_value": "some_value"},{"int64_value": 2}
				],
        "timestamp": 1381346632000000,
        "sequence_number": 2
      }
    ],
    "name": "foo",
    "fields": [{"type": "STRING","name": "column_one"},{"type": "INT64","name": "column_two"}]
  },
  {
    "points": [
      {
        "values": [
				  { "string_value": "some_value"},{"int64_value": 3}
        ],
        "timestamp": 1381346633000000,
        "sequence_number": 1
      },
      {
        "values": [
				  {"string_value": "some_value"},{"int64_value": 4}
				],
        "timestamp": 1381346634000000,
        "sequence_number": 2
      }
    ],
    "name": "foo",
    "fields": [{"type": "STRING","name": "column_one"},{"type": "INT64","name": "column_two"}]
  }
]
`)
	if err != nil {
		return err
	}
	if err := yield(series[0]); err != nil {
		return err
	}
	return yield(series[1])
}

type MockCoordinator struct {
	series           []*protocol.Series
	db               string
	initialApiKey    string
	requestingApiKey string
}

func (self *MockCoordinator) DistributeQuery(db string, query *parser.Query, yield func(*protocol.Series) error) error {
	return nil
}
func (self *MockCoordinator) WriteSeriesData(db string, series *protocol.Series) error {
	self.series = append(self.series, series)
	return nil
}
func (self *MockCoordinator) CreateDatabase(db, initialApiKey, requestingApiKey string) error {
	self.db = db
	self.initialApiKey = initialApiKey
	self.requestingApiKey = requestingApiKey
	return nil
}

func (self *MockCoordinator) GetUser(username, password string) (*coordinator.User, error) {
	return nil, nil
}
func (self *MockCoordinator) GetUserWithoutPassword(username string) *coordinator.User { return nil }
func (self *MockCoordinator) SaveUser(user *coordinator.User) error                    { return nil }

func (self *ApiSuite) SetUpSuite(c *C) {
	self.coordinator = &MockCoordinator{}
	self.server = NewHttpServer("", &MockEngine{}, self.coordinator)
	var err error
	self.listener, err = net.Listen("tcp4", ":8081")
	c.Assert(err, IsNil)
	go func() {
		self.server.Serve(self.listener)
	}()
	time.Sleep(1 * time.Second)
}

func (self *ApiSuite) TearDownSuite(c *C) {
	self.server.Close()
}

func (self *ApiSuite) SetUpTest(c *C) {
	self.coordinator.series = nil
}

func (self *ApiSuite) TestQueryWithSecondsPrecision(c *C) {
	port := self.listener.Addr().(*net.TCPAddr).Port
	query := "select * from foo where column_one == 'some_value';"
	query = url.QueryEscape(query)
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?q=%s&time_precision=s", port, query)
	resp, err := libhttp.Get(addr)
	c.Assert(err, IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	data, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	series := []SerializedSeries{}
	err = json.Unmarshal(data, &series)
	c.Assert(err, IsNil)
	c.Assert(series, HasLen, 1)
	c.Assert(series[0].Name, Equals, "foo")
	// time, seq, column_one, column_two
	c.Assert(series[0].Columns, HasLen, 4)
	c.Assert(series[0].Points, HasLen, 4)
	c.Assert(int(series[0].Points[0][0].(float64)), Equals, 1381346631)
}

func (self *ApiSuite) TestNotChunkedQuery(c *C) {
	port := self.listener.Addr().(*net.TCPAddr).Port
	query := "select * from foo where column_one == 'some_value';"
	query = url.QueryEscape(query)
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?q=%s", port, query)
	resp, err := libhttp.Get(addr)
	c.Assert(err, IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	data, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	series := []SerializedSeries{}
	err = json.Unmarshal(data, &series)
	c.Assert(err, IsNil)
	c.Assert(series, HasLen, 1)
	c.Assert(series[0].Name, Equals, "foo")
	// time, seq, column_one, column_two
	c.Assert(series[0].Columns, HasLen, 4)
	c.Assert(series[0].Points, HasLen, 4)
	// timestamp precision is milliseconds by default
	c.Assert(int(series[0].Points[0][0].(float64)), Equals, 1381346631000)
}

func (self *ApiSuite) TestChunkedQuery(c *C) {
	port := self.listener.Addr().(*net.TCPAddr).Port
	query := "select * from foo where column_one == 'some_value';"
	query = url.QueryEscape(query)
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?q=%s&chunked=true", port, query)
	resp, err := libhttp.Get(addr)
	c.Assert(err, IsNil)
	defer resp.Body.Close()

	for i := 0; i < 2; i++ {
		chunk := make([]byte, 2048, 2048)
		n, err := resp.Body.Read(chunk)
		c.Assert(err, IsNil)

		series := SerializedSeries{}
		err = json.Unmarshal(chunk[0:n], &series)
		c.Assert(err, IsNil)
		c.Assert(series.Name, Equals, "foo")
		// time, seq, column_one, column_two
		c.Assert(series.Columns, HasLen, 4)
		// each chunk should have 2 points
		c.Assert(series.Points, HasLen, 2)
	}
}

func (self *ApiSuite) TestWriteDataWithTimeInSeconds(c *C) {
	data := `
[
  {
    "points": [
				[1382131686, "1"]
    ],
    "name": "foo",
    "columns": ["time", "column_one"]
  }
]
`

	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series?time_precision=s", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	c.Assert(self.coordinator.series, HasLen, 1)
	series := self.coordinator.series[0]

	// check the types
	c.Assert(series.Fields, HasLen, 1)
	c.Assert(*series.Fields[0].Name, Equals, "column_one")
	c.Assert(*series.Fields[0].Type, Equals, protocol.FieldDefinition_STRING)

	// check the values
	c.Assert(series.Points, HasLen, 1)
	c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
	c.Assert(*series.Points[0].GetTimestampInMicroseconds(), Equals, int64(1382131686000000))
}

func (self *ApiSuite) TestWriteDataWithTime(c *C) {
	data := `
[
  {
    "points": [
				[1382131686000, "1"]
    ],
    "name": "foo",
    "columns": ["time", "column_one"]
  }
]
`

	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	fmt.Printf("body: %s\n", string(body))
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	c.Assert(self.coordinator.series, HasLen, 1)
	series := self.coordinator.series[0]

	// check the types
	c.Assert(series.Fields, HasLen, 1)
	c.Assert(*series.Fields[0].Name, Equals, "column_one")
	c.Assert(*series.Fields[0].Type, Equals, protocol.FieldDefinition_STRING)

	// check the values
	c.Assert(series.Points, HasLen, 1)
	c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
	c.Assert(*series.Points[0].GetTimestampInMicroseconds(), Equals, int64(1382131686000000))
}

func (self *ApiSuite) TestWriteData(c *C) {
	data := `
[
  {
    "points": [
				["1", 1, 1.0, true],
				["2", 2, 2.0, false],
				["3", 3, 3.0, true]
    ],
    "name": "foo",
    "integer_columns": [1],
    "columns": ["column_one", "column_two", "column_three", "column_four"]
  }
]
`

	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db/foo/series", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	fmt.Printf("body: %s\n", string(body))
	c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
	c.Assert(self.coordinator.series, HasLen, 1)
	series := self.coordinator.series[0]
	c.Assert(series.Fields, HasLen, 4)

	// check the types
	c.Assert(*series.Fields[0].Name, Equals, "column_one")
	c.Assert(*series.Fields[0].Type, Equals, protocol.FieldDefinition_STRING)
	c.Assert(*series.Fields[1].Name, Equals, "column_two")
	c.Assert(*series.Fields[1].Type, Equals, protocol.FieldDefinition_INT64)
	c.Assert(*series.Fields[2].Name, Equals, "column_three")
	c.Assert(*series.Fields[2].Type, Equals, protocol.FieldDefinition_DOUBLE)
	c.Assert(*series.Fields[3].Name, Equals, "column_four")
	c.Assert(*series.Fields[3].Type, Equals, protocol.FieldDefinition_BOOL)

	// check the values
	c.Assert(series.Points, HasLen, 3)
	c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
	c.Assert(*series.Points[0].Values[1].Int64Value, Equals, int64(1))
	c.Assert(*series.Points[0].Values[2].DoubleValue, Equals, 1.0)
	c.Assert(*series.Points[0].Values[3].BoolValue, Equals, true)
}

func (self *ApiSuite) TestCreateDatabase(c *C) {
	data := `{"name": "foo", "apiKey": "bar"}`
	port := self.listener.Addr().(*net.TCPAddr).Port
	addr := fmt.Sprintf("http://localhost:%d/db?api_key=asdf", port)
	resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
	c.Assert(err, IsNil)
	_, err = ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	c.Assert(resp.StatusCode, Equals, libhttp.StatusCreated)
	c.Assert(self.coordinator.db, Equals, "foo")
	c.Assert(self.coordinator.initialApiKey, Equals, "bar")
	c.Assert(self.coordinator.requestingApiKey, Equals, "asdf")
}
<|endoftext|>