<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cloudup

import (
	"fmt"
	"github.com/golang/glog"
	api "k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/featureflag"
	"k8s.io/kops/pkg/model"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kubernetes/federation/pkg/dnsprovider"
	"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
	"net"
	"os"
	"strings"
)

const (
	// This IP is from TEST-NET-3
	// https://en.wikipedia.org/wiki/Reserved_IP_addresses
	PlaceholderIP  = "203.0.113.123"
	PlaceholderTTL = 10
)

func findZone(cluster *api.Cluster, cloud fi.Cloud) (dnsprovider.Zone, error) {
	dns, err := cloud.DNS()
	if err != nil {
		return nil, fmt.Errorf("error building DNS provider: %v", err)
	}

	zonesProvider, ok := dns.Zones()
	if !ok {
		return nil, fmt.Errorf("error getting DNS zones provider")
	}

	zones, err := zonesProvider.List()
	if err != nil {
		return nil, fmt.Errorf("error listing DNS zones: %v", err)
	}

	var matches []dnsprovider.Zone
	findName := strings.TrimSuffix(cluster.Spec.DNSZone, ".")
	for _, zone := range zones {
		id := zone.ID()
		name := strings.TrimSuffix(zone.Name(), ".")
		if id == cluster.Spec.DNSZone || name == findName {
			matches = append(matches, zone)
		}
	}
	if len(matches) == 0 {
		return nil, fmt.Errorf("cannot find DNS Zone %q.  Please pre-create the zone and set up NS records so that it resolves.", cluster.Spec.DNSZone)
	}

	if len(matches) > 1 {
		return nil, fmt.Errorf("found multiple DNS Zones matching %q", cluster.Spec.DNSZone)
	}

	zone := matches[0]
	return zone, nil
}

func validateDNS(cluster *api.Cluster, cloud fi.Cloud) error {
	kopsModelContext := &model.KopsModelContext{
		Cluster: cluster,
		// We are not initializing a lot of the fields here; revisit once UsePrivateDNS is "real"
	}

	if kopsModelContext.UsePrivateDNS() {
		glog.Infof("Private DNS: skipping DNS validation")
		return nil
	}

	zone, err := findZone(cluster, cloud)
	if err != nil {
		return err
	}
	dnsName := strings.TrimSuffix(zone.Name(), ".")

	glog.V(2).Infof("Doing DNS lookup to verify NS records for %q", dnsName)
	ns, err := net.LookupNS(dnsName)
	if err != nil {
		return fmt.Errorf("error doing DNS lookup for NS records for %q: %v", dnsName, err)
	}

	if len(ns) == 0 {
		if os.Getenv("DNS_IGNORE_NS_CHECK") == "" {
			return fmt.Errorf("NS records not found for %q - please make sure they are correctly configured", dnsName)
		} else {
			glog.Warningf("Ignoring failed NS record check because DNS_IGNORE_NS_CHECK is set")
		}
	} else {
		var hosts []string
		for _, n := range ns {
			hosts = append(hosts, n.Host)
		}
		glog.V(2).Infof("Found NS records for %q: %v", dnsName, hosts)
	}

	return nil
}

func precreateDNS(cluster *api.Cluster, cloud fi.Cloud) error {
	// TODO: Move to update
	if !featureflag.DNSPreCreate.Enabled() {
		glog.V(4).Infof("Skipping DNS record pre-creation because feature flag not enabled")
		return nil
	}

	glog.Infof("Pre-creating DNS records")

	// We precreate some DNS names (where they don't exist), with a dummy IP address
	// This avoids hitting negative TTL on DNS lookups, which tend to be very long
	// If we get the names wrong here, it doesn't really matter (extra DNS name, slower boot)
	dnsSuffix := cluster.Spec.MasterPublicName

	var dnsHostnames []string

	if cluster.Spec.MasterPublicName != "" {
		dnsHostnames = append(dnsHostnames, cluster.Spec.MasterPublicName)
	} else {
		glog.Warningf("cannot pre-create MasterPublicName - not set")
	}

	if cluster.Spec.MasterInternalName != "" {
		dnsHostnames = append(dnsHostnames, cluster.Spec.MasterInternalName)
	} else {
		glog.Warningf("cannot pre-create MasterInternalName - not set")
	}

	for _, etcdCluster := range cluster.Spec.EtcdClusters {
		etcClusterName := "etcd-" + etcdCluster.Name
		if etcdCluster.Name == "main" {
			// Special case
			etcClusterName = "etcd"
		}
		for _, etcdClusterMember := range etcdCluster.Members {
			name := etcClusterName + "-" + etcdClusterMember.Name + ".internal." + dnsSuffix
			dnsHostnames = append(dnsHostnames, name)
		}
	}

	zone, err := findZone(cluster, cloud)
	if err != nil {
		return err
	}

	rrs, ok := zone.ResourceRecordSets()
	if !ok {
		return fmt.Errorf("error getting DNS resource records for %q", zone.Name())
	}

	records, err := rrs.List()
	if err != nil {
		return fmt.Errorf("error listing DNS resource records for %q: %v", zone.Name(), err)
	}

	recordsMap := make(map[string]dnsprovider.ResourceRecordSet)
	for _, record := range records {
		name := strings.TrimSuffix(record.Name(), ".")
		key := string(record.Type()) + "::" + name
		recordsMap[key] = record
	}

	changeset := rrs.StartChangeset()
	// TODO: Add ChangeSet.IsEmpty() method
	var created []string

	for _, dnsHostname := range dnsHostnames {
		dnsRecord := recordsMap["A::"+dnsHostname]
		found := false
		if dnsRecord != nil {
			rrdatas := dnsRecord.Rrdatas()
			if len(rrdatas) > 0 {
				glog.V(4).Infof("Found DNS record %s => %s; won't create", dnsHostname, rrdatas)
				found = true
			}
		}

		if found {
			continue
		}

		glog.V(2).Infof("Pre-creating DNS record %s => %s", dnsHostnames, PlaceholderIP)

		changeset.Add(rrs.New(dnsHostname, []string{PlaceholderIP}, PlaceholderTTL, rrstype.A))
		created = append(created, dnsHostname)
	}

	if len(created) != 0 {
		err := changeset.Apply()
		if err != nil {
			return fmt.Errorf("Error pre-creating DNS records: %v", err)
		}
		glog.V(2).Infof("Pre-created DNS names: %v", created)
	}

	return nil
}
<commit_msg>Skip DNS precreation if we have no records<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cloudup

import (
	"fmt"
	"github.com/golang/glog"
	api "k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/featureflag"
	"k8s.io/kops/pkg/model"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kubernetes/federation/pkg/dnsprovider"
	"k8s.io/kubernetes/federation/pkg/dnsprovider/rrstype"
	"net"
	"os"
	"strings"
)

const (
	// This IP is from TEST-NET-3
	// https://en.wikipedia.org/wiki/Reserved_IP_addresses
	PlaceholderIP  = "203.0.113.123"
	PlaceholderTTL = 10
)

func findZone(cluster *api.Cluster, cloud fi.Cloud) (dnsprovider.Zone, error) {
	dns, err := cloud.DNS()
	if err != nil {
		return nil, fmt.Errorf("error building DNS provider: %v", err)
	}

	zonesProvider, ok := dns.Zones()
	if !ok {
		return nil, fmt.Errorf("error getting DNS zones provider")
	}

	zones, err := zonesProvider.List()
	if err != nil {
		return nil, fmt.Errorf("error listing DNS zones: %v", err)
	}

	var matches []dnsprovider.Zone
	findName := strings.TrimSuffix(cluster.Spec.DNSZone, ".")
	for _, zone := range zones {
		id := zone.ID()
		name := strings.TrimSuffix(zone.Name(), ".")
		if id == cluster.Spec.DNSZone || name == findName {
			matches = append(matches, zone)
		}
	}
	if len(matches) == 0 {
		return nil, fmt.Errorf("cannot find DNS Zone %q.  Please pre-create the zone and set up NS records so that it resolves.", cluster.Spec.DNSZone)
	}

	if len(matches) > 1 {
		return nil, fmt.Errorf("found multiple DNS Zones matching %q", cluster.Spec.DNSZone)
	}

	zone := matches[0]
	return zone, nil
}

func validateDNS(cluster *api.Cluster, cloud fi.Cloud) error {
	kopsModelContext := &model.KopsModelContext{
		Cluster: cluster,
		// We are not initializing a lot of the fields here; revisit once UsePrivateDNS is "real"
	}

	if kopsModelContext.UsePrivateDNS() {
		glog.Infof("Private DNS: skipping DNS validation")
		return nil
	}

	zone, err := findZone(cluster, cloud)
	if err != nil {
		return err
	}
	dnsName := strings.TrimSuffix(zone.Name(), ".")

	glog.V(2).Infof("Doing DNS lookup to verify NS records for %q", dnsName)
	ns, err := net.LookupNS(dnsName)
	if err != nil {
		return fmt.Errorf("error doing DNS lookup for NS records for %q: %v", dnsName, err)
	}

	if len(ns) == 0 {
		if os.Getenv("DNS_IGNORE_NS_CHECK") == "" {
			return fmt.Errorf("NS records not found for %q - please make sure they are correctly configured", dnsName)
		} else {
			glog.Warningf("Ignoring failed NS record check because DNS_IGNORE_NS_CHECK is set")
		}
	} else {
		var hosts []string
		for _, n := range ns {
			hosts = append(hosts, n.Host)
		}
		glog.V(2).Infof("Found NS records for %q: %v", dnsName, hosts)
	}

	return nil
}

func precreateDNS(cluster *api.Cluster, cloud fi.Cloud) error {
	// TODO: Move to update
	if !featureflag.DNSPreCreate.Enabled() {
		glog.V(4).Infof("Skipping DNS record pre-creation because feature flag not enabled")
		return nil
	}

	glog.Infof("Pre-creating DNS records")

	// We precreate some DNS names (where they don't exist), with a dummy IP address
	// This avoids hitting negative TTL on DNS lookups, which tend to be very long
	// If we get the names wrong here, it doesn't really matter (extra DNS name, slower boot)
	dnsSuffix := cluster.Spec.MasterPublicName

	var dnsHostnames []string

	if cluster.Spec.MasterPublicName != "" {
		dnsHostnames = append(dnsHostnames, cluster.Spec.MasterPublicName)
	} else {
		glog.Warningf("cannot pre-create MasterPublicName - not set")
	}

	if cluster.Spec.MasterInternalName != "" {
		dnsHostnames = append(dnsHostnames, cluster.Spec.MasterInternalName)
	} else {
		glog.Warningf("cannot pre-create MasterInternalName - not set")
	}

	for _, etcdCluster := range cluster.Spec.EtcdClusters {
		etcClusterName := "etcd-" + etcdCluster.Name
		if etcdCluster.Name == "main" {
			// Special case
			etcClusterName = "etcd"
		}
		for _, etcdClusterMember := range etcdCluster.Members {
			name := etcClusterName + "-" + etcdClusterMember.Name + ".internal." + dnsSuffix
			dnsHostnames = append(dnsHostnames, name)
		}
	}

	zone, err := findZone(cluster, cloud)
	if err != nil {
		return err
	}

	rrs, ok := zone.ResourceRecordSets()
	if !ok {
		return fmt.Errorf("error getting DNS resource records for %q", zone.Name())
	}

	records, err := rrs.List()
	if err != nil {
		return fmt.Errorf("error listing DNS resource records for %q: %v", zone.Name(), err)
	}

	recordsMap := make(map[string]dnsprovider.ResourceRecordSet)
	for _, record := range records {
		name := strings.TrimSuffix(record.Name(), ".")
		key := string(record.Type()) + "::" + name
		recordsMap[key] = record
	}

	changeset := rrs.StartChangeset()
	// TODO: Add ChangeSet.IsEmpty() method
	var created []string

	for _, dnsHostname := range dnsHostnames {
		dnsHostname = strings.TrimSuffix(dnsHostname, ".")
		dnsRecord := recordsMap["A::"+dnsHostname]
		found := false
		if dnsRecord != nil {
			rrdatas := dnsRecord.Rrdatas()
			if len(rrdatas) > 0 {
				glog.V(4).Infof("Found DNS record %s => %s; won't create", dnsHostname, rrdatas)
				found = true
			} else {
				// This is probably an alias target; leave it alone...
				glog.V(4).Infof("Found DNS record %s, but no records", dnsHostname)
				found = true
			}
		}

		if found {
			continue
		}

		glog.V(2).Infof("Pre-creating DNS record %s => %s", dnsHostname, PlaceholderIP)

		changeset.Add(rrs.New(dnsHostname, []string{PlaceholderIP}, PlaceholderTTL, rrstype.A))
		created = append(created, dnsHostname)
	}

	if len(created) != 0 {
		err := changeset.Apply()
		if err != nil {
			return fmt.Errorf("Error pre-creating DNS records: %v", err)
		}
		glog.V(2).Infof("Pre-created DNS names: %v", created)
	}

	return nil
}
<|endoftext|>


