<commit_before>package complaints

import (
	"encoding/csv"
	"fmt"
	"net/http"
	"sort"
	"time"

	"appengine"

	"github.com/skypies/util/date"

	"github.com/skypies/complaints/complaintdb"
	"github.com/skypies/complaints/sessions"
	"github.com/skypies/util/widget"
)

func init() {
	http.HandleFunc("/download-complaints", downloadHandler)
	http.HandleFunc("/personal-report", personalReportHandler)
}

// These guys *should* be in backend, but they depend on user sessions, which segfault
// because of being in another module or something.

// {{{ keysByIntValDesc, keysByKeyAsc

// Yay, sorting things is so easy in go
func keysByIntValDesc(m map[string]int) []string {
	// Invert the map
	inv := map[int][]string{}
	for k,v := range m { inv[v] = append(inv[v], k) }

	// List the unique vals
	vals := []int{}
	for k,_ := range inv { vals = append(vals, k) }

	// Sort the vals
	sort.Sort(sort.Reverse(sort.IntSlice(vals)))

	// Now list the keys corresponding to each val
	keys := []string{}
	for _,val := range vals {
		for _,key := range inv[val] {
			keys = append(keys, key)
		}
	}

	return keys
}

func keysByKeyAsc(m map[string]int) []string {
	// List the unique vals
	keys := []string{}
	for k,_ := range m { keys = append(keys, k) }

	// Sort the vals
	sort.Sort(sort.StringSlice(keys))

	return keys
}

// }}}

// {{{ downloadHandler

func downloadHandler(w http.ResponseWriter, r *http.Request) {
	session := sessions.Get(r)
	if session.Values["email"] == nil {
		http.Error(w, "session was empty; no cookie ? is this browser in privacy mode ?",
			http.StatusInternalServerError)
		return
	}

	c := appengine.Timeout(appengine.NewContext(r), 60*time.Second)

	cdb := complaintdb.ComplaintDB{C: c}
	cap, err := cdb.GetAllByEmailAddress(session.Values["email"].(string), true)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	_ = cap

	filename := date.NowInPdt().Format("complaints-20060102.csv")
	w.Header().Set("Content-Type", "application/csv")
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))

	cols := []string{
		"Date", "Time(PDT)", "Notes", "Speedbrakes", "Loudness", "Activity",
		"Flightnumber", "Origin", "Destination", "Speed(Knots)", "Altitude(Feet)",
		"Lat", "Long", "Registration", "Callsign",
		"VerticalSpeed(FeetPerMin)", "Dist2(km)", "Dist3(km)",
		"City",
	}

	csvWriter := csv.NewWriter(w)
	csvWriter.Write(cols)

	for _,c := range cap.Complaints {
		a := c.AircraftOverhead
		speedbrakes := ""
		if c.HeardSpeedbreaks { speedbrakes = "y" }
		r := []string{
			c.Timestamp.Format("2006/01/02"),
			c.Timestamp.Format("15:04:05"),
			c.Description, speedbrakes, fmt.Sprintf("%d", c.Loudness), c.Activity,
			a.FlightNumber, a.Origin, a.Destination,
			fmt.Sprintf("%.0f",a.Speed), fmt.Sprintf("%.0f",a.Altitude),
			fmt.Sprintf("%.5f", a.Lat), fmt.Sprintf("%.5f", a.Long),
			a.Registration, a.Callsign, fmt.Sprintf("%.0f",a.VerticalSpeed),
			fmt.Sprintf("%.1f", c.Dist2KM), fmt.Sprintf("%.1f", c.Dist3KM),
			c.Profile.GetStructuredAddress().City,
		}

		if err := csvWriter.Write(r); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
	csvWriter.Flush()
}

// }}}
// {{{ personalReportHandler

func personalReportHandler(w http.ResponseWriter, r *http.Request) {
	session := sessions.Get(r)
	if session.Values["email"] == nil {
		http.Error(w, "session was empty; no cookie ?", http.StatusInternalServerError)
		return
	}
	email := session.Values["email"].(string)

	if r.FormValue("date") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0,0,-1),
		}
		if err := templates.ExecuteTemplate(w, "personal-report-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	start,end,_ := widget.FormValueDateRange(r)

	ctx := appengine.Timeout(appengine.NewContext(r), 60*time.Second)
	cdb := complaintdb.ComplaintDB{C: ctx}

	w.Header().Set("Content-Type", "text/plain")
	// w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", "sc.txt"))
	fmt.Fprintf(w, "Personal disturbances report for <%s>:\n From [%s]\n To   [%s]\n",
		email, start, end)

	complaintStrings := []string{}
	var countsByHour [24]int
	countsByDate := map[string]int{}
	countsByAirline := map[string]int{}
	countsByAirport := map[string]int{}

	iter := cdb.NewIter(cdb.QueryInSpanByEmailAddress(start,end,email))
	n := 0
	for {
		c := iter.Next();
		if c == nil { break }

		str := fmt.Sprintf("Time: %s, Loudness:%d, Speedbrakes:%v, Flight:%6.6s, Notes:%s",
			c.Timestamp.Format("2006.01.02 15:04:05"), c.Loudness, c.HeardSpeedbreaks,
			c.AircraftOverhead.FlightNumber, c.Description)

		n++
		complaintStrings = append(complaintStrings, str)

		countsByHour[c.Timestamp.Hour()]++
		countsByDate[c.Timestamp.Format("2006.01.02")]++
		countsByAirport[c.AircraftOverhead.Origin]++
		countsByAirport[c.AircraftOverhead.Destination]++
		if airline := c.AircraftOverhead.IATAAirlineCode(); airline != "" {
			countsByAirline[airline]++
		}
	}

	fmt.Fprintf(w, "\nTotal number of disturbance reports, over %d days:  %d\n",
		len(countsByDate), n)

	fmt.Fprintf(w, "\nDisturbance reports, counted by Airline (where known):\n")
	for _,k := range keysByIntValDesc(countsByAirline) {
		fmt.Fprintf(w, " %s: % 4d\n", k, countsByAirline[k])
	}

	fmt.Fprintf(w, "\nDisturbance reports, counted by Airport (where known):\n")
	for _,k := range keysByIntValDesc(countsByAirport) {
		if (k != "") {
			fmt.Fprintf(w, " %s: % 4d\n", k, countsByAirport[k])
		}
	}

	fmt.Fprintf(w, "\nDisturbance reports, counted by date:\n")
	for _,k := range keysByKeyAsc(countsByDate) {
		fmt.Fprintf(w, " %s: % 4d\n", k, countsByDate[k])
	}
	fmt.Fprintf(w, "\nDisturbance reports, counted by hour of day (across all dates):\n")
	for i,n := range countsByHour {
		fmt.Fprintf(w, " %02d: % 4d\n", i, n)
	}
	fmt.Fprintf(w, "\nFull dump of all disturbance reports:\n\n")
	for _,s := range complaintStrings {
		fmt.Fprint(w, s+"\n")
	}
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<commit_msg>use iterators, avoid running out of memory for thousands of complaints<commit_after>package complaints

import (
	"encoding/csv"
	"fmt"
	"net/http"
	"sort"
	"time"

	"appengine"

	"github.com/skypies/util/date"

	"github.com/skypies/complaints/complaintdb"
	"github.com/skypies/complaints/sessions"
	"github.com/skypies/util/widget"
)

func init() {
	http.HandleFunc("/download-complaints", downloadHandler)
	http.HandleFunc("/personal-report", personalReportHandler)
}

// These guys *should* be in backend, but they depend on user sessions, which segfault
// because of being in another module or something.

// {{{ keysByIntValDesc, keysByKeyAsc

// Yay, sorting things is so easy in go
func keysByIntValDesc(m map[string]int) []string {
	// Invert the map
	inv := map[int][]string{}
	for k,v := range m { inv[v] = append(inv[v], k) }

	// List the unique vals
	vals := []int{}
	for k,_ := range inv { vals = append(vals, k) }

	// Sort the vals
	sort.Sort(sort.Reverse(sort.IntSlice(vals)))

	// Now list the keys corresponding to each val
	keys := []string{}
	for _,val := range vals {
		for _,key := range inv[val] {
			keys = append(keys, key)
		}
	}

	return keys
}

func keysByKeyAsc(m map[string]int) []string {
	// List the unique vals
	keys := []string{}
	for k,_ := range m { keys = append(keys, k) }

	// Sort the vals
	sort.Sort(sort.StringSlice(keys))

	return keys
}

// }}}

// {{{ downloadHandler

func downloadHandler(w http.ResponseWriter, r *http.Request) {
	session := sessions.Get(r)
	if session.Values["email"] == nil {
		http.Error(w, "session was empty; no cookie ? is this browser in privacy mode ?",
			http.StatusInternalServerError)
		return
	}

	filename := date.NowInPdt().Format("complaints-20060102.csv")
	w.Header().Set("Content-Type", "application/csv")
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))

	cols := []string{
		"Date", "Time(PDT)", "Notes", "Speedbrakes", "Loudness", "Activity",
		"Flightnumber", "Origin", "Destination", "Speed(Knots)", "Altitude(Feet)",
		"Lat", "Long", "Registration", "Callsign",
		"VerticalSpeed(FeetPerMin)", "Dist2(km)", "Dist3(km)",
		"City",
	}

	csvWriter := csv.NewWriter(w)
	csvWriter.Write(cols)

	email := session.Values["email"].(string)
	ctx := appengine.Timeout(appengine.NewContext(r), 60*time.Second)
	cdb := complaintdb.ComplaintDB{C: ctx}
	iter := cdb.NewIter(cdb.QueryAllByEmailAddress(email))
	for {
		c,err := iter.NextWithErr();
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if c == nil { break }

		a := c.AircraftOverhead
		speedbrakes := ""
		if c.HeardSpeedbreaks { speedbrakes = "y" }
		r := []string{
			c.Timestamp.Format("2006/01/02"),
			c.Timestamp.Format("15:04:05"),
			c.Description, speedbrakes, fmt.Sprintf("%d", c.Loudness), c.Activity,
			a.FlightNumber, a.Origin, a.Destination,
			fmt.Sprintf("%.0f",a.Speed), fmt.Sprintf("%.0f",a.Altitude),
			fmt.Sprintf("%.5f", a.Lat), fmt.Sprintf("%.5f", a.Long),
			a.Registration, a.Callsign, fmt.Sprintf("%.0f",a.VerticalSpeed),
			fmt.Sprintf("%.1f", c.Dist2KM), fmt.Sprintf("%.1f", c.Dist3KM),
			c.Profile.GetStructuredAddress().City,
		}

		if err := csvWriter.Write(r); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}

	csvWriter.Flush()
}

// }}}
// {{{ personalReportHandler

