<commit_before>package google

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"

	"google.golang.org/api/storage/v1"
)

func resourceStorageBucketAcl() *schema.Resource {
	return &schema.Resource{
		Create:        resourceStorageBucketAclCreate,
		Read:          resourceStorageBucketAclRead,
		Update:        resourceStorageBucketAclUpdate,
		Delete:        resourceStorageBucketAclDelete,
		CustomizeDiff: resourceStorageRoleEntityCustomizeDiff,

		Schema: map[string]*schema.Schema{
			"bucket": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"default_acl": {
				Type:     schema.TypeString,
				Optional: true,
			},

			"predefined_acl": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"role_entity"},
			},

			"role_entity": {
				Type:          schema.TypeList,
				Optional:      true,
				Computed:      true,
				Elem:          &schema.Schema{Type: schema.TypeString},
				ConflictsWith: []string{"predefined_acl"},
			},
		},
	}
}

func resourceStorageRoleEntityCustomizeDiff(diff *schema.ResourceDiff, meta interface{}) error {
	keys := diff.GetChangedKeysPrefix("role_entity")
	if len(keys) < 1 {
		return nil
	}
	count := diff.Get("role_entity.#").(int)
	if count < 1 {
		return nil
	}
	state := map[string]struct{}{}
	conf := map[string]struct{}{}
	for i := 0; i < count; i++ {
		old, new := diff.GetChange(fmt.Sprintf("role_entity.%d", i))
		state[old.(string)] = struct{}{}
		conf[new.(string)] = struct{}{}
	}
	if len(state) != len(conf) {
		return nil
	}
	for k := range state {
		if _, ok := conf[k]; !ok {
			return nil
		}
	}
	return diff.Clear("role_entity")
}

type RoleEntity struct {
	Role   string
	Entity string
}

func getBucketAclId(bucket string) string {
	return bucket + "-acl"
}

func getRoleEntityPair(role_entity string) (*RoleEntity, error) {
	split := strings.Split(role_entity, ":")
	if len(split) != 2 {
		return nil, fmt.Errorf("Error, each role entity pair must be " +
			"formatted as ROLE:entity")
	}

	return &RoleEntity{Role: split[0], Entity: split[1]}, nil
}

func resourceStorageBucketAclCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	predefined_acl := ""
	default_acl := ""
	role_entity := make([]interface{}, 0)

	if v, ok := d.GetOk("predefined_acl"); ok {
		predefined_acl = v.(string)
	}

	if v, ok := d.GetOk("role_entity"); ok {
		role_entity = v.([]interface{})
	}

	if v, ok := d.GetOk("default_acl"); ok {
		default_acl = v.(string)
	}

	if len(predefined_acl) > 0 {
		res, err := config.clientStorage.Buckets.Get(bucket).Do()

		if err != nil {
			return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
		}

		_, err = config.clientStorage.Buckets.Update(bucket,
			res).PredefinedAcl(predefined_acl).Do()

		if err != nil {
			return fmt.Errorf("Error updating bucket %s: %v", bucket, err)
		}

	}

	if len(role_entity) > 0 {
		current, err := config.clientStorage.BucketAccessControls.List(bucket).Do()
		if err != nil {
			return fmt.Errorf("Error retrieving current ACLs: %s", err)
		}
		for _, v := range role_entity {
			pair, err := getRoleEntityPair(v.(string))
			if err != nil {
				return err
			}
			var alreadyInserted bool
			for _, cur := range current.Items {
				if cur.Entity == pair.Entity && cur.Role == pair.Role {
					alreadyInserted = true
					break
				}
			}
			if alreadyInserted {
				log.Printf("[DEBUG]: pair %s-%s already exists, not trying to insert again\n", pair.Role, pair.Entity)
				continue
			}
			bucketAccessControl := &storage.BucketAccessControl{
				Role:   pair.Role,
				Entity: pair.Entity,
			}

			log.Printf("[DEBUG]: storing re %s-%s", pair.Role, pair.Entity)

			_, err = config.clientStorage.BucketAccessControls.Insert(bucket, bucketAccessControl).Do()

			if err != nil {
				return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err)
			}
		}

	}

	if len(default_acl) > 0 {
		res, err := config.clientStorage.Buckets.Get(bucket).Do()

		if err != nil {
			return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
		}

		_, err = config.clientStorage.Buckets.Update(bucket,
			res).PredefinedDefaultObjectAcl(default_acl).Do()

		if err != nil {
			return fmt.Errorf("Error updating bucket %s: %v", bucket, err)
		}

	}

	d.SetId(getBucketAclId(bucket))
	return resourceStorageBucketAclRead(d, meta)
}

func resourceStorageBucketAclRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)

	// The API offers no way to retrieve predefined ACLs,
	// and we can't tell which access controls were created
	// by the predefined roles, so...
	//
	// This is, needless to say, a bad state of affairs and
	// should be fixed.
	if _, ok := d.GetOk("role_entity"); ok {
		res, err := config.clientStorage.BucketAccessControls.List(bucket).Do()

		if err != nil {
			return handleNotFoundError(err, d, fmt.Sprintf("Storage Bucket ACL for bucket %q", d.Get("bucket").(string)))
		}
		entities := make([]string, 0, len(res.Items))
		for _, item := range res.Items {
			entities = append(entities, item.Role+":"+item.Entity)
		}

		d.Set("role_entity", entities)
	} else {
		// if we don't set `role_entity` to nil (effectively setting it
		// to empty in Terraform state), because it's computed now,
		// Terraform will think it's missing from state, is supposed
		// to be there, and throw up a diff for role_entity.#. So it
		// must always be set in state.
		d.Set("role_entity", nil)
	}

	return nil
}

func resourceStorageBucketAclUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)

	if d.HasChange("role_entity") {
		bkt, err := config.clientStorage.Buckets.Get(bucket).Do()
		if err != nil {
			return fmt.Errorf("Error reading bucket %q: %v", bucket, err)
		}

		project := strconv.FormatUint(bkt.ProjectNumber, 10)
		o, n := d.GetChange("role_entity")
		old_re, new_re := o.([]interface{}), n.([]interface{})

		old_re_map := make(map[string]string)
		for _, v := range old_re {
			res, err := getRoleEntityPair(v.(string))

			if err != nil {
				return fmt.Errorf(
					"Old state has malformed Role/Entity pair: %v", err)
			}

			old_re_map[res.Entity] = res.Role
		}

		for _, v := range new_re {
			pair, err := getRoleEntityPair(v.(string))

			bucketAccessControl := &storage.BucketAccessControl{
				Role:   pair.Role,
				Entity: pair.Entity,
			}

			// If the old state is missing this entity, it needs to be inserted
			if _, ok := old_re_map[pair.Entity]; !ok {
				_, err = config.clientStorage.BucketAccessControls.Insert(
					bucket, bucketAccessControl).Do()
			}

			// Now we only store the keys that have to be removed
			delete(old_re_map, pair.Entity)

			if err != nil {
				return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err)
			}
		}

		for entity, role := range old_re_map {
			if entity == fmt.Sprintf("project-owners-%s", project) && role == "OWNER" {
				log.Printf("[WARN]: Skipping %s-%s; not deleting owner ACL.", role, entity)
				continue
			}
			log.Printf("[DEBUG]: removing entity %s", entity)
			err := config.clientStorage.BucketAccessControls.Delete(bucket, entity).Do()

			if err != nil {
				return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err)
			}
		}

		return resourceStorageBucketAclRead(d, meta)
	}

	if d.HasChange("default_acl") {
		default_acl := d.Get("default_acl").(string)

		res, err := config.clientStorage.Buckets.Get(bucket).Do()

		if err != nil {
			return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
		}

		_, err = config.clientStorage.Buckets.Update(bucket,
			res).PredefinedDefaultObjectAcl(default_acl).Do()

		if err != nil {
			return fmt.Errorf("Error updating bucket %s: %v", bucket, err)
		}

		return resourceStorageBucketAclRead(d, meta)
	}

	return nil
}

func resourceStorageBucketAclDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)

	bkt, err := config.clientStorage.Buckets.Get(bucket).Do()
	if err != nil {
		return fmt.Errorf("Error retrieving bucket %q: %v", bucket, err)
	}
	project := strconv.FormatUint(bkt.ProjectNumber, 10)

	re_local := d.Get("role_entity").([]interface{})
	for _, v := range re_local {
		res, err := getRoleEntityPair(v.(string))
		if err != nil {
			return err
		}

		if res.Entity == fmt.Sprintf("project-owners-%s", project) && res.Role == "OWNER" {
			log.Printf("[WARN]: Skipping %s-%s; not deleting owner ACL.", res.Role, res.Entity)
			continue
		}

		log.Printf("[DEBUG]: removing entity %s", res.Entity)

		err = config.clientStorage.BucketAccessControls.Delete(bucket, res.Entity).Do()

		if err != nil {
			return fmt.Errorf("Error deleting entity %s ACL: %s", res.Entity, err)
		}
	}

	return nil
}
<commit_msg>Avoid permadiff trying to remove project-owners (#5479)<commit_after>package google

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"

	"google.golang.org/api/storage/v1"
)

func resourceStorageBucketAcl() *schema.Resource {
	return &schema.Resource{
		Create:        resourceStorageBucketAclCreate,
		Read:          resourceStorageBucketAclRead,
		Update:        resourceStorageBucketAclUpdate,
		Delete:        resourceStorageBucketAclDelete,
		CustomizeDiff: resourceStorageRoleEntityCustomizeDiff,

		Schema: map[string]*schema.Schema{
			"bucket": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"default_acl": {
				Type:     schema.TypeString,
				Optional: true,
			},

			"predefined_acl": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"role_entity"},
			},

			"role_entity": {
				Type:          schema.TypeList,
				Optional:      true,
				Computed:      true,
				Elem:          &schema.Schema{Type: schema.TypeString},
				ConflictsWith: []string{"predefined_acl"},
			},
		},
	}
}

func resourceStorageRoleEntityCustomizeDiff(diff *schema.ResourceDiff, meta interface{}) error {
	keys := diff.GetChangedKeysPrefix("role_entity")
	if len(keys) < 1 {
		return nil
	}
	count := diff.Get("role_entity.#").(int)
	if count < 1 {
		return nil
	}
	state := map[string]struct{}{}
	conf := map[string]struct{}{}
	for i := 0; i < count; i++ {
		old, new := diff.GetChange(fmt.Sprintf("role_entity.%d", i))
		state[old.(string)] = struct{}{}
		conf[new.(string)] = struct{}{}
	}
	if len(state) != len(conf) {
		return nil
	}
	for k := range state {
		if _, ok := conf[k]; !ok {
			// project-owners- is explicitly stripped from the roles that this
			// resource will delete
			if strings.Contains(k, "OWNER:project-owners-") {
				continue
			}
			return nil
		}
	}
	return diff.Clear("role_entity")
}

type RoleEntity struct {
	Role   string
	Entity string
}

func getBucketAclId(bucket string) string {
	return bucket + "-acl"
}

func getRoleEntityPair(role_entity string) (*RoleEntity, error) {
	split := strings.Split(role_entity, ":")
	if len(split) != 2 {
		return nil, fmt.Errorf("Error, each role entity pair must be " +
			"formatted as ROLE:entity")
	}

	return &RoleEntity{Role: split[0], Entity: split[1]}, nil
}

func resourceStorageBucketAclCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	predefined_acl := ""
	default_acl := ""
	role_entity := make([]interface{}, 0)

	if v, ok := d.GetOk("predefined_acl"); ok {
		predefined_acl = v.(string)
	}

	if v, ok := d.GetOk("role_entity"); ok {
		role_entity = v.([]interface{})
	}

	if v, ok := d.GetOk("default_acl"); ok {
		default_acl = v.(string)
	}

	if len(predefined_acl) > 0 {
		res, err := config.clientStorage.Buckets.Get(bucket).Do()

		if err != nil {
			return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
		}

		_, err = config.clientStorage.Buckets.Update(bucket,
			res).PredefinedAcl(predefined_acl).Do()

		if err != nil {
			return fmt.Errorf("Error updating bucket %s: %v", bucket, err)
		}

	}

	if len(role_entity) > 0 {
		current, err := config.clientStorage.BucketAccessControls.List(bucket).Do()
		if err != nil {
			return fmt.Errorf("Error retrieving current ACLs: %s", err)
		}
		for _, v := range role_entity {
			pair, err := getRoleEntityPair(v.(string))
			if err != nil {
				return err
			}
			var alreadyInserted bool
			for _, cur := range current.Items {
				if cur.Entity == pair.Entity && cur.Role == pair.Role {
					alreadyInserted = true
					break
				}
			}
			if alreadyInserted {
				log.Printf("[DEBUG]: pair %s-%s already exists, not trying to insert again\n", pair.Role, pair.Entity)
				continue
			}
			bucketAccessControl := &storage.BucketAccessControl{
				Role:   pair.Role,
				Entity: pair.Entity,
			}

			log.Printf("[DEBUG]: storing re %s-%s", pair.Role, pair.Entity)

			_, err = config.clientStorage.BucketAccessControls.Insert(bucket, bucketAccessControl).Do()

			if err != nil {
				return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err)
			}
		}

	}

	if len(default_acl) > 0 {
		res, err := config.clientStorage.Buckets.Get(bucket).Do()

		if err != nil {
			return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
		}

		_, err = config.clientStorage.Buckets.Update(bucket,
			res).PredefinedDefaultObjectAcl(default_acl).Do()

		if err != nil {
			return fmt.Errorf("Error updating bucket %s: %v", bucket, err)
		}

	}

	d.SetId(getBucketAclId(bucket))
	return resourceStorageBucketAclRead(d, meta)
}

func resourceStorageBucketAclRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)

	// The API offers no way to retrieve predefined ACLs,
	// and we can't tell which access controls were created
	// by the predefined roles, so...
	//
	// This is, needless to say, a bad state of affairs and
	// should be fixed.
	if _, ok := d.GetOk("role_entity"); ok {
		res, err := config.clientStorage.BucketAccessControls.List(bucket).Do()

		if err != nil {
			return handleNotFoundError(err, d, fmt.Sprintf("Storage Bucket ACL for bucket %q", d.Get("bucket").(string)))
		}
		entities := make([]string, 0, len(res.Items))
		for _, item := range res.Items {
			entities = append(entities, item.Role+":"+item.Entity)
		}

		d.Set("role_entity", entities)
	} else {
		// if we don't set `role_entity` to nil (effectively setting it
		// to empty in Terraform state), because it's computed now,
		// Terraform will think it's missing from state, is supposed
		// to be there, and throw up a diff for role_entity.#. So it
		// must always be set in state.
		d.Set("role_entity", nil)
	}

	return nil
}

func resourceStorageBucketAclUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)

	if d.HasChange("role_entity") {
		bkt, err := config.clientStorage.Buckets.Get(bucket).Do()
		if err != nil {
			return fmt.Errorf("Error reading bucket %q: %v", bucket, err)
		}

		project := strconv.FormatUint(bkt.ProjectNumber, 10)
		o, n := d.GetChange("role_entity")
		old_re, new_re := o.([]interface{}), n.([]interface{})

		old_re_map := make(map[string]string)
		for _, v := range old_re {
			res, err := getRoleEntityPair(v.(string))

			if err != nil {
				return fmt.Errorf(
					"Old state has malformed Role/Entity pair: %v", err)
			}

			old_re_map[res.Entity] = res.Role
		}

		for _, v := range new_re {
			pair, err := getRoleEntityPair(v.(string))

			bucketAccessControl := &storage.BucketAccessControl{
				Role:   pair.Role,
				Entity: pair.Entity,
			}

			// If the old state is missing this entity, it needs to be inserted
			if _, ok := old_re_map[pair.Entity]; !ok {
				_, err = config.clientStorage.BucketAccessControls.Insert(
					bucket, bucketAccessControl).Do()
			}

			// Now we only store the keys that have to be removed
			delete(old_re_map, pair.Entity)

			if err != nil {
				return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err)
			}
		}

		for entity, role := range old_re_map {
			if entity == fmt.Sprintf("project-owners-%s", project) && role == "OWNER" {
				log.Printf("[WARN]: Skipping %s-%s; not deleting owner ACL.", role, entity)
				continue
			}
			log.Printf("[DEBUG]: removing entity %s", entity)
			err := config.clientStorage.BucketAccessControls.Delete(bucket, entity).Do()

			if err != nil {
				return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err)
			}
		}

		return resourceStorageBucketAclRead(d, meta)
	}

	if d.HasChange("default_acl") {
		default_acl := d.Get("default_acl").(string)

		res, err := config.clientStorage.Buckets.Get(bucket).Do()

		if err != nil {
			return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
		}

		_, err = config.clientStorage.Buckets.Update(bucket,
			res).PredefinedDefaultObjectAcl(default_acl).Do()

		if err != nil {
			return fmt.Errorf("Error updating bucket %s: %v", bucket, err)
		}

		return resourceStorageBucketAclRead(d, meta)
	}

	return nil
}

func resourceStorageBucketAclDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)

	bkt, err := config.clientStorage.Buckets.Get(bucket).Do()
	if err != nil {
		return fmt.Errorf("Error retrieving bucket %q: %v", bucket, err)
	}
	project := strconv.FormatUint(bkt.ProjectNumber, 10)

	re_local := d.Get("role_entity").([]interface{})
	for _, v := range re_local {
		res, err := getRoleEntityPair(v.(string))
		if err != nil {
			return err
		}

		if res.Entity == fmt.Sprintf("project-owners-%s", project) && res.Role == "OWNER" {
			log.Printf("[WARN]: Skipping %s-%s; not deleting owner ACL.", res.Role, res.Entity)
			continue
		}

		log.Printf("[DEBUG]: removing entity %s", res.Entity)

		err = config.clientStorage.BucketAccessControls.Delete(bucket, res.Entity).Do()

		if err != nil {
			return fmt.Errorf("Error deleting entity %s ACL: %s", res.Entity, err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package docker

import (
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
)

func TestAccDockerImage_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccDockerImageConfig,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(
						"docker_image.foo",
						"latest",
						"d0955f21bf24f5bfffd32d2d0bb669d0564701c271bc3dfc64cfc5adfdec2d07"),
				),
			},
		},
	})
}

const testAccDockerImageConfig = `
resource "docker_image" "foo" {
	name = "ubuntu:trusty-20150320"
	keep_updated = true
}
`
<commit_msg>provider/docker: update image sha<commit_after>package docker

import (
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
)

func TestAccDockerImage_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccDockerImageConfig,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(
						"docker_image.foo",
						"latest",
						"b7cf8f0d9e82c9d96bd7afd22c600bfdb86b8d66c50d29164e5ad2fb02f7187b"),
				),
			},
		},
	})
}

const testAccDockerImageConfig = `
resource "docker_image" "foo" {
	name = "ubuntu:trusty-20150320"
	keep_updated = true
}
`
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/BurntSushi/toml"
)

type status struct {
	Name   string `toml:"name"`
	Type   string `toml:"type"`
	Status string
	URL    string `toml:"url"`
}

type sites struct {
	Service []status
}

type Status interface {
	Check(url string) (bool, error)
}

var check map[string]Status

type server struct {
	configfile  string
	lastconfig  time.Time
	htmlfile    string
	templ       *template.Template
	site_status []status
	next_status time.Time
	last_status time.Time
	html        []byte
	sync.Mutex
}

func (s *server) initialize() error {
	var err error

	s.templ, err = template.ParseFiles(s.htmlfile)
	if err != nil {
		return err
	}

	return nil
}

func (s *server) readConfig() error {
	var config sites

	fi, err := os.Stat(s.configfile)
	if err != nil {
		return err
	}

	if s.lastconfig.After(fi.ModTime()) {
		return nil
	}

	_, err = toml.DecodeFile(s.configfile, &config)
	if err != nil {
		return err
	}

	s.lastconfig = time.Now()
	s.site_status = config.Service

	for i, _ := range s.site_status {
		s.site_status[i].Status = "unknown"
	}

	return nil
}

func (s *server) checkStatus() {
	var wg sync.WaitGroup

	for i, stat := range s.site_status {
		ck, ok := check[stat.Type]
		if ok == false {
			log.Println(stat.Type, stat.URL, "unknown type")
			continue
		}

		wg.Add(1)
		go func(idx int) {
			defer wg.Done()
			healthy, err := ck.Check(s.site_status[idx].URL)
			if err == nil && healthy {
				s.site_status[idx].Status = "online"
				return
			}

			s.site_status[idx].Status = "offline"
			log.Println(s.site_status[idx].Type, s.site_status[idx].URL, err)
		}(i)
	}

	wg.Wait()
}

func (s *server) updateStatus() error {
	s.Lock()
	defer s.Unlock()

	if s.next_status.Before(time.Now()) {
		err := s.readConfig()
		if err != nil {
			return err
		}

		s.checkStatus()

		s.last_status = time.Now()
		s.next_status = s.last_status.Add(time.Second * 30)
	}

	x := &struct {
		Status   []status
		DateTime string
	}{
		Status:   s.site_status,
		DateTime: s.last_status.String(),
	}

	b := &bytes.Buffer{}

	err := s.templ.Execute(b, x)
	if err != nil {
		return err
	}

	s.html, err = ioutil.ReadAll(b)
	if err != nil {
		return err
	}

	return nil
}

func (s *server) statusHandler(w http.ResponseWriter, r *http.Request) {
	host, _, _ := net.SplitHostPort(r.RemoteAddr)
	log.Println("request from", host)

	s.updateStatus()

	b := bytes.NewBuffer(s.html)

	io.Copy(w, b)
}

func init() {
	check = map[string]Status{
		"website":  new(Website),
		"etcd":     new(Etcd),
		"docker":   new(Docker),
		"registry": new(Registry),
	}
}

func main() {
	var (
		port     = flag.String("port", "", "HTTP service address (.e.g. 8080)")
		conffile = flag.String("conf", "sitecheck.conf", "Configuration file")
	)

	flag.Parse()

	if *port == "" {
		flag.Usage()
		return
	}

	s := &server{
		configfile: *conffile,
		htmlfile:   "status.html",
	}
	err := s.initialize()
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", s.statusHandler)
	log.Fatal(http.ListenAndServe(":"+*port, nil))
}
<commit_msg>reduce status check cycle to 5 seconds<commit_after>package main

import (
	"bytes"
	"flag"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/BurntSushi/toml"
)

type status struct {
	Name   string `toml:"name"`
	Type   string `toml:"type"`
	Status string
	URL    string `toml:"url"`
}

type sites struct {
	Service []status
}

type Status interface {
	Check(url string) (bool, error)
}

var check map[string]Status

type server struct {
	configfile  string
	lastconfig  time.Time
	htmlfile    string
	templ       *template.Template
	site_status []status
	next_status time.Time
	last_status time.Time
	html        []byte
	sync.Mutex
}

func (s *server) initialize() error {
	var err error

	s.templ, err = template.ParseFiles(s.htmlfile)
	if err != nil {
		return err
	}

	return nil
}

func (s *server) readConfig() error {
	var config sites

	fi, err := os.Stat(s.configfile)
	if err != nil {
		return err
	}

	if s.lastconfig.After(fi.ModTime()) {
		return nil
	}

	_, err = toml.DecodeFile(s.configfile, &config)
	if err != nil {
		return err
	}

	s.lastconfig = time.Now()
	s.site_status = config.Service

	for i, _ := range s.site_status {
		s.site_status[i].Status = "unknown"
	}

	return nil
}

func (s *server) checkStatus() {
	var wg sync.WaitGroup

	for i, stat := range s.site_status {
		ck, ok := check[stat.Type]
		if ok == false {
			log.Println(stat.Type, stat.URL, "unknown type")
			continue
		}

		wg.Add(1)
		go func(idx int) {
			defer wg.Done()
			healthy, err := ck.Check(s.site_status[idx].URL)
			if err == nil && healthy {
				s.site_status[idx].Status = "online"
				return
			}

			s.site_status[idx].Status = "offline"
			log.Println(s.site_status[idx].Type, s.site_status[idx].URL, err)
		}(i)
	}

	wg.Wait()
}

func (s *server) updateStatus() error {
	s.Lock()
	defer s.Unlock()

	if s.next_status.Before(time.Now()) {
		err := s.readConfig()
		if err != nil {
			return err
		}

		s.checkStatus()

		s.last_status = time.Now()
		s.next_status = s.last_status.Add(time.Second * 5)
	}

	x := &struct {
		Status   []status
		DateTime string
	}{
		Status:   s.site_status,
		DateTime: s.last_status.String(),
	}

	b := &bytes.Buffer{}

	err := s.templ.Execute(b, x)
	if err != nil {
		return err
	}

	s.html, err = ioutil.ReadAll(b)
	if err != nil {
		return err
	}

	return nil
}

func (s *server) statusHandler(w http.ResponseWriter, r *http.Request) {
	host, _, _ := net.SplitHostPort(r.RemoteAddr)
	log.Println("request from", host)

	s.updateStatus()

	b := bytes.NewBuffer(s.html)

	io.Copy(w, b)
}

func init() {
	check = map[string]Status{
		"website":  new(Website),
		"etcd":     new(Etcd),
		"docker":   new(Docker),
		"registry": new(Registry),
	}
}

func main() {
	var (
		port     = flag.String("port", "", "HTTP service address (.e.g. 8080)")
		conffile = flag.String("conf", "sitecheck.conf", "Configuration file")
	)

	flag.Parse()

	if *port == "" {
		flag.Usage()
		return
	}

	s := &server{
		configfile: *conffile,
		htmlfile:   "status.html",
	}
	err := s.initialize()
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", s.statusHandler)
	log.Fatal(http.ListenAndServe(":"+*port, nil))
}
<|endoftext|>


<commit_before>package slug_test

import (
	"github.com/tv42/slug"
	"testing"
)

func TestSlug(t *testing.T) {
	tests := []struct {
		In, Want string
	}{
		{"foo bar", "foo-bar"},
		{"foo  bar", "foo-bar"},
		{"foo   ", "foo"},
		{"exam҉ple", "example"},
		{"Foo Bar", "foo-bar"},
	}

	for _, test := range tests {
		got := slug.Slug(test.In)
		if got != test.Want {
			t.Errorf("wrong slug: URL(%q)=%q want %q", test.In, got, test.Want)
		}
	}
}
<commit_msg>Demonstrate Slug disarms filename attacks<commit_after>package slug_test