<commit_before>package usageevents

import (
	"fmt"

	"github.com/cloudfoundry-community/firehose-to-syslog/caching"

	"sync"
	"time"

	"github.com/cloudfoundry/sonde-go/events"
)

// Event is a struct represented an event augmented/decorated with corresponding app/space/org data.
type Event struct {
	//Fields         logrus.Fields `json:"fields"`
	Msg            string `json:"message"`
	Type           string `json:"event_type"`
	Origin         string `json:"origin"`
	AppID          string `json:"app_id"`
	Timestamp      int64  `json:"timestamp"`
	SourceType     string `json:"source_type"`
	MessageType    string `json:"message_type"`
	SourceInstance string `json:"source_instance"`
	AppName        string `json:"app_name"`
	OrgName        string `json:"org_name"`
	SpaceName      string `json:"space_name"`
	OrgID          string `json:"org_id"`
	SpaceID        string `json:"space_id"`
}

/*
"origin":          msg.GetOrigin(),
"cf_app_id":       logMessage.GetAppId(),
"timestamp":       logMessage.GetTimestamp(),
"source_type":     logMessage.GetSourceType(),
"message_type":    logMessage.GetMessageType().String(),
"source_instance": logMessage.GetSourceInstance(),*/

// ApplicationStat represents the observed metadata about an app, e.g. last router event time, etc.
type ApplicationStat struct {
	LastEventTime int64  `json:"last_event_time"`
	LastEvent     Event  `json:"last_event"`
	EventCount    int64  `json:"event_count"`
	AppName       string `json:"app_name"`
	OrgName       string `json:"org_name"`
	SpaceName     string `json:"space_name"`
}

// ApplicationDetail represents a time snapshot of the RPS and elapsed time since last event for an app
type ApplicationDetail struct {
	Stats                 ApplicationStat `json:"stats"`
	RequestsPerSecond     float64         `json:"req_per_second"`
	ElapsedSinceLastEvent int64           `json:"elapsed_since_last_event"`
}

var mutex sync.Mutex

// AppStats is a map of app names to collected stats.
var AppStats = make(map[string]ApplicationStat)

var feedStarted int64

// ProcessEvents churns through the firehose channel, processing incoming events.
func ProcessEvents(in chan *events.Envelope) {
	feedStarted = time.Now().UnixNano()
	for msg := range in {
		processEvent(msg)
	}
}

func processEvent(msg *events.Envelope) {
	eventType := msg.GetEventType()

	var event Event
	if eventType == events.Envelope_LogMessage {
		event = LogMessage(msg)
		if event.SourceType == "RTR" {
			event.AnnotateWithAppData()
			updateAppStat(event)
		}
	}
	//fmt.Println("tick")
}

// CalculateDetailedStat takes application stats, uses the clock time, and calculates elapsed times and requests/second.
func CalculateDetailedStat(stat ApplicationStat) (detail ApplicationDetail) {
	detail.Stats = stat
	if len(stat.LastEvent.Type) > 0 {
		eventElapsed := time.Now().UnixNano() - stat.LastEventTime
		detail.ElapsedSinceLastEvent = eventElapsed / 1000000000
		totalElapsed := time.Now().UnixNano() - feedStarted
		elapsedSeconds := totalElapsed / 1000000000
		detail.RequestsPerSecond = float64(stat.EventCount) / float64(elapsedSeconds)
	}
	return
}

// GetMapKeyFromAppData converts the combo of an app, space, and org into a hashmap key
func GetMapKeyFromAppData(orgName string, spaceName string, appName string) string {
	return fmt.Sprintf("%s/%s/%s", orgName, spaceName, appName)
}

func updateAppStat(logEvent Event) {
	appName := logEvent.AppName
	appOrg := logEvent.OrgName
	appSpace := logEvent.SpaceName

	appKey := GetMapKeyFromAppData(appOrg, appSpace, appName)
	appStat := AppStats[appKey]
	appStat.LastEventTime = time.Now().UnixNano()
	appStat.EventCount++
	appStat.AppName = appName
	appStat.SpaceName = appSpace
	appStat.OrgName = appOrg
	appStat.LastEvent = logEvent
	AppStats[appKey] = appStat
}

func getAppInfo(appGUID string) caching.App {
	if app := caching.GetAppInfo(appGUID); app.Name != "" {
		return app
	}
	caching.GetAppByGuid(appGUID)

	return caching.GetAppInfo(appGUID)
}

// LogMessage augments a raw message Envelope with log message metadata.
func LogMessage(msg *events.Envelope) Event {
	logMessage := msg.GetLogMessage()

	return Event{
		Origin:         msg.GetOrigin(),
		AppID:          logMessage.GetAppId(),
		Timestamp:      logMessage.GetTimestamp(),
		SourceType:     logMessage.GetSourceType(),
		SourceInstance: logMessage.GetSourceInstance(),
		MessageType:    logMessage.GetMessageType().String(),
		Msg:            string(logMessage.GetMessage()),
		Type:           msg.GetEventType().String(),
	}
}

// AnnotateWithAppData adds application specific details to an event by looking up the GUID in the cache.
func (e *Event) AnnotateWithAppData() {

	cfAppID := e.AppID
	appGUID := ""
	if cfAppID != "" {
		appGUID = fmt.Sprintf("%s", cfAppID)
	}

	if appGUID != "<nil>" && cfAppID != "" {
		appInfo := getAppInfo(appGUID)
		cfAppName := appInfo.Name
		cf_space_id := appInfo.SpaceGuid
		cf_space_name := appInfo.SpaceName
		cf_org_id := appInfo.OrgGuid
		cf_org_name := appInfo.OrgName

		if cfAppName != "" {
			e.AppName = cfAppName
		}

		if cf_space_id != "" {
			e.SpaceID = cf_space_id
		}

		if cf_space_name != "" {
			e.SpaceName = cf_space_name
		}

		if cf_org_id != "" {
			e.OrgID = cf_org_id
		}

		if cf_org_name != "" {
			e.OrgName = cf_org_name
		}
	}
}
<commit_msg>Refactoring variable names to more idiomatic Go<commit_after>package usageevents

import (
	"fmt"

	"github.com/cloudfoundry-community/firehose-to-syslog/caching"

	"sync"
	"time"

	"github.com/cloudfoundry/sonde-go/events"
)

// Event is a struct represented an event augmented/decorated with corresponding app/space/org data.
type Event struct {
	Msg            string `json:"message"`
	Type           string `json:"event_type"`
	Origin         string `json:"origin"`
	AppID          string `json:"app_id"`
	Timestamp      int64  `json:"timestamp"`
	SourceType     string `json:"source_type"`
	MessageType    string `json:"message_type"`
	SourceInstance string `json:"source_instance"`
	AppName        string `json:"app_name"`
	OrgName        string `json:"org_name"`
	SpaceName      string `json:"space_name"`
	OrgID          string `json:"org_id"`
	SpaceID        string `json:"space_id"`
}

// ApplicationStat represents the observed metadata about an app, e.g. last router event time, etc.
type ApplicationStat struct {
	LastEventTime int64  `json:"last_event_time"`
	LastEvent     Event  `json:"last_event"`
	EventCount    int64  `json:"event_count"`
	AppName       string `json:"app_name"`
	OrgName       string `json:"org_name"`
	SpaceName     string `json:"space_name"`
}

// ApplicationDetail represents a time snapshot of the RPS and elapsed time since last event for an app
type ApplicationDetail struct {
	Stats                 ApplicationStat `json:"stats"`
	RequestsPerSecond     float64         `json:"req_per_second"`
	ElapsedSinceLastEvent int64           `json:"elapsed_since_last_event"`
}

var mutex sync.Mutex

// AppStats is a map of app names to collected stats.
var AppStats = make(map[string]ApplicationStat)

var feedStarted int64

// ProcessEvents churns through the firehose channel, processing incoming events.
func ProcessEvents(in chan *events.Envelope) {
	feedStarted = time.Now().UnixNano()
	for msg := range in {
		processEvent(msg)
	}
}

func processEvent(msg *events.Envelope) {
	eventType := msg.GetEventType()

	var event Event
	if eventType == events.Envelope_LogMessage {
		event = LogMessage(msg)
		if event.SourceType == "RTR" {
			event.AnnotateWithAppData()
			updateAppStat(event)
		}
	}
}

// CalculateDetailedStat takes application stats, uses the clock time, and calculates elapsed times and requests/second.
func CalculateDetailedStat(stat ApplicationStat) (detail ApplicationDetail) {
	detail.Stats = stat
	if len(stat.LastEvent.Type) > 0 {
		eventElapsed := time.Now().UnixNano() - stat.LastEventTime
		detail.ElapsedSinceLastEvent = eventElapsed / 1000000000
		totalElapsed := time.Now().UnixNano() - feedStarted
		elapsedSeconds := totalElapsed / 1000000000
		detail.RequestsPerSecond = float64(stat.EventCount) / float64(elapsedSeconds)
	}
	return
}

// GetMapKeyFromAppData converts the combo of an app, space, and org into a hashmap key
func GetMapKeyFromAppData(orgName string, spaceName string, appName string) string {
	return fmt.Sprintf("%s/%s/%s", orgName, spaceName, appName)
}

func updateAppStat(logEvent Event) {
	appName := logEvent.AppName
	appOrg := logEvent.OrgName
	appSpace := logEvent.SpaceName

	appKey := GetMapKeyFromAppData(appOrg, appSpace, appName)
	appStat := AppStats[appKey]
	appStat.LastEventTime = time.Now().UnixNano()
	appStat.EventCount++
	appStat.AppName = appName
	appStat.SpaceName = appSpace
	appStat.OrgName = appOrg
	appStat.LastEvent = logEvent
	AppStats[appKey] = appStat
}

func getAppInfo(appGUID string) caching.App {
	if app := caching.GetAppInfo(appGUID); app.Name != "" {
		return app
	}
	caching.GetAppByGuid(appGUID)

	return caching.GetAppInfo(appGUID)
}

// LogMessage augments a raw message Envelope with log message metadata.
func LogMessage(msg *events.Envelope) Event {
	logMessage := msg.GetLogMessage()

	return Event{
		Origin:         msg.GetOrigin(),
		AppID:          logMessage.GetAppId(),
		Timestamp:      logMessage.GetTimestamp(),
		SourceType:     logMessage.GetSourceType(),
		SourceInstance: logMessage.GetSourceInstance(),
		MessageType:    logMessage.GetMessageType().String(),
		Msg:            string(logMessage.GetMessage()),
		Type:           msg.GetEventType().String(),
	}
}

// AnnotateWithAppData adds application specific details to an event by looking up the GUID in the cache.
func (e *Event) AnnotateWithAppData() {

	cfAppID := e.AppID
	appGUID := ""
	if cfAppID != "" {
		appGUID = fmt.Sprintf("%s", cfAppID)
	}

	if appGUID != "<nil>" && cfAppID != "" {
		appInfo := getAppInfo(appGUID)
		cfAppName := appInfo.Name
		cfSpaceID := appInfo.SpaceGuid
		cfSpaceName := appInfo.SpaceName
		cfOrgID := appInfo.OrgGuid
		cfOrgName := appInfo.OrgName

		if cfAppName != "" {
			e.AppName = cfAppName
		}

		if cfSpaceID != "" {
			e.SpaceID = cfSpaceID
		}

		if cfSpaceName != "" {
			e.SpaceName = cfSpaceName
		}

		if cfOrgID != "" {
			e.OrgID = cfOrgID
		}

		if cfOrgName != "" {
			e.OrgName = cfOrgName
		}
	}
}
<|endoftext|>


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