func personalReportHandler(w http.ResponseWriter, r *http.Request) {
	session := sessions.Get(r)
	if session.Values["email"] == nil {
		http.Error(w, "session was empty; no cookie ?", http.StatusInternalServerError)
		return
	}
	email := session.Values["email"].(string)

	if r.FormValue("date") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0,0,-1),
		}
		if err := templates.ExecuteTemplate(w, "personal-report-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	start,end,_ := widget.FormValueDateRange(r)

	ctx := appengine.Timeout(appengine.NewContext(r), 60*time.Second)
	cdb := complaintdb.ComplaintDB{C: ctx}

	w.Header().Set("Content-Type", "text/plain")
	// w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", "sc.txt"))
	fmt.Fprintf(w, "Personal disturbances report for <%s>:\n From [%s]\n To   [%s]\n",
		email, start, end)

	complaintStrings := []string{}
	var countsByHour [24]int
	countsByDate := map[string]int{}
	countsByAirline := map[string]int{}
	countsByAirport := map[string]int{}

	iter := cdb.NewIter(cdb.QueryInSpanByEmailAddress(start,end,email))
	n := 0
	for {
		c := iter.Next();
		if c == nil { break }

		str := fmt.Sprintf("Time: %s, Loudness:%d, Speedbrakes:%v, Flight:%6.6s, Notes:%s",
			c.Timestamp.Format("2006.01.02 15:04:05"), c.Loudness, c.HeardSpeedbreaks,
			c.AircraftOverhead.FlightNumber, c.Description)

		n++
		complaintStrings = append(complaintStrings, str)

		countsByHour[c.Timestamp.Hour()]++
		countsByDate[c.Timestamp.Format("2006.01.02")]++
		countsByAirport[c.AircraftOverhead.Origin]++
		countsByAirport[c.AircraftOverhead.Destination]++
		if airline := c.AircraftOverhead.IATAAirlineCode(); airline != "" {
			countsByAirline[airline]++
		}
	}

	fmt.Fprintf(w, "\nTotal number of disturbance reports, over %d days:  %d\n",
		len(countsByDate), n)

	fmt.Fprintf(w, "\nDisturbance reports, counted by Airline (where known):\n")
	for _,k := range keysByIntValDesc(countsByAirline) {
		fmt.Fprintf(w, " %s: % 4d\n", k, countsByAirline[k])
	}

	fmt.Fprintf(w, "\nDisturbance reports, counted by Airport (where known):\n")
	for _,k := range keysByIntValDesc(countsByAirport) {
		if (k != "") {
			fmt.Fprintf(w, " %s: % 4d\n", k, countsByAirport[k])
		}
	}

	fmt.Fprintf(w, "\nDisturbance reports, counted by date:\n")
	for _,k := range keysByKeyAsc(countsByDate) {
		fmt.Fprintf(w, " %s: % 4d\n", k, countsByDate[k])
	}
	fmt.Fprintf(w, "\nDisturbance reports, counted by hour of day (across all dates):\n")
	for i,n := range countsByHour {
		fmt.Fprintf(w, " %02d: % 4d\n", i, n)
	}
	fmt.Fprintf(w, "\nFull dump of all disturbance reports:\n\n")
	for _,s := range complaintStrings {
		fmt.Fprint(w, s+"\n")
	}
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<|endoftext|>


<commit_before>package machine

import (
	"io/ioutil"
	"net"
	"strings"

	log "github.com/golang/glog"
)

const boot_id_path = "/proc/sys/kernel/random/boot_id"

type Machine struct {
	BootId   string
	PublicIP string
	Metadata map[string]string
}

func New(bootId string, publicIP string, metadata map[string]string) (m *Machine) {
	if bootId == "" {
		bootId = ReadLocalBootId()
	}
	if publicIP == "" {
		publicIP = getLocalIP()
	}
	return &Machine{bootId, publicIP, metadata}
}

func (m *Machine) String() string {
	return m.BootId
}

func (m *Machine) HasMetadata(metadata map[string][]string) bool {
	for key, values := range metadata {
		local, ok := m.Metadata[key]
		if !ok {
			log.V(1).Infof("No local values found for Metadata(%s)", key)
			return false
		}

		log.V(2).Infof("Asserting local Metadata(%s) meets requirements", key)

		var localMatch bool
		for _, val := range values {
			if local == val {
				log.V(1).Infof("Local Metadata(%s) meets requirement", key)
				localMatch = true
			}
		}

		if !localMatch {
			log.V(1).Infof("Local Metadata(%s) does not match requirement", key)
			return false
		}
	}

	return true
}

func ReadLocalBootId() string {
	id, err := ioutil.ReadFile(boot_id_path)
	if err != nil {
		panic(err)
	}
	return strings.TrimSpace(string(id))
}

func getLocalIP() string {
	iface, err := net.InterfaceByName("eth0")
	if err != nil {
		return ""
	}

	addrs, err := iface.Addrs()
	if err != nil || len(addrs) == 0 {
		return ""
	}

	return strings.SplitN(addrs[0].String(), "/", 2)[0]
}
<commit_msg>fix(machine): Use IPv4 addr when grabbing default public IP<commit_after>package machine

import (
	"io/ioutil"
	"net"
	"strings"

	log "github.com/golang/glog"
)

const boot_id_path = "/proc/sys/kernel/random/boot_id"

type Machine struct {
	BootId   string
	PublicIP string
	Metadata map[string]string
}

func New(bootId string, publicIP string, metadata map[string]string) (m *Machine) {
	if bootId == "" {
		bootId = ReadLocalBootId()
	}
	if publicIP == "" {
		publicIP = getLocalIP()
	}
	return &Machine{bootId, publicIP, metadata}
}

func (m *Machine) String() string {
	return m.BootId
}

func (m *Machine) HasMetadata(metadata map[string][]string) bool {
	for key, values := range metadata {
		local, ok := m.Metadata[key]
		if !ok {
			log.V(1).Infof("No local values found for Metadata(%s)", key)
			return false
		}

		log.V(2).Infof("Asserting local Metadata(%s) meets requirements", key)

		var localMatch bool
		for _, val := range values {
			if local == val {
				log.V(1).Infof("Local Metadata(%s) meets requirement", key)
				localMatch = true
			}
		}

		if !localMatch {
			log.V(1).Infof("Local Metadata(%s) does not match requirement", key)
			return false
		}
	}

	return true
}

func ReadLocalBootId() string {
	id, err := ioutil.ReadFile(boot_id_path)
	if err != nil {
		panic(err)
	}
	return strings.TrimSpace(string(id))
}

func getLocalIP() string {
	iface, err := net.InterfaceByName("eth0")
	if err != nil {
		return ""
	}

	addrs, err := iface.Addrs()
	if err != nil || len(addrs) == 0 {
		return ""
	}

	for _, addr := range addrs {
		// Attempt to parse the address in CIDR notation
		// and assert it is IPv4
		ip, _, err := net.ParseCIDR(addr.String())
		if err == nil && ip.To4() != nil {
			return ip.String()
		}
	}

	return ""
}
<|endoftext|>


<commit_before>package providers

import (
	. "bitbucket.org/sinbad/git-lob/Godeps/_workspace/src/github.com/onsi/ginkgo"
	. "bitbucket.org/sinbad/git-lob/Godeps/_workspace/src/github.com/onsi/gomega"
	. "bitbucket.org/sinbad/git-lob/util"
	"testing"
)

func TestAll(t *testing.T) {
	// Connect Ginkgo to Gomega
	RegisterFailHandler(Fail)

	// Set manual logging off
	loggingOff := true
	//loggingOff = false
	if loggingOff {
		LogSuppressAllConsoleOutput()
	}

	// Run everything
	RunSpecs(t, "Git Lob Util Test Suite")
}
<commit_msg>Fix name of providers test suite<commit_after>package providers

import (
	. "bitbucket.org/sinbad/git-lob/Godeps/_workspace/src/github.com/onsi/ginkgo"
	. "bitbucket.org/sinbad/git-lob/Godeps/_workspace/src/github.com/onsi/gomega"
	. "bitbucket.org/sinbad/git-lob/util"
	"testing"
)

func TestAll(t *testing.T) {
	// Connect Ginkgo to Gomega
	RegisterFailHandler(Fail)

	// Set manual logging off
	loggingOff := true
	//loggingOff = false
	if loggingOff {
		LogSuppressAllConsoleOutput()
	}

	// Run everything
	RunSpecs(t, "Git Lob Providers Test Suite")
}
<|endoftext|>


<commit_before>// (c) 2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
	"fmt"

	"github.com/ava-labs/avalanchego/utils/metricutils"
	"github.com/ava-labs/avalanchego/utils/wrappers"
	"github.com/prometheus/client_golang/prometheus"
)

func newCallsMetric(namespace, name string) prometheus.Counter {
	return prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      fmt.Sprintf("%s_calls", name),
		Help:      fmt.Sprintf("Number of times %s has been called", name),
	})
}

type metrics struct {
	numTxRefreshes, numTxRefreshHits, numTxRefreshMisses prometheus.Counter

	apiRequestMetric metricutils.APIRequestMetrics
}

func (m *metrics) Initialize(
	namespace string,
	registerer prometheus.Registerer,
) error {

	m.numTxRefreshes = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refreshes",
		Help:      "Number of times unique txs have been refreshed",
	})
	m.numTxRefreshHits = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_hits",
		Help:      "Number of times unique txs have not been unique, but were cached",
	})
	m.numTxRefreshMisses = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_misses",
		Help:      "Number of times unique txs have not been unique and weren't cached",
	})

	m.apiRequestMetric = metricutils.NewAPIMetrics(namespace)
	errs := wrappers.Errs{}
	errs.Add(
		registerer.Register(m.numTxRefreshes),
		registerer.Register(m.numTxRefreshHits),
		registerer.Register(m.numTxRefreshMisses),

		m.apiRequestMetric.Register(registerer),
	)
	return errs.Err
}
<commit_msg>removed unused fn newCallsMetric, formatting<commit_after>// (c) 2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
	"github.com/ava-labs/avalanchego/utils/metricutils"
	"github.com/ava-labs/avalanchego/utils/wrappers"
	"github.com/prometheus/client_golang/prometheus"
)

type metrics struct {
	numTxRefreshes, numTxRefreshHits, numTxRefreshMisses prometheus.Counter

	apiRequestMetric metricutils.APIRequestMetrics
}

func (m *metrics) Initialize(
	namespace string,
	registerer prometheus.Registerer,
) error {
	m.numTxRefreshes = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refreshes",
		Help:      "Number of times unique txs have been refreshed",
	})
	m.numTxRefreshHits = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_hits",
		Help:      "Number of times unique txs have not been unique, but were cached",
	})
	m.numTxRefreshMisses = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "tx_refresh_misses",
		Help:      "Number of times unique txs have not been unique and weren't cached",
	})

	m.apiRequestMetric = metricutils.NewAPIMetrics(namespace)
	errs := wrappers.Errs{}
	errs.Add(
		registerer.Register(m.numTxRefreshes),
		registerer.Register(m.numTxRefreshHits),
		registerer.Register(m.numTxRefreshMisses),

		m.apiRequestMetric.Register(registerer),
	)
	return errs.Err
}
<|endoftext|>


<commit_before>package goesl

import (
	"bufio"
	"fmt"
	"net/textproto"
)

// Message -
type Message struct {
	Header map[string]string
	Body   string

	r  *bufio.Reader
	tr *textproto.Reader
}

// String - Will return message representation as string
func (m *Message) String() string {
	return fmt.Sprintf("%s body=%s", m.Header, m.Body)
}

// GetHeader - Will return event header value, or "" if the key is not set.
func (m *Message) GetHeader(key string) string {
	return m.Header[key]
}

func newMessage(r *bufio.Reader) (*Message, error) {

	msg := Message{
		r:  r,
		tr: textproto.NewReader(r),
	}

	msg.

	return &msg, nil
}
<commit_msg>Fixing message bug<commit_after>package goesl

import (
	"bufio"
	"fmt"
	"net/textproto"
)

// Message -
type Message struct {
	Header map[string]string
	Body   string

	r  *bufio.Reader
	tr *textproto.Reader
}

// String - Will return message representation as string
func (m *Message) String() string {
	return fmt.Sprintf("%s body=%s", m.Header, m.Body)
}

// GetHeader - Will return event header value, or "" if the key is not set.
func (m *Message) GetHeader(key string) string {
	return m.Header[key]
}

func newMessage(r *bufio.Reader) (*Message, error) {

	msg := Message{
		r:  r,
		tr: textproto.NewReader(r),
	}

	return &msg, nil
}
<|endoftext|>


<commit_before>package cli

import (
	"testing"

	"github.com/libopenstorage/openstorage/api"
	"github.com/stretchr/testify/require"
)

func TestCmdMarshalProto(t *testing.T) {
	volumeSpec := &api.VolumeSpec{
		Size:   64,
		Format: api.FSType_FS_TYPE_EXT4,
	}
	data := cmdMarshalProto(volumeSpec, false)
	require.Equal(
		t,
		`{
 "ephemeral": false,
 "size": "64",
 "format": "ext4",
 "block_size": "0",
 "ha_level": "0",
 "cos": 0,
 "dedupe": false,
 "snapshot_interval": 0,
 "shared": false,
 "aggregation_level": 0,
 "encrypted": false,
 "passphrase": "",
 "snapshot_schedule": ""
}`,
		data,
	)
}
<commit_msg>Fix build<commit_after>package cli

import (
	"testing"

	"github.com/libopenstorage/openstorage/api"
	"github.com/stretchr/testify/require"
)

func TestCmdMarshalProto(t *testing.T) {
	volumeSpec := &api.VolumeSpec{
		Size:   64,
		Format: api.FSType_FS_TYPE_EXT4,
	}
	data := cmdMarshalProto(volumeSpec, false)
	require.Equal(
		t,
		`{
 "ephemeral": false,
 "size": "64",
 "format": "ext4",
 "block_size": "0",
 "ha_level": "0",
 "cos": "none",
 "dedupe": false,
 "snapshot_interval": 0,
 "shared": false,
 "aggregation_level": 0,
 "encrypted": false,
 "passphrase": "",
 "snapshot_schedule": ""
}`,
		data,
	)
}
<|endoftext|>


<commit_before>package cli

import (
	"testing"
	"fmt"
)

func TestCmdexec(t *testing.T) {
	type args struct {
		cmd    string
		system string
	}
	tests := []struct {
		name  string
		args  args
		want  bool
		want1 string
		want2 string
	}{
		{
			name: "git status",
			args: args{
				cmd: "git status",
			},
			want:  true,
			want1: "exit status 0",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, got1, got2 := CmdExec(tt.args.cmd, tt.args.system)
			if got != tt.want {
				t.Errorf("CmdExec() got = %v, want %v", got, tt.want)
			}
			if got1 != tt.want1 {
				t.Errorf("CmdExec() got1 = %v, want %v", got1, tt.want1)
			}
			fmt.Printf("Success %v\nProcess Status: %v\nOut: %v", got, got1, got2)
			//if got2 != tt.want2 {
			//	t.Errorf("CmdExec() got2 = %v, want %v", got2, tt.want2)
			//}
		})
	}
}
<commit_msg>update test name<commit_after>package cli