import (
	"github.com/tv42/slug"
	"testing"
)

func TestSlug(t *testing.T) {
	tests := []struct {
		In, Want string
	}{
		{"foo bar", "foo-bar"},
		{"foo  bar", "foo-bar"},
		{"foo   ", "foo"},
		{"exam҉ple", "example"},
		{"Foo Bar", "foo-bar"},
		{".foo", "foo"},
		{"../evil", "evil"},
		{"../../etc/passwd", "etc-passwd"},
	}

	for _, test := range tests {
		got := slug.Slug(test.In)
		if got != test.Want {
			t.Errorf("wrong slug: URL(%q)=%q want %q", test.In, got, test.Want)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"time"
)

const (
	maxDatagramSize = 8192
)

var discover = []byte("{\"system\":{\"get_sysinfo\":null},\"emeter\":{\"get_realtime\":null}}")

type SmartPlugMessage struct {
	Emeter Emeter `json:"emeter"`
	System System `json:"system"`
}

type Emeter struct {
	Realtime Realtime `json:"get_realtime"`
}

type System struct {
	SysInfo SysInfo `json:"get_sysinfo"`
}

type Realtime struct {
	Current float32
	Error   int `json:"err_code"`
	Power   float32
	Total   float32
	Voltage float32
}

type SysInfo struct {
	Mode       string `json:"active_mode"`
	Name       string `json:"alias"`
	DeviceName string `json:"dev_name"`
	ID         string `json:"deviceId"`
	Error      int    `json:"err_code"`
	MAC        string
	Model      string
	State      int `json:"relay_state"`
}

func obfuscate(data []byte) []byte {
	k := byte(171)
	ret := make([]byte, len(data))
	for i := 0; i < len(data); i++ {
		ret[i] = data[i] ^ k
		k = ret[i]
	}
	return ret
}

func deobfuscate(data []byte) []byte {
	k := byte(171)
	ret := make([]byte, len(data))
	for i := 0; i < len(data); i++ {
		ret[i] = data[i] ^ k
		k = data[i]
	}
	return ret
}

func main() {
	addr, err := net.ResolveUDPAddr("udp", "255.255.255.255:9999")
	if err != nil {
		log.Fatal("Failed to resolve UDP addr:", err)
	}

	conn, err := net.ListenUDP("udp", nil)
	packetCh := make(chan []byte)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	go func() {
		for {
			buf := make([]byte, maxDatagramSize)
			conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
			n, _, _ := conn.ReadFromUDP(buf)
			if n > 0 {
				packetCh <- buf[:n]
			}
			if ctx.Err() != nil {
				close(packetCh)
				return
			}
		}
	}()
	conn.WriteTo(obfuscate(discover), addr)
	for packet := range packetCh {
		fmt.Println(string(deobfuscate(packet)))
		var message SmartPlugMessage
		err = json.Unmarshal(deobfuscate(packet), &message)
		if err != nil {
			log.Fatal("Failed to decode as JSON")
		}
		out, _ := json.MarshalIndent(message, "", "  ")
		fmt.Printf("%s\n", out)
	}
}
<commit_msg>Generate discover message<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"time"
)

const (
	maxDatagramSize = 8192
)

type SmartPlugMessage struct {
	Emeter Emeter `json:"emeter"`
	System System `json:"system"`
}

type Emeter struct {
	Realtime Realtime `json:"get_realtime"`
}

type System struct {
	SysInfo SysInfo `json:"get_sysinfo"`
}

type Realtime struct {
	Current float32
	Error   int `json:"err_code"`
	Power   float32
	Total   float32
	Voltage float32
}

type SysInfo struct {
	Mode       string `json:"active_mode"`
	Name       string `json:"alias"`
	DeviceName string `json:"dev_name"`
	ID         string `json:"deviceId"`
	Error      int    `json:"err_code"`
	MAC        string
	Model      string
	State      int `json:"relay_state"`
}

func obfuscate(data []byte) []byte {
	k := byte(171)
	ret := make([]byte, len(data))
	for i := 0; i < len(data); i++ {
		ret[i] = data[i] ^ k
		k = ret[i]
	}
	return ret
}

func deobfuscate(data []byte) []byte {
	k := byte(171)
	ret := make([]byte, len(data))
	for i := 0; i < len(data); i++ {
		ret[i] = data[i] ^ k
		k = data[i]
	}
	return ret
}

func main() {
	addr, err := net.ResolveUDPAddr("udp", "255.255.255.255:9999")
	if err != nil {
		log.Fatal("Failed to resolve UDP addr:", err)
	}

	conn, err := net.ListenUDP("udp", nil)
	packetCh := make(chan []byte)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	go func() {
		for {
			buf := make([]byte, maxDatagramSize)
			conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
			n, _, _ := conn.ReadFromUDP(buf)
			if n > 0 {
				packetCh <- buf[:n]
			}
			if ctx.Err() != nil {
				close(packetCh)
				return
			}
		}
	}()

	discover := SmartPlugMessage{
		System: System{
			SysInfo: SysInfo{},
		},
		Emeter: Emeter{
			Realtime: Realtime{},
		},
	}
	j, err := json.Marshal(discover)
	if err != nil {
		log.Fatal("Error encoding json", err)
	}
	conn.WriteTo(obfuscate(j), addr)
	for packet := range packetCh {
		fmt.Println(string(deobfuscate(packet)))
		var message SmartPlugMessage
		err = json.Unmarshal(deobfuscate(packet), &message)
		if err != nil {
			log.Fatal("Failed to decode as JSON")
		}
		out, _ := json.MarshalIndent(message, "", "  ")
		fmt.Printf("%s\n", out)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/ziutek/gogammu"
	"github.com/ziutek/mymysql/autorc"
	_ "github.com/ziutek/mymysql/native"
	"io"
	"log"
	"strings"
	"time"
)

type SMSd struct {
	sm *gammu.StateMachine
	db *autorc.Conn

	end, newMsg chan event
	wait        bool

	sqlNumToId string

	stmtOutboxGet, stmtRecipGet, stmtRecipSent, stmtInboxPut,
	stmtRecipReport, stmtOutboxDel, stmtNumToId autorc.Stmt

	filter *Filter
}

func NewSMSd(db *autorc.Conn, numId, filter string) (*SMSd, error) {
	var err error
	smsd := new(SMSd)
	smsd.sm, err = gammu.NewStateMachine("")
	if err != nil {
		return nil, err
	}
	if filter != "" {
		smsd.filter, err = NewFilter(filter)
		if err != nil {
			return nil, err
		}
	}
	smsd.db = db
	smsd.db.Register(setNames)
	smsd.db.Register(createOutbox)
	smsd.db.Register(createRecipients)
	smsd.db.Register(createInbox)
	smsd.db.Register(setLocPrefix)
	smsd.sqlNumToId = numId
	smsd.end = make(chan event)
	smsd.newMsg = make(chan event, 1)
	return smsd, nil
}

// Selects messages from Outbox that have any recipient without sent flag set
const outboxGet = `SELECT
	o.id, o.src, o.report, o.body
FROM
	` + outboxTable + ` o
WHERE
	EXISTS (SELECT * FROM ` + recipientsTable + ` p WHERE p.msgId=o.id && !p.sent)
`

// Selects all recipients without sent flag set for givem msgId
const recipientsGet = `SELECT
	id, number
FROM
	` + recipientsTable + `
WHERE
	!sent && msgId=?
`

const recipientsSent = "UPDATE " + recipientsTable + " SET sent=? WHERE id=?"

// Send messages from Outbox
func (smsd *SMSd) sendMessages() (gammuErr bool) {
	if !prepareOnce(smsd.db, &smsd.stmtOutboxGet, outboxGet) {
		return
	}
	if !prepareOnce(smsd.db, &smsd.stmtRecipGet, recipientsGet) {
		return
	}
	if !prepareOnce(smsd.db, &smsd.stmtRecipSent, recipientsSent) {
		return
	}
	msgs, res, err := smsd.stmtOutboxGet.Exec()
	if err != nil {
		log.Println("Can't get a messages from Outbox:", err)
		return
	}
	colMid := res.Map("id")
	colReport := res.Map("report")
	colBody := res.Map("body")
	for _, msg := range msgs {
		mid := msg.Uint(colMid)
		report := msg.Bool(colReport)
		body := msg.Str(colBody)

		recipients, res, err := smsd.stmtRecipGet.Exec(mid)
		if err != nil {
			log.Printf("Can't get a phone number for msg #%d: %s", mid, err)
			return
		}
		colPid := res.Map("id")
		colNum := res.Map("number")
		for _, p := range recipients {
			pid := p.Uint(colPid)
			num := p.Str(colNum)
			if !checkNumber(num) {
				continue
			}
			if isGammuError(smsd.sm.SendLongSMS(num, body, report)) {
				// Phone error or bad values
				gammuErr = true
			}
			_, _, err = smsd.stmtRecipSent.Exec(time.Now(), pid)
			if err != nil {
				log.Printf(
					"Can't mark a msg/recip #%d/#%d as sent: %s",
					mid, pid, err,
				)
				return
			}
		}
	}
	return
}

const inboxPut = `INSERT
	` + inboxTable + `
SET
	time=?,
	number=?,
	srcId=?,
	rd=?,
	body=?
`

const recipReport = `UPDATE
	` + recipientsTable + `
SET
	report=?
WHERE
	!report && (number=? || concat(@localPrefix, number)=?)
ORDER BY
	abs(timediff(?, sent))
LIMIT 1`

type Msg struct {
	Time   time.Time
	Number string
	SrcId  uint
	Body   string
	Note   string
}

func (smsd *SMSd) recvMessages() (gammuErr bool) {
	if !prepareOnce(smsd.db, &smsd.stmtInboxPut, inboxPut) {
		return
	}
	if !prepareOnce(smsd.db, &smsd.stmtRecipReport, recipReport) {
		return
	}
	if smsd.sqlNumToId != "" {
		if !prepareOnce(smsd.db, &smsd.stmtNumToId, smsd.sqlNumToId) {
			return
		}
	}

	var msg Msg
	smsd.stmtInboxPut.Bind(&msg)

	for {
		sms, err := smsd.sm.GetSMS()
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Printf("Can't get message from phone: %s", err)
			return true
		}
		if sms.Report {
			// Find a message and sender in Outbox and mark it
			m := strings.TrimSpace(sms.Body)
			if strings.ToLower(m) == "delivered" {
				_, _, err = smsd.stmtRecipReport.Exec(
					sms.SMSCTime, sms.Number, sms.Number, sms.Time,
				)
				if err != nil {
					log.Printf(
						"Can't mark recipient %s as reported: %s",
						sms.Number, err,
					)
					return
				}
			}
		} else {
			// Save a message in Inbox
			msg.Time = sms.Time
			msg.Number = sms.Number
			msg.SrcId = 0
			msg.Body = sms.Body
			//log.Printf("Odebrano: %+v", msg)
			if smsd.stmtNumToId.Raw != nil {
				id, _, err := smsd.stmtNumToId.ExecFirst(msg.Number)
				if err != nil {
					log.Printf(
						"Can't get srcId for number %s: %s",
						sms.Number, err,
					)
					return
				}
				if id != nil {
					msg.SrcId, err = id.UintErr(0)
					if err != nil {
						log.Printf("Bad srcId '%v': %s", id[0], err)
						return
					}
				}
			}
			if f := smsd.filter; f != nil {
				accept, err := f.Filter(&msg)
				if err != nil {
					log.Printf("Filter error: %s", err)
				} else if !accept {
					// Drop this message
					continue
				}
			}
			_, _, err = smsd.stmtInboxPut.Exec() // using msg
			if err != nil {
				log.Printf(
					"Can't insert message from %s into Inbox: %s",
					sms.Number, err,
				)
				return
			}
		}
	}
	return
}

const outboxDel = `DELETE FROM
	o
USING
	SMSd_Outbox o
WHERE
	o.del && !EXISTS(
		SELECT
			*
		FROM
			SMSd_Recipients r
		WHERE
			r.msgId = o.id && (!r.sent || o.report && !r.report)
	)
`

func (smsd *SMSd) delMessages() {
	if !prepareOnce(smsd.db, &smsd.stmtOutboxDel, outboxDel) {
		return
	}
	_, _, err := smsd.stmtOutboxDel.Exec()
	if err != nil {
		log.Println("Can't delete messages:", err)
		return
	}
}

func (smsd *SMSd) sendRecvDel(send bool) {
	var gammuErr bool
	if !smsd.sm.IsConnected() {
		if isGammuError(smsd.sm.Connect()) {
			return
		}
	}
	if send {
		gammuErr = smsd.sendMessages()
	}
	gammuErr = smsd.recvMessages() || gammuErr
	if send {
		smsd.delMessages()
	}
	if gammuErr && smsd.sm.IsConnected() {
		smsd.sm.Disconnect()
	}
}

func (smsd *SMSd) loop() {
	send := true
	for {
		smsd.sendRecvDel(send)
		// Wait for some event or timeout
		select {
		case <-smsd.end:
			return
		case <-smsd.newMsg:
			send = true
		case <-time.After(15 * time.Second): // if 11s my phone works bad
			// send and del two times less frequently than recv
			send = !send
		}
	}
}

func (smsd *SMSd) Start() {
	go smsd.loop()
}

func (smsd *SMSd) Stop() {
	smsd.end <- event{}
}

func (smsd *SMSd) NewMsg() {
	select {
	case smsd.newMsg <- event{}:
	default:
	}
}
<commit_msg>Fix bug in inbox insert<commit_after>package main

import (
	"github.com/ziutek/gogammu"
	"github.com/ziutek/mymysql/autorc"
	_ "github.com/ziutek/mymysql/native"
	"io"
	"log"
	"strings"
	"time"
)

type SMSd struct {
	sm *gammu.StateMachine
	db *autorc.Conn

	end, newMsg chan event
	wait        bool

	sqlNumToId string

	stmtOutboxGet, stmtRecipGet, stmtRecipSent, stmtInboxPut,
	stmtRecipReport, stmtOutboxDel, stmtNumToId autorc.Stmt

	filter *Filter
}

func NewSMSd(db *autorc.Conn, numId, filter string) (*SMSd, error) {
	var err error
	smsd := new(SMSd)
	smsd.sm, err = gammu.NewStateMachine("")
	if err != nil {
		return nil, err
	}
	if filter != "" {
		smsd.filter, err = NewFilter(filter)
		if err != nil {
			return nil, err
		}
	}
	smsd.db = db
	smsd.db.Register(setNames)
	smsd.db.Register(createOutbox)
	smsd.db.Register(createRecipients)
	smsd.db.Register(createInbox)
	smsd.db.Register(setLocPrefix)
	smsd.sqlNumToId = numId
	smsd.end = make(chan event)
	smsd.newMsg = make(chan event, 1)
	return smsd, nil
}

// Selects messages from Outbox that have any recipient without sent flag set
const outboxGet = `SELECT
	o.id, o.src, o.report, o.body
FROM
	` + outboxTable + ` o
WHERE
	EXISTS (SELECT * FROM ` + recipientsTable + ` p WHERE p.msgId=o.id && !p.sent)
`

// Selects all recipients without sent flag set for givem msgId
const recipientsGet = `SELECT
	id, number
FROM
	` + recipientsTable + `
WHERE
	!sent && msgId=?
`

const recipientsSent = "UPDATE " + recipientsTable + " SET sent=? WHERE id=?"

// Send messages from Outbox
func (smsd *SMSd) sendMessages() (gammuErr bool) {
	if !prepareOnce(smsd.db, &smsd.stmtOutboxGet, outboxGet) {
		return
	}
	if !prepareOnce(smsd.db, &smsd.stmtRecipGet, recipientsGet) {
		return
	}
	if !prepareOnce(smsd.db, &smsd.stmtRecipSent, recipientsSent) {
		return
	}
	msgs, res, err := smsd.stmtOutboxGet.Exec()
	if err != nil {
		log.Println("Can't get a messages from Outbox:", err)
		return
	}
	colMid := res.Map("id")
	colReport := res.Map("report")
	colBody := res.Map("body")
	for _, msg := range msgs {
		mid := msg.Uint(colMid)
		report := msg.Bool(colReport)
		body := msg.Str(colBody)

		recipients, res, err := smsd.stmtRecipGet.Exec(mid)
		if err != nil {
			log.Printf("Can't get a phone number for msg #%d: %s", mid, err)
			return
		}
		colPid := res.Map("id")
		colNum := res.Map("number")
		for _, p := range recipients {
			pid := p.Uint(colPid)
			num := p.Str(colNum)
			if !checkNumber(num) {
				continue
			}
			if isGammuError(smsd.sm.SendLongSMS(num, body, report)) {
				// Phone error or bad values
				gammuErr = true
			}
			_, _, err = smsd.stmtRecipSent.Exec(time.Now(), pid)
			if err != nil {
				log.Printf(
					"Can't mark a msg/recip #%d/#%d as sent: %s",
					mid, pid, err,
				)
				return
			}
		}
	}
	return
}

const inboxPut = `INSERT
	` + inboxTable + `
SET
	time=?,
	number=?,
	srcId=?,
	body=?
	note=?,
`

const recipReport = `UPDATE
	` + recipientsTable + `
SET
	report=?
WHERE
	!report && (number=? || concat(@localPrefix, number)=?)
ORDER BY
	abs(timediff(?, sent))
LIMIT 1`

type Msg struct {
	Time   time.Time
	Number string
	SrcId  uint
	Body   string
	Note   string
}

func (smsd *SMSd) recvMessages() (gammuErr bool) {
	if !prepareOnce(smsd.db, &smsd.stmtInboxPut, inboxPut) {
		return
	}
	if !prepareOnce(smsd.db, &smsd.stmtRecipReport, recipReport) {
		return
	}
	if smsd.sqlNumToId != "" {
		if !prepareOnce(smsd.db, &smsd.stmtNumToId, smsd.sqlNumToId) {
			return
		}
	}

	var msg Msg
	smsd.stmtInboxPut.Bind(&msg)

	for {
		sms, err := smsd.sm.GetSMS()
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Printf("Can't get message from phone: %s", err)
			return true
		}
		if sms.Report {
			// Find a message and sender in Outbox and mark it
			m := strings.TrimSpace(sms.Body)
			if strings.ToLower(m) == "delivered" {
				_, _, err = smsd.stmtRecipReport.Exec(
					sms.SMSCTime, sms.Number, sms.Number, sms.Time,
				)
				if err != nil {
					log.Printf(
						"Can't mark recipient %s as reported: %s",
						sms.Number, err,
					)
					return
				}
			}
		} else {
			// Save a message in Inbox
			msg.Time = sms.Time
			msg.Number = sms.Number
			msg.SrcId = 0
			msg.Body = sms.Body
			//log.Printf("Odebrano: %+v", msg)
			if smsd.stmtNumToId.Raw != nil {
				id, _, err := smsd.stmtNumToId.ExecFirst(msg.Number)
				if err != nil {
					log.Printf(
						"Can't get srcId for number %s: %s",
						sms.Number, err,
					)
					return
				}
				if id != nil {
					msg.SrcId, err = id.UintErr(0)
					if err != nil {
						log.Printf("Bad srcId '%v': %s", id[0], err)
						return
					}
				}
			}
			if f := smsd.filter; f != nil {
				accept, err := f.Filter(&msg)
				if err != nil {
					log.Printf("Filter error: %s", err)
				} else if !accept {
					// Drop this message
					continue
				}
			}
			_, _, err = smsd.stmtInboxPut.Exec() // using msg
			if err != nil {
				log.Printf(
					"Can't insert message from %s into Inbox: %s",
					sms.Number, err,
				)
				return
			}
		}
	}
	return
}