// Limited clone of cat. Can only read files, not standard input, and only one file.
package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Wrong number of arguments.")
		os.Exit(2)
	}
	f, err := os.Open(os.Args[1])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer f.Close()
	_, err = io.Copy(os.Stdout, f)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>basic/cat: fix formatting of code<commit_after>// Copyright 2013 Francisco Souza. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Limited clone of cat. Can only read files, not standard input, and only one
// file.
package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Wrong number of arguments.")
		os.Exit(2)
	}
	f, err := os.Open(os.Args[1])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer f.Close()
	_, err = io.Copy(os.Stdout, f)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"../../builder"
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"os"
	"strings"
)

func addRemote(url *string, job builder.Job) (int, error) {
	j, err := json.Marshal(job)
	if err != nil {
		builder.LogFail(err, "Can't marshal job: %v")
	}

	resp, err := http.Post(*url, "application/json", bytes.NewReader(j))
	if err != nil {
		log.Fatalf("Can't connect to '%s'", url)
	}
	res := &builder.Resp{}
	if err := json.NewDecoder(resp.Body).Decode(res); err != nil {
		log.Fatalf("Invalid response from server! %v", err)
	}

	resp.Body.Close()

	if res.Error != "" {
		log.Fatalf(res.Error)
	}

	return res.JobID, nil
}

func addLocal(job builder.Job, lines []string) (int, error) {
	db, err := builder.Connect()
	builder.LogFail(err, "Can't connect to DB: %v")

	jobid, err := builder.CreateJob(db, &job)
	builder.LogFail(err, "Can't create job: %v")

	log.Printf("Created jobid %d", jobid)
	return jobid, nil
}