import (
	"testing"
	"fmt"
)

func TestCmdExec(t *testing.T) {
	type args struct {
		cmd    string
		system string
	}
	tests := []struct {
		name  string
		args  args
		want  bool
		want1 string
		want2 string
	}{
		{
			name: "git status",
			args: args{
				cmd: "git status",
			},
			want:  true,
			want1: "exit status 0",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, got1, got2 := CmdExec(tt.args.cmd, tt.args.system)
			if got != tt.want {
				t.Errorf("CmdExec() got = %v, want %v", got, tt.want)
			}
			if got1 != tt.want1 {
				t.Errorf("CmdExec() got1 = %v, want %v", got1, tt.want1)
			}
			fmt.Printf("Success %v\nProcess Status: %v\nOut: %v", got, got1, got2)
			//if got2 != tt.want2 {
			//	t.Errorf("CmdExec() got2 = %v, want %v", got2, tt.want2)
			//}
		})
	}
}
<|endoftext|>


<commit_before>package erasablekv

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	"github.com/keybase/client/go/libkb"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/net/context"
)

type boxedData struct {
	V int
	N [libkb.NaclDHNonceSize]byte
	E []byte
}

// ***
// If we change this, make sure to update the key derivation reason for all callers of ErasableKVStore!
// ***
const cryptoVersion = 1
const noiseSuffix = ".ns"
const storageSubDir = "eraseablekvstore"

func getStorageDir(g *libkb.GlobalContext, subDir string) string {
	return filepath.Join(g.Env.GetDataDir(), storageSubDir, subDir)
}

type ErasableKVStore interface {
	Put(ctx context.Context, key string, val interface{}) error
	Get(ctx context.Context, key string, val interface{}) error
	Erase(ctx context.Context, key string) error
	AllKeys(ctx context.Context) ([]string, error)
}

// File based erasable kv store. Thread safe.
// We encrypt all data stored here with a mix of the device long term key and a
// large random noise file. We use the random noise file to make it more
// difficult to recover the encrypted data once the noise file is wiped from
// the filesystem as is done for the secret_store_file.
type FileErasableKVStore struct {
	libkb.Contextified
	sync.Mutex
	storageDir string
}

var _ ErasableKVStore = (*FileErasableKVStore)(nil)

func NewFileErasableKVStore(g *libkb.GlobalContext, subDir string) *FileErasableKVStore {
	return &FileErasableKVStore{
		Contextified: libkb.NewContextified(g),
		storageDir:   getStorageDir(g, subDir),
	}
}

func (s *FileErasableKVStore) filepath(key string) string {
	return filepath.Join(s.storageDir, url.QueryEscape(key))
}

func (s *FileErasableKVStore) noiseKey(key string) string {
	return fmt.Sprintf("%s%s", url.QueryEscape(key), noiseSuffix)
}

func (s *FileErasableKVStore) getEncryptionKey(ctx context.Context, noiseBytes libkb.NoiseBytes) (fkey [32]byte, err error) {
	enckey, err := getLocalStorageSecretBoxKey(ctx, s.G())
	if err != nil {
		return fkey, err
	}

	xor, err := libkb.NoiseXOR(enckey, noiseBytes)
	if err != nil {
		return fkey, err
	}
	copy(fkey[:], xor)
	return fkey, nil
}

func (s *FileErasableKVStore) unbox(ctx context.Context, data []byte, noiseBytes libkb.NoiseBytes, val interface{}) (err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#unbox", func() error { return err })()
	// Decode encrypted box
	var boxed boxedData
	if err := libkb.MPackDecode(data, &boxed); err != nil {
		return err
	}
	if boxed.V > cryptoVersion {
		return fmt.Errorf("unexpected crypto version: %d current: %d", boxed.V,
			cryptoVersion)
	}
	enckey, err := s.getEncryptionKey(ctx, noiseBytes)
	if err != nil {
		return err
	}
	pt, ok := secretbox.Open(nil, boxed.E, &boxed.N, &enckey)
	if !ok {
		return fmt.Errorf("failed to unbox item")
	}

	return libkb.MPackDecode(pt, val)
}

func (s *FileErasableKVStore) box(ctx context.Context, val interface{}, noiseBytes libkb.NoiseBytes) (data []byte, err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#box", func() error { return err })()
	data, err = libkb.MPackEncode(val)
	if err != nil {
		return data, err
	}

	enckey, err := s.getEncryptionKey(ctx, noiseBytes)
	if err != nil {
		return data, err
	}
	var nonce []byte
	nonce, err = libkb.RandBytes(libkb.NaclDHNonceSize)
	if err != nil {
		return data, err
	}
	var fnonce [libkb.NaclDHNonceSize]byte
	copy(fnonce[:], nonce)
	sealed := secretbox.Seal(nil, data, &fnonce, &enckey)
	boxed := boxedData{
		V: cryptoVersion,
		E: sealed,
		N: fnonce,
	}

	// Encode encrypted box
	return libkb.MPackEncode(boxed)
}

func (s *FileErasableKVStore) Put(ctx context.Context, key string, val interface{}) (err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#Put", func() error { return err })()
	s.Lock()
	defer s.Unlock()

	noiseBytes, err := libkb.MakeNoise()
	data, err := s.box(ctx, val, noiseBytes)
	if err != nil {
		return err
	}
	err = s.write(ctx, key, data)
	if err != nil {
		return err
	}
	noiseKey := s.noiseKey(key)
	return s.write(ctx, noiseKey, noiseBytes[:])
}

func (s *FileErasableKVStore) write(ctx context.Context, key string, data []byte) (err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#write", func() error { return err })()
	filepath := s.filepath(key)
	if err := libkb.MakeParentDirs(s.G().Log, filepath); err != nil {
		return err
	}

	tmp, err := ioutil.TempFile(s.storageDir, key)
	if err != nil {
		return err
	}
	// remove the temp file if it still exists at the end of this function
	defer libkb.ShredFile(tmp.Name())

	if SetDisableBackup(ctx, s.G(), tmp.Name()); err != nil {
		return err
	}

	if runtime.GOOS != "windows" {
		// os.Fchmod not supported on windows
		if err := tmp.Chmod(libkb.PermFile); err != nil {
			return err
		}
	}
	if _, err := tmp.Write(data); err != nil {
		return err
	}
	if err := tmp.Close(); err != nil {
		return err
	}

	// NOTE: Pre-existing maybe-bug: I think this step breaks atomicity. It's
	// possible that the rename below fails, in which case we'll have already
	// destroyed the previous value.

	// On Unix we could solve this by hard linking the old file to a new tmp
	// location, and then shredding it after the rename. On Windows, I think
	// we'd need to somehow call the ReplaceFile Win32 function (which Go
	// doesn't expose anywhere as far as I know, so this would require CGO) to
	// take advantage of its lpBackupFileName param.
	s.erase(key)

	if err := os.Rename(tmp.Name(), filepath); err != nil {
		return err
	}
	if SetDisableBackup(ctx, s.G(), filepath); err != nil {
		return err
	}

	if runtime.GOOS != "windows" {
		// os.Fchmod not supported on windows
		if err := os.Chmod(filepath, libkb.PermFile); err != nil {
			return err
		}
	}
	return nil
}

func (s *FileErasableKVStore) Get(ctx context.Context, key string, val interface{}) (err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#Get", func() error { return err })()
	s.Lock()
	defer s.Unlock()
	return s.get(ctx, key, val)
}

func (s *FileErasableKVStore) get(ctx context.Context, key string, val interface{}) (err error) {
	noiseKey := s.noiseKey(key)
	noise, err := s.read(ctx, noiseKey)
	if err != nil {
		return err
	}
	var noiseBytes libkb.NoiseBytes
	copy(noiseBytes[:], noise)

	data, err := s.read(ctx, key)
	if err != nil {
		return err
	}

	return s.unbox(ctx, data, noiseBytes, val)
}

func (s *FileErasableKVStore) read(ctx context.Context, key string) (data []byte, err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#read", func() error { return err })()
	filepath := s.filepath(key)
	return ioutil.ReadFile(filepath)
}

func (s *FileErasableKVStore) Erase(ctx context.Context, key string) (err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#Erase", func() error { return err })()
	s.Lock()
	defer s.Unlock()
	noiseKey := s.noiseKey(key)
	epick := libkb.FirstErrorPicker{}
	epick.Push(s.erase(noiseKey))
	epick.Push(s.erase(key))
	return epick.Error()
}