const outboxDel = `DELETE FROM
	o
USING
	SMSd_Outbox o
WHERE
	o.del && !EXISTS(
		SELECT
			*
		FROM
			SMSd_Recipients r
		WHERE
			r.msgId = o.id && (!r.sent || o.report && !r.report)
	)
`

func (smsd *SMSd) delMessages() {
	if !prepareOnce(smsd.db, &smsd.stmtOutboxDel, outboxDel) {
		return
	}
	_, _, err := smsd.stmtOutboxDel.Exec()
	if err != nil {
		log.Println("Can't delete messages:", err)
		return
	}
}

func (smsd *SMSd) sendRecvDel(send bool) {
	var gammuErr bool
	if !smsd.sm.IsConnected() {
		if isGammuError(smsd.sm.Connect()) {
			return
		}
	}
	if send {
		gammuErr = smsd.sendMessages()
	}
	gammuErr = smsd.recvMessages() || gammuErr
	if send {
		smsd.delMessages()
	}
	if gammuErr && smsd.sm.IsConnected() {
		smsd.sm.Disconnect()
	}
}

func (smsd *SMSd) loop() {
	send := true
	for {
		smsd.sendRecvDel(send)
		// Wait for some event or timeout
		select {
		case <-smsd.end:
			return
		case <-smsd.newMsg:
			send = true
		case <-time.After(15 * time.Second): // if 11s my phone works bad
			// send and del two times less frequently than recv
			send = !send
		}
	}
}

func (smsd *SMSd) Start() {
	go smsd.loop()
}

func (smsd *SMSd) Stop() {
	smsd.end <- event{}
}

func (smsd *SMSd) NewMsg() {
	select {
	case smsd.newMsg <- event{}:
	default:
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"testing"
)

func init() {
	Path = os.Getenv("PATH_TO_RASPISTILL-MOCK")
}

func TestCameraStill(t *testing.T) {
	imageBytes, err := ioutil.ReadFile("helpers/raspipic.jpg")
	if err != nil {
		t.Error(err)
	}

	//where param is valid
	flip := ""
	output := bytes.NewBuffer(nil)
	cameraStill(output, flip)

	if bytes.Equal(output.Bytes(), imageBytes) {
		fmt.Println("test1 passed")
	} else {
		t.Errorf("test1 failed")
	}

	//where param is invalid
	flip = "asdf"
	output = bytes.NewBuffer(nil)
	cameraStill(output, flip)

	if !bytes.Equal(output.Bytes(), imageBytes) {
		fmt.Println("test2 passed")
	} else {
		t.Errorf("test2 failed")
	}

}
<commit_msg>clean up tests<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"testing"
)

func init() {
	Path = os.Getenv("PATH_TO_RASPISTILL-MOCK")
}

func TestCameraStill(t *testing.T) {
	imageBytes, err := ioutil.ReadFile("helpers/raspipic.jpg")
	if err != nil {
		t.Error(err)
	}

	//Where flip param is valid.
	output := bytes.NewBuffer(nil)
	cameraStill(output, "")

	if !bytes.Equal(output.Bytes(), imageBytes) {
		t.Errorf("Test failed when flip param is empty")
	}

	//Where flip param is invalid.
	output = bytes.NewBuffer(nil)
	cameraStill(output, "asdf")

	if bytes.Equal(output.Bytes(), imageBytes) {
		t.Errorf("Test failed when flip param is invalid.")
	}
}
<|endoftext|>


<commit_before>// poolc.go 连接池为 backend 存放来自 frontend 之间的连接

package trafcacc

import (
	"encoding/gob"
	"sync"

	log "github.com/Sirupsen/logrus"
)

// poole holds connections from frontend for backend
type poole struct {
	cond *sync.Cond
	pl   []*gob.Encoder
	id   int
}

func newPoole() *poole {
	return &poole{cond: sync.NewCond(&sync.Mutex{})}
}

func (p *poole) add(c *gob.Encoder) {
	p.cond.L.Lock()
	p.pl = append(p.pl, c)
	p.cond.L.Unlock()
	p.cond.Broadcast()
}

func (p *poole) next() *gob.Encoder {
	p.cond.L.Lock()
	for len(p.pl) == 0 {
		log.WithFields(log.Fields{
			"poolen": len(p.pl),
		}).Debugln("wait for connections from frontend")
		p.cond.Wait()
	}
	defer p.cond.L.Unlock()
	p.id++
	return p.pl[p.id%len(p.pl)]
}

func (p *poole) remove(c *gob.Encoder) {
	// TODO: need to be called some time
	p.cond.L.Lock()
	for id, v := range p.pl {
		if v == c {
			p.pl = append(p.pl[:id], p.pl[id+1:]...)
			return
		}
	}
	p.cond.L.Unlock()
	p.cond.Broadcast()
}
<commit_msg>Update poole.go<commit_after>// poolc.go 连接池为 backend 存放来自 frontend 之间的连接

package trafcacc

import (
	"encoding/gob"
	"math/rand"
	"sync"

	log "github.com/Sirupsen/logrus"
)

// poole holds connections from frontend for backend
type poole struct {
	cond *sync.Cond
	pl   []*gob.Encoder
	id   int
}

func newPoole() *poole {
	return &poole{cond: sync.NewCond(&sync.Mutex{})}
}

func (p *poole) add(c *gob.Encoder) {
	p.cond.L.Lock()
	p.pl = append(p.pl, c)
	p.cond.L.Unlock()
	p.cond.Broadcast()
}

func (p *poole) next() *gob.Encoder {
	p.cond.L.Lock()
	for len(p.pl) == 0 {
		log.WithFields(log.Fields{
			"poolen": len(p.pl),
		}).Debugln("wait for connections from frontend")
		p.cond.Wait()
	}
	defer p.cond.L.Unlock()
	p.id += uint32(rand.Intn(int(p.end)))
	return p.pl[p.id%len(p.pl)]
}

func (p *poole) remove(c *gob.Encoder) {
	// TODO: need to be called some time
	p.cond.L.Lock()
	for id, v := range p.pl {
		if v == c {
			p.pl = append(p.pl[:id], p.pl[id+1:]...)
			return
		}
	}
	p.cond.L.Unlock()
	p.cond.Broadcast()
}
<|endoftext|>


<commit_before>// statspipe is a metrics pipeline
package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"net"
	"regexp"
	"sort"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	//"github.com/davecgh/go-spew/spew"
	"github.com/davecheney/profile"
)

const FlushInterval = time.Duration(10 * time.Second)
const BufSize = 8192