func main() {
	var url = flag.String("url", "http://localhost:8001/new", "URL of server")
	var dfile = flag.String("diff", "", "Diff to be tested")
	var title = flag.String("title", "", "Title of job")
	var desc = flag.String("desc", "", "Description of job")
	var port = flag.String("port", "", "Port being updated")
	var lines []string

	flag.Parse()
	file, err := os.Open(*dfile)

	defer file.Close()
	if err != nil {
		log.Fatalf("Can't open file! - %v", err)
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	var job = builder.Job{Title: *title, Descr: *desc, Port: *port, Diffdata: strings.Join(lines, "\n")}
	jobid, err := addRemote(url, job)
	if err != nil {
		log.Fatalf("Can't blablab")
	}

	log.Printf("Title: %s, Desc: %s, JobID: %d", *title, *desc, jobid)
}
<commit_msg>pgenv changes<commit_after>package main

import (
	"../../builder"
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"os"
	"strings"
)

func addRemote(url *string, job builder.Job) (int, error) {
	j, err := json.Marshal(job)
	if err != nil {
		builder.LogFail(err, "Can't marshal job: %v")
	}

	resp, err := http.Post(*url, "application/json", bytes.NewReader(j))
	if err != nil {
		log.Fatalf("Can't connect to '%s'", url)
	}
	res := &builder.Resp{}
	if err := json.NewDecoder(resp.Body).Decode(res); err != nil {
		log.Fatalf("Invalid response from server! %v", err)
	}

	resp.Body.Close()

	if res.Error != "" {
		log.Fatalf(res.Error)
	}

	return res.JobID, nil
}

func addLocal(job builder.Job, lines []string) (int, error) {
	dbuser, dbpass, dbname := builder.GetCreds()

	db, err := builder.Connect(dbuser, dbpass, dbname)
	builder.LogFail(err, "Can't connect to DB: %v")

	jobid, err := builder.CreateJob(db, &job)
	builder.LogFail(err, "Can't create job: %v")

	log.Printf("Created jobid %d", jobid)
	return jobid, nil
}

func main() {
	var url = flag.String("url", "http://localhost:8001/new", "URL of server")
	var dfile = flag.String("diff", "", "Diff to be tested")
	var title = flag.String("title", "", "Title of job")
	var desc = flag.String("desc", "", "Description of job")
	var port = flag.String("port", "", "Port being updated")
	var lines []string

	flag.Parse()
	file, err := os.Open(*dfile)

	defer file.Close()
	if err != nil {
		log.Fatalf("Can't open file! - %v", err)
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	var job = builder.Job{Title: *title, Descr: *desc, Port: *port, Diffdata: strings.Join(lines, "\n")}
	jobid, err := addRemote(url, job)
	if err != nil {
		log.Fatalf("Can't blablab")
	}

	log.Printf("Title: %s, Desc: %s, JobID: %d", *title, *desc, jobid)
}
<|endoftext|>


<commit_before>package beat

import (
	"flag"
	"fmt"
	"os"
	"runtime"

	"github.com/elastic/libbeat/cfgfile"
	"github.com/elastic/libbeat/logp"
	"github.com/elastic/libbeat/outputs"
	"github.com/elastic/libbeat/publisher"
	"github.com/elastic/libbeat/service"
)

// Beater interface that every beat must use
type Beater interface {
	Config(*Beat) error
	Setup(*Beat) error
	Run(*Beat) error
	Cleanup(*Beat) error
	Stop()
}

// Extended Beater interface for additional CLI handling before loading the
// config file
type CLIBeater interface {
	Beater

	CLIFlags(*Beat)
}

// Basic beat information
type Beat struct {
	Name    string
	Version string
	Config  *BeatConfig
	BT      Beater
	Events  publisher.Client
}

// Basic configuration of every beat
type BeatConfig struct {
	Output  map[string]outputs.MothershipConfig
	Logging logp.Logging
	Shipper publisher.ShipperConfig
}

var printVersion *bool

func init() {
	printVersion = flag.Bool("version", false, "Print version and exit")
}

// Initiates a new beat object
func NewBeat(name string, version string, bt Beater) *Beat {
	b := Beat{
		Version: version,
		Name:    name,
		BT:      bt,
	}

	return &b
}

// Initiates and runs a new beat object
func Run(name string, version string, bt Beater) *Beat {
	b := NewBeat(name, version, bt)

	// Additional command line args are used to overwrite config options
	b.CommandLineSetup()

	// Loads base config
	b.LoadConfig()

	// Configures beat
	err := bt.Config(b)
	if err != nil {
		logp.Critical("Config error: %v", err)
		os.Exit(1)
	}

	// Run beat. This calls first beater.Setup,
	// then beater.Run and beater.Cleanup in the end
	b.Run()

	return b
}

// Reads and parses the default command line params
// To set additional cmd line args use the beat.CmdLine type before calling the function
func (beat *Beat) CommandLineSetup() {

	// The -c flag is treated separately because it needs the Beat name
	err := cfgfile.ChangeDefaultCfgfileFlag(beat.Name)
	if err != nil {
		fmt.Printf("Failed to fix the -c flag: %v\n", err)
		os.Exit(1)
	}

	flag.Parse()

	if *printVersion {
		fmt.Printf("%s version %s (%s)\n", beat.Name, beat.Version, runtime.GOARCH)
		os.Exit(0)
	}

	// if beater implements CLIFlags for additional CLI handling, call it now
	if cliExtra, ok := beat.BT.(CLIBeater); ok {
		cliExtra.CLIFlags(beat)
	}
}

// LoadConfig inits the config file and reads the default config information
// into Beat.Config. It exists the processes in case of errors.
func (b *Beat) LoadConfig() {

	err := cfgfile.Read(&b.Config, "")
	if err != nil {
		// logging not yet initialized, so using fmt.Printf
		fmt.Printf("Loading config file error: %v\n", err)
		os.Exit(1)
	}

	err = logp.Init(b.Name, &b.Config.Logging)
	if err != nil {
		fmt.Printf("Error initializing logging: %v\n", err)
		os.Exit(1)
	}

	// Disable stderr logging if requested by cmdline flag
	logp.SetStderr()

	logp.Debug("beat", "Initializing output plugins")

	if err := publisher.Publisher.Init(b.Name, b.Config.Output, b.Config.Shipper); err != nil {
		fmt.Printf("Error Initialising publisher: %v\n", err)
		logp.Critical(err.Error())
		os.Exit(1)
	}

	b.Events = publisher.Publisher.Client()

	logp.Info("Init Beat: %s; Version: %s", b.Name, b.Version)
}

// Run calls the beater Setup and Run methods. In case of errors
// during the setup phase, it exits the process.
func (b *Beat) Run() {

	// Setup beater object
	err := b.BT.Setup(b)
	if err != nil {
		logp.Critical("Setup returned an error: %v", err)
		os.Exit(1)
	}

	// Up to here was the initialization, now about running
	if cfgfile.IsTestConfig() {
		// all good, exit with 0
		os.Exit(0)
	}
	service.BeforeRun()

	// Callback is called if the processes is asked to stop.
	// This needs to be called before the main loop is started so that
	// it can register the signals that stop or query (on Windows) the loop.
	service.HandleSignals(b.BT.Stop)

	logp.Info("%s sucessfully setup. Start running.", b.Name)

	// Run beater specific stuff
	err = b.BT.Run(b)
	if err != nil {
		logp.Critical("Run returned an error: %v", err)
	}

	service.Cleanup()

	logp.Info("Cleaning up %s before shutting down.", b.Name)

	// Call beater cleanup function
	err = b.BT.Cleanup(b)
	if err != nil {
		logp.Err("Cleanup returned an error: %v", err)
	}
}

// Stop calls the beater Stop action.
func (beat *Beat) Stop() {
	beat.BT.Stop()
}
<commit_msg>Refactor CLIBeater to FlagsHandler<commit_after>package beat

import (
	"flag"
	"fmt"
	"os"
	"runtime"

	"github.com/elastic/libbeat/cfgfile"
	"github.com/elastic/libbeat/logp"
	"github.com/elastic/libbeat/outputs"
	"github.com/elastic/libbeat/publisher"
	"github.com/elastic/libbeat/service"
)

// Beater interface that every beat must use
type Beater interface {
	Config(*Beat) error
	Setup(*Beat) error
	Run(*Beat) error
	Cleanup(*Beat) error
	Stop()
}

// FlagsHandler (optional) Beater extension for
// handling flags input on startup. The HandleFlags callback will
// be called after parsing the command line arguments and handling
// the '--help' or '--version' flags.
type FlagsHandler interface {
	HandleFlags(*Beat)
}

// Basic beat information
type Beat struct {
	Name    string
	Version string
	Config  *BeatConfig
	BT      Beater
	Events  publisher.Client
}

// Basic configuration of every beat
type BeatConfig struct {
	Output  map[string]outputs.MothershipConfig
	Logging logp.Logging
	Shipper publisher.ShipperConfig
}

var printVersion *bool

func init() {
	printVersion = flag.Bool("version", false, "Print version and exit")
}

// Initiates a new beat object
func NewBeat(name string, version string, bt Beater) *Beat {
	b := Beat{
		Version: version,
		Name:    name,
		BT:      bt,
	}

	return &b
}

// Initiates and runs a new beat object
func Run(name string, version string, bt Beater) *Beat {
	b := NewBeat(name, version, bt)

	// Additional command line args are used to overwrite config options
	b.CommandLineSetup()

	// Loads base config
	b.LoadConfig()

	// Configures beat
	err := bt.Config(b)
	if err != nil {
		logp.Critical("Config error: %v", err)
		os.Exit(1)
	}

	// Run beat. This calls first beater.Setup,
	// then beater.Run and beater.Cleanup in the end
	b.Run()

	return b
}

// Reads and parses the default command line params
// To set additional cmd line args use the beat.CmdLine type before calling the function
func (beat *Beat) CommandLineSetup() {

	// The -c flag is treated separately because it needs the Beat name
	err := cfgfile.ChangeDefaultCfgfileFlag(beat.Name)
	if err != nil {
		fmt.Printf("Failed to fix the -c flag: %v\n", err)
		os.Exit(1)
	}

	flag.Parse()

	if *printVersion {
		fmt.Printf("%s version %s (%s)\n", beat.Name, beat.Version, runtime.GOARCH)
		os.Exit(0)
	}

	// if beater implements CLIFlags for additional CLI handling, call it now
	if flagsHandler, ok := beat.BT.(FlagsHandler); ok {
		flagsHandler.HandleFlags(beat)
	}
}

// LoadConfig inits the config file and reads the default config information
// into Beat.Config. It exists the processes in case of errors.
func (b *Beat) LoadConfig() {

	err := cfgfile.Read(&b.Config, "")
	if err != nil {
		// logging not yet initialized, so using fmt.Printf
		fmt.Printf("Loading config file error: %v\n", err)
		os.Exit(1)
	}

	err = logp.Init(b.Name, &b.Config.Logging)
	if err != nil {
		fmt.Printf("Error initializing logging: %v\n", err)
		os.Exit(1)
	}

	// Disable stderr logging if requested by cmdline flag
	logp.SetStderr()

	logp.Debug("beat", "Initializing output plugins")

	if err := publisher.Publisher.Init(b.Name, b.Config.Output, b.Config.Shipper); err != nil {
		fmt.Printf("Error Initialising publisher: %v\n", err)
		logp.Critical(err.Error())
		os.Exit(1)
	}

	b.Events = publisher.Publisher.Client()

	logp.Info("Init Beat: %s; Version: %s", b.Name, b.Version)
}

// Run calls the beater Setup and Run methods. In case of errors
// during the setup phase, it exits the process.
func (b *Beat) Run() {

	// Setup beater object
	err := b.BT.Setup(b)
	if err != nil {
		logp.Critical("Setup returned an error: %v", err)
		os.Exit(1)
	}

	// Up to here was the initialization, now about running
	if cfgfile.IsTestConfig() {
		// all good, exit with 0
		os.Exit(0)
	}
	service.BeforeRun()

	// Callback is called if the processes is asked to stop.
	// This needs to be called before the main loop is started so that
	// it can register the signals that stop or query (on Windows) the loop.
	service.HandleSignals(b.BT.Stop)

	logp.Info("%s sucessfully setup. Start running.", b.Name)

	// Run beater specific stuff
	err = b.BT.Run(b)
	if err != nil {
		logp.Critical("Run returned an error: %v", err)
	}

	service.Cleanup()

	logp.Info("Cleaning up %s before shutting down.", b.Name)

	// Call beater cleanup function
	err = b.BT.Cleanup(b)
	if err != nil {
		logp.Err("Cleanup returned an error: %v", err)
	}
}

// Stop calls the beater Stop action.
func (beat *Beat) Stop() {
	beat.BT.Stop()
}
<|endoftext|>


<commit_before>package orm

// The ORM package is designed to tie everything together: a database connection, schema,
// relevant objects, etc. The current design is a WIP. While not finished, it is serviceable
// and can be used effectively.

import (
	"context"
	"database/sql"
	"fmt"
	"os"

	"github.com/pkg/errors"
	"github.com/rbastic/dyndao/object"
	"github.com/rbastic/dyndao/schema"
)

// GetParentsViaChild retrieves all direct (one-level 'up') parents for a given child object.
// If a child contains multiple parent tables (possibility?) then this would return an Array
// of objects with multiple potential values for their obj.Type fields.
func (o ORM) GetParentsViaChild(ctx context.Context, childObj *object.Object) (object.Array, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	table := childObj.Type

	// Retrieve schema table object
	objTable := o.s.GetTable(table)
	if objTable == nil {
		return nil, errors.New("GetParentsViaChild: unknown object table " + table)
	}

	var parentObjs object.Array
	// This method can only work if the schema is configured hierarchically
	if objTable.ParentTables == nil {
		return nil, errors.New("GetParentsViaChild: cannot retrieve parents for table " + table + ", schema ParentTables is nil")
	}
	for _, pt := range objTable.ParentTables {
		// 'Capture' the primary key(s)
		pkQueryVals, err := pkQueryValsFromKV(childObj, o.s, pt)
		if err != nil {
			return nil, err
		}
		// Retrieve + append the relevant parent objs
		objs, err := o.RetrieveMany(ctx, pt, pkQueryVals)
		if err != nil {
			return nil, err
		}
		parentObjs = append(parentObjs, objs...)
	}

	return parentObjs, nil
}

// RetrieveWithChildren function will fleshen an *entire* object structure, given some primary keys
// By entire, we mean that we also retrieve any relevant children objects. However, we do not call RetrieveWithChildren
// when fleshening the children structures -- when retrieving the children, we do a single-level retrieve, ignoring
// any child structures that may be configured at two levels of depth.
func (o ORM) RetrieveWithChildren(ctx context.Context, table string, pkValues map[string]interface{}) (*object.Object, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	// Retrieve schema.Table object
	objTable := o.s.GetTable(table)
	if objTable == nil {
		return nil, errors.New("RetrieveWithChildren: unknown object table " + table)
	}

	// Retrieve single object from database
	obj, err := o.Retrieve(ctx, table, pkValues)
	if err != nil {
		return nil, errors.Wrap(err, "RetrieveWithChildren/Retrieve")
	}

	// Iterate the configured 'children' for this particular object type
	for name := range objTable.Children {
		childPkValues := make(map[string]interface{})

		// Retrieve the active 'schema table' for this child
		childSchemaTable := o.s.GetTable(name)
		if childSchemaTable == nil {
			return nil, fmt.Errorf("RetrieveWithChildren: unknown object table for child type %s", name)
		}

		// (For each child...) Propagate the 'primary key value' from the parent object if needed.
		childPkName := childSchemaTable.Primary
		pVal, ok := pkValues[childPkName]
		if ok {
			childPkValues[childPkName] = pVal
		}

		// Propagate foreign key values for retrieval
		if childSchemaTable.MultiKey && childSchemaTable.ForeignKeys != nil {
			for _, fk := range childSchemaTable.ForeignKeys {
				// TODO: Check that value exists before we
				// attempt to set?
				/*
					v, ok := pkValues[fk]
					if ok {
						childPkValues[fk] = v
					} else {
						// TODO: is this an error condition?
					}
				*/

				childPkValues[fk] = pkValues[fk]
			}
		}

		// Retrieve a single child (TODO: Implement RetrieveMany options as well)
		childObj, err := o.Retrieve(ctx, name, childPkValues)
		if err != nil {
			return nil, errors.Wrap(err, "RetrieveWithChildren/Retrieve("+name+")")
		}
		// Populate single child inside parent
		if obj.Children[name] == nil {
			obj.Children[name] = make(object.Array, 1)
		}
		obj.Children[name][0] = childObj
	}

	return obj, nil
}

// retrieveCore function will fleshen an object structure, given some primary keys.
// Technically, we call RetrieveMany internally. Since we do not have LIMIT implemented yet,
// it's just a cheap implementation that returns the zeroeth value. Nil will be returned
// for both the object and the error if a row is unable to be matched by the underlying
// datastore.
// TODO: Implement LIMIT so that we can improve this.
func (o ORM) retrieveCore(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (*object.Object, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	objAry, err := o.retrieveManyCore(ctx, tx, table, queryVals)
	if err != nil {
		return nil, err
	}
	// We return nil, nil to indicate a lack of result.
	if objAry == nil {
		return nil, nil
	}
	return objAry[0], nil
}

// RetrieveTx function will fleshen an object structure, given some primary keys.
// Technically, we call RetrieveMany internally. Since we do not have LIMIT implemented yet,
// it's just a cheap implementation that returns the zeroeth value. Nil will be returned
// for both the object and the error if a row is unable to be matched by the underlying
// datastore.
// TODO: Implement LIMIT so that we can improve this.
func (o ORM) RetrieveTx(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (*object.Object, error) {
	return o.retrieveCore(ctx, tx, table, queryVals)
}

// Retrieve function will fleshen an object structure, given some primary keys.
// Technically, we call RetrieveMany internally. Since we do not have LIMIT implemented yet,
// it's just a cheap implementation that returns the zeroeth value. Nil will be returned
// for both the object and the error if a row is unable to be matched by the underlying
// datastore.
// TODO: Implement LIMIT so that we can improve this.
func (o ORM) Retrieve(ctx context.Context, table string, queryVals map[string]interface{}) (*object.Object, error) {
	return o.retrieveCore(ctx, nil, table, queryVals)
}

// FleshenChildren function accepts an object and resets it's children.
func (o ORM) FleshenChildren(ctx context.Context, obj *object.Object) (*object.Object, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	// Retrieve schema configuration for this object type (schema.Table)
	schemaTable := o.s.GetTable(obj.Type)

	// Retrieve primary key
	pkKey := schemaTable.Primary
	pkVal := obj.Get(pkKey)

	// If this table is configured with child tables, then we iterate over
	// them and call RetrieveMany using the singular primary key value.
	// FIXME: We need to support multikey in this instance if we are going
	// to consider this complete.
	if len(schemaTable.Children) > 0 {
		for childTableName := range schemaTable.Children {
			// TODO: multi-key support here...
			m := map[string]interface{}{}
			m[pkKey] = pkVal
			childObjs, err := o.RetrieveMany(ctx, childTableName, m)
			if err != nil {
				return nil, err
			}
			obj.Children[childTableName] = childObjs
		}
	}
	return obj, nil
}

// RetrieveManyFromCustomSQL will fleshen an object structure, given a custom SQL string. It must still be told
// the column names and the binding arguments in addition to the SQL string, so that it can dynamically map
// the column types accordingly to the destination object. (Mainly, so we know the array length..)
func (o ORM) RetrieveManyFromCustomSQL(ctx context.Context, table string, sqlStr string, columnNames []string, bindArgs []interface{}) (object.Array, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	var objectArray object.Array

	if os.Getenv("DEBUG_RETRIEVECUSTOM") != "" {
		fmt.Println("RetrieveManyFromCustomSQL/sqlStr=", sqlStr, "columnNames=", columnNames, "bindArgs=", bindArgs)
	}

	stmt, err := o.RawConn.PrepareContext(ctx, sqlStr)
	if err != nil {
		return nil, err
	}
	defer func() {
		stmtErr := stmt.Close()
		if stmtErr != nil {
			fmt.Println("defer stmt.Close error:", stmtErr) // TODO: logger implementation
		}
	}()

	res, err := stmt.QueryContext(ctx, bindArgs...)
	if err != nil {
		return nil, err
	}
	defer func() {
		resErr := res.Close()
		if resErr != nil {
			fmt.Println("defer res.Close error:", resErr) // TODO: logger implementation
		}
	}()

	columnTypes, err := res.ColumnTypes()
	if err != nil {
		return nil, err
	}
	sg := o.sqlGen
	for res.Next() {
		columnPointers, err := sg.MakeColumnPointers(len(columnNames), columnTypes)
		if err != nil {
			return nil, err
		}

		if err := res.Scan(columnPointers...); err != nil {
			return nil, err
		}

		obj := object.New(table)
		err = sg.DynamicObjectSetter(columnNames, columnPointers, columnTypes, obj)
		if err != nil {
			return nil, err
		}

		obj.SetSaved(true)
		obj.ResetChangedFields()

		objectArray = append(objectArray, obj)
	}

	err = res.Err()
	if err != nil {
		return nil, err
	}
	return objectArray, nil
}

func (o ORM) makeQueryObj(objTable *schema.Table, queryVals map[string]interface{}) *object.Object {
	queryObj := object.New(objTable.Name)

	if objTable.FieldAliases == nil {
		queryObj.KV = queryVals
		return queryObj
	}
	for k, v := range queryVals {
		realName := objTable.GetFieldName(k)
		queryObj.KV[realName] = v
	}
	return queryObj
}

func (o ORM) retrieveManyCore(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (object.Array, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}

	objTable := o.s.GetTable(table)
	if objTable == nil {
		return nil, errors.New("RetrieveMany: unknown object table " + table)
	}
	if objTable.Name == "" {
		return nil, errors.New("RetrieveMany: schema table object has unset 'Name' property")
	}

	var objectArray object.Array
	queryObj := o.makeQueryObj(objTable, queryVals)

	sqlStr, columnNames, bindArgs, err := o.sqlGen.BindingRetrieve(o.s, queryObj)
	if os.Getenv("DEBUG_RETRIEVEMANY") != "" {
		fmt.Println("RetrieveMany/sqlStr=", sqlStr, "columnNames=", columnNames, "bindArgs=", bindArgs)
	}

	if err != nil {
		return nil, err
	}

	stmt, err := stmtFromDbOrTx(ctx, o, tx, sqlStr)
	if err != nil {
		return nil, err
	}

	defer func() {
		err := stmt.Close()
		if err != nil {
			fmt.Println(err) // TODO logger implementation
		}
	}()

	res, err := stmt.QueryContext(ctx, bindArgs...)
	if err != nil {
		return nil, err
	}

	defer func() {
		err := res.Close()
		if err != nil {
			fmt.Println(err) // TODO logger implementation
		}
	}()

	columnTypes, err := res.ColumnTypes()
	if err != nil {
		return nil, err
	}

	sg := o.sqlGen
	for res.Next() {
		columnPointers, err := sg.MakeColumnPointers(len(columnNames), columnTypes)
		if err != nil {
			return nil, err
		}

		obj := object.New(table)
		if err := res.Scan(columnPointers...); err != nil {
			return nil, err
		}

		err = sg.DynamicObjectSetter(columnNames, columnPointers, columnTypes, obj)
		if err != nil {
			return nil, err
		}

		obj.SetSaved(true)
		obj.ResetChangedFields()
		objectArray = append(objectArray, obj)
	}

	err = res.Err()
	if err != nil {
		return nil, err
	}
	return objectArray, nil
}

// RetrieveManyTx function will fleshen a top-level object structure, given some primary keys. And
// it's transactional!
func (o ORM) RetrieveManyTx(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (object.Array, error) {
	return o.retrieveManyCore(ctx, tx, table, queryVals)
}

// RetrieveMany function will fleshen a top-level object structure, given some primary keys
func (o ORM) RetrieveMany(ctx context.Context, table string, queryVals map[string]interface{}) (object.Array, error) {
	return o.retrieveManyCore(ctx, nil, table, queryVals)
}
<commit_msg>some comments<commit_after>package orm

// The ORM package is designed to tie everything together: a database connection, schema,
// relevant objects, etc. The current design is a WIP. While not finished, it is serviceable
// and can be used effectively.

import (
	"context"
	"database/sql"
	"fmt"
	"os"

	"github.com/pkg/errors"
	"github.com/rbastic/dyndao/object"
	"github.com/rbastic/dyndao/schema"
)

// GetParentsViaChild retrieves all direct (one-level 'up') parents for a given child object.
// If a child contains multiple parent tables (possibility?) then this would return an Array
// of objects with multiple potential values for their obj.Type fields.
func (o ORM) GetParentsViaChild(ctx context.Context, childObj *object.Object) (object.Array, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	table := childObj.Type

	// Retrieve schema table object
	objTable := o.s.GetTable(table)
	if objTable == nil {
		return nil, errors.New("GetParentsViaChild: unknown object table " + table)
	}

	var parentObjs object.Array
	// This method can only work if the schema is configured hierarchically
	if objTable.ParentTables == nil {
		return nil, errors.New("GetParentsViaChild: cannot retrieve parents for table " + table + ", schema ParentTables is nil")
	}
	for _, pt := range objTable.ParentTables {
		// 'Capture' the primary key(s)
		pkQueryVals, err := pkQueryValsFromKV(childObj, o.s, pt)
		if err != nil {
			return nil, err
		}
		// Retrieve + append the relevant parent objs
		objs, err := o.RetrieveMany(ctx, pt, pkQueryVals)
		if err != nil {
			return nil, err
		}
		parentObjs = append(parentObjs, objs...)
	}

	return parentObjs, nil
}

// RetrieveWithChildren function will fleshen an *entire* object structure, given some primary keys
// By entire, we mean that we also retrieve any relevant children objects. However, we do not call RetrieveWithChildren
// when fleshening the children structures -- when retrieving the children, we do a single-level retrieve, ignoring
// any child structures that may be configured at two levels of depth.
func (o ORM) RetrieveWithChildren(ctx context.Context, table string, pkValues map[string]interface{}) (*object.Object, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	// Retrieve schema.Table object
	objTable := o.s.GetTable(table)
	if objTable == nil {
		return nil, errors.New("RetrieveWithChildren: unknown object table " + table)
	}

	// Retrieve single object from database
	obj, err := o.Retrieve(ctx, table, pkValues)
	if err != nil {
		return nil, errors.Wrap(err, "RetrieveWithChildren/Retrieve")
	}

	// Iterate the configured 'children' for this particular object type
	for name := range objTable.Children {
		childPkValues := make(map[string]interface{})

		// Retrieve the active 'schema table' for this child
		childSchemaTable := o.s.GetTable(name)
		if childSchemaTable == nil {
			return nil, fmt.Errorf("RetrieveWithChildren: unknown object table for child type %s", name)
		}

		// (For each child...) Propagate the 'primary key value' from the parent object if needed.
		childPkName := childSchemaTable.Primary
		pVal, ok := pkValues[childPkName]
		if ok {
			childPkValues[childPkName] = pVal
		}

		// Propagate foreign key values for retrieval
		if childSchemaTable.MultiKey && childSchemaTable.ForeignKeys != nil {
			for _, fk := range childSchemaTable.ForeignKeys {
				// TODO: Check that value exists before we
				// attempt to set?
				/*
					v, ok := pkValues[fk]
					if ok {
						childPkValues[fk] = v
					} else {
						// TODO: is this an error condition?
					}
				*/

				childPkValues[fk] = pkValues[fk]
			}
		}

		// Retrieve a single child (TODO: Implement RetrieveMany options as well)
		childObj, err := o.Retrieve(ctx, name, childPkValues)
		if err != nil {
			return nil, errors.Wrap(err, "RetrieveWithChildren/Retrieve("+name+")")
		}
		// Populate single child inside parent
		if obj.Children[name] == nil {
			obj.Children[name] = make(object.Array, 1)
		}
		obj.Children[name][0] = childObj
	}

	return obj, nil
}

// retrieveCore function will fleshen an object structure, given some primary keys.
// Technically, we call RetrieveMany internally. Since we do not have LIMIT implemented yet,
// it's just a cheap implementation that returns the zeroeth value. Nil will be returned
// for both the object and the error if a row is unable to be matched by the underlying
// datastore.
// TODO: Implement LIMIT so that we can improve this.
func (o ORM) retrieveCore(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (*object.Object, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	objAry, err := o.retrieveManyCore(ctx, tx, table, queryVals)
	if err != nil {
		return nil, err
	}
	// We return nil, nil to indicate a lack of result.
	if objAry == nil {
		return nil, nil
	}
	return objAry[0], nil
}

// RetrieveTx function will fleshen an object structure, given some primary keys.
// Technically, we call RetrieveMany internally. Since we do not have LIMIT implemented yet,
// it's just a cheap implementation that returns the zeroeth value. Nil will be returned
// for both the object and the error if a row is unable to be matched by the underlying
// datastore.
// TODO: Implement LIMIT so that we can improve this.
func (o ORM) RetrieveTx(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (*object.Object, error) {
	return o.retrieveCore(ctx, tx, table, queryVals)
}

// Retrieve function will fleshen an object structure, given some primary keys.
// Technically, we call RetrieveMany internally. Since we do not have LIMIT implemented yet,
// it's just a cheap implementation that returns the zeroeth value. Nil will be returned
// for both the object and the error if a row is unable to be matched by the underlying
// datastore.
// TODO: Implement LIMIT so that we can improve this.
func (o ORM) Retrieve(ctx context.Context, table string, queryVals map[string]interface{}) (*object.Object, error) {
	return o.retrieveCore(ctx, nil, table, queryVals)
}

// FleshenChildren function accepts an object and resets it's children.
func (o ORM) FleshenChildren(ctx context.Context, obj *object.Object) (*object.Object, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	// Retrieve schema configuration for this object type (schema.Table)
	schemaTable := o.s.GetTable(obj.Type)

	// Retrieve primary key
	pkKey := schemaTable.Primary
	pkVal := obj.Get(pkKey)

	// If this table is configured with child tables, then we iterate over
	// them and call RetrieveMany using the singular primary key value.
	// FIXME: We need to support multikey in this instance if we are going
	// to consider this complete.
	if len(schemaTable.Children) > 0 {
		for childTableName := range schemaTable.Children {
			// TODO: multi-key support here...
			m := map[string]interface{}{}
			m[pkKey] = pkVal
			childObjs, err := o.RetrieveMany(ctx, childTableName, m)
			if err != nil {
				return nil, err
			}
			obj.Children[childTableName] = childObjs
		}
	}
	return obj, nil
}

// RetrieveManyFromCustomSQL will fleshen an object structure, given a custom SQL string. It must still be told
// the column names and the binding arguments in addition to the SQL string, so that it can dynamically map
// the column types accordingly to the destination object. (Mainly, so we know the array length..)
func (o ORM) RetrieveManyFromCustomSQL(ctx context.Context, table string, sqlStr string, columnNames []string, bindArgs []interface{}) (object.Array, error) {
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}
	var objectArray object.Array

	if os.Getenv("DEBUG_RETRIEVECUSTOM") != "" {
		fmt.Println("RetrieveManyFromCustomSQL/sqlStr=", sqlStr, "columnNames=", columnNames, "bindArgs=", bindArgs)
	}

	stmt, err := o.RawConn.PrepareContext(ctx, sqlStr)
	if err != nil {
		return nil, err
	}
	defer func() {
		stmtErr := stmt.Close()
		if stmtErr != nil {
			fmt.Println("defer stmt.Close error:", stmtErr) // TODO: logger implementation
		}
	}()

	res, err := stmt.QueryContext(ctx, bindArgs...)
	if err != nil {
		return nil, err
	}
	defer func() {
		resErr := res.Close()
		if resErr != nil {
			fmt.Println("defer res.Close error:", resErr) // TODO: logger implementation
		}
	}()

	columnTypes, err := res.ColumnTypes()
	if err != nil {
		return nil, err
	}
	sg := o.sqlGen
	for res.Next() {
		columnPointers, err := sg.MakeColumnPointers(len(columnNames), columnTypes)
		if err != nil {
			return nil, err
		}

		if err := res.Scan(columnPointers...); err != nil {
			return nil, err
		}

		obj := object.New(table)
		err = sg.DynamicObjectSetter(columnNames, columnPointers, columnTypes, obj)
		if err != nil {
			return nil, err
		}

		obj.SetSaved(true)
		obj.ResetChangedFields()

		objectArray = append(objectArray, obj)
	}

	err = res.Err()
	if err != nil {
		return nil, err
	}
	return objectArray, nil
}

func (o ORM) makeQueryObj(objTable *schema.Table, queryVals map[string]interface{}) *object.Object {
	queryObj := object.New(objTable.Name)

	if objTable.FieldAliases == nil {
		queryObj.KV = queryVals
		return queryObj
	}
	for k, v := range queryVals {
		realName := objTable.GetFieldName(k)
		queryObj.KV[realName] = v
	}
	return queryObj
}

// TODO: Have a more powerful querying mechanism, queryVals is very limited.
func (o ORM) retrieveManyCore(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (object.Array, error) {
	// Check for timeout
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}

	// Check to make sure that the table arg is a valid table name We will
	// need objTable later.
	objTable := o.s.GetTable(table)
	if objTable == nil {
		return nil, errors.New("RetrieveMany: unknown object table " + table)
	}
	if objTable.Name == "" {
		return nil, errors.New("RetrieveMany: schema table object has unset 'Name' property")
	}

	var objectArray object.Array

	// Construct a dyndao object from our queryVals
	queryObj := o.makeQueryObj(objTable, queryVals)

	// Generate a sql string, the column names, and the binding parameter
	// arguments from the schema and the query object
	sqlStr, columnNames, bindArgs, err := o.sqlGen.BindingRetrieve(o.s, queryObj)
	if os.Getenv("DEBUG_RETRIEVEMANY") != "" {
		fmt.Println("RetrieveMany/sqlStr=", sqlStr, "columnNames=", columnNames, "bindArgs=", bindArgs)
	}

	if err != nil {
		return nil, err
	}

	// Determines whether we are running inside a transaction or not,
	// returning stmt either way
	stmt, err := stmtFromDbOrTx(ctx, o, tx, sqlStr)
	if err != nil {
		return nil, err
	}

	defer func() {
		err := stmt.Close()
		if err != nil {
			fmt.Println(err) // TODO logger implementation
		}
	}()

	res, err := stmt.QueryContext(ctx, bindArgs...)
	if err != nil {
		return nil, err
	}

	defer func() {
		err := res.Close()
		if err != nil {
			fmt.Println(err) // TODO logger implementation
		}
	}()

	columnTypes, err := res.ColumnTypes()
	if err != nil {
		return nil, err
	}

	sg := o.sqlGen
	for res.Next() {
		columnPointers, err := sg.MakeColumnPointers(len(columnNames), columnTypes)
		if err != nil {
			return nil, err
		}

		obj := object.New(table)
		if err := res.Scan(columnPointers...); err != nil {
			return nil, err
		}

		err = sg.DynamicObjectSetter(columnNames, columnPointers, columnTypes, obj)
		if err != nil {
			return nil, err
		}

		obj.SetSaved(true)
		obj.ResetChangedFields()
		objectArray = append(objectArray, obj)
	}

	err = res.Err()
	if err != nil {
		return nil, err
	}
	return objectArray, nil
}

// RetrieveManyTx function will fleshen a top-level object structure, given some primary keys. And
// it's transactional!
func (o ORM) RetrieveManyTx(ctx context.Context, tx *sql.Tx, table string, queryVals map[string]interface{}) (object.Array, error) {
	return o.retrieveManyCore(ctx, tx, table, queryVals)
}

// RetrieveMany function will fleshen a top-level object structure, given some primary keys
func (o ORM) RetrieveMany(ctx context.Context, table string, queryVals map[string]interface{}) (object.Array, error) {
	return o.retrieveManyCore(ctx, nil, table, queryVals)
}
<|endoftext|>


<commit_before>package colony

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

type Clients struct {
	clients       map[Owner][]chan *Message
	viewingOwners map[Owner]chan *WorldView
	eventLoop     *EventLoop
}

func NewClients(e *EventLoop) *Clients {
	return &Clients{
		clients:       make(map[Owner][]chan *Message),
		viewingOwners: make(map[Owner]chan *WorldView),
		eventLoop:     e,
	}
}

func (c *Clients) BroadcastAll(msg *Message) {
	for _, clients := range c.clients {
		for _, client := range clients {
			client <- msg
		}
	}
}

func (c *Clients) BroadcastOwner(o Owner, msg *Message) {
	clients, exist := c.clients[o]
	if exist {
		for _, client := range clients {
			client <- msg
		}
	}
}

func (c *Clients) Connect(o Owner, ch chan *Message) {
	clients, exists := c.clients[o]
	if !exists {
		clients = make([]chan *Message, 0)
	}
	c.clients[o] = append(clients, ch)
	if _, ok := c.viewingOwners[o]; !ok {
		// TODO: discard overflow to prevent slow clients from blocking engine
		ch := make(chan *WorldView, 10)
		go func() {
			for {
				view := <-ch
				event := &ViewUpdateEvent{
					Owner:     o,
					WorldView: view,
				}
				msg := &Message{
					Type:  event.eventType(),
					Event: event,
				}
				for _, client := range c.clients[o] {
					client <- msg
				}
			}
		}()
		c.eventLoop.View(o, ch)
	}
}

func (c *Clients) Disconnect(o Owner, ch chan *Message) {
	clients, exists := c.clients[o]
	if !exists {
		return
	}
	for i, client := range clients {
		if client == ch {
			c.clients[o] = append(clients[:i], clients[i+1:]...)
			if len(c.clients[o]) == 0 {
				c.eventLoop.Unview(o, c.viewingOwners[o])
			}
			return
		}
	}
}

func (c *Clients) Serve(addr string) {
	go func() {
		ClientWebsocket := func(w http.ResponseWriter, r *http.Request) {
			log.Println("Connected client")
			conn, err := upgrader.Upgrade(w, r, nil)
			if err != nil {
				log.Println("Error while upgrading: ", err)
				return
			}
			defer conn.Close()
			clientChan := make(chan *Message, 10)
			defer close(clientChan)
			c.Connect("joe", clientChan)
			defer c.Disconnect("joe", clientChan)
			done := make(chan bool)
			go func() {
				for {
					msg, ok := <-clientChan
					if !ok {
						done <- true
						return
					}
					err = conn.WriteJSON(msg)
					if err != nil {
						log.Println("Error while writing to client: ", err)
						close(done)
						return
					}
				}
			}()
			go func() {
				for {
					_, message, err := conn.ReadMessage()
					if err != nil {
						log.Println("Error while reading from client: ", err)
						continue
					}
					var msg interface{}
					if err = json.Unmarshal(message, &msg); err != nil {
						log.Println("Error while deserializing message from client: ", string(message))
						continue
					}
					msgMap, ok := msg.(map[string]interface{})
					if !ok {
						log.Println("Unexpected structure of message from client: ", string(message))
						continue
					}
					msgType, ok := msgMap["Type"].(string)
					if !ok {
						log.Println("Message from client does not have Type: ", string(message))
						continue
					}
					msgEvent, ok := msgMap["Event"].(map[string]interface{})
					if !ok {
						log.Println("Message from client does not have event: ", string(message))
						continue
					}
					event, err := UnmarshalEvent(EventType(msgType), msgEvent)
					if err != nil {
						log.Println(err.Error(), ": ", string(message))
						continue
					}
					c.eventLoop.C <- event
				}
			}()
			<-done
			log.Println("Disconnected client")
		}
		http.HandleFunc("/ws", ClientWebsocket)
		http.ListenAndServe(addr, nil)
	}()
}

type Message struct {
	Type  EventType
	Event Event
}

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}
<commit_msg>Stop reading from closed websockets.<commit_after>package colony

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

type Clients struct {
	clients       map[Owner][]chan *Message
	viewingOwners map[Owner]chan *WorldView
	eventLoop     *EventLoop
}

func NewClients(e *EventLoop) *Clients {
	return &Clients{
		clients:       make(map[Owner][]chan *Message),
		viewingOwners: make(map[Owner]chan *WorldView),
		eventLoop:     e,
	}
}

func (c *Clients) BroadcastAll(msg *Message) {
	for _, clients := range c.clients {
		for _, client := range clients {
			client <- msg
		}
	}
}

func (c *Clients) BroadcastOwner(o Owner, msg *Message) {
	clients, exist := c.clients[o]
	if exist {
		for _, client := range clients {
			client <- msg
		}
	}
}

func (c *Clients) Connect(o Owner, ch chan *Message) {
	clients, exists := c.clients[o]
	if !exists {
		clients = make([]chan *Message, 0)
	}
	c.clients[o] = append(clients, ch)
	if _, ok := c.viewingOwners[o]; !ok {
		// TODO: discard overflow to prevent slow clients from blocking engine
		ch := make(chan *WorldView, 10)
		go func() {
			for {
				view := <-ch
				event := &ViewUpdateEvent{
					Owner:     o,
					WorldView: view,
				}
				msg := &Message{
					Type:  event.eventType(),
					Event: event,
				}
				for _, client := range c.clients[o] {
					client <- msg
				}
			}
		}()
		c.eventLoop.View(o, ch)
	}
}

func (c *Clients) Disconnect(o Owner, ch chan *Message) {
	clients, exists := c.clients[o]
	if !exists {
		return
	}
	for i, client := range clients {
		if client == ch {
			c.clients[o] = append(clients[:i], clients[i+1:]...)
			if len(c.clients[o]) == 0 {
				c.eventLoop.Unview(o, c.viewingOwners[o])
			}
			return
		}
	}
}

func (c *Clients) Serve(addr string) {
	go func() {
		ClientWebsocket := func(w http.ResponseWriter, r *http.Request) {
			log.Println("Connected client")
			conn, err := upgrader.Upgrade(w, r, nil)
			if err != nil {
				log.Println("Error while upgrading: ", err)
				return
			}
			defer conn.Close()
			clientChan := make(chan *Message, 10)
			defer close(clientChan)
			c.Connect("joe", clientChan)
			defer c.Disconnect("joe", clientChan)
			done := make(chan bool)
			go func() {
				for {
					msg, ok := <-clientChan
					if !ok {
						done <- true
						return
					}
					err = conn.WriteJSON(msg)
					if err != nil {
						log.Println("Error while writing to client: ", err)
						close(done)
						return
					}
				}
			}()
			go func() {
				for {
					_, message, err := conn.ReadMessage()
					if err != nil {
						log.Println("Error while reading from client: ", err)
						return
					}
					var msg interface{}
					if err = json.Unmarshal(message, &msg); err != nil {
						log.Println("Error while deserializing message from client: ", string(message))
						continue
					}
					msgMap, ok := msg.(map[string]interface{})
					if !ok {
						log.Println("Unexpected structure of message from client: ", string(message))
						continue
					}
					msgType, ok := msgMap["Type"].(string)
					if !ok {
						log.Println("Message from client does not have Type: ", string(message))
						continue
					}
					msgEvent, ok := msgMap["Event"].(map[string]interface{})
					if !ok {
						log.Println("Message from client does not have event: ", string(message))
						continue
					}
					event, err := UnmarshalEvent(EventType(msgType), msgEvent)
					if err != nil {
						log.Println(err.Error(), ": ", string(message))
						continue
					}
					c.eventLoop.C <- event
				}
			}()
			<-done
			log.Println("Disconnected client")
		}
		http.HandleFunc("/ws", ClientWebsocket)
		http.ListenAndServe(addr, nil)
	}()
}

type Message struct {
	Type  EventType
	Event Event
}

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}
<|endoftext|>


<commit_before>package main

import (
  _"fmt"
)

type Block struct {
  transactions []*Transaction
}

func NewBlock(/* TODO use raw data */transactions []*Transaction) *Block {
  block := &Block{
    // Slice of transactions to include in this block
    transactions: transactions,
  }

  return block
}

func (block *Block) Update() {
}
<commit_msg>Serializing block<commit_after>package main

import (
  _"fmt"
  "time"
)

type Block struct {
  RlpSerializer

  number        uint32
  prevHash      string
  uncles        []*Block
  coinbase      string
  // state xxx
  difficulty    int
  time          time.Time
  nonce         int
  transactions  []*Transaction
}

func NewBlock(/* TODO use raw data */transactions []*Transaction) *Block {
  block := &Block{
    // Slice of transactions to include in this block
    transactions: transactions,

    time: time.Now(),
  }

  return block
}

func (block *Block) Update() {
}

func (block *Block) Hash() string {
  return Sha256Hex(block.MarshalRlp())
}

func (block *Block) MarshalRlp() []byte {
  // Encoding method requires []interface{} type. It's actual a slice of strings
  encTx := make([]string, len(block.transactions))
  for i, tx := range block.transactions {
    encTx[i] = string(tx.MarshalRlp())
  }

  enc := RlpEncode([]interface{}{
    block.number,
    block.prevHash,
    // Sha of uncles
    block.coinbase,
    // root state
    Sha256Bin([]byte(RlpEncode(encTx))),
    block.difficulty,
    block.time,
    block.nonce,
    // extra?
  })

  return []byte(enc)
}

func (block *Block) UnmarshalRlp(data []byte) {
}
<|endoftext|>


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

/*
A Bloom filter is a representation of a set of _n_ items, where the main
requirement is to make membership queries; _i.e._, whether an item is a
member of a set.

A Bloom filter has two parameters: _m_, a maximum size (typically a reasonably large
multiple of the cardinality of the set to represent) and _k_, the number of hashing
functions on elements of the set. (The actual hashing functions are important, too,
but this is not a parameter for this implementation). A Bloom filter is backed by
a BitSet; a key is represented in the filter by setting the bits at each value of the
hashing functions (modulo _m_). Set membership is done by _testing_ whether the
bits at each value of the hashing functions (again, modulo _m_) are set. If so,
the item is in the set. If the item is actually in the set, a Bloom filter will
never fail (the true positive rate is 1.0); but it is susceptible to false
positives. The art is to choose _k_ and _m_ correctly.

In this implementation, the hashing function used is FNV, a non-cryptographic
hashing function which is part of the Go package (hash/fnv). For a item, the
64-bit FNV hash is computed, and upper and lower 32 bit numbers, call them h1 and
h2, are used. Then, the _i_th hashing function is:

    h1 + h2*i

Thus, the underlying hash function, FNV, is only called once per key.

This implementation accepts keys for setting as testing as []byte. Thus, to
add a string item, "Love":

    uint n = 1000
    filter := bloom.New(20*n, 5) // load of 20, 5 keys
    filter.Add([]byte("Love"))

Similarly, to test if "Love" is in bloom:

    if filter.Test([]byte("Love"))

For numeric data, I recommend that you look into the binary/encoding library. But,
for example, to add a uint32 to the filter:

    i := uint32(100)
    n1 := make([]byte,4)
    binary.BigEndian.PutUint32(n1,i)
    f.Add(n1)

Finally, there is a method to estimate the false positive rate of a particular
bloom filter for a set of size _n_:

    if filter.EstimateFalsePositiveRate(1000) > 0.001

Given the particular hashing scheme, it's best to be empirical about this. Note
that estimating the FP rate will clear the Bloom filter.
*/
package bloom

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"hash"
	"hash/fnv"
	"io"
	"math"

	"github.com/willf/bitset"
	//"fmt"
)

type BloomFilter struct {
	m       uint
	k       uint
	b       *bitset.BitSet
	locBuff []uint
	present bool
	hasher  hash.Hash64
}

// Create a new Bloom filter with _m_ bits and _k_ hashing functions
func New(m uint, k uint) *BloomFilter {

	return &BloomFilter{m, k, bitset.New(m), make([]uint, k), false, fnv.New64()}
}

// estimate parameters. Based on https://bitbucket.org/ww/bloom/src/829aa19d01d9/bloom.go
// used with permission.
func estimateParameters(n uint, p float64) (m uint, k uint) {
	m = uint(-1 * float64(n) * math.Log(p) / math.Pow(math.Log(2), 2))
	k = uint(math.Ceil(math.Log(2) * float64(m) / float64(n)))
	return
}

// Create a new Bloom filter for about n items with fp
// false positive rate
func NewWithEstimates(n uint, fp float64) *BloomFilter {
	m, k := estimateParameters(n, fp)
	return New(m, k)
}

// Return the capacity, _m_, of a Bloom filter
func (f *BloomFilter) Cap() uint {
	return f.m
}

// Return the number of hash functions used
func (f *BloomFilter) K() uint {
	return f.k
}

// get the two basic hash function values for data
func (f *BloomFilter) base_hashes(data []byte) (a uint32, b uint32) {
	f.hasher.Reset()
	f.hasher.Write(data)
	sum := f.hasher.Sum(nil)
	upper := sum[0:4]
	lower := sum[4:8]
	a = binary.BigEndian.Uint32(lower)
	b = binary.BigEndian.Uint32(upper)
	return
}

// get the _k_ locations to set/test in the underlying bitset
func (f *BloomFilter) locations(data []byte) {
	a, b := f.base_hashes(data)
	ua := uint(a)
	ub := uint(b)
	//fmt.Println(ua, ub)
	for i := uint(0); i < f.k; i++ {
		f.locBuff[i] = (ua + ub*i) % f.m
	}
	//fmt.Println(data, "->", locs)
	return
}

// Add data to the Bloom Filter. Returns the filter (allows chaining)
func (f *BloomFilter) Add(data []byte) *BloomFilter {
	f.locations(data)
	for i := uint(0); i < f.k; i++ {
		f.b.Set(f.locBuff[i])
	}

	return f
}

// Tests for the presence of data in the Bloom filter
func (f *BloomFilter) Test(data []byte) bool {
	f.locations(data)
	for i := uint(0); i < f.k; i++ {
		if !f.b.Test(f.locBuff[i]) {
			return false
		}
	}
	return true
}

// Equivalent to calling Test(data) then Add(data).  Returns the result of Test.
func (f *BloomFilter) TestAndAdd(data []byte) bool {
	f.locations(data)

	for i := uint(0); i < f.k; i++ {
		if !f.b.Test(f.locBuff[i]) {
			f.present = false
		}
		f.b.Set(f.locBuff[i])
	}
	return f.present
}

// Clear all the data in a Bloom filter, removing all keys
func (f *BloomFilter) ClearAll() *BloomFilter {
	f.b.ClearAll()
	return f
}

// Estimate, for a BloomFilter with a limit of m bytes
// and k hash functions, what the false positive rate will be
// whilst storing n entries; runs n * 2 tests.
func (f *BloomFilter) EstimateFalsePositiveRate(n uint) (fp_rate float64) {
	rounds := uint32(n * 2)
	f.ClearAll()
	n1 := make([]byte, 4)
	for i := uint32(0); i < uint32(n); i++ {
		binary.BigEndian.PutUint32(n1, i)
		f.Add(n1)
	}
	fp := 0
	// test for number of rounds
	for i := uint32(0); i < rounds; i++ {
		binary.BigEndian.PutUint32(n1, i+uint32(n)+1)
		if f.Test(n1) {
			fp++
		}
	}
	fp_rate = float64(fp) / float64(100)
	f.ClearAll()
	return
}

// bloomFilterJSON is an unexported type for marshaling/unmarshaling BloomFilter struct.
type bloomFilterJSON struct {
	M uint           `json:"m"`
	K uint           `json:"k"`
	B *bitset.BitSet `json:"b"`
}

// MarshalJSON implements json.Marshaler interface.
func (f *BloomFilter) MarshalJSON() ([]byte, error) {
	return json.Marshal(bloomFilterJSON{f.m, f.k, f.b})
}

// UnmarshalJSON implements json.Unmarshaler interface.
func (f *BloomFilter) UnmarshalJSON(data []byte) error {
	var j bloomFilterJSON
	err := json.Unmarshal(data, &j)
	if err != nil {
		return err
	}
	f.m = j.M
	f.k = j.K
	f.b = j.B
	f.hasher = fnv.New64()
	f.locBuff = make([]uint, f.k)
	return nil
}

// WriteTo writes a binary representation of the BloomFilter to an i/o stream.
// It returns the number of bytes written.
func (f *BloomFilter) WriteTo(stream io.Writer) (int64, error) {
	err := binary.Write(stream, binary.BigEndian, uint64(f.m))
	if err != nil {
		return 0, err
	}
	err = binary.Write(stream, binary.BigEndian, uint64(f.k))
	if err != nil {
		return 0, err
	}
	numBytes, err := f.b.WriteTo(stream)
	return numBytes + int64(2*binary.Size(uint64(0))), err
}

// ReadFrom reads a binary representation of the BloomFilter (such as might
// have been written by WriteTo()) from an i/o stream. It returns the number
// of bytes read.
func (f *BloomFilter) ReadFrom(stream io.Reader) (int64, error) {
	var m, k uint64
	err := binary.Read(stream, binary.BigEndian, &m)
	if err != nil {
		return 0, err
	}
	err = binary.Read(stream, binary.BigEndian, &k)
	if err != nil {
		return 0, err
	}
	b := &bitset.BitSet{}
	numBytes, err := b.ReadFrom(stream)
	if err != nil {
		return 0, err
	}
	f.m = uint(m)
	f.k = uint(k)
	f.b = b
	f.hasher = fnv.New64()
	return numBytes + int64(2*binary.Size(uint64(0))), nil
}

// GobEncode implements gob.GobEncoder interface.
func (f *BloomFilter) GobEncode() ([]byte, error) {
	var buf bytes.Buffer
	_, err := f.WriteTo(&buf)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// GobDecode implements gob.GobDecoder interface.
func (f *BloomFilter) GobDecode(data []byte) error {
	buf := bytes.NewBuffer(data)
	_, err := f.ReadFrom(buf)
	f.locBuff = make([]uint, f.k)
	return err
}
<commit_msg>TestAndAdd bugfix<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.package bloom

/*
A Bloom filter is a representation of a set of _n_ items, where the main
requirement is to make membership queries; _i.e._, whether an item is a
member of a set.

A Bloom filter has two parameters: _m_, a maximum size (typically a reasonably large
multiple of the cardinality of the set to represent) and _k_, the number of hashing
functions on elements of the set. (The actual hashing functions are important, too,
but this is not a parameter for this implementation). A Bloom filter is backed by
a BitSet; a key is represented in the filter by setting the bits at each value of the
hashing functions (modulo _m_). Set membership is done by _testing_ whether the
bits at each value of the hashing functions (again, modulo _m_) are set. If so,
the item is in the set. If the item is actually in the set, a Bloom filter will
never fail (the true positive rate is 1.0); but it is susceptible to false
positives. The art is to choose _k_ and _m_ correctly.

In this implementation, the hashing function used is FNV, a non-cryptographic
hashing function which is part of the Go package (hash/fnv). For a item, the
64-bit FNV hash is computed, and upper and lower 32 bit numbers, call them h1 and
h2, are used. Then, the _i_th hashing function is:

    h1 + h2*i

Thus, the underlying hash function, FNV, is only called once per key.

This implementation accepts keys for setting as testing as []byte. Thus, to
add a string item, "Love":

    uint n = 1000
    filter := bloom.New(20*n, 5) // load of 20, 5 keys
    filter.Add([]byte("Love"))

Similarly, to test if "Love" is in bloom:

    if filter.Test([]byte("Love"))

For numeric data, I recommend that you look into the binary/encoding library. But,
for example, to add a uint32 to the filter:

    i := uint32(100)
    n1 := make([]byte,4)
    binary.BigEndian.PutUint32(n1,i)
    f.Add(n1)

Finally, there is a method to estimate the false positive rate of a particular
bloom filter for a set of size _n_:

    if filter.EstimateFalsePositiveRate(1000) > 0.001

Given the particular hashing scheme, it's best to be empirical about this. Note
that estimating the FP rate will clear the Bloom filter.
*/
package bloom

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"hash"
	"hash/fnv"
	"io"
	"math"

	"github.com/willf/bitset"
	//"fmt"
)

type BloomFilter struct {
	m       uint
	k       uint
	b       *bitset.BitSet
	locBuff []uint
	present bool
	hasher  hash.Hash64
}

// Create a new Bloom filter with _m_ bits and _k_ hashing functions
func New(m uint, k uint) *BloomFilter {

	return &BloomFilter{m, k, bitset.New(m), make([]uint, k), false, fnv.New64()}
}

// estimate parameters. Based on https://bitbucket.org/ww/bloom/src/829aa19d01d9/bloom.go
// used with permission.
func estimateParameters(n uint, p float64) (m uint, k uint) {
	m = uint(-1 * float64(n) * math.Log(p) / math.Pow(math.Log(2), 2))
	k = uint(math.Ceil(math.Log(2) * float64(m) / float64(n)))
	return
}

// Create a new Bloom filter for about n items with fp
// false positive rate
func NewWithEstimates(n uint, fp float64) *BloomFilter {
	m, k := estimateParameters(n, fp)
	return New(m, k)
}

// Return the capacity, _m_, of a Bloom filter
func (f *BloomFilter) Cap() uint {
	return f.m
}

// Return the number of hash functions used
func (f *BloomFilter) K() uint {
	return f.k
}

// get the two basic hash function values for data
func (f *BloomFilter) base_hashes(data []byte) (a uint32, b uint32) {
	f.hasher.Reset()
	f.hasher.Write(data)
	sum := f.hasher.Sum(nil)
	upper := sum[0:4]
	lower := sum[4:8]
	a = binary.BigEndian.Uint32(lower)
	b = binary.BigEndian.Uint32(upper)
	return
}

// get the _k_ locations to set/test in the underlying bitset
func (f *BloomFilter) locations(data []byte) {
	a, b := f.base_hashes(data)
	ua := uint(a)
	ub := uint(b)
	//fmt.Println(ua, ub)
	for i := uint(0); i < f.k; i++ {
		f.locBuff[i] = (ua + ub*i) % f.m
	}
	//fmt.Println(data, "->", locs)
	return
}

// Add data to the Bloom Filter. Returns the filter (allows chaining)
func (f *BloomFilter) Add(data []byte) *BloomFilter {
	f.locations(data)
	for i := uint(0); i < f.k; i++ {
		f.b.Set(f.locBuff[i])
	}

	return f
}

// Tests for the presence of data in the Bloom filter
func (f *BloomFilter) Test(data []byte) bool {
	f.locations(data)
	for i := uint(0); i < f.k; i++ {
		if !f.b.Test(f.locBuff[i]) {
			return false
		}
	}
	return true
}

// Equivalent to calling Test(data) then Add(data).  Returns the result of Test.
func (f *BloomFilter) TestAndAdd(data []byte) bool {
	f.locations(data)
	f.present = true
	for i := uint(0); i < f.k; i++ {
		if !f.b.Test(f.locBuff[i]) {
			f.present = false
		}
		f.b.Set(f.locBuff[i])
	}
	return f.present
}

// Clear all the data in a Bloom filter, removing all keys
func (f *BloomFilter) ClearAll() *BloomFilter {
	f.b.ClearAll()
	return f
}

// Estimate, for a BloomFilter with a limit of m bytes
// and k hash functions, what the false positive rate will be
// whilst storing n entries; runs n * 2 tests.
func (f *BloomFilter) EstimateFalsePositiveRate(n uint) (fp_rate float64) {
	rounds := uint32(n * 2)
	f.ClearAll()
	n1 := make([]byte, 4)
	for i := uint32(0); i < uint32(n); i++ {
		binary.BigEndian.PutUint32(n1, i)
		f.Add(n1)
	}
	fp := 0
	// test for number of rounds
	for i := uint32(0); i < rounds; i++ {
		binary.BigEndian.PutUint32(n1, i+uint32(n)+1)
		if f.Test(n1) {
			fp++
		}
	}
	fp_rate = float64(fp) / float64(100)
	f.ClearAll()
	return
}

// bloomFilterJSON is an unexported type for marshaling/unmarshaling BloomFilter struct.
type bloomFilterJSON struct {
	M uint           `json:"m"`
	K uint           `json:"k"`
	B *bitset.BitSet `json:"b"`
}

// MarshalJSON implements json.Marshaler interface.
func (f *BloomFilter) MarshalJSON() ([]byte, error) {
	return json.Marshal(bloomFilterJSON{f.m, f.k, f.b})
}

// UnmarshalJSON implements json.Unmarshaler interface.
func (f *BloomFilter) UnmarshalJSON(data []byte) error {
	var j bloomFilterJSON
	err := json.Unmarshal(data, &j)
	if err != nil {
		return err
	}
	f.m = j.M
	f.k = j.K
	f.b = j.B
	f.hasher = fnv.New64()
	f.locBuff = make([]uint, f.k)
	return nil
}

// WriteTo writes a binary representation of the BloomFilter to an i/o stream.
// It returns the number of bytes written.
func (f *BloomFilter) WriteTo(stream io.Writer) (int64, error) {
	err := binary.Write(stream, binary.BigEndian, uint64(f.m))
	if err != nil {
		return 0, err
	}
	err = binary.Write(stream, binary.BigEndian, uint64(f.k))
	if err != nil {
		return 0, err
	}
	numBytes, err := f.b.WriteTo(stream)
	return numBytes + int64(2*binary.Size(uint64(0))), err
}

// ReadFrom reads a binary representation of the BloomFilter (such as might
// have been written by WriteTo()) from an i/o stream. It returns the number
// of bytes read.
func (f *BloomFilter) ReadFrom(stream io.Reader) (int64, error) {
	var m, k uint64
	err := binary.Read(stream, binary.BigEndian, &m)
	if err != nil {
		return 0, err
	}
	err = binary.Read(stream, binary.BigEndian, &k)
	if err != nil {
		return 0, err
	}
	b := &bitset.BitSet{}
	numBytes, err := b.ReadFrom(stream)
	if err != nil {
		return 0, err
	}
	f.m = uint(m)
	f.k = uint(k)
	f.b = b
	f.hasher = fnv.New64()
	return numBytes + int64(2*binary.Size(uint64(0))), nil
}

// GobEncode implements gob.GobEncoder interface.
func (f *BloomFilter) GobEncode() ([]byte, error) {
	var buf bytes.Buffer
	_, err := f.WriteTo(&buf)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// GobDecode implements gob.GobDecoder interface.
func (f *BloomFilter) GobDecode(data []byte) error {
	buf := bytes.NewBuffer(data)
	_, err := f.ReadFrom(buf)
	f.locBuff = make([]uint, f.k)
	return err
}
<|endoftext|>


<commit_before>/*
A note on indexing of the board

0,0 is the left side if you stand on the high side of the board.

For pixels:  along the high side is X, along the left is Y
For squares: lid 0,0 is the left side. 0,3 is the right side.
The board sensors map to the same.

*/

package main

import "fmt"
import "errors"

type Board struct {
	strand  *Strand
	sensors *Sensors
	pixelW  int
	pixelH  int
	squareW int
	squareH int
}

/////////////////////////////////
// CONNECTION FUNCTIONS
/////////////////////////////////

func (brd *Board) Connect(pixelW int, pixelH int, squareW int, squareH int) error {
	brd.pixelW = pixelW
	brd.pixelH = pixelH
	brd.squareW = squareW
	brd.squareH = squareH
	brd.strand = &Strand{}
	brd.sensors = &Sensors{}
	brd.sensors.initSensors()
	return brd.strand.Connect(pixelW * pixelH)
}

func (brd *Board) Free() {
	brd.strand.Free()
	brd.sensors.stopSensors()
}

func (brd *Board) Save() {
	brd.strand.Save()
}

/////////////////////////////////
// DRAWING FUNCTIONS
/////////////////////////////////

func (brd *Board) DrawPixel(x int, y int, c Color) error {
	if x < 0 || x >= brd.pixelW || y < 0 || y >= brd.pixelH {
		return errors.New("Pixel was drawn outside the board's space")
	}
	pixelNum := getPixelNum(x, y)
	brd.strand.SetColor(pixelNum, c)

	return nil
}

func (brd *Board) DrawSquare(col int, row int, c Color) error {
	for i := 0; i < 5; i++ {
		for j := 0; j < 5; j++ {
			_ = brd.DrawPixel(col*5+i, row*5+j, c)
		}
	}
	return nil
}

func (brd *Board) DrawAll(c Color) error {
	for i := 0; i < brd.pixelW*brd.pixelH; i++ {
		brd.strand.SetColor(i, c)
	}
	return nil
}

/////////////////////////////////
// INTERNAL FUNCTIONS
/////////////////////////////////

func getPixelNum(x int, y int) int {
	col := x / 5
	row := y / 5
	xPixelInSq := x % 5
	yPixelInSq := y % 5

	var boardNum, pixelNum int

	// NOTE: this is hardcoded for a 4 x 5 board with 25px/square
	if row%2 == 1 {
		boardNum = row*4 + col
	} else {
		boardNum = row*4 + 3 - col
	}

	if yPixelInSq%2 == 1 {
		pixelNum = yPixelInSq*5 + xPixelInSq
	} else {
		pixelNum = yPixelInSq*5 + 4 - xPixelInSq
	}

	return boardNum*25 + pixelNum
}

func (brd *Board) getBoardState(row int, col int) int {
	return brd.sensors.getBoardState(row, col)
}

func (brd *Board) printBoardState() error {
	for r := 0; r < rows; r++ {
		for c := 0; c < cols; c++ {
			switch {
			case brd.sensors.net[r*cols+c] == up:
				fmt.Printf("-")
			case brd.sensors.net[r*cols+c] == down:
				fmt.Printf("X")
			case brd.sensors.net[r*cols+c] == pressed:
				fmt.Printf("|")
			case brd.sensors.net[r*cols+c] == released:
				fmt.Printf("+")
			}
		}
		fmt.Printf("\n")
	}
	fmt.Printf("\n\n")
	return nil
}

func (brd *Board) pollSensors(poll chan string) {
	brd.sensors.readSensors()
	poll <- "ready"
}

func (brd *Board) processSensors() {
	brd.sensors.processSensors()
}
<commit_msg>Add stubs for new drawing functions<commit_after>/*
A note on indexing of the board

0,0 is the left side if you stand on the high side of the board.

For pixels:  along the high side is X, along the left is Y
For squares: lid 0,0 is the left side. 0,3 is the right side.
The board sensors map to the same.

*/

package main

import "fmt"
import "errors"

type Board struct {
	strand  *Strand
	sensors *Sensors
	pixelW  int
	pixelH  int
	squareW int
	squareH int
}

/////////////////////////////////
// CONNECTION FUNCTIONS
/////////////////////////////////

func (brd *Board) Connect(pixelW int, pixelH int, squareW int, squareH int) error {
	brd.pixelW = pixelW
	brd.pixelH = pixelH
	brd.squareW = squareW
	brd.squareH = squareH
	brd.strand = &Strand{}
	brd.sensors = &Sensors{}
	brd.sensors.initSensors()
	return brd.strand.Connect(pixelW * pixelH)
}

func (brd *Board) Free() {
	brd.strand.Free()
	brd.sensors.stopSensors()
}

func (brd *Board) Save() {
	brd.strand.Save()
}

/////////////////////////////////
// DRAWING FUNCTIONS
/////////////////////////////////

func (brd *Board) DrawPixel(x int, y int, c Color) error {
	if x < 0 || x >= brd.pixelW || y < 0 || y >= brd.pixelH {
		return errors.New("Pixel was drawn outside the board's space")
	}
	pixelNum := getPixelNum(x, y)
	brd.strand.SetColor(pixelNum, c)

	return nil
}

func (brd *Board) DrawSquare(col int, row int, c Color) error {
	for i := 0; i < 5; i++ {
		for j := 0; j < 5; j++ {
			_ = brd.DrawPixel(col*5+i, row*5+j, c)
		}
	}
	return nil
}

func (brd *Board) DrawAll(c Color) error {
	for i := 0; i < brd.pixelW*brd.pixelH; i++ {
		brd.strand.SetColor(i, c)
	}
	return nil
}

func (brd *Board) DrawLine(x1, y1, x2, y2 int, c Color) error {
	return errors.New("Not implemented")
}

func (brd *Board) DrawRect(x1, y1, x2, y2 int, c Color) error {
	return errors.New("Not implemented")
}

func (brd *Board) DrawRectOutline(x1, y1, x2, y2 int, c Color) error {
	return errors.New("Not implemented")
}

func (brd *Board) DrawCircle(x1, y1, r int, c Color) error {
	return errors.New("Not implemented")
}

func (brd *Board) DrawCircleOutline(x1, y1, r int, c Color) error {
	return errors.New("Not implemented")
}

// func (brd *Board) DrawSprite(x1, y1, r int, c Color) error {
// 	return errors.New("Not implemented")
// }

/////////////////////////////////
// INTERNAL FUNCTIONS
/////////////////////////////////

func getPixelNum(x int, y int) int {
	col := x / 5
	row := y / 5
	xPixelInSq := x % 5
	yPixelInSq := y % 5

	var boardNum, pixelNum int

	// NOTE: this is hardcoded for a 4 x 5 board with 25px/square
	if row%2 == 1 {
		boardNum = row*4 + col
	} else {
		boardNum = row*4 + 3 - col
	}

	if yPixelInSq%2 == 1 {
		pixelNum = yPixelInSq*5 + xPixelInSq
	} else {
		pixelNum = yPixelInSq*5 + 4 - xPixelInSq
	}

	return boardNum*25 + pixelNum
}

func (brd *Board) getBoardState(row int, col int) int {
	return brd.sensors.getBoardState(row, col)
}

func (brd *Board) printBoardState() error {
	for r := 0; r < rows; r++ {
		for c := 0; c < cols; c++ {
			switch {
			case brd.sensors.net[r*cols+c] == up:
				fmt.Printf("-")
			case brd.sensors.net[r*cols+c] == down:
				fmt.Printf("X")
			case brd.sensors.net[r*cols+c] == pressed:
				fmt.Printf("|")
			case brd.sensors.net[r*cols+c] == released:
				fmt.Printf("+")
			}
		}
		fmt.Printf("\n")
	}
	fmt.Printf("\n\n")
	return nil
}

func (brd *Board) pollSensors(poll chan string) {
	brd.sensors.readSensors()
	poll <- "ready"
}

func (brd *Board) processSensors() {
	brd.sensors.processSensors()
}
<|endoftext|>