func (s *FileErasableKVStore) erase(key string) error {
	filepath := s.filepath(key)
	exists, err := libkb.FileExists(filepath)
	if err != nil {
		return err
	}
	if exists {
		err = libkb.ShredFile(filepath)
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *FileErasableKVStore) AllKeys(ctx context.Context) (keys []string, err error) {
	defer s.G().CTrace(ctx, "FileErasableKVStore#AllKeys", func() error { return err })()
	s.Lock()
	defer s.Unlock()
	if err := os.MkdirAll(s.storageDir, libkb.PermDir); err != nil {
		return keys, err
	}
	files, err := ioutil.ReadDir(s.storageDir)
	if err != nil {
		return keys, err
	}
	for _, file := range files {
		filename := filepath.Base(file.Name())
		if strings.HasSuffix(filename, noiseSuffix) {
			continue
		}
		key, err := url.QueryUnescape(filename)
		if err != nil {
			return []string{}, err
		}
		keys = append(keys, key)
	}
	return keys, nil
}

func getLocalStorageSecretBoxKey(ctx context.Context, g *libkb.GlobalContext) (fkey [32]byte, err error) {
	// Get secret device key
	encKey, err := g.ActiveDevice.EncryptionKey()
	if err != nil {
		return fkey, err
	}
	kp, ok := encKey.(libkb.NaclDHKeyPair)
	if !ok || kp.Private == nil {
		return fkey, libkb.KeyCannotDecryptError{}
	}

	// Derive symmetric key from device key
	skey, err := encKey.SecretSymmetricKey(libkb.EncryptionReasonErasableKVLocalStorage)
	if err != nil {
		return fkey, err
	}

	copy(fkey[:], skey[:])
	return fkey, nil
}
<commit_msg>Add timed trace to eraseablekvstore (#12192)<commit_after>package erasablekv

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	"github.com/keybase/client/go/libkb"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/net/context"
)

type boxedData struct {
	V int
	N [libkb.NaclDHNonceSize]byte
	E []byte
}

// ***
// If we change this, make sure to update the key derivation reason for all callers of ErasableKVStore!
// ***
const cryptoVersion = 1
const noiseSuffix = ".ns"
const storageSubDir = "eraseablekvstore"

func getStorageDir(g *libkb.GlobalContext, subDir string) string {
	return filepath.Join(g.Env.GetDataDir(), storageSubDir, subDir)
}

type ErasableKVStore interface {
	Put(ctx context.Context, key string, val interface{}) error
	Get(ctx context.Context, key string, val interface{}) error
	Erase(ctx context.Context, key string) error
	AllKeys(ctx context.Context) ([]string, error)
}

// File based erasable kv store. Thread safe.
// We encrypt all data stored here with a mix of the device long term key and a
// large random noise file. We use the random noise file to make it more
// difficult to recover the encrypted data once the noise file is wiped from
// the filesystem as is done for the secret_store_file.
type FileErasableKVStore struct {
	libkb.Contextified
	sync.Mutex
	storageDir string
}

var _ ErasableKVStore = (*FileErasableKVStore)(nil)

func NewFileErasableKVStore(g *libkb.GlobalContext, subDir string) *FileErasableKVStore {
	return &FileErasableKVStore{
		Contextified: libkb.NewContextified(g),
		storageDir:   getStorageDir(g, subDir),
	}
}

func (s *FileErasableKVStore) filepath(key string) string {
	return filepath.Join(s.storageDir, url.QueryEscape(key))
}

func (s *FileErasableKVStore) noiseKey(key string) string {
	return fmt.Sprintf("%s%s", url.QueryEscape(key), noiseSuffix)
}

func (s *FileErasableKVStore) getEncryptionKey(ctx context.Context, noiseBytes libkb.NoiseBytes) (fkey [32]byte, err error) {
	enckey, err := getLocalStorageSecretBoxKey(ctx, s.G())
	if err != nil {
		return fkey, err
	}

	xor, err := libkb.NoiseXOR(enckey, noiseBytes)
	if err != nil {
		return fkey, err
	}
	copy(fkey[:], xor)
	return fkey, nil
}

func (s *FileErasableKVStore) unbox(ctx context.Context, data []byte, noiseBytes libkb.NoiseBytes, val interface{}) (err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#unbox", func() error { return err })()
	// Decode encrypted box
	var boxed boxedData
	if err := libkb.MPackDecode(data, &boxed); err != nil {
		return err
	}
	if boxed.V > cryptoVersion {
		return fmt.Errorf("unexpected crypto version: %d current: %d", boxed.V,
			cryptoVersion)
	}
	enckey, err := s.getEncryptionKey(ctx, noiseBytes)
	if err != nil {
		return err
	}
	pt, ok := secretbox.Open(nil, boxed.E, &boxed.N, &enckey)
	if !ok {
		return fmt.Errorf("failed to unbox item")
	}

	return libkb.MPackDecode(pt, val)
}

func (s *FileErasableKVStore) box(ctx context.Context, val interface{}, noiseBytes libkb.NoiseBytes) (data []byte, err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#box", func() error { return err })()
	data, err = libkb.MPackEncode(val)
	if err != nil {
		return data, err
	}

	enckey, err := s.getEncryptionKey(ctx, noiseBytes)
	if err != nil {
		return data, err
	}
	var nonce []byte
	nonce, err = libkb.RandBytes(libkb.NaclDHNonceSize)
	if err != nil {
		return data, err
	}
	var fnonce [libkb.NaclDHNonceSize]byte
	copy(fnonce[:], nonce)
	sealed := secretbox.Seal(nil, data, &fnonce, &enckey)
	boxed := boxedData{
		V: cryptoVersion,
		E: sealed,
		N: fnonce,
	}

	// Encode encrypted box
	return libkb.MPackEncode(boxed)
}

func (s *FileErasableKVStore) Put(ctx context.Context, key string, val interface{}) (err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#Put", func() error { return err })()
	s.Lock()
	defer s.Unlock()

	noiseBytes, err := libkb.MakeNoise()
	data, err := s.box(ctx, val, noiseBytes)
	if err != nil {
		return err
	}
	err = s.write(ctx, key, data)
	if err != nil {
		return err
	}
	noiseKey := s.noiseKey(key)
	return s.write(ctx, noiseKey, noiseBytes[:])
}

func (s *FileErasableKVStore) write(ctx context.Context, key string, data []byte) (err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#write", func() error { return err })()
	filepath := s.filepath(key)
	if err := libkb.MakeParentDirs(s.G().Log, filepath); err != nil {
		return err
	}

	tmp, err := ioutil.TempFile(s.storageDir, key)
	if err != nil {
		return err
	}
	// remove the temp file if it still exists at the end of this function
	defer libkb.ShredFile(tmp.Name())

	if SetDisableBackup(ctx, s.G(), tmp.Name()); err != nil {
		return err
	}

	if runtime.GOOS != "windows" {
		// os.Fchmod not supported on windows
		if err := tmp.Chmod(libkb.PermFile); err != nil {
			return err
		}
	}
	if _, err := tmp.Write(data); err != nil {
		return err
	}
	if err := tmp.Close(); err != nil {
		return err
	}

	// NOTE: Pre-existing maybe-bug: I think this step breaks atomicity. It's
	// possible that the rename below fails, in which case we'll have already
	// destroyed the previous value.

	// On Unix we could solve this by hard linking the old file to a new tmp
	// location, and then shredding it after the rename. On Windows, I think
	// we'd need to somehow call the ReplaceFile Win32 function (which Go
	// doesn't expose anywhere as far as I know, so this would require CGO) to
	// take advantage of its lpBackupFileName param.
	s.erase(key)

	if err := os.Rename(tmp.Name(), filepath); err != nil {
		return err
	}
	if SetDisableBackup(ctx, s.G(), filepath); err != nil {
		return err
	}

	if runtime.GOOS != "windows" {
		// os.Fchmod not supported on windows
		if err := os.Chmod(filepath, libkb.PermFile); err != nil {
			return err
		}
	}
	return nil
}

func (s *FileErasableKVStore) Get(ctx context.Context, key string, val interface{}) (err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#Get", func() error { return err })()
	s.Lock()
	defer s.Unlock()
	return s.get(ctx, key, val)
}

func (s *FileErasableKVStore) get(ctx context.Context, key string, val interface{}) (err error) {
	noiseKey := s.noiseKey(key)
	noise, err := s.read(ctx, noiseKey)
	if err != nil {
		return err
	}
	var noiseBytes libkb.NoiseBytes
	copy(noiseBytes[:], noise)

	data, err := s.read(ctx, key)
	if err != nil {
		return err
	}

	return s.unbox(ctx, data, noiseBytes, val)
}

func (s *FileErasableKVStore) read(ctx context.Context, key string) (data []byte, err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#read", func() error { return err })()
	filepath := s.filepath(key)
	return ioutil.ReadFile(filepath)
}

func (s *FileErasableKVStore) Erase(ctx context.Context, key string) (err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#Erase", func() error { return err })()
	s.Lock()
	defer s.Unlock()
	noiseKey := s.noiseKey(key)
	epick := libkb.FirstErrorPicker{}
	epick.Push(s.erase(noiseKey))
	epick.Push(s.erase(key))
	return epick.Error()
}

func (s *FileErasableKVStore) erase(key string) error {
	filepath := s.filepath(key)
	exists, err := libkb.FileExists(filepath)
	if err != nil {
		return err
	}
	if exists {
		err = libkb.ShredFile(filepath)
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *FileErasableKVStore) AllKeys(ctx context.Context) (keys []string, err error) {
	defer s.G().CTraceTimed(ctx, "FileErasableKVStore#AllKeys", func() error { return err })()
	s.Lock()
	defer s.Unlock()
	if err := os.MkdirAll(s.storageDir, libkb.PermDir); err != nil {
		return keys, err
	}
	files, err := ioutil.ReadDir(s.storageDir)
	if err != nil {
		return keys, err
	}
	for _, file := range files {
		filename := filepath.Base(file.Name())
		if strings.HasSuffix(filename, noiseSuffix) {
			continue
		}
		key, err := url.QueryUnescape(filename)
		if err != nil {
			return []string{}, err
		}
		keys = append(keys, key)
	}
	return keys, nil
}

func getLocalStorageSecretBoxKey(ctx context.Context, g *libkb.GlobalContext) (fkey [32]byte, err error) {
	// Get secret device key
	encKey, err := g.ActiveDevice.EncryptionKey()
	if err != nil {
		return fkey, err
	}
	kp, ok := encKey.(libkb.NaclDHKeyPair)
	if !ok || kp.Private == nil {
		return fkey, libkb.KeyCannotDecryptError{}
	}

	// Derive symmetric key from device key
	skey, err := encKey.SecretSymmetricKey(libkb.EncryptionReasonErasableKVLocalStorage)
	if err != nil {
		return fkey, err
	}

	copy(fkey[:], skey[:])
	return fkey, nil
}
<|endoftext|>


<commit_before>package dnode

import (
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"sync"
)

type DNode struct {
	SendChan     chan []byte
	Closed       bool
	OnRemote     func(remote Remote)
	OnReady      func()
	OnRootMethod func(method string, args []interface{})
	closeMutex   sync.Mutex
	callbacks    []reflect.Value
}

type message struct {
	Method    interface{}           `json:"method"`
	Arguments []interface{}         `json:"arguments"`
	Links     []string              `json:"links"`
	Callbacks map[string]([]string) `json:"callbacks"`
}

type Remote map[string]interface{}

type Callback func(args ...interface{})

func New() *DNode {
	d := DNode{
		make(chan []byte),
		false,
		nil, nil, nil,
		sync.Mutex{},
		make([]reflect.Value, 0),
	}
	return &d
}

func (d *DNode) SendRemote(object interface{}) {
	d.Send("methods", []interface{}{object})
}

func (d *DNode) Send(method interface{}, arguments []interface{}) {
	message := message{
		method,
		arguments,
		[]string{},
		make(map[string]([]string)),
	}
	d.collectCallbacks(arguments, make([]string, 0), message.Callbacks)
	data, err := json.Marshal(message)
	if err != nil {
		panic(err)
	}

	d.closeMutex.Lock()
	defer d.closeMutex.Unlock()
	if !d.Closed {
		d.SendChan <- data
	}
}

func (d *DNode) Close() {
	d.closeMutex.Lock()
	defer d.closeMutex.Unlock()
	d.Closed = true
	close(d.SendChan)
}

func (d *DNode) collectCallbacks(rawObj interface{}, path []string, callbackMap map[string]([]string)) {
	switch obj := rawObj.(type) {
	case nil:
		// skip
	case []interface{}:
		for i, v := range obj {
			d.collectCallbacks(v, append(path, strconv.Itoa(i)), callbackMap)
		}
	case map[string]interface{}:
		for key, value := range obj {
			v := reflect.ValueOf(value)
			if v.Kind() == reflect.Func {
				d.registerCallback(key, v, path, callbackMap)
				delete(obj, key)
			}
		}
	default:
		v := reflect.ValueOf(obj)
		for i := 0; i < v.NumMethod(); i++ {
			name := v.Type().Method(i).Name
			name = strings.ToLower(name[0:1]) + name[1:]
			d.registerCallback(name, v.Method(i), path, callbackMap)
		}
	}
}

func (d *DNode) registerCallback(name string, callback reflect.Value, path []string, callbackMap map[string]([]string)) {
	pathCopy := make([]string, len(path)+1)
	copy(pathCopy, path)
	pathCopy[len(path)] = name

	callbackMap[strconv.Itoa(len(d.callbacks))] = pathCopy
	d.callbacks = append(d.callbacks, callback)
}

func (d *DNode) ProcessMessage(data []byte) {
	var m message
	err := json.Unmarshal(data, &m)
	if err != nil {
		panic(err)
	}

	for id, path := range m.Callbacks {
		methodId, err := strconv.Atoi(id)
		if err != nil {
			panic(err)
		}
		callback := Callback(func(args ...interface{}) {
			d.Send(methodId, args)
		})

		var rawObj interface{} = m.Arguments
		for i := 0; i < len(path); i++ {
			isLast := i == len(path)-1
			switch obj := rawObj.(type) {
			case []interface{}:
				index, err := strconv.Atoi(path[i])
				if err != nil {
					panic(fmt.Sprintf("Integer expected, got %v.", path[i]))
				}
				if isLast {
					obj[index] = callback
				} else {
					rawObj = obj[index]
				}
			case map[string]interface{}:
				if isLast {
					obj[path[i]] = callback
				} else {
					rawObj = obj[path[i]]
				}
			default:
				panic(fmt.Sprintf("Unhandled object type %T of %v.", obj, obj))
			}
		}
	}

	index, err := strconv.Atoi(fmt.Sprint(m.Method))
	if err == nil {
		args := make([]reflect.Value, len(m.Arguments))
		for i, v := range m.Arguments {
			args[i] = reflect.ValueOf(v)
		}
		d.callbacks[index].Call(args)
	} else if m.Method == "methods" {
		remote := m.Arguments[0].(map[string]interface{})
		if d.OnRemote != nil {
			d.OnRemote(remote)
		}
		if d.OnReady != nil {
			d.OnReady()
		}
	} else if d.OnRootMethod != nil {
		d.OnRootMethod(fmt.Sprint(m.Method), m.Arguments)
	} else {
		panic(fmt.Sprintf("Unknown method: %v.", m.Method))
	}
}
<commit_msg>go dnode: Only encode exported methods.<commit_after>package dnode

import (
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"sync"
)

type DNode struct {
	SendChan     chan []byte
	Closed       bool
	OnRemote     func(remote Remote)
	OnReady      func()
	OnRootMethod func(method string, args []interface{})
	closeMutex   sync.Mutex
	callbacks    []reflect.Value
}

type message struct {
	Method    interface{}           `json:"method"`
	Arguments []interface{}         `json:"arguments"`
	Links     []string              `json:"links"`
	Callbacks map[string]([]string) `json:"callbacks"`
}

type Remote map[string]interface{}

type Callback func(args ...interface{})

func New() *DNode {
	d := DNode{
		make(chan []byte),
		false,
		nil, nil, nil,
		sync.Mutex{},
		make([]reflect.Value, 0),
	}
	return &d
}

func (d *DNode) SendRemote(object interface{}) {
	d.Send("methods", []interface{}{object})
}

func (d *DNode) Send(method interface{}, arguments []interface{}) {
	message := message{
		method,
		arguments,
		[]string{},
		make(map[string]([]string)),
	}
	d.collectCallbacks(arguments, make([]string, 0), message.Callbacks)
	data, err := json.Marshal(message)
	if err != nil {
		panic(err)
	}

	d.closeMutex.Lock()
	defer d.closeMutex.Unlock()
	if !d.Closed {
		d.SendChan <- data
	}
}

func (d *DNode) Close() {
	d.closeMutex.Lock()
	defer d.closeMutex.Unlock()
	d.Closed = true
	close(d.SendChan)
}

func (d *DNode) collectCallbacks(rawObj interface{}, path []string, callbackMap map[string]([]string)) {
	switch obj := rawObj.(type) {
	case nil:
		// skip
	case []interface{}:
		for i, v := range obj {
			d.collectCallbacks(v, append(path, strconv.Itoa(i)), callbackMap)
		}
	case map[string]interface{}:
		for key, value := range obj {
			v := reflect.ValueOf(value)
			if v.Kind() == reflect.Func {
				d.registerCallback(key, v, path, callbackMap)
				delete(obj, key)
			}
		}
	default:
		v := reflect.ValueOf(obj)
		for i := 0; i < v.NumMethod(); i++ {
			if v.Type().Method(i).PkgPath == "" { // exported
				name := v.Type().Method(i).Name
				name = strings.ToLower(name[0:1]) + name[1:]
				d.registerCallback(name, v.Method(i), path, callbackMap)
			}
		}
	}
}

func (d *DNode) registerCallback(name string, callback reflect.Value, path []string, callbackMap map[string]([]string)) {
	pathCopy := make([]string, len(path)+1)
	copy(pathCopy, path)
	pathCopy[len(path)] = name

	callbackMap[strconv.Itoa(len(d.callbacks))] = pathCopy
	d.callbacks = append(d.callbacks, callback)
}

func (d *DNode) ProcessMessage(data []byte) {
	var m message
	err := json.Unmarshal(data, &m)
	if err != nil {
		panic(err)
	}

	for id, path := range m.Callbacks {
		methodId, err := strconv.Atoi(id)
		if err != nil {
			panic(err)
		}
		callback := Callback(func(args ...interface{}) {
			d.Send(methodId, args)
		})

		var rawObj interface{} = m.Arguments
		for i := 0; i < len(path); i++ {
			isLast := i == len(path)-1
			switch obj := rawObj.(type) {
			case []interface{}:
				index, err := strconv.Atoi(path[i])
				if err != nil {
					panic(fmt.Sprintf("Integer expected, got %v.", path[i]))
				}
				if isLast {
					obj[index] = callback
				} else {
					rawObj = obj[index]
				}
			case map[string]interface{}:
				if isLast {
					obj[path[i]] = callback
				} else {
					rawObj = obj[path[i]]
				}
			default:
				panic(fmt.Sprintf("Unhandled object type %T of %v.", obj, obj))
			}
		}
	}

	index, err := strconv.Atoi(fmt.Sprint(m.Method))
	if err == nil {
		args := make([]reflect.Value, len(m.Arguments))
		for i, v := range m.Arguments {
			args[i] = reflect.ValueOf(v)
		}
		d.callbacks[index].Call(args)
	} else if m.Method == "methods" {
		remote := m.Arguments[0].(map[string]interface{})
		if d.OnRemote != nil {
			d.OnRemote(remote)
		}
		if d.OnReady != nil {
			d.OnReady()
		}
	} else if d.OnRootMethod != nil {
		d.OnRootMethod(fmt.Sprint(m.Method), m.Arguments)
	} else {
		panic(fmt.Sprintf("Unknown method: %v.", m.Method))
	}
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

type Channel struct {
	// unique identifier of the channel
	Id int64 `json:"id"`

	// Name of the channel
	Name string `json:"name"                         sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Creator of the channel
	CreatorId int64 `json:"creatorId"                sql:"NOT NULL"`

	// Name of the group which channel is belong to
	GroupName string `json:"groupName"               sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Purpose of the channel
	Purpose string `json:"purpose"`

	// Secret key of the channel for event propagation purposes
	// we can put this key into another table?
	SecretKey string `json:"secretKey"`

	// Type of the channel
	TypeConstant string `json:"typeConstant"         sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Privacy constant of the channel
	PrivacyConstant string `json:"privacyConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation date of the channel
	CreatedAt time.Time `json:"createdAt"            sql:"NOT NULL"`

	// Modification date of the channel
	UpdatedAt time.Time `json:"updatedAt"            sql:"NOT NULL"`
}

// to-do check for allowed channels
const (
	// TYPES
	Channel_TYPE_GROUP           = "group"
	Channel_TYPE_TOPIC           = "topic"
	Channel_TYPE_FOLLOWINGFEED   = "followingfeed"
	Channel_TYPE_FOLLOWERS       = "followers"
	Channel_TYPE_CHAT            = "chat"
	Channel_TYPE_PINNED_ACTIVITY = "pinnedActivity"
	// Privacy
	Channel_TYPE_PUBLIC  = "public"
	Channel_TYPE_PRIVATE = "private"
	// Koding Group Name
	Channel_KODING_NAME = "koding"
)

func NewChannel() *Channel {
	return &Channel{
		Name:            "koding",
		CreatorId:       123,
		GroupName:       Channel_KODING_NAME,
		Purpose:         "string",
		SecretKey:       "string",
		TypeConstant:    "default",
		PrivacyConstant: Channel_TYPE_PRIVATE,
	}
}

func (c *Channel) BeforeCreate() {
	c.CreatedAt = time.Now()
	c.UpdatedAt = time.Now()
}

func (c *Channel) BeforeUpdate() {
	c.UpdatedAt = time.Now()
}

func (c *Channel) GetId() int64 {
	return c.Id
}

func (c Channel) TableName() string {
	return "api.channel"
}

func (c *Channel) Fetch() error {
	return bongo.B.Fetch(c)
}

func (c *Channel) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *Channel) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c *Channel) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c *Channel) Update() error {
	if c.Name == "" || c.GroupName == "" {
		return fmt.Errorf("Validation failed %s - %s", c.Name, c.GroupName)
	}

	return bongo.B.Update(c)
}