//-----------------------------------------------------------------------------

// Command line flags
var (
	listen     = flag.String("listen", ":1514", "UDP listener address")
	graphite   = flag.String("graphite", "localhost:2003", "Graphite server address")
	cpuprofile = flag.Bool("cpuprofile", false, "Enable CPU profiling")
)

// Metric Types
var In = make(chan *Metric)

var counters = struct {
	sync.RWMutex
	m map[string]int64
}{m: make(map[string]int64)}

var gauges = struct {
	sync.RWMutex
	m map[string]uint64
}{m: make(map[string]uint64)}

type Timers []uint64

func (t Timers) Len() int           { return len(t) }
func (t Timers) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t Timers) Less(i, j int) bool { return t[i] < t[j] }

var timers = struct {
	sync.RWMutex
	m map[string]Timers
}{m: make(map[string]Timers)}

var Percentiles = []int{5, 95}

// Internal metrics
type Stats struct {
	IngressRate     int64
	IngressMetrics  int64
	IngressCounters int64
	IngressGauges   int64
	IngressTimers   int64
}

var stats = &Stats{}

//-----------------------------------------------------------------------------
// Read syslog stream

func ListenUDP(addr string) error {
	var buf = make([]byte, 1024)
	ln, err := net.ResolveUDPAddr("udp", addr)

	if err != nil {
		return err
	}

	sock, err := net.ListenUDP("udp", ln)

	if err != nil {
		return err
	}

	log.Printf("Listening on UDP %s\n", ln)

	for {
		n, raddr, err := sock.ReadFromUDP(buf[:])

		if err != nil {
			// TODO: handle error
			continue
		}

		log.Printf("Read %d bytes from %s\n", n, raddr)
		go handleMessage(buf)
	}
}

func ListenTCP(addr string) error {
	l, err := net.Listen("tcp", addr)

	if err != nil {
		return err
	}

	defer l.Close()
	log.Printf("Listening on TCP %s\n", l.Addr())

	for {
		conn, err := l.Accept()

		if err != nil {
			// TODO: handle error
			continue
		}

		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)

	for {
		line, err := r.ReadBytes('\n')

		if err != nil {
			if err == io.EOF {
				break
			} else {
				// TODO: handle error
			}
		}

		go handleMessage(line)
	}
}

// Metrics should be in statsd format
// <metric_name>:<metric_value>|<metric_type>
var statsPattern = regexp.MustCompile(`[\w\.]+:-?\d+\|(?:c|ms|g)(?:\|\@[\d\.]+)?`)

// Handle an event message
func handleMessage(buf []byte) {
	//log.Printf("DEBUG: buf is %d bytes\n", len(buf))
	// Parse metrics from the message
	m := statsPattern.FindAll(buf, -1)
	//spew.Dump(m)

	if m != nil {
		for _, metric := range m {
			err := handleMetric(metric)

			if err != nil {
				log.Printf("ERROR: Unable to process metric %s: %s",
					metric, err)
			}
		}
	} else {
		log.Println("No metrics found in message")
	}
}

type Metric struct {
	Name  string
	Value interface{}
	Type  string
}

// handle a single metric
func handleMetric(b []byte) error {
	i := bytes.Index(b, []byte(":"))
	j := bytes.Index(b, []byte("|"))
	k := bytes.Index(b, []byte("@"))
	v := b[i+1 : j]

	// End position of the metric type is the end of the byte slice
	// if no sample was sent.
	tEnd := len(b)
	var sampleRate float64 = 1

	if k > -1 {
		tEnd = k - 1 // Use -1 because of the | before the @
		sr := b[(k + 1):len(b)]
		var err error
		sampleRate, err = strconv.ParseFloat(string(sr), 64)

		if err != nil {
			return err
		}
	}

	m := &Metric{
		Name: string(b[0:i]),
		Type: string(b[j+1 : tEnd]),
	}

	switch m.Type {
	case "c":
		val, err := strconv.ParseInt(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = int64(float64(val) / sampleRate)
	default:
		val, err := strconv.ParseUint(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = val
	}

	In <- m
	return nil
}

func processMetrics() {
	ticker := time.NewTicker(FlushInterval)

	for {
		select {
		case <-ticker.C:
			flushMetrics()
		case m := <-In:
			atomic.AddInt64(&stats.IngressMetrics, 1)

			switch m.Type {
			case "c":
				counters.Lock()
				counters.m[m.Name] += m.Value.(int64)
				counters.Unlock()
				atomic.AddInt64(&stats.IngressCounters, 1)

			case "g":
				gauges.Lock()
				gauges.m[m.Name] = m.Value.(uint64)
				gauges.Unlock()
				atomic.AddInt64(&stats.IngressGauges, 1)

			case "ms":
				timers.Lock()
				_, ok := timers.m[m.Name]

				if !ok {
					var t Timers
					timers.m[m.Name] = t
				}

				timers.m[m.Name] = append(timers.m[m.Name], m.Value.(uint64))
				timers.Unlock()
				atomic.AddInt64(&stats.IngressTimers, 1)

			}
		}
	}
}

func flushMetrics() {
	var buf bytes.Buffer
	now := time.Now().Unix()

	log.Printf("%+v", stats)

	// Build buffer of stats
	flushCounters(&buf, now)
	flushGauges(&buf, now)
	flushTimers(&buf, now)
	flushInternalStats(&buf, now)

	// Send metrics to Graphite
	sendGraphite(&buf)
}

func flushInternalStats(buf *bytes.Buffer, now int64) {
	//fmt.Fprintf(buf, "statsd.metrics.per_second %d %d\n", v, now)
	fmt.Fprintf(buf, "statsd.metrics.count %d %d\n",
		atomic.LoadInt64(&stats.IngressMetrics), now)
	fmt.Fprintf(buf, "statsd.counters.count %d %d\n",
		atomic.LoadInt64(&stats.IngressCounters), now)
	fmt.Fprintf(buf, "statsd.gauges.count %d %d\n",
		atomic.LoadInt64(&stats.IngressGauges), now)
	fmt.Fprintf(buf, "statsd.timers.count %d %d\n",
		atomic.LoadInt64(&stats.IngressTimers), now)

	// Clear internal metrics
	atomic.StoreInt64(&stats.IngressMetrics, 0)
	atomic.StoreInt64(&stats.IngressCounters, 0)
	atomic.StoreInt64(&stats.IngressGauges, 0)
	atomic.StoreInt64(&stats.IngressTimers, 0)

}

func flushCounters(buf *bytes.Buffer, now int64) {
	counters.Lock()
	defer counters.Unlock()

	for k, v := range counters.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(counters.m, k)
	}
}

func flushGauges(buf *bytes.Buffer, now int64) {
	gauges.Lock()
	defer gauges.Unlock()

	for k, v := range gauges.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(gauges.m, k)
	}
}

func flushTimers(buf *bytes.Buffer, now int64) {
	timers.RLock()
	defer timers.RUnlock()
	var n int64

	for k, t := range timers.m {
		count := len(t)

		// Skip processing if there are no timer values
		if count < 1 {
			break
		}

		var sum uint64

		for _, v := range t {
			sum += v
			n++
		}

		// Linear average (mean)
		mean := float64(sum) / float64(count)

		// Min and Max
		sort.Sort(t)
		min := t[0]
		max := t[len(t)-1]

		// Write out all derived stats
		fmt.Fprintf(buf, "%s.count %d %d\n", k, count, now)
		fmt.Fprintf(buf, "%s.mean %f %d\n", k, mean, now)
		fmt.Fprintf(buf, "%s.lower %d %d\n", k, min, now)
		fmt.Fprintf(buf, "%s.upper %d %d\n", k, max, now)

		// Calculate and write out percentiles
		for _, pct := range Percentiles {
			p := perc(t, pct)
			fmt.Fprintf(buf, "%s.perc%d %f %d\n", k, pct, p, now)
		}

		delete(timers.m, k)
	}
}

// percentile calculates Nth percentile of a list of values
func perc(values []uint64, pct int) float64 {
	p := float64(pct) / float64(100)
	n := float64(len(values))
	i := math.Ceil(p*n) - 1

	return float64(values[int(i)])
}

// sendGraphite sends metrics to graphite
func sendGraphite(buf *bytes.Buffer) {
	conn, err := net.Dial("tcp", *graphite)

	if err != nil {
		log.Fatal("ERROR: Unable to connect to graphite")
	}

	w := bufio.NewWriter(conn)
	n, err := buf.WriteTo(w)

	if err != nil {
		log.Fatal("ERROR: Unable to write to graphite")
	}

	w.Flush()
	conn.Close()

	log.Printf("Wrote %d bytes to Graphite", n)
}

//-----------------------------------------------------------------------------

func main() {
	flag.Parse()

	// Profiling
	cfg := profile.Config{
		CPUProfile:   *cpuprofile,
		MemProfile:   false,
		BlockProfile: false,
		ProfilePath:  ".",
	}

	p := profile.Start(&cfg)
	defer p.Stop()

	// Process metrics as they arrive
	go processMetrics()

	// Setup listeners
	go log.Fatal(ListenTCP(*listen))

}
<commit_msg>Add options for memory and block profilers<commit_after>// statspipe is a metrics pipeline
package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"net"
	"regexp"
	"sort"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	//"github.com/davecgh/go-spew/spew"
	"github.com/davecheney/profile"
)

const FlushInterval = time.Duration(10 * time.Second)
const BufSize = 8192

//-----------------------------------------------------------------------------

// Command line flags
var (
	listen       = flag.String("listen", ":1514", "UDP listener address")
	graphite     = flag.String("graphite", "localhost:2003", "Graphite server address")
	cpuprofile   = flag.Bool("cpuprofile", false, "Enable CPU profiling")
	memprofile   = flag.Bool("memprofile", false, "Enable memory profiling")
	blockprofile = flag.Bool("blockprofile", false, "Enable memory profiling")
)

// Metric Types
var In = make(chan *Metric)

var counters = struct {
	sync.RWMutex
	m map[string]int64
}{m: make(map[string]int64)}

var gauges = struct {
	sync.RWMutex
	m map[string]uint64
}{m: make(map[string]uint64)}

type Timers []uint64

func (t Timers) Len() int           { return len(t) }
func (t Timers) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t Timers) Less(i, j int) bool { return t[i] < t[j] }

var timers = struct {
	sync.RWMutex
	m map[string]Timers
}{m: make(map[string]Timers)}

var Percentiles = []int{5, 95}

// Internal metrics
type Stats struct {
	IngressRate     int64
	IngressMetrics  int64
	IngressCounters int64
	IngressGauges   int64
	IngressTimers   int64
}

var stats = &Stats{}

//-----------------------------------------------------------------------------
// Read syslog stream

func ListenUDP(addr string) error {
	var buf = make([]byte, 1024)
	ln, err := net.ResolveUDPAddr("udp", addr)

	if err != nil {
		return err
	}

	sock, err := net.ListenUDP("udp", ln)

	if err != nil {
		return err
	}

	log.Printf("Listening on UDP %s\n", ln)

	for {
		n, raddr, err := sock.ReadFromUDP(buf[:])

		if err != nil {
			// TODO: handle error
			continue
		}

		log.Printf("Read %d bytes from %s\n", n, raddr)
		go handleMessage(buf)
	}
}

func ListenTCP(addr string) error {
	l, err := net.Listen("tcp", addr)

	if err != nil {
		return err
	}

	defer l.Close()
	log.Printf("Listening on TCP %s\n", l.Addr())

	for {
		conn, err := l.Accept()

		if err != nil {
			// TODO: handle error
			continue
		}

		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)

	for {
		line, err := r.ReadBytes('\n')

		if err != nil {
			if err == io.EOF {
				break
			} else {
				// TODO: handle error
			}
		}

		go handleMessage(line)
	}
}

// Metrics should be in statsd format
// <metric_name>:<metric_value>|<metric_type>
var statsPattern = regexp.MustCompile(`[\w\.]+:-?\d+\|(?:c|ms|g)(?:\|\@[\d\.]+)?`)

// Handle an event message
func handleMessage(buf []byte) {
	//log.Printf("DEBUG: buf is %d bytes\n", len(buf))
	// Parse metrics from the message
	m := statsPattern.FindAll(buf, -1)
	//spew.Dump(m)

	if m != nil {
		for _, metric := range m {
			err := handleMetric(metric)

			if err != nil {
				log.Printf("ERROR: Unable to process metric %s: %s",
					metric, err)
			}
		}
	} else {
		log.Println("No metrics found in message")
	}
}

type Metric struct {
	Name  string
	Value interface{}
	Type  string
}