func (c *Channel) Create() error {
	if c.Name == "" || c.GroupName == "" || c.TypeConstant == "" {
		return fmt.Errorf("Validation failed %s - %s", c.Name, c.GroupName)
	}

	// golang returns -1 if item not in the string
	if strings.Index(c.Name, " ") > -1 {
		return fmt.Errorf("Channel name %q has empty space in it", c.Name)
	}

	if c.TypeConstant == Channel_TYPE_GROUP /* we can add more types here */ {
		selector := map[string]interface{}{
			"group_name":    c.GroupName,
			"type_constant": c.TypeConstant,
		}

		// if err is nil
		// it means we already have that channel
		err := c.One(bongo.NewQS(selector))
		if err == nil {
			return nil
			// return fmt.Errorf("%s typed channel is already created before for %s group", c.TypeConstant, c.GroupName)
		}

		if err != gorm.RecordNotFound {
			return err
		}

	}

	return bongo.B.Create(c)
}

func (c *Channel) Delete() error {
	return bongo.B.Delete(c)
}

func (c *Channel) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *Channel) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func (c *Channel) FetchByIds(ids []int64) ([]Channel, error) {
	var channels []Channel

	if len(ids) == 0 {
		return channels, nil
	}

	if err := bongo.B.FetchByIds(c, &channels, ids); err != nil {
		return nil, err
	}
	return channels, nil
}

func (c *Channel) AddParticipant(participantId int64) (*ChannelParticipant, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	if err != nil && err != gorm.RecordNotFound {
		return nil, err
	}

	// if we have this record in DB
	if cp.Id != 0 {
		// if status is not active
		if cp.StatusConstant == ChannelParticipant_STATUS_ACTIVE {
			return nil, errors.New(fmt.Sprintf("Account %d is already a participant of channel %d", cp.AccountId, cp.ChannelId))
		}
		cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE
		if err := cp.Update(); err != nil {
			return nil, err
		}
		return cp, nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE

	if err := cp.Create(); err != nil {
		return nil, err
	}

	return cp, nil
}

func (c *Channel) RemoveParticipant(participantId int64) error {
	if c.Id == 0 {
		return errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	// if user is not in this channel, do nothing
	if err == gorm.RecordNotFound {
		return nil
	}

	if err != nil {
		return err
	}

	if cp.StatusConstant == ChannelParticipant_STATUS_LEFT {
		return nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_LEFT
	if err := cp.Update(); err != nil {
		return err
	}

	return nil
}

func (c *Channel) FetchParticipantIds() ([]int64, error) {
	var participantIds []int64

	if c.Id == 0 {
		return participantIds, errors.New("Channel Id is not set")
	}

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id":      c.Id,
			"status_constant": ChannelParticipant_STATUS_ACTIVE,
		},
		Pluck: "account_id",
	}

	cp := NewChannelParticipant()
	err := cp.Some(&participantIds, query)
	if err != nil {
		return nil, err
	}

	return participantIds, nil
}

func (c *Channel) AddMessage(messageId int64) (*ChannelMessageList, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()

	selector := map[string]interface{}{
		"channel_id": c.Id,
		"message_id": messageId,
	}
	err := cml.One(bongo.NewQS(selector))
	if err == nil {
		return nil, errors.New("Message is already in the channel")
	}

	if err != gorm.RecordNotFound {
		return nil, err
	}
	// silence record not found err

	cml.ChannelId = c.Id
	cml.MessageId = messageId

	if err := cml.Create(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) RemoveMessage(messageId int64) (*ChannelMessageList, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()
	selector := map[string]interface{}{
		"channel_id": c.Id,
		"message_id": messageId,
	}
	err := cml.One(bongo.NewQS(selector))
	// one returns error when record not found case
	// but we dont care if it is not there tho
	if err != nil {
		return nil, err
	}

	if err := cml.Delete(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) List(q *Query) ([]Channel, error) {

	if q.GroupName == "" {
		return nil, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	var channels []Channel

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"group_name": q.GroupName,
		},
	}

	if q.Type != "" {
		query.Selector["type_constant"] = q.Type
	}

	err := bongo.B.Some(c, &channels, query)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<commit_msg>Social: add more descriptive error message<commit_after>package models

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

type Channel struct {
	// unique identifier of the channel
	Id int64 `json:"id"`

	// Name of the channel
	Name string `json:"name"                         sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Creator of the channel
	CreatorId int64 `json:"creatorId"                sql:"NOT NULL"`

	// Name of the group which channel is belong to
	GroupName string `json:"groupName"               sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Purpose of the channel
	Purpose string `json:"purpose"`

	// Secret key of the channel for event propagation purposes
	// we can put this key into another table?
	SecretKey string `json:"secretKey"`

	// Type of the channel
	TypeConstant string `json:"typeConstant"         sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Privacy constant of the channel
	PrivacyConstant string `json:"privacyConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation date of the channel
	CreatedAt time.Time `json:"createdAt"            sql:"NOT NULL"`

	// Modification date of the channel
	UpdatedAt time.Time `json:"updatedAt"            sql:"NOT NULL"`
}

// to-do check for allowed channels
const (
	// TYPES
	Channel_TYPE_GROUP           = "group"
	Channel_TYPE_TOPIC           = "topic"
	Channel_TYPE_FOLLOWINGFEED   = "followingfeed"
	Channel_TYPE_FOLLOWERS       = "followers"
	Channel_TYPE_CHAT            = "chat"
	Channel_TYPE_PINNED_ACTIVITY = "pinnedActivity"
	// Privacy
	Channel_TYPE_PUBLIC  = "public"
	Channel_TYPE_PRIVATE = "private"
	// Koding Group Name
	Channel_KODING_NAME = "koding"
)

func NewChannel() *Channel {
	return &Channel{
		Name:            "koding",
		CreatorId:       123,
		GroupName:       Channel_KODING_NAME,
		Purpose:         "string",
		SecretKey:       "string",
		TypeConstant:    "default",
		PrivacyConstant: Channel_TYPE_PRIVATE,
	}
}

func (c *Channel) BeforeCreate() {
	c.CreatedAt = time.Now()
	c.UpdatedAt = time.Now()
}

func (c *Channel) BeforeUpdate() {
	c.UpdatedAt = time.Now()
}

func (c *Channel) GetId() int64 {
	return c.Id
}

func (c Channel) TableName() string {
	return "api.channel"
}

func (c *Channel) Fetch() error {
	return bongo.B.Fetch(c)
}

func (c *Channel) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *Channel) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c *Channel) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c *Channel) Update() error {
	if c.Name == "" || c.GroupName == "" {
		return fmt.Errorf("Validation failed %s - %s", c.Name, c.GroupName)
	}

	return bongo.B.Update(c)
}

func (c *Channel) Create() error {
	if c.Name == "" || c.GroupName == "" || c.TypeConstant == "" {
		return fmt.Errorf("Validation failed %s - %s -%s", c.Name, c.GroupName, c.TypeConstant)
	}

	// golang returns -1 if item not in the string
	if strings.Index(c.Name, " ") > -1 {
		return fmt.Errorf("Channel name %q has empty space in it", c.Name)
	}

	if c.TypeConstant == Channel_TYPE_GROUP /* we can add more types here */ {
		selector := map[string]interface{}{
			"group_name":    c.GroupName,
			"type_constant": c.TypeConstant,
		}

		// if err is nil
		// it means we already have that channel
		err := c.One(bongo.NewQS(selector))
		if err == nil {
			return nil
			// return fmt.Errorf("%s typed channel is already created before for %s group", c.TypeConstant, c.GroupName)
		}

		if err != gorm.RecordNotFound {
			return err
		}

	}

	return bongo.B.Create(c)
}

func (c *Channel) Delete() error {
	return bongo.B.Delete(c)
}

func (c *Channel) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *Channel) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func (c *Channel) FetchByIds(ids []int64) ([]Channel, error) {
	var channels []Channel

	if len(ids) == 0 {
		return channels, nil
	}

	if err := bongo.B.FetchByIds(c, &channels, ids); err != nil {
		return nil, err
	}
	return channels, nil
}

func (c *Channel) AddParticipant(participantId int64) (*ChannelParticipant, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	if err != nil && err != gorm.RecordNotFound {
		return nil, err
	}

	// if we have this record in DB
	if cp.Id != 0 {
		// if status is not active
		if cp.StatusConstant == ChannelParticipant_STATUS_ACTIVE {
			return nil, errors.New(fmt.Sprintf("Account %d is already a participant of channel %d", cp.AccountId, cp.ChannelId))
		}
		cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE
		if err := cp.Update(); err != nil {
			return nil, err
		}
		return cp, nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE

	if err := cp.Create(); err != nil {
		return nil, err
	}

	return cp, nil
}

func (c *Channel) RemoveParticipant(participantId int64) error {
	if c.Id == 0 {
		return errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	// if user is not in this channel, do nothing
	if err == gorm.RecordNotFound {
		return nil
	}

	if err != nil {
		return err
	}

	if cp.StatusConstant == ChannelParticipant_STATUS_LEFT {
		return nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_LEFT
	if err := cp.Update(); err != nil {
		return err
	}

	return nil
}

func (c *Channel) FetchParticipantIds() ([]int64, error) {
	var participantIds []int64

	if c.Id == 0 {
		return participantIds, errors.New("Channel Id is not set")
	}

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id":      c.Id,
			"status_constant": ChannelParticipant_STATUS_ACTIVE,
		},
		Pluck: "account_id",
	}

	cp := NewChannelParticipant()
	err := cp.Some(&participantIds, query)
	if err != nil {
		return nil, err
	}

	return participantIds, nil
}

func (c *Channel) AddMessage(messageId int64) (*ChannelMessageList, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()

	selector := map[string]interface{}{
		"channel_id": c.Id,
		"message_id": messageId,
	}
	err := cml.One(bongo.NewQS(selector))
	if err == nil {
		return nil, errors.New("Message is already in the channel")
	}

	if err != gorm.RecordNotFound {
		return nil, err
	}
	// silence record not found err

	cml.ChannelId = c.Id
	cml.MessageId = messageId

	if err := cml.Create(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) RemoveMessage(messageId int64) (*ChannelMessageList, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()
	selector := map[string]interface{}{
		"channel_id": c.Id,
		"message_id": messageId,
	}
	err := cml.One(bongo.NewQS(selector))
	// one returns error when record not found case
	// but we dont care if it is not there tho
	if err != nil {
		return nil, err
	}

	if err := cml.Delete(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) List(q *Query) ([]Channel, error) {

	if q.GroupName == "" {
		return nil, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	var channels []Channel

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"group_name": q.GroupName,
		},
	}

	if q.Type != "" {
		query.Selector["type_constant"] = q.Type
	}

	err := bongo.B.Some(c, &channels, query)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<|endoftext|>


<commit_before>package vtctld

import (
	"fmt"
	"sort"
	"sync"

	"github.com/youtube/vitess/go/vt/discovery"
	"github.com/youtube/vitess/go/vt/proto/topodata"
	"github.com/youtube/vitess/go/vt/topo/topoproto"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

// yLabel is used to keep track of the outer and inner labels of the heatmap.
type yLabel struct {
	Label        label
	NestedLabels []label
}

// label is used to keep track of one label of a heatmap and how many rows it should span.
type label struct {
	Name    string
	Rowspan int
}

// heatmap stores all the needed info to construct the heatmap.
type heatmap struct {
	// Labels has the outer and inner labels for each row.
	Labels []yLabel
	// Data is a 2D array of values of the specified metric.
	Data [][]float64
	// Aliases is a 2D array holding references to the tablet aliases.
	Aliases [][]*topodata.TabletAlias
}

type byTabletUID []*discovery.TabletStats

func (a byTabletUid) Len() int           { return len(a) }
func (a byTabletUid) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byTabletUid) Less(i, j int) bool { return a[i].Tablet.Alias.Uid < a[j].Tablet.Alias.Uid }

const tabletMissing = -1

// tabletStatsCache holds the most recent status update received for
// each tablet. The tablets are indexed by uid, so it is different
// than discovery.TabletStatsCache.
type tabletStatsCache struct {
	// mu guards access to the fields below.
	mu sync.Mutex
	// statuses keeps a map of TabletStats.
	// The first key is the keyspace, the second key is the shard,
	// the third key is the cell, the last key is the tabletType.
	// The keys are strings to allow exposing this map as a JSON object in api.go.
	statuses map[string]map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats
	// statusesByAlias is a copy of statuses and will be updated simultaneously.
	// The first key is the string representation of the tablet alias.
	statusesByAlias map[string]*discovery.TabletStats
	// cells counts the number of tablets per cell.
	tabletCountsByCell map[string]int
}

func newTabletStatsCache() *tabletStatsCache {
	return &tabletStatsCache{
		statuses:           make(map[string]map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats),
		statusesByAlias:    make(map[string]*discovery.TabletStats),
		tabletCountsByCell: make(map[string]int),
	}
}

// StatsUpdate is part of the discovery.HealthCheckStatsListener interface.
// Upon receiving a new TabletStats, it updates the two maps in tablet_stats_cache.
func (c *tabletStatsCache) StatsUpdate(stats *discovery.TabletStats) {
	c.mu.Lock()
	defer c.mu.Unlock()

	keyspace := stats.Target.Keyspace
	shard := stats.Target.Shard
	cell := stats.Tablet.Alias.Cell
	tabletType := stats.Target.TabletType

	aliasKey := tabletToMapKey(stats)
	ts, ok := c.statusesByAlias[aliasKey]
	if !stats.Up {
		if !ok {
			// Tablet doesn't exist and was recently deleted or changed its type. Panic as this is unexpected behavior.
			panic(fmt.Sprintf("BUG: tablet (%v) doesn't exist", aliasKey))
		}
		// The tablet still exists in our cache but was recently deleted or changed its type. Delete it now.
		c.statuses[keyspace][shard][cell][tabletType] = remove(c.statuses[keyspace][shard][cell][tabletType], stats.Tablet.Alias)
		delete(c.statusesByAlias, aliasKey)
		c.tabletCountsByCell[cell]--
		if c.tabletCountsByCell[cell] == 0 {
			delete(c.tabletCountsByCell, cell)
		}
		return
	}

	if !ok {
		// Tablet isn't tracked yet so just add it.
		shards, ok := c.statuses[keyspace]
		if !ok {
			shards = make(map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats)
			c.statuses[keyspace] = shards
		}

		cells, ok := c.statuses[keyspace][shard]
		if !ok {
			cells = make(map[string]map[topodatapb.TabletType][]*discovery.TabletStats)
			c.statuses[keyspace][shard] = cells
		}

		types, ok := c.statuses[keyspace][shard][cell]
		if !ok {
			types = make(map[topodatapb.TabletType][]*discovery.TabletStats)
			c.statuses[keyspace][shard][cell] = types
		}

		tablets, ok := c.statuses[keyspace][shard][cell][tabletType]
		if !ok {
			tablets = make([]*discovery.TabletStats, 0)
			c.statuses[keyspace][shard][cell][tabletType] = tablets
		}

		c.statuses[keyspace][shard][cell][tabletType] = append(c.statuses[keyspace][shard][cell][tabletType], stats)
		sort.Sort(byTabletUid(c.statuses[keyspace][shard][cell][tabletType]))
		c.statusesByAlias[aliasKey] = stats
		c.tabletCountsByCell[cell]++
		return
	}

	// Tablet already exists so just update it in the cache.
	*ts = *stats
}

func tabletToMapKey(stats *discovery.TabletStats) string {
	return stats.Tablet.Alias.String()
}

// remove takes in an array and returns it with the specified element removed
// (leaves the array unchanged if element isn't in the array).
func remove(tablets []*discovery.TabletStats, tabletAlias *topodata.TabletAlias) []*discovery.TabletStats {
	filteredTablets := tablets[:0]
	for _, tablet := range tablets {
		if !topoproto.TabletAliasEqual(tablet.Tablet.Alias, tabletAlias) {
			filteredTablets = append(filteredTablets, tablet)
		}
	}
	return filteredTablets
}

// heatmapData returns a 2D array of data (based on the specified metric) as well as the labels for the heatmap.
func (c *tabletStatsCache) heatmapData(keyspace, cell, tabletType, metric string) (heatmap, error) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Get the metric data.
	var metricFunc func(stats *discovery.TabletStats) float64
	switch metric {
	case "lag":
		metricFunc = replicationLag
	case "cpu":
		metricFunc = cpu
	case "qps":
		metricFunc = qps
	default:
		return heatmap{}, fmt.Errorf("invalid metric: %v Select 'lag', 'cpu', or 'qps'", metric)
	}

	var cells []string
	for cell := range c.tabletCountsByCell {
		cells = append(cells, cell)
	}
	sort.Strings(cells)

	var shards []string
	for s := range c.statuses[keyspace] {
		shards = append(shards, s)
	}
	sort.Strings(shards)

	types := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY}

	// TODO(pkulshre): Generalize the following algorithm to support any combination of keyspace-cell-type.
	var heatmapData [][]float64
	var heatmapTabletAliases [][]*topodata.TabletAlias
	var yLabels []yLabel
	// The loop goes through every outer label (in this case, cell).
	for _, cell := range cells {
		perCellYLabel := yLabel{}
		labelSpan := 0

		// This loop goes through every nested label (in this case, tablet type).
		for _, tabletType := range types {
			maxRowLength := 0

			// The loop calculates the maximum number of rows needed.
			for _, shard := range shards {
				tabletsCount := len(c.statuses[keyspace][shard][cell][tabletType])
				if maxRowLength < tabletsCount {
					maxRowLength = tabletsCount
				}
			}

			// dataRowsPerType is a 2D array that will hold the data of the tablets of one (cell, type) combination.
			dataRowsPerType := make([][]float64, maxRowLength)
			// aliasRowsPerType is a 2D array that will hold the aliases of the tablets of one (cell, type) combination.
			aliasRowsPerType := make([][]*topodata.TabletAlias, maxRowLength)
			for i := range dataRowsPerType {
				dataRowsPerType[i] = make([]float64, len(shards))
				aliasRowsPerType[i] = make([]*topodata.TabletAlias, len(shards))
			}

			// Filling in the 2D array with tablet data by columns.
			for shardIndex, shard := range shards {
				for tabletIndex := 0; tabletIndex < maxRowLength; tabletIndex++ {
					// If the key doesn't exist then the tablet must not exist so that data is set to -1 (tabletMissing).
					if tabletIndex < len(c.statuses[keyspace][shard][cell][tabletType]) {
						dataRowsPerType[tabletIndex][shardIndex] = metricFunc(c.statuses[keyspace][shard][cell][tabletType][tabletIndex])
						aliasRowsPerType[tabletIndex][shardIndex] = c.statuses[keyspace][shard][cell][tabletType][tabletIndex].Tablet.Alias
					} else {
						dataRowsPerType[tabletIndex][shardIndex] = tabletMissing
						aliasRowsPerType[tabletIndex][shardIndex] = nil
					}

					// Adding the labels for the yaxis only if it is the first column.
					if shardIndex == 0 && tabletIndex == (maxRowLength-1) {
						tempLabel := label{
							Name:    tabletType.String(),
							Rowspan: maxRowLength,
						}
						perCellYLabel.NestedLabels = append(perCellYLabel.NestedLabels, tempLabel)
						labelSpan += maxRowLength
					}
				}
			}

			for i := 0; i < len(dataRowsPerType); i++ {
				heatmapData = append(heatmapData, dataRowsPerType[i])
				heatmapTabletAliases = append(heatmapTabletAliases, aliasRowsPerType[i])
			}
		}
		perCellYLabel.Label = label{
			Name:    cell,
			Rowspan: labelSpan,
		}
		yLabels = append(yLabels, perCellYLabel)
	}

	return heatmap{
		Data:    heatmapData,
		Labels:  yLabels,
		Aliases: heatmapTabletAliases,
	}, nil
}

func (c *tabletStatsCache) tabletStatsByAlias(tabletAlias *topodatapb.TabletAlias) *discovery.TabletStats {
	c.mu.Lock()
	defer c.mu.Unlock()

	ts, ok := c.statusesByAlias[tabletAlias.String()]
	if !ok {
		return nil
	}
	return ts
}

func replicationLag(stat *discovery.TabletStats) float64 {
	return float64(stat.Stats.SecondsBehindMaster)
}

func cpu(stat *discovery.TabletStats) float64 {
	return stat.Stats.CpuUsage
}

func qps(stat *discovery.TabletStats) float64 {
	return stat.Stats.Qps
}

// compile-time interface check
var _ discovery.HealthCheckStatsListener = (*tabletStatsCache)(nil)
<commit_msg>Fixed golint error<commit_after>package vtctld

import (
	"fmt"
	"sort"
	"sync"

	"github.com/youtube/vitess/go/vt/discovery"
	"github.com/youtube/vitess/go/vt/proto/topodata"
	"github.com/youtube/vitess/go/vt/topo/topoproto"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

// yLabel is used to keep track of the outer and inner labels of the heatmap.
type yLabel struct {
	Label        label
	NestedLabels []label
}

// label is used to keep track of one label of a heatmap and how many rows it should span.
type label struct {
	Name    string
	Rowspan int
}

// heatmap stores all the needed info to construct the heatmap.
type heatmap struct {
	// Labels has the outer and inner labels for each row.
	Labels []yLabel
	// Data is a 2D array of values of the specified metric.
	Data [][]float64
	// Aliases is a 2D array holding references to the tablet aliases.
	Aliases [][]*topodata.TabletAlias
}

type byTabletUID []*discovery.TabletStats

func (a byTabletUID) Len() int           { return len(a) }
func (a byTabletUID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byTabletUID) Less(i, j int) bool { return a[i].Tablet.Alias.Uid < a[j].Tablet.Alias.Uid }

const tabletMissing = -1

// tabletStatsCache holds the most recent status update received for
// each tablet. The tablets are indexed by uid, so it is different
// than discovery.TabletStatsCache.
type tabletStatsCache struct {
	// mu guards access to the fields below.
	mu sync.Mutex
	// statuses keeps a map of TabletStats.
	// The first key is the keyspace, the second key is the shard,
	// the third key is the cell, the last key is the tabletType.
	// The keys are strings to allow exposing this map as a JSON object in api.go.
	statuses map[string]map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats
	// statusesByAlias is a copy of statuses and will be updated simultaneously.
	// The first key is the string representation of the tablet alias.
	statusesByAlias map[string]*discovery.TabletStats
	// cells counts the number of tablets per cell.
	tabletCountsByCell map[string]int
}

func newTabletStatsCache() *tabletStatsCache {
	return &tabletStatsCache{
		statuses:           make(map[string]map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats),
		statusesByAlias:    make(map[string]*discovery.TabletStats),
		tabletCountsByCell: make(map[string]int),
	}
}

// StatsUpdate is part of the discovery.HealthCheckStatsListener interface.
// Upon receiving a new TabletStats, it updates the two maps in tablet_stats_cache.
func (c *tabletStatsCache) StatsUpdate(stats *discovery.TabletStats) {
	c.mu.Lock()
	defer c.mu.Unlock()

	keyspace := stats.Target.Keyspace
	shard := stats.Target.Shard
	cell := stats.Tablet.Alias.Cell
	tabletType := stats.Target.TabletType

	aliasKey := tabletToMapKey(stats)
	ts, ok := c.statusesByAlias[aliasKey]
	if !stats.Up {
		if !ok {
			// Tablet doesn't exist and was recently deleted or changed its type. Panic as this is unexpected behavior.
			panic(fmt.Sprintf("BUG: tablet (%v) doesn't exist", aliasKey))
		}
		// The tablet still exists in our cache but was recently deleted or changed its type. Delete it now.
		c.statuses[keyspace][shard][cell][tabletType] = remove(c.statuses[keyspace][shard][cell][tabletType], stats.Tablet.Alias)
		delete(c.statusesByAlias, aliasKey)
		c.tabletCountsByCell[cell]--
		if c.tabletCountsByCell[cell] == 0 {
			delete(c.tabletCountsByCell, cell)
		}
		return
	}

	if !ok {
		// Tablet isn't tracked yet so just add it.
		shards, ok := c.statuses[keyspace]
		if !ok {
			shards = make(map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats)
			c.statuses[keyspace] = shards
		}

		cells, ok := c.statuses[keyspace][shard]
		if !ok {
			cells = make(map[string]map[topodatapb.TabletType][]*discovery.TabletStats)
			c.statuses[keyspace][shard] = cells
		}

		types, ok := c.statuses[keyspace][shard][cell]
		if !ok {
			types = make(map[topodatapb.TabletType][]*discovery.TabletStats)
			c.statuses[keyspace][shard][cell] = types
		}

		tablets, ok := c.statuses[keyspace][shard][cell][tabletType]
		if !ok {
			tablets = make([]*discovery.TabletStats, 0)
			c.statuses[keyspace][shard][cell][tabletType] = tablets
		}

		c.statuses[keyspace][shard][cell][tabletType] = append(c.statuses[keyspace][shard][cell][tabletType], stats)
		sort.Sort(byTabletUID(c.statuses[keyspace][shard][cell][tabletType]))
		c.statusesByAlias[aliasKey] = stats
		c.tabletCountsByCell[cell]++
		return
	}

	// Tablet already exists so just update it in the cache.
	*ts = *stats
}

func tabletToMapKey(stats *discovery.TabletStats) string {
	return stats.Tablet.Alias.String()
}

// remove takes in an array and returns it with the specified element removed
// (leaves the array unchanged if element isn't in the array).
func remove(tablets []*discovery.TabletStats, tabletAlias *topodata.TabletAlias) []*discovery.TabletStats {
	filteredTablets := tablets[:0]
	for _, tablet := range tablets {
		if !topoproto.TabletAliasEqual(tablet.Tablet.Alias, tabletAlias) {
			filteredTablets = append(filteredTablets, tablet)
		}
	}
	return filteredTablets
}

// heatmapData returns a 2D array of data (based on the specified metric) as well as the labels for the heatmap.
func (c *tabletStatsCache) heatmapData(keyspace, cell, tabletType, metric string) (heatmap, error) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Get the metric data.
	var metricFunc func(stats *discovery.TabletStats) float64
	switch metric {
	case "lag":
		metricFunc = replicationLag
	case "cpu":
		metricFunc = cpu
	case "qps":
		metricFunc = qps
	default:
		return heatmap{}, fmt.Errorf("invalid metric: %v Select 'lag', 'cpu', or 'qps'", metric)
	}

	var cells []string
	for cell := range c.tabletCountsByCell {
		cells = append(cells, cell)
	}
	sort.Strings(cells)

	var shards []string
	for s := range c.statuses[keyspace] {
		shards = append(shards, s)
	}
	sort.Strings(shards)

	types := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY}

	// TODO(pkulshre): Generalize the following algorithm to support any combination of keyspace-cell-type.
	var heatmapData [][]float64
	var heatmapTabletAliases [][]*topodata.TabletAlias
	var yLabels []yLabel
	// The loop goes through every outer label (in this case, cell).
	for _, cell := range cells {
		perCellYLabel := yLabel{}
		labelSpan := 0

		// This loop goes through every nested label (in this case, tablet type).
		for _, tabletType := range types {
			maxRowLength := 0

			// The loop calculates the maximum number of rows needed.
			for _, shard := range shards {
				tabletsCount := len(c.statuses[keyspace][shard][cell][tabletType])
				if maxRowLength < tabletsCount {
					maxRowLength = tabletsCount
				}
			}

			// dataRowsPerType is a 2D array that will hold the data of the tablets of one (cell, type) combination.
			dataRowsPerType := make([][]float64, maxRowLength)
			// aliasRowsPerType is a 2D array that will hold the aliases of the tablets of one (cell, type) combination.
			aliasRowsPerType := make([][]*topodata.TabletAlias, maxRowLength)
			for i := range dataRowsPerType {
				dataRowsPerType[i] = make([]float64, len(shards))
				aliasRowsPerType[i] = make([]*topodata.TabletAlias, len(shards))
			}

			// Filling in the 2D array with tablet data by columns.
			for shardIndex, shard := range shards {
				for tabletIndex := 0; tabletIndex < maxRowLength; tabletIndex++ {
					// If the key doesn't exist then the tablet must not exist so that data is set to -1 (tabletMissing).
					if tabletIndex < len(c.statuses[keyspace][shard][cell][tabletType]) {
						dataRowsPerType[tabletIndex][shardIndex] = metricFunc(c.statuses[keyspace][shard][cell][tabletType][tabletIndex])
						aliasRowsPerType[tabletIndex][shardIndex] = c.statuses[keyspace][shard][cell][tabletType][tabletIndex].Tablet.Alias
					} else {
						dataRowsPerType[tabletIndex][shardIndex] = tabletMissing
						aliasRowsPerType[tabletIndex][shardIndex] = nil
					}

					// Adding the labels for the yaxis only if it is the first column.
					if shardIndex == 0 && tabletIndex == (maxRowLength-1) {
						tempLabel := label{
							Name:    tabletType.String(),
							Rowspan: maxRowLength,
						}
						perCellYLabel.NestedLabels = append(perCellYLabel.NestedLabels, tempLabel)
						labelSpan += maxRowLength
					}
				}
			}

			for i := 0; i < len(dataRowsPerType); i++ {
				heatmapData = append(heatmapData, dataRowsPerType[i])
				heatmapTabletAliases = append(heatmapTabletAliases, aliasRowsPerType[i])
			}
		}
		perCellYLabel.Label = label{
			Name:    cell,
			Rowspan: labelSpan,
		}
		yLabels = append(yLabels, perCellYLabel)
	}

	return heatmap{
		Data:    heatmapData,
		Labels:  yLabels,
		Aliases: heatmapTabletAliases,
	}, nil
}