// handle a single metric
func handleMetric(b []byte) error {
	i := bytes.Index(b, []byte(":"))
	j := bytes.Index(b, []byte("|"))
	k := bytes.Index(b, []byte("@"))
	v := b[i+1 : j]

	// End position of the metric type is the end of the byte slice
	// if no sample was sent.
	tEnd := len(b)
	var sampleRate float64 = 1

	if k > -1 {
		tEnd = k - 1 // Use -1 because of the | before the @
		sr := b[(k + 1):len(b)]
		var err error
		sampleRate, err = strconv.ParseFloat(string(sr), 64)

		if err != nil {
			return err
		}
	}

	m := &Metric{
		Name: string(b[0:i]),
		Type: string(b[j+1 : tEnd]),
	}

	switch m.Type {
	case "c":
		val, err := strconv.ParseInt(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = int64(float64(val) / sampleRate)
	default:
		val, err := strconv.ParseUint(string(v), 10, 64)

		if err != nil {
			return err
		}

		m.Value = val
	}

	In <- m
	return nil
}

func processMetrics() {
	ticker := time.NewTicker(FlushInterval)

	for {
		select {
		case <-ticker.C:
			flushMetrics()
		case m := <-In:
			atomic.AddInt64(&stats.IngressMetrics, 1)

			switch m.Type {
			case "c":
				counters.Lock()
				counters.m[m.Name] += m.Value.(int64)
				counters.Unlock()
				atomic.AddInt64(&stats.IngressCounters, 1)

			case "g":
				gauges.Lock()
				gauges.m[m.Name] = m.Value.(uint64)
				gauges.Unlock()
				atomic.AddInt64(&stats.IngressGauges, 1)

			case "ms":
				timers.Lock()
				_, ok := timers.m[m.Name]

				if !ok {
					var t Timers
					timers.m[m.Name] = t
				}

				timers.m[m.Name] = append(timers.m[m.Name], m.Value.(uint64))
				timers.Unlock()
				atomic.AddInt64(&stats.IngressTimers, 1)

			}
		}
	}
}

func flushMetrics() {
	var buf bytes.Buffer
	now := time.Now().Unix()

	log.Printf("%+v", stats)

	// Build buffer of stats
	flushCounters(&buf, now)
	flushGauges(&buf, now)
	flushTimers(&buf, now)
	flushInternalStats(&buf, now)

	// Send metrics to Graphite
	sendGraphite(&buf)
}

func flushInternalStats(buf *bytes.Buffer, now int64) {
	//fmt.Fprintf(buf, "statsd.metrics.per_second %d %d\n", v, now)
	fmt.Fprintf(buf, "statsd.metrics.count %d %d\n",
		atomic.LoadInt64(&stats.IngressMetrics), now)
	fmt.Fprintf(buf, "statsd.counters.count %d %d\n",
		atomic.LoadInt64(&stats.IngressCounters), now)
	fmt.Fprintf(buf, "statsd.gauges.count %d %d\n",
		atomic.LoadInt64(&stats.IngressGauges), now)
	fmt.Fprintf(buf, "statsd.timers.count %d %d\n",
		atomic.LoadInt64(&stats.IngressTimers), now)

	// Clear internal metrics
	atomic.StoreInt64(&stats.IngressMetrics, 0)
	atomic.StoreInt64(&stats.IngressCounters, 0)
	atomic.StoreInt64(&stats.IngressGauges, 0)
	atomic.StoreInt64(&stats.IngressTimers, 0)
}

func flushCounters(buf *bytes.Buffer, now int64) {
	counters.Lock()
	defer counters.Unlock()

	for k, v := range counters.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(counters.m, k)
	}
}

func flushGauges(buf *bytes.Buffer, now int64) {
	gauges.Lock()
	defer gauges.Unlock()

	for k, v := range gauges.m {
		fmt.Fprintf(buf, "%s %d %d\n", k, v, now)
		delete(gauges.m, k)
	}
}

func flushTimers(buf *bytes.Buffer, now int64) {
	timers.RLock()
	defer timers.RUnlock()
	var n int64

	for k, t := range timers.m {
		count := len(t)

		// Skip processing if there are no timer values
		if count < 1 {
			break
		}

		var sum uint64

		for _, v := range t {
			sum += v
			n++
		}

		// Linear average (mean)
		mean := float64(sum) / float64(count)

		// Min and Max
		sort.Sort(t)
		min := t[0]
		max := t[len(t)-1]

		// Write out all derived stats
		fmt.Fprintf(buf, "%s.count %d %d\n", k, count, now)
		fmt.Fprintf(buf, "%s.mean %f %d\n", k, mean, now)
		fmt.Fprintf(buf, "%s.lower %d %d\n", k, min, now)
		fmt.Fprintf(buf, "%s.upper %d %d\n", k, max, now)

		// Calculate and write out percentiles
		for _, pct := range Percentiles {
			p := perc(t, pct)
			fmt.Fprintf(buf, "%s.perc%d %f %d\n", k, pct, p, now)
		}

		delete(timers.m, k)
	}
}

// percentile calculates Nth percentile of a list of values
func perc(values []uint64, pct int) float64 {
	p := float64(pct) / float64(100)
	n := float64(len(values))
	i := math.Ceil(p*n) - 1

	return float64(values[int(i)])
}

// sendGraphite sends metrics to graphite
func sendGraphite(buf *bytes.Buffer) {
	conn, err := net.Dial("tcp", *graphite)

	if err != nil {
		log.Fatal("ERROR: Unable to connect to graphite")
	}

	w := bufio.NewWriter(conn)
	n, err := buf.WriteTo(w)

	if err != nil {
		log.Fatal("ERROR: Unable to write to graphite")
	}

	w.Flush()
	conn.Close()

	log.Printf("Wrote %d bytes to Graphite", n)
}

//-----------------------------------------------------------------------------

func main() {
	flag.Parse()

	// Profiling
	cfg := profile.Config{
		CPUProfile:   *cpuprofile,
		MemProfile:   *memprofile,
		BlockProfile: *blockprofile,
		ProfilePath:  ".",
	}

	p := profile.Start(&cfg)
	defer p.Stop()

	// Process metrics as they arrive
	go processMetrics()

	// Setup listeners
	go log.Fatal(ListenTCP(*listen))
}
<|endoftext|>


<commit_before>package beep

// Silence returns a Streamer which streams n samples of silence. If n is negative, silence is
// streamed forever.
func Silence(n int) Streamer {
	return StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
		if n == 0 {
			return n, false
		}
		for i := range samples {
			if n == 0 {
				break
			}
			samples[i] = [2]float64{}
			if n > 0 {
				n--
			}
		}
		return n, true
	})
}

// Callback returns a Streamer, which does not stream any samples, but instead calls f the first
// time its Stream method is called.
func Callback(f func()) Streamer {
	return StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
		if f != nil {
			f()
			f = nil
		}
		return 0, false
	})
}
<commit_msg>fix Silence<commit_after>package beep

// Silence returns a Streamer which streams num samples of silence. If n is negative, silence is
// streamed forever.
func Silence(num int) Streamer {
	return StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
		if num == 0 {
			return 0, false
		}
		for i := range samples {
			if num == 0 {
				break
			}
			samples[i] = [2]float64{}
			if num > 0 {
				num--
			}
			n++
		}
		return n, true
	})
}

// Callback returns a Streamer, which does not stream any samples, but instead calls f the first
// time its Stream method is called.
func Callback(f func()) Streamer {
	return StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
		if f != nil {
			f()
			f = nil
		}
		return 0, false
	})
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"strconv"
	"unsafe"

	"github.com/stampzilla/stampzilla-go/nodes/basenode"
	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-telldus-events/sensormonitor"
	"github.com/stampzilla/stampzilla-go/pkg/notifier"
	"github.com/stampzilla/stampzilla-go/protocol"
)

/*
#cgo LDFLAGS: -ltelldus-core

#include <telldus-core.h>

extern void registerCallbacks();
extern void unregisterCallbacks();
extern int updateDevices();

*/
import "C"

var node *protocol.Node
var state *State = &State{make(map[string]*Device), make(map[string]*Sensor, 0)}
var serverConnection basenode.Connection
var sensorMonitor sensorMonitor.Monitor

func main() {
	// Load logger
	//logger, err := log.LoggerFromConfigAsFile("../logconfig.xml")
	//if err != nil {
	//panic(err)
	//}
	//log.ReplaceLogger(logger)

	//Get a config with the correct parameters
	config := basenode.NewConfig()
	basenode.SetConfig(config)

	// Load flags
	//var host string
	//var port string
	//flag.StringVar(&host, "host", "localhost", "Stampzilla server hostname")
	//flag.StringVar(&port, "port", "8282", "Stampzilla server port")
	flag.Parse()

	log.Println("Starting TELLDUS-events node")

	C.registerCallbacks()
	defer C.unregisterCallbacks()

	// Create new node description
	node = protocol.NewNode("telldus-events")
	node.SetState(state)

	// Describe available actions
	node.AddAction("set", "Set", []string{"Devices.Id"})
	node.AddAction("toggle", "Toggle", []string{"Devices.Id"})
	node.AddAction("dim", "Dim", []string{"Devices.Id", "value"})

	// Describe available layouts
	//node.AddLayout("1", "switch", "toggle", "Devices", []string{"on"}, "Switches")
	//node.AddLayout("2", "slider", "dim", "Devices", []string{"dim"}, "Dimmers")
	//node.AddLayout("3", "slider", "dim", "Devices", []string{"dim"}, "Specials")

	// Add devices
	cnt := C.updateDevices()
	log.Println("Updated devices (", cnt, " in total)")

	for _, dev := range state.Devices {
		node.AddElement(&protocol.Element{
			Type: protocol.ElementTypeToggle,
			Name: dev.Name,
			Command: &protocol.Command{
				Cmd:  "toggle",
				Args: []string{dev.Id},
			},
			Feedback: `Devices[` + dev.Id + `].State.On`,
		})
	}

	// Start the connection
	//go connection(host, port, node)

	serverConnection = basenode.Connect()
	notify := notifier.New(serverConnection)
	notify.SetSource(node)

	sensorMonitor = sensormonitor.New(notify)
	sensorMonitor.Start()

	go monitorState(serverConnection)

	// This worker recives all incomming commands
	go serverRecv(serverConnection)

	select {}
}

// WORKER that monitors the current connection state
func monitorState(connection basenode.Connection) {
	for s := range connection.State() {
		switch s {
		case basenode.ConnectionStateConnected:
			connection.Send(node.Node())
		case basenode.ConnectionStateDisconnected:
		}
	}
}

// WORKER that recives all incomming commands
func serverRecv(connection basenode.Connection) {
	send := processCommandWorker()
	for d := range connection.Receive() {
		send <- d
	}
}

func processCommandWorker() chan protocol.Command {
	var send = make(chan protocol.Command, 100)

	go func() {
		for c := range send {
			if err := processCommand(c); err != nil {
				log.Println(err)
			}
		}
	}()

	return send
}

func processCommand(cmd protocol.Command) error {
	log.Println("Processing command", cmd)
	var result C.int = C.TELLSTICK_ERROR_UNKNOWN
	var id C.int = 0

	i, err := strconv.Atoi(cmd.Args[0])
	if err != nil {
		return fmt.Errorf("Failed to decode arg[0] to int %s %s", err, cmd.Args[0])
	}

	id = C.int(i)

	switch cmd.Cmd {
	case "on":
		result = C.tdTurnOn(id)
	case "off":
		result = C.tdTurnOff(id)
	case "toggle":
		s := C.tdLastSentCommand(id, C.TELLSTICK_TURNON|C.TELLSTICK_TURNOFF|C.TELLSTICK_DIM)
		switch {
		case s&C.TELLSTICK_DIM != 0:
			var state *C.char = C.tdLastSentValue(id)
			log.Println("DIM: ", C.GoString(state))
			if C.GoString(state) == "0" {
				result = C.tdTurnOn(id)
			} else {
				result = C.tdTurnOff(id)
			}
			C.tdReleaseString(state)
		case s&C.TELLSTICK_TURNON != 0:
			result = C.tdTurnOff(id)
		case s&C.TELLSTICK_TURNOFF != 0:
			result = C.tdTurnOn(id)
		}
	}

	if result != C.TELLSTICK_SUCCESS {
		var errorString *C.char = C.tdGetErrorString(result)
		C.tdReleaseString(errorString)
		return errors.New(C.GoString(errorString))
	}

	return nil
}

//export newDevice
func newDevice(id int, name *C.char, methods, s int, value *C.char) {
	//log.Println(id, C.GoString(name))

	features := []string{}
	if methods&C.TELLSTICK_TURNON != 0 {
		features = append(features, "on")
	}
	if methods&C.TELLSTICK_TURNOFF != 0 {
		features = append(features, "off")
	}
	if methods&C.TELLSTICK_BELL != 0 {
		features = append(features, "bell")
	}
	if methods&C.TELLSTICK_TOGGLE != 0 {
		features = append(features, "toggle")
	}
	if methods&C.TELLSTICK_DIM != 0 {
		features = append(features, "dim")
	}
	if methods&C.TELLSTICK_EXECUTE != 0 {
		features = append(features, "execute")
	}
	if methods&C.TELLSTICK_UP != 0 {
		features = append(features, "up")
	}
	if methods&C.TELLSTICK_DOWN != 0 {
		features = append(features, "down")
	}
	if methods&C.TELLSTICK_STOP != 0 {
		features = append(features, "stop")
	}

	if s&C.TELLSTICK_TURNON != 0 {
		state.AddDevice(strconv.Itoa(id), C.GoString(name), features, DeviceState{On: true, Dim: 100})
	}
	if s&C.TELLSTICK_TURNOFF != 0 {
		state.AddDevice(strconv.Itoa(id), C.GoString(name), features, DeviceState{On: false})
	}
	if s&C.TELLSTICK_DIM != 0 {
		var currentState = C.GoString(value)
		level, _ := strconv.ParseUint(currentState, 10, 16)
		state.AddDevice(strconv.Itoa(id), C.GoString(name), features, DeviceState{On: level > 0, Dim: int(level)})
	}

}