func (c *tabletStatsCache) tabletStatsByAlias(tabletAlias *topodatapb.TabletAlias) *discovery.TabletStats {
	c.mu.Lock()
	defer c.mu.Unlock()

	ts, ok := c.statusesByAlias[tabletAlias.String()]
	if !ok {
		return nil
	}
	return ts
}

func replicationLag(stat *discovery.TabletStats) float64 {
	return float64(stat.Stats.SecondsBehindMaster)
}

func cpu(stat *discovery.TabletStats) float64 {
	return stat.Stats.CpuUsage
}

func qps(stat *discovery.TabletStats) float64 {
	return stat.Stats.Qps
}

// compile-time interface check
var _ discovery.HealthCheckStatsListener = (*tabletStatsCache)(nil)
<|endoftext|>


<commit_before>package kite

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"koding/newKite/kd/util"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

type Install struct{}

func NewInstall() *Install {
	return &Install{}
}

func (*Install) Definition() string {
	return "Install kite from Koding repository"
}

const s3URL = "http://koding-kites.s3.amazonaws.com/"

func (*Install) Exec() error {
	flag.Parse()
	if flag.NArg() != 1 {
		return errors.New("You should give a kite name")
	}

	// Generate download URL
	kiteName := flag.Arg(0)
	kiteURL := s3URL + kiteName + ".kite.tar.gz"
	log.Println(kiteURL)

	// Make download request
	fmt.Println("Downloading...")
	res, err := http.Get(kiteURL)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	// Extract gzip
	gz, err := gzip.NewReader(res.Body)
	if err != nil {
		return err
	}
	defer gz.Close()

	// Extract tar
	tempKitePath, err := ioutil.TempDir("", "koding-kite-")
	log.Println("Created temp dir:", tempKitePath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(tempKitePath)
	err = extractTar(gz, tempKitePath)
	if err != nil {
		return err
	}

	// Move kite from tmp to kites folder (~/.kd/kites)
	tempKitePath = filepath.Join(tempKitePath, kiteName+".kite")
	kitesPath := filepath.Join(util.GetKdPath(), "kites")
	os.MkdirAll(kitesPath, 0700)
	kitePath := filepath.Join(kitesPath, kiteName+".kite")
	log.Println("Moving from:", tempKitePath, "to:", kitePath)
	err = os.Rename(tempKitePath, kitePath)
	if err != nil {
		return err
	}

	fmt.Println("Done.")
	return nil
}

// extractTar reads from the io.Reader and writes the files into the directory.
func extractTar(r io.Reader, dir string) error {
	tr := tar.NewReader(r)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			break
		}
		if err != nil {
			return err
		}

		fi := hdr.FileInfo()
		name := fi.Name()
		path := filepath.Join(dir, name)

		// TODO make the binary under /bin executable
		// TODO assert contents of the tar file, it must contain online one directory named kitename-0.0.1.kite

		if fi.IsDir() {
			os.MkdirAll(path, 0700)
		} else {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
			if err != nil {
				return err
			}

			if _, err := io.Copy(f, tr); err != nil {
				return err
			}
		}
	}
	return nil
}

// splitVersion takes a name like "asdf-1.2.3" and
// returns the name "asdf" and version "1.2.3" seperately.
func splitVersion(fullname string) (name, version string, err error) {
	notFound := errors.New("name does not contain a version number")

	parts := strings.Split(fullname, "-")
	n := len(parts)
	if n < 2 {
		return "", "", notFound
	}

	version = parts[n-1]
	versionParts := strings.Split(version, ".")
	for _, v := range versionParts {
		if _, err := strconv.ParseUint(v, 10, 64); err != nil {
			return "", "", notFound
		}
	}

	name = strings.Join(parts[:n-2], "-")
	return name, version, nil
}
<commit_msg>assert status code from server<commit_after>package kite

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"koding/newKite/kd/util"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