//export sensorEvent
func sensorEvent(protocol, model *C.char, sensorId, dataType int, value *C.char) {
	//log.Println("SensorEVENT: ", C.GoString(protocol), C.GoString(model), sensorId)

	var s *Sensor
	if s = state.GetSensor(sensorId); s == nil {
		s = state.AddSensor(sensorId, "UNKNOWN")
	}
	sensorMonitor.Alive(s.Id)

	if dataType == C.TELLSTICK_TEMPERATURE {
		t, _ := strconv.ParseFloat(C.GoString(value), 64)
		log.Printf("Temperature %d : %f\n", s.Id, t)
		if s.Temp != t {
			//log.Println("Difference, sending to server")
			s.Temp = t
			serverConnection.Send(node.Node())
		}
	} else if dataType == C.TELLSTICK_HUMIDITY {
		h, _ := strconv.ParseFloat(C.GoString(value), 64)
		log.Printf("Humidity %d : %f\n", s.Id, h)
		if s.Humidity != h {
			//log.Println("Difference, sending to server")
			s.Humidity = h
			serverConnection.Send(node.Node())
		}
	}
}

//export deviceEvent
func deviceEvent(deviceId, method int, data *C.char, callbackId int, context unsafe.Pointer) {
	//log.Println("DeviceEVENT: ", deviceId, method, C.GoString(data))
	device := state.GetDevice(strconv.Itoa(deviceId))
	if method&C.TELLSTICK_TURNON != 0 {
		device.State.On = true
		serverConnection.Send(node.Node())
	}
	if method&C.TELLSTICK_TURNOFF != 0 {
		device.State.On = false
		serverConnection.Send(node.Node())
	}
	if method&C.TELLSTICK_DIM != 0 {
		level, err := strconv.ParseUint(C.GoString(data), 10, 16)
		if err != nil {
			log.Println(err)
			return
		}
		if level == 0 {
			device.State.On = false
		}
		if level > 0 {
			device.State.On = true
		}
		device.State.Dim = int(level)
		serverConnection.Send(node.Node())
	}
}

//export deviceChangeEvent
func deviceChangeEvent(deviceId, changeEvent, changeType, callbackId int, context unsafe.Pointer) {
	//log.Println("DeviceChangeEVENT: ", deviceId, changeEvent, changeType)
}

//export rawDeviceEvent
func rawDeviceEvent(data *C.char, controllerId, callbackId int, context unsafe.Pointer) {
	//log.Println("rawDeviceEVENT: ", controllerId, C.GoString(data))
}
<commit_msg>fix bug<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"strconv"
	"unsafe"

	"github.com/stampzilla/stampzilla-go/nodes/basenode"
	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-telldus-events/sensormonitor"
	"github.com/stampzilla/stampzilla-go/pkg/notifier"
	"github.com/stampzilla/stampzilla-go/protocol"
)

/*
#cgo LDFLAGS: -ltelldus-core

#include <telldus-core.h>

extern void registerCallbacks();
extern void unregisterCallbacks();
extern int updateDevices();

*/
import "C"

var node *protocol.Node
var state *State = &State{make(map[string]*Device), make(map[string]*Sensor, 0)}
var serverConnection basenode.Connection
var sensorMonitor sensormonitor.Monitor

func main() {
	// Load logger
	//logger, err := log.LoggerFromConfigAsFile("../logconfig.xml")
	//if err != nil {
	//panic(err)
	//}
	//log.ReplaceLogger(logger)

	//Get a config with the correct parameters
	config := basenode.NewConfig()
	basenode.SetConfig(config)

	// Load flags
	//var host string
	//var port string
	//flag.StringVar(&host, "host", "localhost", "Stampzilla server hostname")
	//flag.StringVar(&port, "port", "8282", "Stampzilla server port")
	flag.Parse()

	log.Println("Starting TELLDUS-events node")

	C.registerCallbacks()
	defer C.unregisterCallbacks()

	// Create new node description
	node = protocol.NewNode("telldus-events")
	node.SetState(state)

	// Describe available actions
	node.AddAction("set", "Set", []string{"Devices.Id"})
	node.AddAction("toggle", "Toggle", []string{"Devices.Id"})
	node.AddAction("dim", "Dim", []string{"Devices.Id", "value"})

	// Describe available layouts
	//node.AddLayout("1", "switch", "toggle", "Devices", []string{"on"}, "Switches")
	//node.AddLayout("2", "slider", "dim", "Devices", []string{"dim"}, "Dimmers")
	//node.AddLayout("3", "slider", "dim", "Devices", []string{"dim"}, "Specials")

	// Add devices
	cnt := C.updateDevices()
	log.Println("Updated devices (", cnt, " in total)")

	for _, dev := range state.Devices {
		node.AddElement(&protocol.Element{
			Type: protocol.ElementTypeToggle,
			Name: dev.Name,
			Command: &protocol.Command{
				Cmd:  "toggle",
				Args: []string{dev.Id},
			},
			Feedback: `Devices[` + dev.Id + `].State.On`,
		})
	}

	// Start the connection
	//go connection(host, port, node)

	serverConnection = basenode.Connect()
	notify := notifier.New(serverConnection)
	notify.SetSource(node)

	sensorMonitor = sensormonitor.New(notify)
	sensorMonitor.Start()

	go monitorState(serverConnection)

	// This worker recives all incomming commands
	go serverRecv(serverConnection)

	select {}
}

// WORKER that monitors the current connection state
func monitorState(connection basenode.Connection) {
	for s := range connection.State() {
		switch s {
		case basenode.ConnectionStateConnected:
			connection.Send(node.Node())
		case basenode.ConnectionStateDisconnected:
		}
	}
}

// WORKER that recives all incomming commands
func serverRecv(connection basenode.Connection) {
	send := processCommandWorker()
	for d := range connection.Receive() {
		send <- d
	}
}

func processCommandWorker() chan protocol.Command {
	var send = make(chan protocol.Command, 100)

	go func() {
		for c := range send {
			if err := processCommand(c); err != nil {
				log.Println(err)
			}
		}
	}()

	return send
}

func processCommand(cmd protocol.Command) error {
	log.Println("Processing command", cmd)
	var result C.int = C.TELLSTICK_ERROR_UNKNOWN
	var id C.int = 0

	i, err := strconv.Atoi(cmd.Args[0])
	if err != nil {
		return fmt.Errorf("Failed to decode arg[0] to int %s %s", err, cmd.Args[0])
	}

	id = C.int(i)

	switch cmd.Cmd {
	case "on":
		result = C.tdTurnOn(id)
	case "off":
		result = C.tdTurnOff(id)
	case "toggle":
		s := C.tdLastSentCommand(id, C.TELLSTICK_TURNON|C.TELLSTICK_TURNOFF|C.TELLSTICK_DIM)
		switch {
		case s&C.TELLSTICK_DIM != 0:
			var state *C.char = C.tdLastSentValue(id)
			log.Println("DIM: ", C.GoString(state))
			if C.GoString(state) == "0" {
				result = C.tdTurnOn(id)
			} else {
				result = C.tdTurnOff(id)
			}
			C.tdReleaseString(state)
		case s&C.TELLSTICK_TURNON != 0:
			result = C.tdTurnOff(id)
		case s&C.TELLSTICK_TURNOFF != 0:
			result = C.tdTurnOn(id)
		}
	}

	if result != C.TELLSTICK_SUCCESS {
		var errorString *C.char = C.tdGetErrorString(result)
		C.tdReleaseString(errorString)
		return errors.New(C.GoString(errorString))
	}

	return nil
}

//export newDevice
func newDevice(id int, name *C.char, methods, s int, value *C.char) {
	//log.Println(id, C.GoString(name))

	features := []string{}
	if methods&C.TELLSTICK_TURNON != 0 {
		features = append(features, "on")
	}
	if methods&C.TELLSTICK_TURNOFF != 0 {
		features = append(features, "off")
	}
	if methods&C.TELLSTICK_BELL != 0 {
		features = append(features, "bell")
	}
	if methods&C.TELLSTICK_TOGGLE != 0 {
		features = append(features, "toggle")
	}
	if methods&C.TELLSTICK_DIM != 0 {
		features = append(features, "dim")
	}
	if methods&C.TELLSTICK_EXECUTE != 0 {
		features = append(features, "execute")
	}
	if methods&C.TELLSTICK_UP != 0 {
		features = append(features, "up")
	}
	if methods&C.TELLSTICK_DOWN != 0 {
		features = append(features, "down")
	}
	if methods&C.TELLSTICK_STOP != 0 {
		features = append(features, "stop")
	}

	if s&C.TELLSTICK_TURNON != 0 {
		state.AddDevice(strconv.Itoa(id), C.GoString(name), features, DeviceState{On: true, Dim: 100})
	}
	if s&C.TELLSTICK_TURNOFF != 0 {
		state.AddDevice(strconv.Itoa(id), C.GoString(name), features, DeviceState{On: false})
	}
	if s&C.TELLSTICK_DIM != 0 {
		var currentState = C.GoString(value)
		level, _ := strconv.ParseUint(currentState, 10, 16)
		state.AddDevice(strconv.Itoa(id), C.GoString(name), features, DeviceState{On: level > 0, Dim: int(level)})
	}

}

//export sensorEvent
func sensorEvent(protocol, model *C.char, sensorId, dataType int, value *C.char) {
	//log.Println("SensorEVENT: ", C.GoString(protocol), C.GoString(model), sensorId)

	var s *Sensor
	if s = state.GetSensor(sensorId); s == nil {
		s = state.AddSensor(sensorId, "UNKNOWN")
	}
	sensorMonitor.Alive(s.Id)

	if dataType == C.TELLSTICK_TEMPERATURE {
		t, _ := strconv.ParseFloat(C.GoString(value), 64)
		log.Printf("Temperature %d : %f\n", s.Id, t)
		if s.Temp != t {
			//log.Println("Difference, sending to server")
			s.Temp = t
			serverConnection.Send(node.Node())
		}
	} else if dataType == C.TELLSTICK_HUMIDITY {
		h, _ := strconv.ParseFloat(C.GoString(value), 64)
		log.Printf("Humidity %d : %f\n", s.Id, h)
		if s.Humidity != h {
			//log.Println("Difference, sending to server")
			s.Humidity = h
			serverConnection.Send(node.Node())
		}
	}
}

//export deviceEvent
func deviceEvent(deviceId, method int, data *C.char, callbackId int, context unsafe.Pointer) {
	//log.Println("DeviceEVENT: ", deviceId, method, C.GoString(data))
	device := state.GetDevice(strconv.Itoa(deviceId))
	if method&C.TELLSTICK_TURNON != 0 {
		device.State.On = true
		serverConnection.Send(node.Node())
	}
	if method&C.TELLSTICK_TURNOFF != 0 {
		device.State.On = false
		serverConnection.Send(node.Node())
	}
	if method&C.TELLSTICK_DIM != 0 {
		level, err := strconv.ParseUint(C.GoString(data), 10, 16)
		if err != nil {
			log.Println(err)
			return
		}
		if level == 0 {
			device.State.On = false
		}
		if level > 0 {
			device.State.On = true
		}
		device.State.Dim = int(level)
		serverConnection.Send(node.Node())
	}
}

//export deviceChangeEvent
func deviceChangeEvent(deviceId, changeEvent, changeType, callbackId int, context unsafe.Pointer) {
	//log.Println("DeviceChangeEVENT: ", deviceId, changeEvent, changeType)
}

//export rawDeviceEvent
func rawDeviceEvent(data *C.char, controllerId, callbackId int, context unsafe.Pointer) {
	//log.Println("rawDeviceEVENT: ", controllerId, C.GoString(data))
}
<|endoftext|>


<commit_before>package emu

const (
	memorySize      = 4096
	vramSize        = 64 * 32
	registersNumber = 16
	stackSize       = 16
)

// Chip8 is the main struct holding all data relevant to the emulator.
// This includes registers (V0 to VF, PC, etc.), ram and framebuffer.
type Chip8 struct {
	I      uint16
	pc     uint16
	sp     uint16
	stack  []uint16
	V      []uint8
	memory []uint8
	vram   []uint8
	keypad []uint8
	delayt uint8
	soundt uint8
}

// OpcodeFunc is a function that implements an opcode for Chip8
type OpcodeFunc func(*Chip8)

// New initializes basic Chip8 data, but the emulator won't be in a runnable
// state until something is loaded.
func New() Chip8 {
	return Chip8{
		0,
		0,
		0,
		make([]uint16, stackSize, stackSize),
		make([]uint8, registersNumber, registersNumber),
		make([]uint8, memorySize, memorySize),
		make([]uint8, vramSize, vramSize),
		make([]uint8, 16, 16),
		0,
		0,
	}
}
<commit_msg>Add basic step function implementation<commit_after>package emu

import "github.com/valep27/chip8/util"
import "fmt"

const (
	memorySize      = 4096
	vramSize        = 64 * 32
	registersNumber = 16
	stackSize       = 16
)