type Install struct{}

func NewInstall() *Install {
	return &Install{}
}

func (*Install) Definition() string {
	return "Install kite from Koding repository"
}

const s3URL = "http://koding-kites.s3.amazonaws.com/"

func (*Install) Exec() error {
	flag.Parse()
	if flag.NArg() != 1 {
		return errors.New("You should give a kite name")
	}

	// Generate download URL
	kiteName := flag.Arg(0)
	kiteURL := s3URL + kiteName + ".kite.tar.gz"
	log.Println(kiteURL)

	// Make download request
	fmt.Println("Downloading...")
	res, err := http.Get(kiteURL)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return fmt.Errorf("Unexpected response from server: %d", res.StatusCode)
	}

	// Extract gzip
	gz, err := gzip.NewReader(res.Body)
	if err != nil {
		return err
	}
	defer gz.Close()

	// Extract tar
	tempKitePath, err := ioutil.TempDir("", "koding-kite-")
	log.Println("Created temp dir:", tempKitePath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(tempKitePath)
	err = extractTar(gz, tempKitePath)
	if err != nil {
		return err
	}

	// Move kite from tmp to kites folder (~/.kd/kites)
	tempKitePath = filepath.Join(tempKitePath, kiteName+".kite")
	kitesPath := filepath.Join(util.GetKdPath(), "kites")
	os.MkdirAll(kitesPath, 0700)
	kitePath := filepath.Join(kitesPath, kiteName+".kite")
	log.Println("Moving from:", tempKitePath, "to:", kitePath)
	err = os.Rename(tempKitePath, kitePath)
	if err != nil {
		return err
	}

	fmt.Println("Done.")
	return nil
}

// extractTar reads from the io.Reader and writes the files into the directory.
func extractTar(r io.Reader, dir string) error {
	tr := tar.NewReader(r)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			break
		}
		if err != nil {
			return err
		}

		fi := hdr.FileInfo()
		name := fi.Name()
		path := filepath.Join(dir, name)

		// TODO make the binary under /bin executable
		// TODO assert contents of the tar file, it must contain online one directory named kitename-0.0.1.kite

		if fi.IsDir() {
			os.MkdirAll(path, 0700)
		} else {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
			if err != nil {
				return err
			}

			if _, err := io.Copy(f, tr); err != nil {
				return err
			}
		}
	}
	return nil
}

// splitVersion takes a name like "asdf-1.2.3" and
// returns the name "asdf" and version "1.2.3" seperately.
func splitVersion(fullname string) (name, version string, err error) {
	notFound := errors.New("name does not contain a version number")

	parts := strings.Split(fullname, "-")
	n := len(parts)
	if n < 2 {
		return "", "", notFound
	}

	version = parts[n-1]
	versionParts := strings.Split(version, ".")
	for _, v := range versionParts {
		if _, err := strconv.ParseUint(v, 10, 64); err != nil {
			return "", "", notFound
		}
	}

	name = strings.Join(parts[:n-2], "-")
	return name, version, nil
}
<|endoftext|>


<commit_before>// syscfg
package main

import (
	"crypto/md5"
	"database/sql"
	"encoding/hex"
	"fmt"

	_ "github.com/mattn/go-sqlite3"
)

var (
	sysCfgDb              *sql.DB
	sysDbErr              error
	DbName                = "bdgfcsys"
	SysTabCreate_sys_user = `
		CREATE TABLE IF NOT EXISTS sys_user
		(
			--id 			INTEGER PRIMARY KEY AUTOINCREMENT,
			user_id		VARCHAR(128) PRIMARY KEY NOT NULL,
			user_pass 	VARCHAR(128) NOT NULL,
			user_sign	VARCHAR(32) DEFAULT NULL,
			trustzone	VARCHAR(256) DEFAULT NULL,
			user_status	INTEGER DEFAULT 1 NOT NULL,
			last_login 	DATETIME DEFAULT NULL,
			create_time DATETIME DEFAULT(DATETIME('now', 'localtime')) NOT NULL
		);`
	sysTab_sys_user_list    = `select * from sys_user`
	sysTab_sys_user_add     = `insert into sys_user(user_id,user_pass) values(?,?)`
	sysTab_sys_user_Login   = `update sys_user set last_login=DATETIME('now', 'localtime') where user_id=? and user_pass=?`
	sysTab_sys_user_SetPass = `update sys_user set user_pass=? where user_id=? and user_pass=?`

	SysTabCreate_sys_cfg = `
		CREATE TABLE IF NOT EXISTS sys_method
		(
			--id 			INTEGER PRIMARY KEY AUTOINCREMENT,
			method_name		VARCHAR(128) PRIMARY KEY NOT NULL,
			method_content 	VARCHAR(128) NOT NULL,
			dbdriver		VARCHAR(32) DEFAULT NULL,
			update_time 	DATETIME DEFAULT NULL,
			create_time 	DATETIME DEFAULT(DATETIME('now', 'localtime')) NOT NULL
		);`
	sysTab_sys_method_list         = `select method_name,method_content,dbdriver from sys_method`
	sysTab_sys_method_add          = `insert into sys_method(method_name,method_content,dbdriver) values(?,?,?)`
	sysTab_sys_method_Content_Set  = `update sys_method set method_content=? where method_name=?`
	sysTab_sys_method_Dbdriver_set = `update sys_method set dbdriver=? where method_name=?`
)

func init() {
	sysCfgDb, sysDbErr = sql.Open("sqlite3", DbName)
	if sysDbErr != nil {
		panic(sysDbErr)
	}
	_, sysDbErr := sysCfgDb.Exec(SysTabCreate_sys_user)
	if nil != sysDbErr {
		fmt.Println(sysDbErr.Error())
	}

	AddUser("jhf", "123")
	AddUser("tf", "tfpass")
	printab(sysTab_sys_user_list)

	ChangeUserPass("jhf", "123", "3456")
	printab(sysTab_sys_user_list)

}

func str2md5(str string) string {
	sum := md5.Sum([]byte(str))
	return hex.EncodeToString(sum[:])
}

func modifydb(strsql string, args ...interface{}) (RowsAffected int64, ok bool) {
	stmt, err := sysCfgDb.Prepare(strsql)
	if nil != err {
		fmt.Println(err.Error())
		return -1, false
	}
	defer stmt.Close()

	rst, err := stmt.Exec(args...)
	if nil != err {
		fmt.Println(err.Error())
		return -1, false
	}

	count, err := rst.RowsAffected()
	if nil != err {
		fmt.Println(err.Error())
		return -1, false
	}

	return count, true
}

func AddUser(id, pass string) bool {
	_, ok := modifydb(sysTab_sys_user_add, id, str2md5(id+pass))
	return ok
}

func CheckUser(id, pass string) bool {
	count, ok := modifydb(sysTab_sys_user_Login, id, str2md5(id+pass))
	return ok && count == 1
}

func ChangeUserPass(id, pass, newPass string) bool {
	count, ok := modifydb(sysTab_sys_user_SetPass, str2md5(id+newPass), id, str2md5(id+pass))
	return ok && count == 1
}

func printab(strsql string) {
	rows, err := sysCfgDb.Query(strsql)
	if err != nil {
		return
	}
	defer rows.Close()

	columns, err := rows.Columns()

	if err != nil {
		return
	}

	//fix bug time.Time nil
	//values := make([]sql.RawBytes, len(columns))
	values := make([]sql.NullString, len(columns))
	scans := make([]interface{}, len(columns))

	for i := range values {
		scans[i] = &values[i]
	}

	for rows.Next() {
		err = rows.Scan(scans...)
		if err != nil {
			panic(err.Error())
		}

		strVal := ""
		for _, col := range values {
			if !col.Valid {
				strVal = "NULL"
			} else {
				strVal = col.String
			}
			fmt.Printf(strVal, " ")
		}
		fmt.Println()
	}
}
<commit_msg>add sqlite<commit_after>// syscfg
package main

import (
	"crypto/md5"
	"database/sql"
	"encoding/hex"
	"fmt"

	_ "github.com/mattn/go-sqlite3"
)

var (
	sysCfgDb              *sql.DB
	sysDbErr              error
	DbName                = "bdgfcsys"
	SysTabCreate_sys_user = `
		CREATE TABLE IF NOT EXISTS sys_user
		(
			--id 			INTEGER PRIMARY KEY AUTOINCREMENT,
			user_id		VARCHAR(128) PRIMARY KEY NOT NULL,
			user_pass 	VARCHAR(128) NOT NULL,
			user_sign	VARCHAR(32) DEFAULT NULL,
			trustzone	VARCHAR(256) DEFAULT NULL,
			user_status	INTEGER DEFAULT 1 NOT NULL,
			last_login 	DATETIME DEFAULT NULL,
			create_time DATETIME DEFAULT(DATETIME('now', 'localtime')) NOT NULL
		);`
	sysTab_sys_user_list    = `select * from sys_user`
	sysTab_sys_user_add     = `insert into sys_user(user_id,user_pass) values(?,?)`
	sysTab_sys_user_Login   = `update sys_user set last_login=DATETIME('now', 'localtime') where user_id=? and user_pass=?`
	sysTab_sys_user_SetPass = `update sys_user set user_pass=? where user_id=? and user_pass=?`

	SysTabCreate_sys_cfg = `
		CREATE TABLE IF NOT EXISTS sys_method
		(
			--id 			INTEGER PRIMARY KEY AUTOINCREMENT,
			method_name		VARCHAR(128) PRIMARY KEY NOT NULL,
			method_content 	VARCHAR(128) NOT NULL,
			dbdriver		VARCHAR(32) DEFAULT NULL,
			update_time 	DATETIME DEFAULT NULL,
			create_time 	DATETIME DEFAULT(DATETIME('now', 'localtime')) NOT NULL
		);`
	sysTab_sys_method_list         = `select method_name,method_content,dbdriver from sys_method`
	sysTab_sys_method_add          = `insert into sys_method(method_name,method_content,dbdriver) values(?,?,?)`
	sysTab_sys_method_Content_Set  = `update sys_method set method_content=? where method_name=?`
	sysTab_sys_method_Dbdriver_set = `update sys_method set dbdriver=? where method_name=?`
)

func init() {
	sysCfgDb, sysDbErr = sql.Open("sqlite3", DbName)
	if sysDbErr != nil {
		panic(sysDbErr)
	}
	_, sysDbErr := sysCfgDb.Exec(SysTabCreate_sys_user)
	if nil != sysDbErr {
		fmt.Println(sysDbErr.Error())
	}

	AddUser("jhf", "123")
	AddUser("tf", "tfpass")
	printab(sysTab_sys_user_list)

	ChangeUserPass("jhf", "123", "3456")
	printab(sysTab_sys_user_list)

}

func str2md5(str string) string {
	sum := md5.Sum([]byte(str))
	return hex.EncodeToString(sum[:])
}

func chekError(err error, output bool) bool {
	if err != nil {
		if output {
			fmt.Println(err.Error())
		}
		return false
	}
	return true
}

func printab(strsql string, args ...interface{}) {
	stmt, err := sysCfgDb.Prepare(strsql)
	if chekError(err, true) {
		return
	}
	defer stmt.Close()

	rows, err := stmt.Query(args...)
	if chekError(err, true) {
		return
	}

	columns, err := rows.Columns()
	if chekError(err, true) {
		return
	}

	//fix bug time.Time nil
	//values := make([]sql.RawBytes, len(columns))
	values := make([]sql.NullString, len(columns))
	scans := make([]interface{}, len(columns))

	for i := range values {
		scans[i] = &values[i]
	}

	for rows.Next() {
		err = rows.Scan(scans...)
		if chekError(err, true) {
			return
		}

		strVal := ""
		for _, col := range values {
			if !col.Valid {
				strVal = "NULL"
			} else {
				strVal = col.String
			}
			fmt.Printf(strVal, " ")
		}
		fmt.Println()
	}
}

//for insert update delete use
func modifydb(strsql string, args ...interface{}) (RowsAffected int64, ok bool) {
	stmt, err := sysCfgDb.Prepare(strsql)
	if chekError(err, true) {
		return -1, false
	}
	defer stmt.Close()

	rst, err := stmt.Exec(args...)
	if chekError(err, true) {
		return -1, false
	}

	count, err := rst.RowsAffected()
	if chekError(err, true) {
		return -1, false
	}

	return count, true
}

func AddUser(id, pass string) bool {
	_, ok := modifydb(sysTab_sys_user_add, id, str2md5(id+pass))
	return ok
}

func CheckUser(id, pass string) bool {
	count, ok := modifydb(sysTab_sys_user_Login, id, str2md5(id+pass))
	return ok && count == 1
}

func ChangeUserPass(id, pass, newPass string) bool {
	count, ok := modifydb(sysTab_sys_user_SetPass, str2md5(id+newPass), id, str2md5(id+pass))
	return ok && count == 1
}
<|endoftext|>