// Chip8 is the main struct holding all data relevant to the emulator.
// This includes registers (V0 to VF, PC, etc.), ram and framebuffer.
type Chip8 struct {
	I      uint16
	pc     uint16
	sp     uint16
	stack  []uint16
	V      []uint8
	memory []uint8
	vram   []uint8
	keypad []uint8
	delayt uint8
	soundt uint8
}

// OpcodeFunc is a function that implements an opcode for Chip8
type OpcodeFunc func(*Chip8)

// New initializes basic Chip8 data, but the emulator won't be in a runnable
// state until something is loaded.
func New() Chip8 {
	return Chip8{
		0,
		0,
		0,
		make([]uint16, stackSize, stackSize),
		make([]uint8, registersNumber, registersNumber),
		make([]uint8, memorySize, memorySize),
		make([]uint8, vramSize, vramSize),
		make([]uint8, 16, 16),
		0,
		0,
	}
}

// Step executes a single cycle of emulation.
func (c8 *Chip8) Step() {
	// fetch
	opcode := util.CombineBytes(c8.memory[c8.pc+1], c8.memory[c8.pc])

	// decode
	instr, ok := OpcodeMap[opcode]

	if ok {
		// exec
		instr(c8)
	} else {
		// opcode not found
		panic(fmt.Sprintf("No instruction for opcode: %v", opcode))
	}

	// TODO: wrap if > 4096?
	c8.pc += 2

	// TODO: update timers
}
<|endoftext|>


<commit_before>package manta

// A fieldpath, used to walk through the flattened table hierarchy
type fieldpath struct {
	hierarchy []*dt
	index     []int32
}

// Initialize a fieldpath object
func fielpath_init(parentTbl *dt) *fieldpath {
	fp := &fieldpath{
		hierarchy: make([]*dt, 0),
		index:     make([]int32, 0),
	}

	fp.hierarchy = append(fp.hierarchy, parentTbl)
	fp.index = append(fp.index, -1) // Always start at -1

	return fp
}

// Returns a huffman tree based on the operation weights
func fieldpath_huffman() HuffmanTree {
	FieldPathOperations := make(map[int]interface{})

	FieldPathOperations[36271] = PlusOne
	FieldPathOperations[10334] = PlusTwo
	FieldPathOperations[1375] = PlusThree
	FieldPathOperations[646] = PlusFour
	FieldPathOperations[4128] = PlusN
	FieldPathOperations[35] = PushOneLeftDeltaZeroRightZero
	FieldPathOperations[3] = PushOneLeftDeltaZeroRightNonZero
	FieldPathOperations[521] = PushOneLeftDeltaOneRightZero
	FieldPathOperations[2942] = PushOneLeftDeltaOneRightNonZero
	FieldPathOperations[560] = PushOneLeftDeltaNRightZero
	FieldPathOperations[471] = PushOneLeftDeltaNRightNonZero
	FieldPathOperations[10530] = PushOneLeftDeltaNRightNonZeroPack6Bits
	FieldPathOperations[251] = PushOneLeftDeltaNRightNonZeroPack8Bits
	FieldPathOperations[0] = PushTwoLeftDeltaZero
	FieldPathOperations[0] = PushTwoLeftDeltaOne
	FieldPathOperations[0] = PushTwoLeftDeltaN
	FieldPathOperations[0] = PushTwoPack5LeftDeltaZero
	FieldPathOperations[0] = PushTwoPack5LeftDeltaOne
	FieldPathOperations[0] = PushTwoPack5LeftDeltaN
	FieldPathOperations[0] = PushThreeLeftDeltaZero
	FieldPathOperations[0] = PushThreeLeftDeltaOne
	FieldPathOperations[0] = PushThreeLeftDeltaN
	FieldPathOperations[0] = PushThreePack5LeftDeltaZero
	FieldPathOperations[0] = PushThreePack5LeftDeltaOne
	FieldPathOperations[0] = PushThreePack5LeftDeltaN
	FieldPathOperations[0] = PushN
	FieldPathOperations[310] = PushNAndNonTopological
	FieldPathOperations[2] = PopOnePlusOne
	FieldPathOperations[0] = PopOnePlusN
	FieldPathOperations[1837] = PopAllButOnePlusOne
	FieldPathOperations[149] = PopAllButOnePlusN
	FieldPathOperations[300] = PopAllButOnePlusNPack3Bits
	FieldPathOperations[634] = PopAllButOnePlusNPack6Bits
	FieldPathOperations[0] = PopNPlusOne
	FieldPathOperations[0] = PopNPlusN
	FieldPathOperations[1] = PopNAndNonTopographical
	FieldPathOperations[76] = NonTopoComplex
	FieldPathOperations[271] = NonTopoPenultimatePlusOne
	FieldPathOperations[99] = NonTopoComplexPack4Bits
	FieldPathOperations[25474] = FieldPathEncodeFinish

	printCodes(buildTree(FieldPathOperations), []byte{})
	return buildTree(FieldPathOperations)
}

func PlusOne(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 1
}

func PlusTwo(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 2
}

func PlusThree(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 3
}

func PlusFour(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 4
}

func PlusN(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaZeroRightZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaZeroRightNonZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaOneRightZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaOneRightNonZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightNonZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightNonZeroPack6Bits(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightNonZeroPack8Bits(r *reader, fp *fieldpath) {

}

func PushTwoLeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushTwoLeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushTwoLeftDeltaN(r *reader, fp *fieldpath) {

}

func PushTwoPack5LeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushTwoPack5LeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushTwoPack5LeftDeltaN(r *reader, fp *fieldpath) {

}

func PushThreeLeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushThreeLeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushThreeLeftDeltaN(r *reader, fp *fieldpath) {

}

func PushThreePack5LeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushThreePack5LeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushThreePack5LeftDeltaN(r *reader, fp *fieldpath) {

}

func PushN(r *reader, fp *fieldpath) {

}

func PushNAndNonTopological(r *reader, fp *fieldpath) {

}

func PopOnePlusOne(r *reader, fp *fieldpath) {

}

func PopOnePlusN(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusOne(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusN(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusNPackN(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusNPack3Bits(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusNPack6Bits(r *reader, fp *fieldpath) {

}

func PopNPlusOne(r *reader, fp *fieldpath) {

}

func PopNPlusN(r *reader, fp *fieldpath) {

}

func PopNAndNonTopographical(r *reader, fp *fieldpath) {

}

func NonTopoComplex(r *reader, fp *fieldpath) {

}

func NonTopoPenultimatePlusOne(r *reader, fp *fieldpath) {

}

func NonTopoComplexPack4Bits(r *reader, fp *fieldpath) {

}

func FieldPathEncodeFinish(r *reader, fp *fieldpath) {

}
<commit_msg>Added fieldpath_walk<commit_after>package manta

// A fieldpath, used to walk through the flattened table hierarchy
type fieldpath struct {
	hierarchy []*dt
	index     []int32
	tree      *HuffmanTree
	finished  bool
}

// Typedef for a field operation function
type FieldPathOpFcn func(*reader, *fieldpath)

// Initialize a fieldpath object
func fielpath_init(parentTbl *dt) *fieldpath {
	fp := &fieldpath{
		hierarchy: make([]*dt, 0),
		index:     make([]int32, 0),
	}

	fp.hierarchy = append(fp.hierarchy, parentTbl)
	fp.index = append(fp.index, -1) // Always start at -1
	fp.finished = false

	return fp
}

// Walk an encoded fieldpath based on a huffman tree
func (fp *fieldpath) fieldpath_walk(r *reader) []dt_field {
	fields := make([]dt_field, 0)

	// where is do-while when you need it -.-
	node := (*fp.tree).(HuffmanNode)
	for fp.finished == false {
		if r.readBits(1) == 1 {
			switch i := node.right.(type) {
			case HuffmanLeaf:
				i.value.(FieldPathOpFcn)(r, fp)
				break
			case HuffmanNode:
				node = i
				break
			}
		} else {
			switch i := node.left.(type) {
			case HuffmanLeaf:
				i.value.(FieldPathOpFcn)(r, fp)
				break
			case HuffmanNode:
				node = i
				break
			}
		}
	}

	return fields
}

// Returns a huffman tree based on the operation weights
func fieldpath_huffman() HuffmanTree {
	FieldPathOperations := make(map[int]interface{})

	FieldPathOperations[36271] = PlusOne
	FieldPathOperations[10334] = PlusTwo
	FieldPathOperations[1375] = PlusThree
	FieldPathOperations[646] = PlusFour
	FieldPathOperations[4128] = PlusN
	FieldPathOperations[35] = PushOneLeftDeltaZeroRightZero
	FieldPathOperations[3] = PushOneLeftDeltaZeroRightNonZero
	FieldPathOperations[521] = PushOneLeftDeltaOneRightZero
	FieldPathOperations[2942] = PushOneLeftDeltaOneRightNonZero
	FieldPathOperations[560] = PushOneLeftDeltaNRightZero
	FieldPathOperations[471] = PushOneLeftDeltaNRightNonZero
	FieldPathOperations[10530] = PushOneLeftDeltaNRightNonZeroPack6Bits
	FieldPathOperations[251] = PushOneLeftDeltaNRightNonZeroPack8Bits
	FieldPathOperations[0] = PushTwoLeftDeltaZero
	FieldPathOperations[0] = PushTwoLeftDeltaOne
	FieldPathOperations[0] = PushTwoLeftDeltaN
	FieldPathOperations[0] = PushTwoPack5LeftDeltaZero
	FieldPathOperations[0] = PushTwoPack5LeftDeltaOne
	FieldPathOperations[0] = PushTwoPack5LeftDeltaN
	FieldPathOperations[0] = PushThreeLeftDeltaZero
	FieldPathOperations[0] = PushThreeLeftDeltaOne
	FieldPathOperations[0] = PushThreeLeftDeltaN
	FieldPathOperations[0] = PushThreePack5LeftDeltaZero
	FieldPathOperations[0] = PushThreePack5LeftDeltaOne
	FieldPathOperations[0] = PushThreePack5LeftDeltaN
	FieldPathOperations[0] = PushN
	FieldPathOperations[310] = PushNAndNonTopological
	FieldPathOperations[2] = PopOnePlusOne
	FieldPathOperations[0] = PopOnePlusN
	FieldPathOperations[1837] = PopAllButOnePlusOne
	FieldPathOperations[149] = PopAllButOnePlusN
	FieldPathOperations[300] = PopAllButOnePlusNPack3Bits
	FieldPathOperations[634] = PopAllButOnePlusNPack6Bits
	FieldPathOperations[0] = PopNPlusOne
	FieldPathOperations[0] = PopNPlusN
	FieldPathOperations[1] = PopNAndNonTopographical
	FieldPathOperations[76] = NonTopoComplex
	FieldPathOperations[271] = NonTopoPenultimatePlusOne
	FieldPathOperations[99] = NonTopoComplexPack4Bits
	FieldPathOperations[25474] = FieldPathEncodeFinish

	return buildTree(FieldPathOperations)
}

func PlusOne(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 1
}

func PlusTwo(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 2
}

func PlusThree(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 3
}

func PlusFour(r *reader, fp *fieldpath) {
	fp.index[len(fp.index)-1] += 4
}

func PlusN(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaZeroRightZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaZeroRightNonZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaOneRightZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaOneRightNonZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightNonZero(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightNonZeroPack6Bits(r *reader, fp *fieldpath) {

}

func PushOneLeftDeltaNRightNonZeroPack8Bits(r *reader, fp *fieldpath) {

}

func PushTwoLeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushTwoLeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushTwoLeftDeltaN(r *reader, fp *fieldpath) {

}

func PushTwoPack5LeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushTwoPack5LeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushTwoPack5LeftDeltaN(r *reader, fp *fieldpath) {

}

func PushThreeLeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushThreeLeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushThreeLeftDeltaN(r *reader, fp *fieldpath) {

}

func PushThreePack5LeftDeltaZero(r *reader, fp *fieldpath) {

}

func PushThreePack5LeftDeltaOne(r *reader, fp *fieldpath) {

}

func PushThreePack5LeftDeltaN(r *reader, fp *fieldpath) {

}

func PushN(r *reader, fp *fieldpath) {

}

func PushNAndNonTopological(r *reader, fp *fieldpath) {

}

func PopOnePlusOne(r *reader, fp *fieldpath) {

}

func PopOnePlusN(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusOne(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusN(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusNPackN(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusNPack3Bits(r *reader, fp *fieldpath) {

}

func PopAllButOnePlusNPack6Bits(r *reader, fp *fieldpath) {

}

func PopNPlusOne(r *reader, fp *fieldpath) {

}

func PopNPlusN(r *reader, fp *fieldpath) {

}

func PopNAndNonTopographical(r *reader, fp *fieldpath) {

}

func NonTopoComplex(r *reader, fp *fieldpath) {

}

func NonTopoPenultimatePlusOne(r *reader, fp *fieldpath) {

}

func NonTopoComplexPack4Bits(r *reader, fp *fieldpath) {

}

func FieldPathEncodeFinish(r *reader, fp *fieldpath) {
	fp.finished = true
}
<|endoftext|>