<commit_before>package mstate_test

import (
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	state "launchpad.net/juju-core/mstate"
	"sort"
)

type MachineSuite struct {
	ConnSuite
	machine *state.Machine
}

var _ = Suite(&MachineSuite{})

func (s *MachineSuite) SetUpTest(c *C) {
	s.ConnSuite.SetUpTest(c)
	var err error
	s.machine, err = s.State.AddMachine()
	c.Assert(err, IsNil)
}

func (s *MachineSuite) TestMachineInstanceId(c *C) {
	machine, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	err = s.machines.Update(
		bson.D{{"_id", machine.Id()}},
		bson.D{{"$set", bson.D{{"instanceid", "spaceship/0"}}}},
	)
	c.Assert(err, IsNil)

	err = machine.Refresh()
	c.Assert(err, IsNil)
	iid, _ := machine.InstanceId()
	c.Assert(iid, Equals, "spaceship/0")
}

func (s *MachineSuite) TestMachineSetInstanceId(c *C) {
	machine, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	err = machine.SetInstanceId("umbrella/0")
	c.Assert(err, IsNil)

	n, err := s.machines.Find(bson.D{{"instanceid", "umbrella/0"}}).Count()
	c.Assert(err, IsNil)
	c.Assert(n, Equals, 1)
}

func (s *MachineSuite) TestMachineUnits(c *C) {
	// Check that Machine.Units works correctly.

	// Make three machines, three services and three units for each service;
	// variously assign units to machines and check that Machine.Units
	// tells us the right thing.

	m1 := s.machine
	m2, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	m3, err := s.State.AddMachine()
	c.Assert(err, IsNil)

	dummy := s.AddTestingCharm(c, "dummy")
	logging := s.AddTestingCharm(c, "logging")
	s0, err := s.State.AddService("s0", dummy)
	c.Assert(err, IsNil)
	s1, err := s.State.AddService("s1", dummy)
	c.Assert(err, IsNil)
	s2, err := s.State.AddService("s2", dummy)
	c.Assert(err, IsNil)
	s3, err := s.State.AddService("s3", logging)
	c.Assert(err, IsNil)

	units := make([][]*state.Unit, 4)
	for i, svc := range []*state.Service{s0, s1, s2} {
		units[i] = make([]*state.Unit, 3)
		for j := range units[i] {
			units[i][j], err = svc.AddUnit()
			c.Assert(err, IsNil)
		}
	}
	// Add the logging units subordinate to the s2 units.
	units[3] = make([]*state.Unit, 3)
	for i := range units[3] {
		units[3][i], err = s3.AddUnitSubordinateTo(units[2][i])
	}

	assignments := []struct {
		machine      *state.Machine
		units        []*state.Unit
		subordinates []*state.Unit
	}{
		{m1, []*state.Unit{units[0][0]}, nil},
		{m2, []*state.Unit{units[0][1], units[1][0], units[1][1], units[2][0]}, []*state.Unit{units[3][0]}},
		{m3, []*state.Unit{units[2][2]}, []*state.Unit{units[3][2]}},
	}

	for _, a := range assignments {
		for _, u := range a.units {
			err := u.AssignToMachine(a.machine)
			c.Assert(err, IsNil)
		}
	}

	for i, a := range assignments {
		c.Logf("test %d", i)
		got, err := a.machine.Units()
		c.Assert(err, IsNil)
		expect := sortedUnitNames(append(a.units, a.subordinates...))
		c.Assert(sortedUnitNames(got), DeepEquals, expect)
	}
}

func sortedUnitNames(units []*state.Unit) []string {
	names := make([]string, len(units))
	for i, u := range units {
		names[i] = u.Name()
	}
	sort.Strings(names)
	return names
}
<commit_msg>juju: merge lp:~aramh/juju-core/41-mstate-cache-charms<commit_after>package mstate_test

import (
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	state "launchpad.net/juju-core/mstate"
	"sort"
)

type MachineSuite struct {
	ConnSuite
	machine *state.Machine
}

var _ = Suite(&MachineSuite{})

func (s *MachineSuite) SetUpTest(c *C) {
	s.ConnSuite.SetUpTest(c)
	var err error
	s.machine, err = s.State.AddMachine()
	c.Assert(err, IsNil)
}

func (s *MachineSuite) TestMachineInstanceId(c *C) {
	machine, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	err = s.machines.Update(
		bson.D{{"_id", machine.Id()}},
		bson.D{{"$set", bson.D{{"instanceid", "spaceship/0"}}}},
	)
	c.Assert(err, IsNil)

	err = machine.Refresh()
	c.Assert(err, IsNil)
	iid, _ := machine.InstanceId()
	c.Assert(iid, Equals, "spaceship/0")
}

func (s *MachineSuite) TestMachineSetInstanceId(c *C) {
	machine, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	err = machine.SetInstanceId("umbrella/0")
	c.Assert(err, IsNil)

	n, err := s.machines.Find(bson.D{{"instanceid", "umbrella/0"}}).Count()
	c.Assert(err, IsNil)
	c.Assert(n, Equals, 1)
}

func (s *MachineSuite) TestMachineRefresh(c *C) {
	m0, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	m1, err := s.State.Machine(m0.Id())
	c.Assert(err, IsNil)
	err = m0.SetInstanceId("umbrella/0")
	c.Assert(err, IsNil)
	err = m1.Refresh()
	c.Assert(err, IsNil)
	c.Assert(m0, DeepEquals, m1)
}

func (s *MachineSuite) TestMachineUnits(c *C) {
	// Check that Machine.Units works correctly.

	// Make three machines, three services and three units for each service;
	// variously assign units to machines and check that Machine.Units
	// tells us the right thing.

	m1 := s.machine
	m2, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	m3, err := s.State.AddMachine()
	c.Assert(err, IsNil)

	dummy := s.AddTestingCharm(c, "dummy")
	logging := s.AddTestingCharm(c, "logging")
	s0, err := s.State.AddService("s0", dummy)
	c.Assert(err, IsNil)
	s1, err := s.State.AddService("s1", dummy)
	c.Assert(err, IsNil)
	s2, err := s.State.AddService("s2", dummy)
	c.Assert(err, IsNil)
	s3, err := s.State.AddService("s3", logging)
	c.Assert(err, IsNil)

	units := make([][]*state.Unit, 4)
	for i, svc := range []*state.Service{s0, s1, s2} {
		units[i] = make([]*state.Unit, 3)
		for j := range units[i] {
			units[i][j], err = svc.AddUnit()
			c.Assert(err, IsNil)
		}
	}
	// Add the logging units subordinate to the s2 units.
	units[3] = make([]*state.Unit, 3)
	for i := range units[3] {
		units[3][i], err = s3.AddUnitSubordinateTo(units[2][i])
	}

	assignments := []struct {
		machine      *state.Machine
		units        []*state.Unit
		subordinates []*state.Unit
	}{
		{m1, []*state.Unit{units[0][0]}, nil},
		{m2, []*state.Unit{units[0][1], units[1][0], units[1][1], units[2][0]}, []*state.Unit{units[3][0]}},
		{m3, []*state.Unit{units[2][2]}, []*state.Unit{units[3][2]}},
	}

	for _, a := range assignments {
		for _, u := range a.units {
			err := u.AssignToMachine(a.machine)
			c.Assert(err, IsNil)
		}
	}

	for i, a := range assignments {
		c.Logf("test %d", i)
		got, err := a.machine.Units()
		c.Assert(err, IsNil)
		expect := sortedUnitNames(append(a.units, a.subordinates...))
		c.Assert(sortedUnitNames(got), DeepEquals, expect)
	}
}

func sortedUnitNames(units []*state.Unit) []string {
	names := make([]string, len(units))
	for i, u := range units {
		names[i] = u.Name()
	}
	sort.Strings(names)
	return names
}
<|endoftext|>


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

package searchers

import (
	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
	"github.com/blevesearch/bleve/search/scorers"
)

// DocIDSearcher returns documents matching a predefined set of identifiers.
type DocIDSearcher struct {
	reader index.DocIDReader
	scorer *scorers.ConstantScorer
	count  int
}

func NewDocIDSearcher(indexReader index.IndexReader, ids []string, boost float64,
	explain bool) (searcher *DocIDSearcher, err error) {

	// kept := make([]string, len(ids))
	// copy(kept, ids)
	// sort.Strings(kept)
	//
	// if len(ids) > 0 {
	// 	var idReader index.DocIDReader
	// 	endTerm := string(incrementBytes([]byte(kept[len(kept)-1])))
	// 	idReader, err = indexReader.DocIDReader(kept[0], endTerm)
	// 	if err != nil {
	// 		return nil, err
	// 	}
	// 	defer func() {
	// 		if cerr := idReader.Close(); err == nil && cerr != nil {
	// 			err = cerr
	// 		}
	// 	}()
	// 	j := 0
	// 	for _, id := range kept {
	// 		doc, err := idReader.Next()
	// 		if err != nil {
	// 			return nil, err
	// 		}
	// 		// Non-duplicate match
	// 		actualDocID := indexReader.FinalizeDocID(doc)
	// 		if actualDocID == id && (j == 0 || kept[j-1] != id) {
	// 			kept[j] = id
	// 			j++
	// 		}
	// 	}
	// 	kept = kept[:j]
	// }

	reader, err := indexReader.DocIDReaderOnly(ids)
	if err != nil {
		return nil, err
	}
	scorer := scorers.NewConstantScorer(1.0, boost, explain)
	return &DocIDSearcher{
		scorer: scorer,
		reader: reader,
		count:  len(ids),
	}, nil
}

func (s *DocIDSearcher) Count() uint64 {
	// return uint64(len(s.ids))
	return uint64(s.count)
}

func (s *DocIDSearcher) Weight() float64 {
	return s.scorer.Weight()
}

func (s *DocIDSearcher) SetQueryNorm(qnorm float64) {
	s.scorer.SetQueryNorm(qnorm)
}

func (s *DocIDSearcher) Next(preAllocated *search.DocumentMatch) (*search.DocumentMatch, error) {
	// if s.current >= len(s.ids) {
	// 	return nil, nil
	// }
	// id := s.ids[s.current]
	// s.current++
	// docMatch := s.scorer.Score(id)
	// return docMatch, nil

	docidMatch, err := s.reader.Next()
	if err != nil {
		return nil, err
	}
	if docidMatch == nil {
		return nil, nil
	}

	docMatch := s.scorer.Score(docidMatch)
	return docMatch, nil
}

func (s *DocIDSearcher) Advance(ID index.IndexInternalID, preAllocated *search.DocumentMatch) (*search.DocumentMatch, error) {
	// s.current = sort.SearchStrings(s.ids, ID)
	// return s.Next(preAllocated)

	docidMatch, err := s.reader.Advance(ID)
	if err != nil {
		return nil, err
	}
	if docidMatch == nil {
		return nil, nil
	}

	docMatch := s.scorer.Score(docidMatch)
	return docMatch, nil
}

func (s *DocIDSearcher) Close() error {
	return nil
}

func (s *DocIDSearcher) Min() int {
	return 0
}
<commit_msg>remove commented out old code<commit_after>//  Copyright (c) 2015 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package searchers

import (
	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
	"github.com/blevesearch/bleve/search/scorers"
)

// DocIDSearcher returns documents matching a predefined set of identifiers.
type DocIDSearcher struct {
	reader index.DocIDReader
	scorer *scorers.ConstantScorer
	count  int
}

func NewDocIDSearcher(indexReader index.IndexReader, ids []string, boost float64,
	explain bool) (searcher *DocIDSearcher, err error) {

	reader, err := indexReader.DocIDReaderOnly(ids)
	if err != nil {
		return nil, err
	}
	scorer := scorers.NewConstantScorer(1.0, boost, explain)
	return &DocIDSearcher{
		scorer: scorer,
		reader: reader,
		count:  len(ids),
	}, nil
}

func (s *DocIDSearcher) Count() uint64 {
	return uint64(s.count)
}

func (s *DocIDSearcher) Weight() float64 {
	return s.scorer.Weight()
}

func (s *DocIDSearcher) SetQueryNorm(qnorm float64) {
	s.scorer.SetQueryNorm(qnorm)
}

func (s *DocIDSearcher) Next(preAllocated *search.DocumentMatch) (*search.DocumentMatch, error) {
	docidMatch, err := s.reader.Next()
	if err != nil {
		return nil, err
	}
	if docidMatch == nil {
		return nil, nil
	}

	docMatch := s.scorer.Score(docidMatch)
	return docMatch, nil
}

func (s *DocIDSearcher) Advance(ID index.IndexInternalID, preAllocated *search.DocumentMatch) (*search.DocumentMatch, error) {
	docidMatch, err := s.reader.Advance(ID)
	if err != nil {
		return nil, err
	}
	if docidMatch == nil {
		return nil, nil
	}

	docMatch := s.scorer.Score(docidMatch)
	return docMatch, nil
}

func (s *DocIDSearcher) Close() error {
	return nil
}

func (s *DocIDSearcher) Min() int {
	return 0
}
<|endoftext|>


<commit_before>package gouda

import (
	"mysql"
	"strings"
	"fmt"
	"os"
	"strconv"
	"container/vector"
)

type MysqlConnector struct {
	conn *mysql.MySQLInstance
}

func (e *MysqlConnector) Close() {
	e.conn.Quit();
}

func (e *MysqlConnector) Open(connectionString string) bool {
	tab := strings.Split(connectionString, "/", 0)
	db := tab[len(tab)-1]
	tab2 := strings.Split(tab[2], "@", 2)
	tab = strings.Split(tab2[0], ":", 0)
//	fmt.Println(tab)
//	fmt.Println(tab2)
	user := tab[0]
	pass := tab[1]

	dbh, err := mysql.Connect("tcp", "", tab2[1], user, pass, "")
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(1)
	}
	e.conn = dbh
	e.conn.Use(db)
	return false
}

func (e *MysqlConnector) Query(r *Relation) *vector.Vector {
	res, err := e.conn.Query(mysql_query(r))
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(1)
	}
//	fmt.Println(res)
//	fmt.Println(res.FieldCount)

//	fmt.Println(len(res.ResultSet.Rows))
	ret :=new(vector.Vector)
	for rowmap := res.FetchRowMap(); rowmap != nil; rowmap = res.FetchRowMap() {
		tmp := make(map[string]Value)
//		fmt.Printf("%#v\n", rowmap)
//		fmt.Printf("%#v\n", res.ResultSet.Fields)
		for i := 0; i < len(rowmap); i++ {
//			rowmap[rs.ResultSet.Fields[i].Name] = row.Data[i].Data
//			fmt.Println(res.ResultSet.Fields[i].Name)
			var val Value;
//			fmt.Println(res.ResultSet.Fields[i].Type)
			switch res.ResultSet.Fields[i].Type {
			case mysql.MYSQL_TYPE_VAR_STRING:
				val=SysString(rowmap[res.ResultSet.Fields[i].Name]).Value()
			case mysql.MYSQL_TYPE_LONG:
				t,_:=strconv.Atoi(rowmap[res.ResultSet.Fields[i].Name])
				val=SysInt(t).Value()
			}
			tmp[res.ResultSet.Fields[i].Name] = val
//			tmp["id"] = val
		}
		ret.Push(tmp)
	}
//	fmt.Printf("%#v\n",ret)
	return ret
}

func OpenMysql(conStr string) Connection {
	db:= (new(MysqlConnector))
	db.Open(conStr)
	return db
}

func  mysql_query(r * Relation) (sql string) {
	sql = "Select * from " + r.table
	if r.conditions.Len() > 0 {
		sql+=" where ( "
		for _, ss := range r.conditions {
			sql += ss
			if ss != r.conditions.Last() {
				sql += " ) AND ( "
			}
		}
	sql += " )"
	}
	if (r.order_field.Len()>0){
		sql+=" ORDER BY "
			for i, ss := range r.order_field {
				sql += ss+" "+r.order_direction[i]
			}
	}

	if r.limit_count > 0 {
		sql+=" LIMIT "+fmt.Sprint(r.limit_offset)+", "+fmt.Sprint(r.limit_count)
	}
	fmt.Println(sql)
	sql +=";"
	return
}
<commit_msg>stripping debug echo<commit_after>package gouda

import (
	"mysql"
	"strings"
	"fmt"
	"os"
	"strconv"
	"container/vector"
)

type MysqlConnector struct {
	conn *mysql.MySQLInstance
}

func (e *MysqlConnector) Close() {
	e.conn.Quit();
}

func (e *MysqlConnector) Open(connectionString string) bool {
	tab := strings.Split(connectionString, "/", 0)
	db := tab[len(tab)-1]
	tab2 := strings.Split(tab[2], "@", 2)
	tab = strings.Split(tab2[0], ":", 0)
//	fmt.Println(tab)
//	fmt.Println(tab2)
	user := tab[0]
	pass := tab[1]

	dbh, err := mysql.Connect("tcp", "", tab2[1], user, pass, "")
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(1)
	}
	e.conn = dbh
	e.conn.Use(db)
	return false
}

func (e *MysqlConnector) Query(r *Relation) *vector.Vector {
	res, err := e.conn.Query(mysql_query(r))
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(1)
	}
//	fmt.Println(res)
//	fmt.Println(res.FieldCount)

//	fmt.Println(len(res.ResultSet.Rows))
	ret :=new(vector.Vector)
	for rowmap := res.FetchRowMap(); rowmap != nil; rowmap = res.FetchRowMap() {
		tmp := make(map[string]Value)
//		fmt.Printf("%#v\n", rowmap)
//		fmt.Printf("%#v\n", res.ResultSet.Fields)
		for i := 0; i < len(rowmap); i++ {
//			rowmap[rs.ResultSet.Fields[i].Name] = row.Data[i].Data
//			fmt.Println(res.ResultSet.Fields[i].Name)
			var val Value;
//			fmt.Println(res.ResultSet.Fields[i].Type)
			switch res.ResultSet.Fields[i].Type {
			case mysql.MYSQL_TYPE_VAR_STRING:
				val=SysString(rowmap[res.ResultSet.Fields[i].Name]).Value()
			case mysql.MYSQL_TYPE_LONG:
				t,_:=strconv.Atoi(rowmap[res.ResultSet.Fields[i].Name])
				val=SysInt(t).Value()
			}
			tmp[res.ResultSet.Fields[i].Name] = val
//			tmp["id"] = val
		}
		ret.Push(tmp)
	}
//	fmt.Printf("%#v\n",ret)
	return ret
}

func OpenMysql(conStr string) Connection {
	db:= (new(MysqlConnector))
	db.Open(conStr)
	return db
}

func  mysql_query(r * Relation) (sql string) {
	sql = "Select * from " + r.table
	if r.conditions.Len() > 0 {
		sql+=" where ( "
		for _, ss := range r.conditions {
			sql += ss
			if ss != r.conditions.Last() {
				sql += " ) AND ( "
			}
		}
	sql += " )"
	}
	if (r.order_field.Len()>0){
		sql+=" ORDER BY "
			for i, ss := range r.order_field {
				sql += ss+" "+r.order_direction[i]
			}
	}

	if r.limit_count > 0 {
		sql+=" LIMIT "+fmt.Sprint(r.limit_offset)+", "+fmt.Sprint(r.limit_count)
	}
//	fmt.Println(sql)
	sql +=";"
	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 The Jaeger Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://wwr.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package grpcresolver

import (
	"hash"
	"hash/fnv"
	"math/rand"
	"sort"
	"strconv"
	"sync"
	"time"

	"go.uber.org/zap"
	"google.golang.org/grpc/resolver"

	"github.com/jaegertracing/jaeger/pkg/discovery"
)

// GRPCServiceConfig provides grpc service config
const GRPCServiceConfig = `{"loadBalancingPolicy":"round_robin"}`

// Resolver uses notifier to fetch list of available hosts
type Resolver struct {
	scheme            string
	cc                resolver.ClientConn
	notifier          discovery.Notifier
	discoverer        discovery.Discoverer
	logger            *zap.Logger
	discoCh           chan []string // used to receive notifications
	discoveryMinPeers int
	salt              []byte

	// used to block Close() until the watcher goroutine exits its loop
	closing sync.WaitGroup
}
type hostScore struct {
	address string
	score   uint32
}

type hostScores []hostScore

func (s hostScores) Len() int           { return len(s) }
func (s hostScores) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s hostScores) Less(i, j int) bool { return s[i].score < s[j].score }

// New initialize a new grpc resolver with notifier
func New(
	notifier discovery.Notifier,
	discoverer discovery.Discoverer,
	logger *zap.Logger,
	discoveryMinPeers int,
) *Resolver {
	seed := time.Now().UnixNano()
	random := rand.New(rand.NewSource(seed))
	r := &Resolver{
		notifier:          notifier,
		discoverer:        discoverer,
		discoCh:           make(chan []string, 100),
		logger:            logger,
		discoveryMinPeers: discoveryMinPeers,
		salt:              []byte(strconv.FormatInt(random.Int63(), 10)), // random salt for rendezvousHash
		scheme:            strconv.FormatInt(seed, 36),                   // make random scheme which will be used when registering
	}

	// Register the resolver with grpc so it's available for grpc.Dial
	resolver.Register(r)

	// Register the discoCh channel with notifier so it continues to fetch a list of host/port
	notifier.Register(r.discoCh)
	return r
}

// Build returns itself for Resolver, because it's both a builder and a resolver.
func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOption) (resolver.Resolver, error) {
	r.cc = cc

	// Update conn states if proactively updates already work
	instances, err := r.discoverer.Instances()
	if err != nil {
		return nil, err
	}
	r.updateAddresses(instances)
	r.closing.Add(1)
	go r.watcher()
	return r, nil
}

// Scheme returns resolver's scheme.
func (r *Resolver) Scheme() string {
	return r.scheme
}

// ResolveNow is a noop for Resolver since resolver is already firing r.cc.UpdatesState every time
// it receives updates of new instance from discoCh
func (r *Resolver) ResolveNow(o resolver.ResolveNowOption) {}

func (r *Resolver) watcher() {
	defer r.closing.Done()
	for latestHostPorts := range r.discoCh {
		r.logger.Info("Received updates from notifier", zap.Strings("hostPorts", latestHostPorts))
		r.updateAddresses(latestHostPorts)
	}
}

// Close closes both discoCh
func (r *Resolver) Close() {
	r.notifier.Unregister(r.discoCh)
	close(r.discoCh)
	r.closing.Wait()
}

func (r *Resolver) rendezvousHash(addresses []string) []string {
	hasher := fnv.New32()
	hosts := hostScores{}
	for _, address := range addresses {
		hosts = append(hosts, hostScore{
			address: address,
			score:   hashAddr(hasher, []byte(address), r.salt),
		})
	}
	sort.Sort(hosts)
	size := min(r.discoveryMinPeers, len(hosts))
	addressesPerHost := make([]string, size)
	for i := 0; i < size; i++ {
		addressesPerHost[i] = hosts[i].address
	}
	return addressesPerHost
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func hashAddr(hasher hash.Hash32, node, saltKey []byte) uint32 {
	hasher.Reset()
	hasher.Write(saltKey)
	hasher.Write(node)
	return hasher.Sum32()
}

func (r *Resolver) updateAddresses(hostPorts []string) {
	topN := r.rendezvousHash(hostPorts)
	addresses := generateAddresses(topN)
	r.cc.UpdateState(resolver.State{Addresses: addresses})
}

func generateAddresses(instances []string) []resolver.Address {
	var addrs []resolver.Address
	for _, instance := range instances {
		addrs = append(addrs, resolver.Address{Addr: instance})
	}
	return addrs
}
<commit_msg>Fix typo in license URL (#1933)<commit_after>// Copyright (c) 2019 The Jaeger Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package grpcresolver

import (
	"hash"
	"hash/fnv"
	"math/rand"
	"sort"
	"strconv"
	"sync"
	"time"

	"go.uber.org/zap"
	"google.golang.org/grpc/resolver"

	"github.com/jaegertracing/jaeger/pkg/discovery"
)

// GRPCServiceConfig provides grpc service config
const GRPCServiceConfig = `{"loadBalancingPolicy":"round_robin"}`

// Resolver uses notifier to fetch list of available hosts
type Resolver struct {
	scheme            string
	cc                resolver.ClientConn
	notifier          discovery.Notifier
	discoverer        discovery.Discoverer
	logger            *zap.Logger
	discoCh           chan []string // used to receive notifications
	discoveryMinPeers int
	salt              []byte

	// used to block Close() until the watcher goroutine exits its loop
	closing sync.WaitGroup
}
type hostScore struct {
	address string
	score   uint32
}

type hostScores []hostScore

func (s hostScores) Len() int           { return len(s) }
func (s hostScores) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s hostScores) Less(i, j int) bool { return s[i].score < s[j].score }

// New initialize a new grpc resolver with notifier
func New(
	notifier discovery.Notifier,
	discoverer discovery.Discoverer,
	logger *zap.Logger,
	discoveryMinPeers int,
) *Resolver {
	seed := time.Now().UnixNano()
	random := rand.New(rand.NewSource(seed))
	r := &Resolver{
		notifier:          notifier,
		discoverer:        discoverer,
		discoCh:           make(chan []string, 100),
		logger:            logger,
		discoveryMinPeers: discoveryMinPeers,
		salt:              []byte(strconv.FormatInt(random.Int63(), 10)), // random salt for rendezvousHash
		scheme:            strconv.FormatInt(seed, 36),                   // make random scheme which will be used when registering
	}

	// Register the resolver with grpc so it's available for grpc.Dial
	resolver.Register(r)

	// Register the discoCh channel with notifier so it continues to fetch a list of host/port
	notifier.Register(r.discoCh)
	return r
}

// Build returns itself for Resolver, because it's both a builder and a resolver.
func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOption) (resolver.Resolver, error) {
	r.cc = cc

	// Update conn states if proactively updates already work
	instances, err := r.discoverer.Instances()
	if err != nil {
		return nil, err
	}
	r.updateAddresses(instances)
	r.closing.Add(1)
	go r.watcher()
	return r, nil
}

// Scheme returns resolver's scheme.
func (r *Resolver) Scheme() string {
	return r.scheme
}

// ResolveNow is a noop for Resolver since resolver is already firing r.cc.UpdatesState every time
// it receives updates of new instance from discoCh
func (r *Resolver) ResolveNow(o resolver.ResolveNowOption) {}

func (r *Resolver) watcher() {
	defer r.closing.Done()
	for latestHostPorts := range r.discoCh {
		r.logger.Info("Received updates from notifier", zap.Strings("hostPorts", latestHostPorts))
		r.updateAddresses(latestHostPorts)
	}
}

// Close closes both discoCh
func (r *Resolver) Close() {
	r.notifier.Unregister(r.discoCh)
	close(r.discoCh)
	r.closing.Wait()
}

func (r *Resolver) rendezvousHash(addresses []string) []string {
	hasher := fnv.New32()
	hosts := hostScores{}
	for _, address := range addresses {
		hosts = append(hosts, hostScore{
			address: address,
			score:   hashAddr(hasher, []byte(address), r.salt),
		})
	}
	sort.Sort(hosts)
	size := min(r.discoveryMinPeers, len(hosts))
	addressesPerHost := make([]string, size)
	for i := 0; i < size; i++ {
		addressesPerHost[i] = hosts[i].address
	}
	return addressesPerHost
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func hashAddr(hasher hash.Hash32, node, saltKey []byte) uint32 {
	hasher.Reset()
	hasher.Write(saltKey)
	hasher.Write(node)
	return hasher.Sum32()
}

func (r *Resolver) updateAddresses(hostPorts []string) {
	topN := r.rendezvousHash(hostPorts)
	addresses := generateAddresses(topN)
	r.cc.UpdateState(resolver.State{Addresses: addresses})
}

func generateAddresses(instances []string) []resolver.Address {
	var addrs []resolver.Address
	for _, instance := range instances {
		addrs = append(addrs, resolver.Address{Addr: instance})
	}
	return addrs
}
<|endoftext|>


<commit_before>package neurgo

import (
	"testing"
	"github.com/couchbaselabs/go.assert"
	"log"
)

func TestNetworkVerify(t *testing.T) {

	// create network nodes
	neuron1 := &Neuron{Bias: 10, ActivationFunction: identity_activation}
	neuron2 := &Neuron{Bias: 10, ActivationFunction: identity_activation}
	sensor := &Sensor{}
	actuator := &Actuator{}

	// give nodes names
	sensor.Name = "sensor"
	actuator.Name = "actuator"
	neuron1.Name = "neuron1"
	neuron2.Name = "neuron2"

	// connect nodes together
	weights := []float64{20,20,20,20,20}
	sensor.ConnectBidirectionalWeighted(neuron1, weights)
	sensor.ConnectBidirectionalWeighted(neuron2, weights)
	neuron1.ConnectBidirectional(actuator)
	neuron2.ConnectBidirectional(actuator)

	// inputs + expected outputs
	examples := []*TrainingSample{{sampleInputs: [][]float64{[]float64{1,1,1,1,1}}, expectedOutputs: [][]float64{[]float64{110,110}}}}

	// create neural network
	sensors := []*Sensor{sensor}
	actuators := []*Actuator{actuator}
	neuralNet := &NeuralNetwork{sensors: sensors, actuators: actuators}

	// spinup node goroutines
	signallers := []Connector{neuron1, neuron2, sensor, actuator}
	for _, signaller := range signallers {
		go Run(signaller)
	}

	// verify neural network
	verified := neuralNet.Verify(examples)
	assert.True(t, verified)

	// make sure injectors/wiretaps have been removed
	assert.Equals(t, len(sensor.inbound), 0)
	assert.Equals(t, len(actuator.outbound), 0)

}

func TestXnorNetwork(t *testing.T) {

	// create network nodes
	input_neuron1 := &Neuron{Bias: 0, ActivationFunction: identity_activation}
	input_neuron2 := &Neuron{Bias: 0, ActivationFunction: identity_activation}
	hidden_neuron1 := &Neuron{Bias: -30, ActivationFunction: sigmoid}
	hidden_neuron2 := &Neuron{Bias: 10, ActivationFunction: sigmoid}
	output_neuron := &Neuron{Bias: -10, ActivationFunction: sigmoid}
	sensor1 := &Sensor{}
	sensor2 := &Sensor{}
	actuator := &Actuator{}

	// give names to network nodes
	sensor1.Name = "sensor1"
	sensor2.Name = "sensor2"
	input_neuron1.Name = "input_neuron1"
	input_neuron2.Name = "input_neuron2"
	hidden_neuron1.Name = "hidden_neuron1"
	hidden_neuron2.Name = "hidden_neuron2"
	output_neuron.Name = "output_neuron"
	actuator.Name = "actuator"

	// connect nodes together
	sensor1.ConnectBidirectionalWeighted(input_neuron1, []float64{1})
	sensor2.ConnectBidirectionalWeighted(input_neuron2, []float64{1})
	input_neuron1.ConnectBidirectionalWeighted(hidden_neuron1, []float64{20})
	input_neuron2.ConnectBidirectionalWeighted(hidden_neuron1, []float64{20})
	input_neuron1.ConnectBidirectionalWeighted(hidden_neuron2, []float64{-20})
	input_neuron2.ConnectBidirectionalWeighted(hidden_neuron2, []float64{-20})
	hidden_neuron1.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	hidden_neuron2.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	output_neuron.ConnectBidirectional(actuator)

	// create neural network
	sensors := []*Sensor{sensor1, sensor2}
	actuators := []*Actuator{actuator}
	neuralNet := &NeuralNetwork{sensors: sensors, actuators: actuators}

	// inputs + expected outputs
	examples := []*TrainingSample{

		// TODO: how to wrap this?
		{sampleInputs: [][]float64{[]float64{0},[]float64{1}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{1},[]float64{1}}, expectedOutputs: [][]float64{[]float64{1}}},
		{sampleInputs: [][]float64{[]float64{1},[]float64{0}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{0},[]float64{0}}, expectedOutputs: [][]float64{[]float64{1}}}}

	// spinup node goroutines
	signallers := []Connector{input_neuron1, input_neuron2, hidden_neuron1, hidden_neuron2, output_neuron, sensor1, sensor2, actuator}
	for _, signaller := range signallers {
		go Run(signaller)
	}

	// verify neural network
	verified := neuralNet.Verify(examples)
	assert.True(t, verified)

}

func xnorCondensedNetwork() *NeuralNetwork {

	// create network nodes
	hidden_neuron1 := &Neuron{Bias: -30, ActivationFunction: sigmoid}
	hidden_neuron2 := &Neuron{Bias: 10, ActivationFunction: sigmoid}
	output_neuron := &Neuron{Bias: -10, ActivationFunction: sigmoid}
	sensor := &Sensor{}
	actuator := &Actuator{}

	// give names to network nodes
	sensor.Name = "sensor"
	hidden_neuron1.Name = "hidden_neuron1"
	hidden_neuron2.Name = "hidden_neuron2"
	output_neuron.Name = "output_neuron"
	actuator.Name = "actuator"

	// connect nodes together
	sensor.ConnectBidirectionalWeighted(hidden_neuron1, []float64{20,20})
	sensor.ConnectBidirectionalWeighted(hidden_neuron2, []float64{-20, -20})
	hidden_neuron1.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	hidden_neuron2.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	output_neuron.ConnectBidirectional(actuator)

	// create neural network
	sensors := []*Sensor{sensor}
	actuators := []*Actuator{actuator}
	neuralNet := &NeuralNetwork{sensors: sensors, actuators: actuators}

	// spinup node goroutines
	signallers := []Connector{sensor, hidden_neuron1, hidden_neuron2, output_neuron, actuator}
	for _, signaller := range signallers {
		go Run(signaller)
	}

	return neuralNet
}

func xnorTrainingSamples() []*TrainingSample {

	// inputs + expected outputs
	examples := []*TrainingSample{

		// TODO: how to wrap this?
		{sampleInputs: [][]float64{[]float64{0, 1}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{1, 1}}, expectedOutputs: [][]float64{[]float64{1}}},
		{sampleInputs: [][]float64{[]float64{1, 0}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{0, 0}}, expectedOutputs: [][]float64{[]float64{1}}}}

	return examples

}

func TestXnorCondensedNetwork(t *testing.T) {

	// identical to TestXnorNetwork, but uses single sensor with vector outputs, removes
	// the input layer neurons which are useless

	neuralNet := xnorCondensedNetwork()

	// inputs + expected outputs
	examples := xnorTrainingSamples()

	// verify neural network
	verified := neuralNet.Verify(examples)
	assert.True(t, verified)

}

/*func TestUniqueNodes(t *testing.T) {
	neuralNet := xnorCondensedNetwork()
	nodes := neuralNet.uniqueNodes()
	assert.Equals(t, len(nodes), 5)
}*/

func TestCopy(t *testing.T) {

	neuralNet := xnorCondensedNetwork()
	neuralNetCopy := neuralNet.Copy()

	assert.NotEquals(t, neuralNet, neuralNetCopy)
	assert.Equals(t, len(neuralNet.sensors), len(neuralNetCopy.sensors))
	assert.NotEquals(t, neuralNet.sensors[0], neuralNetCopy.sensors[0])
	assert.Equals(t, neuralNet.sensors[0].Name, neuralNetCopy.sensors[0].Name)
	assert.Equals(t, len(neuralNet.actuators), len(neuralNetCopy.actuators))
	assert.NotEquals(t, neuralNet.actuators[0], neuralNetCopy.actuators[0])

	assert.Equals(t, len(neuralNet.sensors[0].outbound), len(neuralNetCopy.sensors[0].outbound))
	assert.NotEquals(t, neuralNet.sensors[0].outbound[0], neuralNetCopy.sensors[0].outbound[0])

	assert.False(t, neuralNetCopy.sensors[0].outbound[0].channel == nil)
	assert.Equals(t, len(neuralNet.actuators[0].inbound), len(neuralNetCopy.actuators[0].inbound))

	assert.Equals(t, len(neuralNetCopy.sensors[0].outbound[0].other.inboundConnections()), len(neuralNet.sensors[0].outbound[0].other.inboundConnections()))

	assert.True(t, neuralNetCopy.sensors[0].outbound[0].channel == neuralNetCopy.sensors[0].outbound[0].other.inboundConnections()[0].channel)

	assert.NotEquals(t, neuralNet.actuators[0].inbound[0], neuralNetCopy.actuators[0].inbound[0])
	assert.Equals(t, len(neuralNetCopy.sensors[0].outbound[0].other.inboundConnections()[0].weights), len(neuralNet.sensors[0].outbound[0].other.inboundConnections()[0].weights))

	otherNeuron := neuralNet.sensors[0].outbound[0].other.(*Neuron)
	otherNeuronCopy := neuralNetCopy.sensors[0].outbound[0].other.(*Neuron)
	assert.Equals(t, otherNeuron.Bias, otherNeuronCopy.Bias)
	assert.Equals(t, otherNeuron.ActivationFunction(1), otherNeuronCopy.ActivationFunction(1))

	// TODO: can't do this because the network is not running

	// verify neural network copy
/*
	examples := xnorTrainingSamples()
	verified := neuralNetCopy.Verify(examples)
	assert.True(t, verified)
  */

	log.Printf("")

}

<commit_msg>neural_network_test.go now passes<commit_after>package neurgo

import (
	"testing"
	"github.com/couchbaselabs/go.assert"
	"log"
)

func TestNetworkVerify(t *testing.T) {

	// create network nodes
	neuronProcessor1 := &Neuron{Bias: 10, ActivationFunction: identity_activation}
	neuronProcessor2 := &Neuron{Bias: 10, ActivationFunction: identity_activation}
	neuron1 := &Node{Name: "neuron1", processor: neuronProcessor1}
	neuron2 := &Node{Name: "neuron2", processor: neuronProcessor2}
	sensor := &Node{Name: "sensor", processor: &Sensor{}}
	actuator := &Node{Name: "actuator", processor: &Actuator{}}

	// connect nodes together
	weights := []float64{20,20,20,20,20}
	sensor.ConnectBidirectionalWeighted(neuron1, weights)
	sensor.ConnectBidirectionalWeighted(neuron2, weights)
	neuron1.ConnectBidirectional(actuator)
	neuron2.ConnectBidirectional(actuator)

	// inputs + expected outputs
	examples := []*TrainingSample{{sampleInputs: [][]float64{[]float64{1,1,1,1,1}}, expectedOutputs: [][]float64{[]float64{110,110}}}}

	// create neural network
	sensors := []*Node{sensor}
	actuators := []*Node{actuator}
	neuralNet := &NeuralNetwork{sensors: sensors, actuators: actuators}

	// spinup node goroutines
	nodes := []*Node{neuron1, neuron2, sensor, actuator}
	for _, node := range nodes {
		go Run(node.processor, node)
	}

	// verify neural network
	verified := neuralNet.Verify(examples)
	assert.True(t, verified)

	// make sure injectors/wiretaps have been removed
	assert.Equals(t, len(sensor.inbound), 0)
	assert.Equals(t, len(actuator.outbound), 0)

}

func TestXnorNetwork(t *testing.T) {

	// create network nodes
	n1_processor := &Neuron{Bias: 0, ActivationFunction: identity_activation}
	input_neuron1 := &Node{Name: "input_neuron1", processor: n1_processor}

	n2_processor := &Neuron{Bias: 0, ActivationFunction: identity_activation}
	input_neuron2 := &Node{Name: "input_neuron2", processor: n2_processor}

	hn1_processor := &Neuron{Bias: -30, ActivationFunction: sigmoid}
	hidden_neuron1 := &Node{Name: "hidden_neuron1", processor: hn1_processor}

	hn2_processor := &Neuron{Bias: 10, ActivationFunction: sigmoid}
	hidden_neuron2 := &Node{Name: "hidden_neuron2", processor: hn2_processor}

	outn_processor := &Neuron{Bias: -10, ActivationFunction: sigmoid}
	output_neuron := &Node{Name: "output_neuron", processor: outn_processor}

	sensor1 := &Node{Name: "sensor1", processor: &Sensor{}}
	sensor2 := &Node{Name: "sensor2", processor: &Sensor{}}
	actuator := &Node{Name: "actuator", processor: &Actuator{}}

	// connect nodes together
	sensor1.ConnectBidirectionalWeighted(input_neuron1, []float64{1})
	sensor2.ConnectBidirectionalWeighted(input_neuron2, []float64{1})
	input_neuron1.ConnectBidirectionalWeighted(hidden_neuron1, []float64{20})
	input_neuron2.ConnectBidirectionalWeighted(hidden_neuron1, []float64{20})
	input_neuron1.ConnectBidirectionalWeighted(hidden_neuron2, []float64{-20})
	input_neuron2.ConnectBidirectionalWeighted(hidden_neuron2, []float64{-20})
	hidden_neuron1.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	hidden_neuron2.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	output_neuron.ConnectBidirectional(actuator)

	// create neural network
	sensors := []*Node{sensor1, sensor2}
	actuators := []*Node{actuator}
	neuralNet := &NeuralNetwork{sensors: sensors, actuators: actuators}

	// inputs + expected outputs
	examples := []*TrainingSample{

		// TODO: how to wrap this?
		{sampleInputs: [][]float64{[]float64{0},[]float64{1}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{1},[]float64{1}}, expectedOutputs: [][]float64{[]float64{1}}},
		{sampleInputs: [][]float64{[]float64{1},[]float64{0}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{0},[]float64{0}}, expectedOutputs: [][]float64{[]float64{1}}}}

	// spinup node goroutines
	nodes := []*Node{input_neuron1, input_neuron2, hidden_neuron1, hidden_neuron2, output_neuron, sensor1, sensor2, actuator}
	for _, node := range nodes {
		go Run(node.processor, node)
	}

	// verify neural network
	verified := neuralNet.Verify(examples)
	assert.True(t, verified)

}

func xnorCondensedNetwork() *NeuralNetwork {

	// create network nodes
	hn1_processor := &Neuron{Bias: -30, ActivationFunction: sigmoid}
	hidden_neuron1 := &Node{Name: "hidden_neuron1", processor: hn1_processor}

	hn2_processor := &Neuron{Bias: 10, ActivationFunction: sigmoid}
	hidden_neuron2 := &Node{Name: "hidden_neuron2", processor: hn2_processor}

	outn_processor := &Neuron{Bias: -10, ActivationFunction: sigmoid}
	output_neuron := &Node{Name: "output_neuron", processor: outn_processor}

	sensor := &Node{Name: "sensor", processor: &Sensor{}}
	actuator := &Node{Name: "actuator", processor: &Actuator{}}

	// connect nodes together
	sensor.ConnectBidirectionalWeighted(hidden_neuron1, []float64{20,20})
	sensor.ConnectBidirectionalWeighted(hidden_neuron2, []float64{-20, -20})
	hidden_neuron1.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	hidden_neuron2.ConnectBidirectionalWeighted(output_neuron, []float64{20})
	output_neuron.ConnectBidirectional(actuator)

	// create neural network
	sensors := []*Node{sensor}
	actuators := []*Node{actuator}
	neuralNet := &NeuralNetwork{sensors: sensors, actuators: actuators}

	// spinup node goroutines
	nodes := []*Node{sensor, hidden_neuron1, hidden_neuron2, output_neuron, actuator}
	for _, node := range nodes {
		go Run(node.processor, node)
	}

	return neuralNet
}

func xnorTrainingSamples() []*TrainingSample {

	// inputs + expected outputs
	examples := []*TrainingSample{

		// TODO: how to wrap this?
		{sampleInputs: [][]float64{[]float64{0, 1}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{1, 1}}, expectedOutputs: [][]float64{[]float64{1}}},
		{sampleInputs: [][]float64{[]float64{1, 0}}, expectedOutputs: [][]float64{[]float64{0}}},
		{sampleInputs: [][]float64{[]float64{0, 0}}, expectedOutputs: [][]float64{[]float64{1}}}}

	return examples

}

func TestXnorCondensedNetwork(t *testing.T) {

	// identical to TestXnorNetwork, but uses single sensor with vector outputs, removes
	// the input layer neurons which are useless

	neuralNet := xnorCondensedNetwork()

	// inputs + expected outputs
	examples := xnorTrainingSamples()

	// verify neural network
	verified := neuralNet.Verify(examples)
	assert.True(t, verified)

}

/*func TestUniqueNodes(t *testing.T) {
	neuralNet := xnorCondensedNetwork()
	nodes := neuralNet.uniqueNodes()
	assert.Equals(t, len(nodes), 5)
}*/

func TestCopy(t *testing.T) {

	neuralNet := xnorCondensedNetwork()
	neuralNetCopy := neuralNet.Copy()

	assert.NotEquals(t, neuralNet, neuralNetCopy)
	assert.Equals(t, len(neuralNet.sensors), len(neuralNetCopy.sensors))
	assert.NotEquals(t, neuralNet.sensors[0], neuralNetCopy.sensors[0])
	assert.Equals(t, neuralNet.sensors[0].Name, neuralNetCopy.sensors[0].Name)
	assert.Equals(t, len(neuralNet.actuators), len(neuralNetCopy.actuators))
	assert.NotEquals(t, neuralNet.actuators[0], neuralNetCopy.actuators[0])

	assert.Equals(t, len(neuralNet.sensors[0].outbound), len(neuralNetCopy.sensors[0].outbound))
	assert.NotEquals(t, neuralNet.sensors[0].outbound[0], neuralNetCopy.sensors[0].outbound[0])

	assert.False(t, neuralNetCopy.sensors[0].outbound[0].channel == nil)
	assert.Equals(t, len(neuralNet.actuators[0].inbound), len(neuralNetCopy.actuators[0].inbound))

	assert.Equals(t, len(neuralNetCopy.sensors[0].outbound[0].other.inboundConnections()), len(neuralNet.sensors[0].outbound[0].other.inboundConnections()))

	assert.True(t, neuralNetCopy.sensors[0].outbound[0].channel == neuralNetCopy.sensors[0].outbound[0].other.inboundConnections()[0].channel)

	assert.NotEquals(t, neuralNet.actuators[0].inbound[0], neuralNetCopy.actuators[0].inbound[0])
	assert.Equals(t, len(neuralNetCopy.sensors[0].outbound[0].other.inboundConnections()[0].weights), len(neuralNet.sensors[0].outbound[0].other.inboundConnections()[0].weights))

	otherNeuron := neuralNet.sensors[0].outbound[0].other.processor.(*Neuron)
	otherNeuronCopy := neuralNetCopy.sensors[0].outbound[0].other.processor.(*Neuron)
	assert.Equals(t, otherNeuron.Bias, otherNeuronCopy.Bias)
	assert.Equals(t, otherNeuron.ActivationFunction(1), otherNeuronCopy.ActivationFunction(1))

	// TODO: in the copy, the sesnsor and actuator nodes have no processors!  test should check for that

	// TODO: can't do this because the network is not running

	// verify neural network copy
/*
	examples := xnorTrainingSamples()
	verified := neuralNetCopy.Verify(examples)
	assert.True(t, verified)
  */

	log.Printf("")

}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"koding/artifact"
	"koding/kites/kontrol/kontrol"

	"net/http"
	_ "net/http/pprof"

	"github.com/koding/kite"
	"github.com/koding/multiconfig"
)

var Name = "kontrol"

func main() {
	loader := multiconfig.MultiLoader(
		&multiconfig.TagLoader{},
		&multiconfig.EnvironmentLoader{Prefix: "kontrol"},
		&multiconfig.FlagLoader{EnvPrefix: "kontrol"},
	)

	conf := new(kontrol.Config)

	// Load the config, it's reads from the file, environment variables and
	// lastly from flags in order
	if err := loader.Load(conf); err != nil {
		panic(err)
	}

	if err := multiconfig.MultiValidator(&multiconfig.RequiredValidator{}).Validate(conf); err != nil {
		panic(err)
	}

	fmt.Printf("Kontrol loaded with following variables: %+v\n", conf)

	k := kontrol.New(conf)

	k.Kite.HandleHTTPFunc("/healthCheck", artifact.HealthCheckHandler(Name))
	k.Kite.HandleHTTPFunc("/version", artifact.VersionHandler())

	if conf.Debug {
		k.Kite.SetLogLevel(kite.DEBUG)
	}

	go func() {
		// Kloud runs on 6060, so we choose 6061 for kontrol
		err := http.ListenAndServe("0.0.0.0:6061", nil)
		k.Kite.Log.Error(err.Error())
	}()

	k.Run()
}
<commit_msg>kontrol: add support for KONFIG_ prefix<commit_after>package main

import (
	"fmt"
	"koding/artifact"
	"koding/kites/kontrol/kontrol"

	"net/http"
	_ "net/http/pprof"

	"github.com/koding/kite"
	"github.com/koding/multiconfig"
)

var Name = "kontrol"

func main() {
	loader := multiconfig.MultiLoader(
		&multiconfig.TagLoader{},
		&multiconfig.EnvironmentLoader{Prefix: "kontrol"},
		&multiconfig.EnvironmentLoader{Prefix: "KONFIG_KONTROL"},
		&multiconfig.FlagLoader{EnvPrefix: "kontrol"},
	)

	conf := new(kontrol.Config)

	// Load the config, it's reads from the file, environment variables and
	// lastly from flags in order
	if err := loader.Load(conf); err != nil {
		panic(err)
	}

	if err := multiconfig.MultiValidator(&multiconfig.RequiredValidator{}).Validate(conf); err != nil {
		panic(err)
	}

	fmt.Printf("Kontrol loaded with following variables: %+v\n", conf)

	k := kontrol.New(conf)

	k.Kite.HandleHTTPFunc("/healthCheck", artifact.HealthCheckHandler(Name))
	k.Kite.HandleHTTPFunc("/version", artifact.VersionHandler())

	if conf.Debug {
		k.Kite.SetLogLevel(kite.DEBUG)
	}

	go func() {
		// Kloud runs on 6060, so we choose 6061 for kontrol
		err := http.ListenAndServe("0.0.0.0:6061", nil)
		k.Kite.Log.Error(err.Error())
	}()

	k.Run()
}
<|endoftext|>


<commit_before>package backendplugin

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"net/http"
	"time"

	"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/expfmt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	datasourceV1 "github.com/grafana/grafana-plugin-model/go/datasource"
	rendererV1 "github.com/grafana/grafana-plugin-model/go/renderer"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/plugins/backendplugin/collector"
	"github.com/grafana/grafana/pkg/util/errutil"
	plugin "github.com/hashicorp/go-plugin"
	dto "github.com/prometheus/client_model/go"
)

// BackendPlugin a registered backend plugin.
type BackendPlugin struct {
	id             string
	executablePath string
	managed        bool
	clientFactory  func() *plugin.Client
	client         *plugin.Client
	logger         log.Logger
	startFns       PluginStartFuncs
	diagnostics    DiagnosticsPlugin
	resource       ResourcePlugin
}

func (p *BackendPlugin) start(ctx context.Context) error {
	p.client = p.clientFactory()
	rpcClient, err := p.client.Client()
	if err != nil {
		return err
	}

	var legacyClient *LegacyClient
	var client *Client

	if p.client.NegotiatedVersion() > 1 {
		rawDiagnostics, err := rpcClient.Dispense("diagnostics")
		if err != nil {
			return err
		}

		rawResource, err := rpcClient.Dispense("resource")
		if err != nil {
			return err
		}

		rawData, err := rpcClient.Dispense("data")
		if err != nil {
			return err
		}

		rawTransform, err := rpcClient.Dispense("transform")
		if err != nil {
			return err
		}

		if rawDiagnostics != nil {
			if plugin, ok := rawDiagnostics.(DiagnosticsPlugin); ok {
				p.diagnostics = plugin
			}
		}

		client = &Client{}
		if rawResource != nil {
			if plugin, ok := rawResource.(ResourcePlugin); ok {
				p.resource = plugin
				client.ResourcePlugin = plugin
			}
		}

		if rawData != nil {
			if plugin, ok := rawData.(DataPlugin); ok {
				client.DataPlugin = plugin
			}
		}

		if rawTransform != nil {
			if plugin, ok := rawTransform.(TransformPlugin); ok {
				client.TransformPlugin = plugin
			}
		}
	} else {
		raw, err := rpcClient.Dispense(p.id)
		if err != nil {
			return err
		}

		legacyClient = &LegacyClient{}
		if plugin, ok := raw.(datasourceV1.DatasourcePlugin); ok {
			legacyClient.DatasourcePlugin = plugin
		}

		if plugin, ok := raw.(rendererV1.RendererPlugin); ok {
			legacyClient.RendererPlugin = plugin
		}
	}

	if legacyClient == nil && client == nil {
		return errors.New("no compatible plugin implementation found")
	}

	if legacyClient != nil && p.startFns.OnLegacyStart != nil {
		if err := p.startFns.OnLegacyStart(p.id, legacyClient, p.logger); err != nil {
			return err
		}
	}

	if client != nil && p.startFns.OnStart != nil {
		if err := p.startFns.OnStart(p.id, client, p.logger); err != nil {
			return err
		}
	}

	return nil
}

func (p *BackendPlugin) stop() error {
	if p.client != nil {
		p.client.Kill()
	}
	return nil
}

// supportsDiagnostics return whether backend plugin supports diagnostics like metrics and health check.
func (p *BackendPlugin) supportsDiagnostics() bool {
	return p.diagnostics != nil
}

// CollectMetrics implements the collector.Collector interface.
func (p *BackendPlugin) CollectMetrics(ctx context.Context, ch chan<- prometheus.Metric) error {
	if p.diagnostics == nil {
		return nil
	}

	if p.client == nil || p.client.Exited() {
		return nil
	}

	res, err := p.diagnostics.CollectMetrics(ctx, &pluginv2.CollectMetricsRequest{})
	if err != nil {
		if st, ok := status.FromError(err); ok {
			if st.Code() == codes.Unimplemented {
				return nil
			}
		}

		return err
	}

	if res == nil || res.Metrics == nil || res.Metrics.Prometheus == nil {
		return nil
	}

	reader := bytes.NewReader(res.Metrics.Prometheus)
	var parser expfmt.TextParser
	families, err := parser.TextToMetricFamilies(reader)
	if err != nil {
		return errutil.Wrap("failed to parse collected metrics", err)
	}

	for _, mf := range families {
		if mf.Help == nil {
			help := fmt.Sprintf("Metric read from %s plugin", p.id)
			mf.Help = &help
		}
	}

	for _, mf := range families {
		convertMetricFamily(p.id, mf, ch, p.logger)
	}

	return nil
}

func (p *BackendPlugin) checkHealth(ctx context.Context, config *PluginConfig) (*pluginv2.CheckHealthResponse, error) {
	if p.diagnostics == nil || p.client == nil || p.client.Exited() {
		return &pluginv2.CheckHealthResponse{
			Status: pluginv2.CheckHealthResponse_UNKNOWN,
		}, nil
	}

	jsonDataBytes, err := config.JSONData.ToDB()
	if err != nil {
		return nil, err
	}

	pconfig := &pluginv2.PluginConfig{
		OrgId:                   config.OrgID,
		PluginId:                config.PluginID,
		JsonData:                jsonDataBytes,
		DecryptedSecureJsonData: config.DecryptedSecureJSONData,
		LastUpdatedMS:           config.Updated.UnixNano() / int64(time.Millisecond),
	}

	res, err := p.diagnostics.CheckHealth(ctx, &pluginv2.CheckHealthRequest{Config: pconfig})
	if err != nil {
		if st, ok := status.FromError(err); ok {
			if st.Code() == codes.Unimplemented {
				return &pluginv2.CheckHealthResponse{
					Status:  pluginv2.CheckHealthResponse_UNKNOWN,
					Message: "Health check not implemented",
				}, nil
			}
		}
		return nil, err
	}

	return res, nil
}

func (p *BackendPlugin) callResource(ctx context.Context, req CallResourceRequest) (callResourceResultStream, error) {
	p.logger.Debug("Calling resource", "path", req.Path, "method", req.Method)

	if p.resource == nil || p.client == nil || p.client.Exited() {
		return nil, errors.New("plugin not running, cannot call resource")
	}

	reqHeaders := map[string]*pluginv2.StringList{}
	for k, v := range req.Headers {
		reqHeaders[k] = &pluginv2.StringList{Values: v}
	}

	jsonDataBytes, err := req.Config.JSONData.ToDB()
	if err != nil {
		return nil, err
	}

	protoReq := &pluginv2.CallResourceRequest{
		Config: &pluginv2.PluginConfig{
			OrgId:                   req.Config.OrgID,
			PluginId:                req.Config.PluginID,
			JsonData:                jsonDataBytes,
			DecryptedSecureJsonData: req.Config.DecryptedSecureJSONData,
			LastUpdatedMS:           req.Config.Updated.UnixNano() / int64(time.Millisecond),
		},
		Path:    req.Path,
		Method:  req.Method,
		Url:     req.URL,
		Headers: reqHeaders,
		Body:    req.Body,
	}

	if req.User != nil {
		protoReq.User = &pluginv2.User{
			Name:  req.User.Name,
			Login: req.User.Login,
			Email: req.User.Email,
			Role:  string(req.User.OrgRole),
		}
	}

	if req.Config.DataSourceConfig != nil {
		datasourceJSONData, err := req.Config.DataSourceConfig.JSONData.ToDB()
		if err != nil {
			return nil, err
		}

		protoReq.Config.DatasourceConfig = &pluginv2.DataSourceConfig{
			Id:                      req.Config.DataSourceConfig.ID,
			Name:                    req.Config.DataSourceConfig.Name,
			Url:                     req.Config.DataSourceConfig.URL,
			Database:                req.Config.DataSourceConfig.Database,
			User:                    req.Config.DataSourceConfig.User,
			BasicAuthEnabled:        req.Config.DataSourceConfig.BasicAuthEnabled,
			BasicAuthUser:           req.Config.DataSourceConfig.BasicAuthUser,
			JsonData:                datasourceJSONData,
			DecryptedSecureJsonData: req.Config.DataSourceConfig.DecryptedSecureJSONData,
			LastUpdatedMS:           req.Config.DataSourceConfig.Updated.UnixNano() / int64(time.Millisecond),
		}
	}

	protoStream, err := p.resource.CallResource(ctx, protoReq)
	if err != nil {
		if st, ok := status.FromError(err); ok {
			if st.Code() == codes.Unimplemented {
				return &singleCallResourceResult{
					result: &CallResourceResult{
						Status: http.StatusNotImplemented,
					},
				}, nil
			}
		}

		return nil, errutil.Wrap("Failed to call resource", err)
	}

	return &callResourceResultStreamImpl{
		stream: protoStream,
	}, nil
}

// convertMetricFamily converts metric family to prometheus.Metric.
// Copied from https://github.com/prometheus/node_exporter/blob/3ddc82c2d8d11eec53ed5faa8db969a1bb81f8bb/collector/textfile.go#L66-L165
func convertMetricFamily(pluginID string, metricFamily *dto.MetricFamily, ch chan<- prometheus.Metric, logger log.Logger) {
	var valType prometheus.ValueType
	var val float64

	allLabelNames := map[string]struct{}{}
	for _, metric := range metricFamily.Metric {
		labels := metric.GetLabel()
		for _, label := range labels {
			if _, ok := allLabelNames[label.GetName()]; !ok {
				allLabelNames[label.GetName()] = struct{}{}
			}
		}
	}

	for _, metric := range metricFamily.Metric {
		if metric.TimestampMs != nil {
			logger.Warn("Ignoring unsupported custom timestamp on metric", "metric", metric)
		}

		labels := metric.GetLabel()
		var names []string
		var values []string
		for _, label := range labels {
			names = append(names, label.GetName())
			values = append(values, label.GetValue())
		}
		names = append(names, "plugin_id")
		values = append(values, pluginID)

		for k := range allLabelNames {
			present := false
			for _, name := range names {
				if k == name {
					present = true
					break
				}
			}
			if !present {
				names = append(names, k)
				values = append(values, "")
			}
		}

		metricName := prometheus.BuildFQName(collector.Namespace, "", *metricFamily.Name)

		metricType := metricFamily.GetType()
		switch metricType {
		case dto.MetricType_COUNTER:
			valType = prometheus.CounterValue
			val = metric.Counter.GetValue()

		case dto.MetricType_GAUGE:
			valType = prometheus.GaugeValue
			val = metric.Gauge.GetValue()

		case dto.MetricType_UNTYPED:
			valType = prometheus.UntypedValue
			val = metric.Untyped.GetValue()

		case dto.MetricType_SUMMARY:
			quantiles := map[float64]float64{}
			for _, q := range metric.Summary.Quantile {
				quantiles[q.GetQuantile()] = q.GetValue()
			}
			ch <- prometheus.MustNewConstSummary(
				prometheus.NewDesc(
					metricName,
					metricFamily.GetHelp(),
					names, nil,
				),
				metric.Summary.GetSampleCount(),
				metric.Summary.GetSampleSum(),
				quantiles, values...,
			)
		case dto.MetricType_HISTOGRAM:
			buckets := map[float64]uint64{}
			for _, b := range metric.Histogram.Bucket {
				buckets[b.GetUpperBound()] = b.GetCumulativeCount()
			}
			ch <- prometheus.MustNewConstHistogram(
				prometheus.NewDesc(
					metricName,
					metricFamily.GetHelp(),
					names, nil,
				),
				metric.Histogram.GetSampleCount(),
				metric.Histogram.GetSampleSum(),
				buckets, values...,
			)
		default:
			logger.Error("unknown metric type", "type", metricType)
			continue
		}

		if metricType == dto.MetricType_GAUGE || metricType == dto.MetricType_COUNTER || metricType == dto.MetricType_UNTYPED {
			ch <- prometheus.MustNewConstMetric(
				prometheus.NewDesc(
					metricName,
					metricFamily.GetHelp(),
					names, nil,
				),
				valType, val, values...,
			)
		}
	}
}
<commit_msg>Datasource config was not mapped for datasource healthcheck (#22848)<commit_after>package backendplugin

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"net/http"
	"time"

	"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/expfmt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	datasourceV1 "github.com/grafana/grafana-plugin-model/go/datasource"
	rendererV1 "github.com/grafana/grafana-plugin-model/go/renderer"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/plugins/backendplugin/collector"
	"github.com/grafana/grafana/pkg/util/errutil"
	plugin "github.com/hashicorp/go-plugin"
	dto "github.com/prometheus/client_model/go"
)

// BackendPlugin a registered backend plugin.
type BackendPlugin struct {
	id             string
	executablePath string
	managed        bool
	clientFactory  func() *plugin.Client
	client         *plugin.Client
	logger         log.Logger
	startFns       PluginStartFuncs
	diagnostics    DiagnosticsPlugin
	resource       ResourcePlugin
}

func (p *BackendPlugin) start(ctx context.Context) error {
	p.client = p.clientFactory()
	rpcClient, err := p.client.Client()
	if err != nil {
		return err
	}

	var legacyClient *LegacyClient
	var client *Client

	if p.client.NegotiatedVersion() > 1 {
		rawDiagnostics, err := rpcClient.Dispense("diagnostics")
		if err != nil {
			return err
		}

		rawResource, err := rpcClient.Dispense("resource")
		if err != nil {
			return err
		}

		rawData, err := rpcClient.Dispense("data")
		if err != nil {
			return err
		}

		rawTransform, err := rpcClient.Dispense("transform")
		if err != nil {
			return err
		}

		if rawDiagnostics != nil {
			if plugin, ok := rawDiagnostics.(DiagnosticsPlugin); ok {
				p.diagnostics = plugin
			}
		}

		client = &Client{}
		if rawResource != nil {
			if plugin, ok := rawResource.(ResourcePlugin); ok {
				p.resource = plugin
				client.ResourcePlugin = plugin
			}
		}

		if rawData != nil {
			if plugin, ok := rawData.(DataPlugin); ok {
				client.DataPlugin = plugin
			}
		}

		if rawTransform != nil {
			if plugin, ok := rawTransform.(TransformPlugin); ok {
				client.TransformPlugin = plugin
			}
		}
	} else {
		raw, err := rpcClient.Dispense(p.id)
		if err != nil {
			return err
		}

		legacyClient = &LegacyClient{}
		if plugin, ok := raw.(datasourceV1.DatasourcePlugin); ok {
			legacyClient.DatasourcePlugin = plugin
		}

		if plugin, ok := raw.(rendererV1.RendererPlugin); ok {
			legacyClient.RendererPlugin = plugin
		}
	}

	if legacyClient == nil && client == nil {
		return errors.New("no compatible plugin implementation found")
	}

	if legacyClient != nil && p.startFns.OnLegacyStart != nil {
		if err := p.startFns.OnLegacyStart(p.id, legacyClient, p.logger); err != nil {
			return err
		}
	}

	if client != nil && p.startFns.OnStart != nil {
		if err := p.startFns.OnStart(p.id, client, p.logger); err != nil {
			return err
		}
	}

	return nil
}

func (p *BackendPlugin) stop() error {
	if p.client != nil {
		p.client.Kill()
	}
	return nil
}

// supportsDiagnostics return whether backend plugin supports diagnostics like metrics and health check.
func (p *BackendPlugin) supportsDiagnostics() bool {
	return p.diagnostics != nil
}

// CollectMetrics implements the collector.Collector interface.
func (p *BackendPlugin) CollectMetrics(ctx context.Context, ch chan<- prometheus.Metric) error {
	if p.diagnostics == nil {
		return nil
	}

	if p.client == nil || p.client.Exited() {
		return nil
	}

	res, err := p.diagnostics.CollectMetrics(ctx, &pluginv2.CollectMetricsRequest{})
	if err != nil {
		if st, ok := status.FromError(err); ok {
			if st.Code() == codes.Unimplemented {
				return nil
			}
		}

		return err
	}

	if res == nil || res.Metrics == nil || res.Metrics.Prometheus == nil {
		return nil
	}

	reader := bytes.NewReader(res.Metrics.Prometheus)
	var parser expfmt.TextParser
	families, err := parser.TextToMetricFamilies(reader)
	if err != nil {
		return errutil.Wrap("failed to parse collected metrics", err)
	}

	for _, mf := range families {
		if mf.Help == nil {
			help := fmt.Sprintf("Metric read from %s plugin", p.id)
			mf.Help = &help
		}
	}

	for _, mf := range families {
		convertMetricFamily(p.id, mf, ch, p.logger)
	}

	return nil
}

func (p *BackendPlugin) checkHealth(ctx context.Context, config *PluginConfig) (*pluginv2.CheckHealthResponse, error) {
	if p.diagnostics == nil || p.client == nil || p.client.Exited() {
		return &pluginv2.CheckHealthResponse{
			Status: pluginv2.CheckHealthResponse_UNKNOWN,
		}, nil
	}

	jsonDataBytes, err := config.JSONData.ToDB()
	if err != nil {
		return nil, err
	}

	pconfig := &pluginv2.PluginConfig{
		OrgId:                   config.OrgID,
		PluginId:                config.PluginID,
		JsonData:                jsonDataBytes,
		DecryptedSecureJsonData: config.DecryptedSecureJSONData,
		LastUpdatedMS:           config.Updated.UnixNano() / int64(time.Millisecond),
	}

	if config.DataSourceConfig != nil {
		datasourceJSONData, err := config.DataSourceConfig.JSONData.ToDB()
		if err != nil {
			return nil, err
		}

		pconfig.DatasourceConfig = &pluginv2.DataSourceConfig{
			Id:                      config.DataSourceConfig.ID,
			Name:                    config.DataSourceConfig.Name,
			Url:                     config.DataSourceConfig.URL,
			User:                    config.DataSourceConfig.User,
			Database:                config.DataSourceConfig.Database,
			BasicAuthEnabled:        config.DataSourceConfig.BasicAuthEnabled,
			BasicAuthUser:           config.DataSourceConfig.BasicAuthUser,
			JsonData:                datasourceJSONData,
			DecryptedSecureJsonData: config.DataSourceConfig.DecryptedSecureJSONData,
			LastUpdatedMS:           config.DataSourceConfig.Updated.Unix() / int64(time.Millisecond),
		}
	}

	res, err := p.diagnostics.CheckHealth(ctx, &pluginv2.CheckHealthRequest{Config: pconfig})
	if err != nil {
		if st, ok := status.FromError(err); ok {
			if st.Code() == codes.Unimplemented {
				return &pluginv2.CheckHealthResponse{
					Status:  pluginv2.CheckHealthResponse_UNKNOWN,
					Message: "Health check not implemented",
				}, nil
			}
		}
		return nil, err
	}

	return res, nil
}

func (p *BackendPlugin) callResource(ctx context.Context, req CallResourceRequest) (callResourceResultStream, error) {
	p.logger.Debug("Calling resource", "path", req.Path, "method", req.Method)

	if p.resource == nil || p.client == nil || p.client.Exited() {
		return nil, errors.New("plugin not running, cannot call resource")
	}

	reqHeaders := map[string]*pluginv2.StringList{}
	for k, v := range req.Headers {
		reqHeaders[k] = &pluginv2.StringList{Values: v}
	}

	jsonDataBytes, err := req.Config.JSONData.ToDB()
	if err != nil {
		return nil, err
	}

	protoReq := &pluginv2.CallResourceRequest{
		Config: &pluginv2.PluginConfig{
			OrgId:                   req.Config.OrgID,
			PluginId:                req.Config.PluginID,
			JsonData:                jsonDataBytes,
			DecryptedSecureJsonData: req.Config.DecryptedSecureJSONData,
			LastUpdatedMS:           req.Config.Updated.UnixNano() / int64(time.Millisecond),
		},
		Path:    req.Path,
		Method:  req.Method,
		Url:     req.URL,
		Headers: reqHeaders,
		Body:    req.Body,
	}

	if req.User != nil {
		protoReq.User = &pluginv2.User{
			Name:  req.User.Name,
			Login: req.User.Login,
			Email: req.User.Email,
			Role:  string(req.User.OrgRole),
		}
	}

	if req.Config.DataSourceConfig != nil {
		datasourceJSONData, err := req.Config.DataSourceConfig.JSONData.ToDB()
		if err != nil {
			return nil, err
		}

		protoReq.Config.DatasourceConfig = &pluginv2.DataSourceConfig{
			Id:                      req.Config.DataSourceConfig.ID,
			Name:                    req.Config.DataSourceConfig.Name,
			Url:                     req.Config.DataSourceConfig.URL,
			Database:                req.Config.DataSourceConfig.Database,
			User:                    req.Config.DataSourceConfig.User,
			BasicAuthEnabled:        req.Config.DataSourceConfig.BasicAuthEnabled,
			BasicAuthUser:           req.Config.DataSourceConfig.BasicAuthUser,
			JsonData:                datasourceJSONData,
			DecryptedSecureJsonData: req.Config.DataSourceConfig.DecryptedSecureJSONData,
			LastUpdatedMS:           req.Config.DataSourceConfig.Updated.UnixNano() / int64(time.Millisecond),
		}
	}

	protoStream, err := p.resource.CallResource(ctx, protoReq)
	if err != nil {
		if st, ok := status.FromError(err); ok {
			if st.Code() == codes.Unimplemented {
				return &singleCallResourceResult{
					result: &CallResourceResult{
						Status: http.StatusNotImplemented,
					},
				}, nil
			}
		}

		return nil, errutil.Wrap("Failed to call resource", err)
	}

	return &callResourceResultStreamImpl{
		stream: protoStream,
	}, nil
}

// convertMetricFamily converts metric family to prometheus.Metric.
// Copied from https://github.com/prometheus/node_exporter/blob/3ddc82c2d8d11eec53ed5faa8db969a1bb81f8bb/collector/textfile.go#L66-L165
func convertMetricFamily(pluginID string, metricFamily *dto.MetricFamily, ch chan<- prometheus.Metric, logger log.Logger) {
	var valType prometheus.ValueType
	var val float64

	allLabelNames := map[string]struct{}{}
	for _, metric := range metricFamily.Metric {
		labels := metric.GetLabel()
		for _, label := range labels {
			if _, ok := allLabelNames[label.GetName()]; !ok {
				allLabelNames[label.GetName()] = struct{}{}
			}
		}
	}

	for _, metric := range metricFamily.Metric {
		if metric.TimestampMs != nil {
			logger.Warn("Ignoring unsupported custom timestamp on metric", "metric", metric)
		}

		labels := metric.GetLabel()
		var names []string
		var values []string
		for _, label := range labels {
			names = append(names, label.GetName())
			values = append(values, label.GetValue())
		}
		names = append(names, "plugin_id")
		values = append(values, pluginID)

		for k := range allLabelNames {
			present := false
			for _, name := range names {
				if k == name {
					present = true
					break
				}
			}
			if !present {
				names = append(names, k)
				values = append(values, "")
			}
		}

		metricName := prometheus.BuildFQName(collector.Namespace, "", *metricFamily.Name)

		metricType := metricFamily.GetType()
		switch metricType {
		case dto.MetricType_COUNTER:
			valType = prometheus.CounterValue
			val = metric.Counter.GetValue()

		case dto.MetricType_GAUGE:
			valType = prometheus.GaugeValue
			val = metric.Gauge.GetValue()

		case dto.MetricType_UNTYPED:
			valType = prometheus.UntypedValue
			val = metric.Untyped.GetValue()

		case dto.MetricType_SUMMARY:
			quantiles := map[float64]float64{}
			for _, q := range metric.Summary.Quantile {
				quantiles[q.GetQuantile()] = q.GetValue()
			}
			ch <- prometheus.MustNewConstSummary(
				prometheus.NewDesc(
					metricName,
					metricFamily.GetHelp(),
					names, nil,
				),
				metric.Summary.GetSampleCount(),
				metric.Summary.GetSampleSum(),
				quantiles, values...,
			)
		case dto.MetricType_HISTOGRAM:
			buckets := map[float64]uint64{}
			for _, b := range metric.Histogram.Bucket {
				buckets[b.GetUpperBound()] = b.GetCumulativeCount()
			}
			ch <- prometheus.MustNewConstHistogram(
				prometheus.NewDesc(
					metricName,
					metricFamily.GetHelp(),
					names, nil,
				),
				metric.Histogram.GetSampleCount(),
				metric.Histogram.GetSampleSum(),
				buckets, values...,
			)
		default:
			logger.Error("unknown metric type", "type", metricType)
			continue
		}

		if metricType == dto.MetricType_GAUGE || metricType == dto.MetricType_COUNTER || metricType == dto.MetricType_UNTYPED {
			ch <- prometheus.MustNewConstMetric(
				prometheus.NewDesc(
					metricName,
					metricFamily.GetHelp(),
					names, nil,
				),
				valType, val, values...,
			)
		}
	}
}
<|endoftext|>


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

package thumbnail

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/common/util/fsutil"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/services/imageconversion"
	"io"
	"path/filepath"
)

var (
	SizeSmall = ThumbDimension{
		MaxWidth:  320,
		MaxHeight: 240,
	}

	SizeMedium = ThumbDimension{
		MaxWidth:  640,
		MaxHeight: 480,
	}

	SizeLarge = ThumbDimension{
		MaxWidth:  1024,
		MaxHeight: 768,
	}
)

func NewConversionService(logger logger.Logger, repository dataaccess.Repository, thumbnailIndex *Index) *ConversionService {

	// create a new conversion service
	conversionService := &ConversionService{
		logger:     logger,
		repository: repository,

		index:           thumbnailIndex,
		thumbnailFolder: thumbnailIndex.GetThumbnailFolder(),
	}

	// start the conversion
	conversionService.startConversion()

	return conversionService
}

type ConversionService struct {
	logger     logger.Logger
	repository dataaccess.Repository

	index           *Index
	thumbnailFolder string
}

// Start the conversion process.
func (conversion *ConversionService) startConversion() {

	// distinctive update
	conversion.repository.OnUpdate(func(route route.Route) {
		item := conversion.repository.Item(route)
		conversion.createThumbnailsForItem(item)
	})

	// full run
	go conversion.fullConversion()
}

// Process all items in the repository.
func (conversion *ConversionService) fullConversion() {
	for _, item := range conversion.repository.Items() {

		go conversion.createThumbnailsForItem(item)

	}
}

// Create thumbnail for all image files found in the supplied item.
func (conversion *ConversionService) createThumbnailsForItem(item *dataaccess.Item) {

	if item == nil {
		return
	}

	for _, file := range item.Files() {

		// create the thumbnails
		conversion.createThumbnailsForFile(file)

	}

}

// Create thumbnail for all image files found in the supplied item.
func (conversion *ConversionService) createThumbnailsForFile(file *dataaccess.File) {

	conversion.createThumbnail(file, SizeSmall)
	conversion.createThumbnail(file, SizeMedium)
	conversion.createThumbnail(file, SizeLarge)

}

// Creates a thumbnail for the supplied file with the specified dimensions.
func (conversion *ConversionService) createThumbnail(file *dataaccess.File, dimensions ThumbDimension) {

	// get the mime type
	mimeType, err := file.MimeType()
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	// check the mime type
	if !imageconversion.MimeTypeIsSupported(mimeType) {
		conversion.logger.Debug("The mime-type %q is currently not supported.", mimeType)
		return
	}

	// determine the file name
	fileExtension := imageconversion.GetFileExtensionFromMimeType(mimeType)
	filename := fmt.Sprintf("%s-%v-%v.%s", file.Id(), dimensions.MaxWidth, dimensions.MaxHeight, fileExtension)

	// assemble the full file route
	fullFileRoute, err := route.Combine(file.Parent(), file.Route())
	if err != nil {
		conversion.logger.Warn("Unable to combine routes %q and %q.", file.Parent(), file.Route())
		return
	}

	thumb := newThumb(fullFileRoute, filename, dimensions)

	// check the index
	if conversion.isInIndex(thumb) {
		conversion.logger.Debug("Thumb %q already available in the index", thumb.String())
		return
	}

	// determine the file path
	filePath := filepath.Join(conversion.thumbnailFolder, filename)

	// create the target file
	created, createError := fsutil.CreateFile(filePath)
	if !created {
		conversion.logger.Warn("Could not create thumbnail file %q. Error: %s", filePath, createError.Error())
		return
	}

	// open the target file
	target, fileError := fsutil.OpenFile(filePath)
	if fileError != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", fileError.Error())
		return
	}

	defer target.Close()

	// convert the image
	conversionError := file.Data(func(content io.ReadSeeker) error {
		return imageconversion.Resize(content, mimeType, dimensions.MaxWidth, dimensions.MaxHeight, target)
	})

	// handle errors
	if conversionError != nil {
		conversion.logger.Warn("Unable to create thumbnail for file %q. Error: %s", file, conversionError.Error())
		return
	}

	// add to index
	conversion.addToIndex(thumb)
	conversion.logger.Debug("Adding Thumb %q to index", thumb.String())
}

func (conversion *ConversionService) isInIndex(thumb Thumb) bool {

	// check if there are thumb for the route
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		return false
	}

	// check if there is a thumb with that dimensions
	if _, thumbExists := thumbs[thumb.Dimensions.String()]; thumbExists {
		// check if the file exists
		thumbnailFilePath := conversion.index.GetThumbnailFilepath(thumb)
		return fsutil.FileExists(thumbnailFilePath)

	}

	return false
}

func (conversion *ConversionService) addToIndex(thumb Thumb) {
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		thumbs = make(Thumbs)
	}

	thumbs[thumb.Dimensions.String()] = thumb
	conversion.index.SetThumbs(thumb.Route, thumbs)
}
<commit_msg>Bug fix for the thumbnail conversion: Adding the parent route is no longer necessary<commit_after>// Copyright 2014 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package thumbnail

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/common/util/fsutil"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/services/imageconversion"
	"io"
	"path/filepath"
)

var (
	SizeSmall = ThumbDimension{
		MaxWidth:  320,
		MaxHeight: 240,
	}

	SizeMedium = ThumbDimension{
		MaxWidth:  640,
		MaxHeight: 480,
	}

	SizeLarge = ThumbDimension{
		MaxWidth:  1024,
		MaxHeight: 768,
	}
)

func NewConversionService(logger logger.Logger, repository dataaccess.Repository, thumbnailIndex *Index) *ConversionService {

	// create a new conversion service
	conversionService := &ConversionService{
		logger:     logger,
		repository: repository,

		index:           thumbnailIndex,
		thumbnailFolder: thumbnailIndex.GetThumbnailFolder(),
	}

	// start the conversion
	conversionService.startConversion()

	return conversionService
}

type ConversionService struct {
	logger     logger.Logger
	repository dataaccess.Repository

	index           *Index
	thumbnailFolder string
}

// Start the conversion process.
func (conversion *ConversionService) startConversion() {

	// distinctive update
	conversion.repository.OnUpdate(func(route route.Route) {
		item := conversion.repository.Item(route)
		conversion.createThumbnailsForItem(item)
	})

	// full run
	go conversion.fullConversion()
}

// Process all items in the repository.
func (conversion *ConversionService) fullConversion() {
	for _, item := range conversion.repository.Items() {

		go conversion.createThumbnailsForItem(item)

	}
}

// Create thumbnail for all image files found in the supplied item.
func (conversion *ConversionService) createThumbnailsForItem(item *dataaccess.Item) {

	if item == nil {
		return
	}

	for _, file := range item.Files() {

		// create the thumbnails
		conversion.createThumbnailsForFile(file)

	}

}

// Create thumbnail for all image files found in the supplied item.
func (conversion *ConversionService) createThumbnailsForFile(file *dataaccess.File) {

	conversion.createThumbnail(file, SizeSmall)
	conversion.createThumbnail(file, SizeMedium)
	conversion.createThumbnail(file, SizeLarge)

}

// Creates a thumbnail for the supplied file with the specified dimensions.
func (conversion *ConversionService) createThumbnail(file *dataaccess.File, dimensions ThumbDimension) {

	// get the mime type
	mimeType, err := file.MimeType()
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	// check the mime type
	if !imageconversion.MimeTypeIsSupported(mimeType) {
		conversion.logger.Debug("The mime-type %q is currently not supported.", mimeType)
		return
	}

	// determine the file name
	fileExtension := imageconversion.GetFileExtensionFromMimeType(mimeType)
	filename := fmt.Sprintf("%s-%v-%v.%s", file.Id(), dimensions.MaxWidth, dimensions.MaxHeight, fileExtension)

	thumb := newThumb(file.Route(), filename, dimensions)

	// check the index
	if conversion.isInIndex(thumb) {
		conversion.logger.Debug("Thumb %q already available in the index", thumb.String())
		return
	}

	// determine the file path
	filePath := filepath.Join(conversion.thumbnailFolder, filename)

	// create the target file
	created, createError := fsutil.CreateFile(filePath)
	if !created {
		conversion.logger.Warn("Could not create thumbnail file %q. Error: %s", filePath, createError.Error())
		return
	}

	// open the target file
	target, fileError := fsutil.OpenFile(filePath)
	if fileError != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", fileError.Error())
		return
	}

	defer target.Close()

	// convert the image
	conversionError := file.Data(func(content io.ReadSeeker) error {
		return imageconversion.Resize(content, mimeType, dimensions.MaxWidth, dimensions.MaxHeight, target)
	})

	// handle errors
	if conversionError != nil {
		conversion.logger.Warn("Unable to create thumbnail for file %q. Error: %s", file, conversionError.Error())
		return
	}

	// add to index
	conversion.addToIndex(thumb)
	conversion.logger.Debug("Adding Thumb %q to index", thumb.String())
}

func (conversion *ConversionService) isInIndex(thumb Thumb) bool {

	// check if there are thumb for the route
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		return false
	}

	// check if there is a thumb with that dimensions
	if _, thumbExists := thumbs[thumb.Dimensions.String()]; thumbExists {
		// check if the file exists
		thumbnailFilePath := conversion.index.GetThumbnailFilepath(thumb)
		return fsutil.FileExists(thumbnailFilePath)

	}

	return false
}

func (conversion *ConversionService) addToIndex(thumb Thumb) {
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		thumbs = make(Thumbs)
	}

	thumbs[thumb.Dimensions.String()] = thumb
	conversion.index.SetThumbs(thumb.Route, thumbs)
}
<|endoftext|>


<commit_before>// +build linux
// Code in this package is heavily adapted from https://github.com/opencontainers/runc/blob/7362fa2d282feffb9b19911150e01e390a23899d/libcontainer/cgroups/systemd
// Credit goes to the runc authors.

package dbusmgr

import (
	"context"
	"errors"
	"strings"
	"sync"

	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
	dbus "github.com/godbus/dbus/v5"
)

var (
	dbusC        *systemdDbus.Conn
	dbusMu       sync.RWMutex
	dbusInited   bool
	dbusRootless bool
)

type DbusConnManager struct{}

// NewDbusConnManager initializes systemd dbus connection manager.
func NewDbusConnManager(rootless bool) *DbusConnManager {
	if dbusInited && rootless != dbusRootless {
		panic("can't have both root and rootless dbus")
	}
	dbusRootless = rootless
	return &DbusConnManager{}
}

// getConnection lazily initializes and returns systemd dbus connection.
func (d *DbusConnManager) GetConnection() (*systemdDbus.Conn, error) {
	// In the case where dbusC != nil
	// Use the read lock the first time to ensure
	// that Conn can be acquired at the same time.
	dbusMu.RLock()
	if conn := dbusC; conn != nil {
		dbusMu.RUnlock()
		return conn, nil
	}
	dbusMu.RUnlock()

	// In the case where dbusC == nil
	// Use write lock to ensure that only one
	// will be created
	dbusMu.Lock()
	defer dbusMu.Unlock()
	if conn := dbusC; conn != nil {
		return conn, nil
	}

	conn, err := d.newConnection()
	if err != nil {
		return nil, err
	}
	dbusC = conn
	return conn, nil
}

func (d *DbusConnManager) newConnection() (*systemdDbus.Conn, error) {
	if dbusRootless {
		return newUserSystemdDbus()
	}
	return systemdDbus.NewWithContext(context.TODO())
}

var errDbusConnClosed = dbus.ErrClosed.Error()

// RetryOnDisconnect calls op, and if the error it returns is about closed dbus
// connection, the connection is re-established and the op is retried. This helps
// with the situation when dbus is restarted and we have a stale connection.
func (d *DbusConnManager) RetryOnDisconnect(op func(*systemdDbus.Conn) error) error {
	for {
		conn, err := d.GetConnection()
		if err != nil {
			return err
		}
		err = op(conn)
		if !isDbusError(err, errDbusConnClosed) {
			return err
		}
		d.resetConnection(conn)
	}
}

// resetConnection resets the connection to its initial state
// (so it can be reconnected if necessary).
func (d *DbusConnManager) resetConnection(conn *systemdDbus.Conn) {
	dbusMu.Lock()
	defer dbusMu.Unlock()
	if dbusC != nil && dbusC == conn {
		dbusC.Close()
		dbusC = nil
	}
}

// isDbusError returns true if the error is a specific dbus error.
func isDbusError(err error, name string) bool {
	if err != nil {
		var derr dbus.Error
		if errors.As(err, &derr) {
			return strings.Contains(derr.Name, name)
		}
	}
	return false
}
<commit_msg>dbusmgr: protect against races in NewDbusConnManager<commit_after>// +build linux
// Code in this package is heavily adapted from https://github.com/opencontainers/runc/blob/7362fa2d282feffb9b19911150e01e390a23899d/libcontainer/cgroups/systemd
// Credit goes to the runc authors.

package dbusmgr

import (
	"context"
	"errors"
	"strings"
	"sync"

	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
	dbus "github.com/godbus/dbus/v5"
)

var (
	dbusC        *systemdDbus.Conn
	dbusMu       sync.RWMutex
	dbusInited   bool
	dbusRootless bool
)

type DbusConnManager struct{}

// NewDbusConnManager initializes systemd dbus connection manager.
func NewDbusConnManager(rootless bool) *DbusConnManager {
	dbusMu.Lock()
	defer dbusMu.Unlock()
	if dbusInited && rootless != dbusRootless {
		panic("can't have both root and rootless dbus")
	}
	dbusRootless = rootless
	dbusInited = true
	return &DbusConnManager{}
}

// getConnection lazily initializes and returns systemd dbus connection.
func (d *DbusConnManager) GetConnection() (*systemdDbus.Conn, error) {
	// In the case where dbusC != nil
	// Use the read lock the first time to ensure
	// that Conn can be acquired at the same time.
	dbusMu.RLock()
	if conn := dbusC; conn != nil {
		dbusMu.RUnlock()
		return conn, nil
	}
	dbusMu.RUnlock()

	// In the case where dbusC == nil
	// Use write lock to ensure that only one
	// will be created
	dbusMu.Lock()
	defer dbusMu.Unlock()
	if conn := dbusC; conn != nil {
		return conn, nil
	}

	conn, err := d.newConnection()
	if err != nil {
		return nil, err
	}
	dbusC = conn
	return conn, nil
}

func (d *DbusConnManager) newConnection() (*systemdDbus.Conn, error) {
	if dbusRootless {
		return newUserSystemdDbus()
	}
	return systemdDbus.NewWithContext(context.TODO())
}

var errDbusConnClosed = dbus.ErrClosed.Error()

// RetryOnDisconnect calls op, and if the error it returns is about closed dbus
// connection, the connection is re-established and the op is retried. This helps
// with the situation when dbus is restarted and we have a stale connection.
func (d *DbusConnManager) RetryOnDisconnect(op func(*systemdDbus.Conn) error) error {
	for {
		conn, err := d.GetConnection()
		if err != nil {
			return err
		}
		err = op(conn)
		if !isDbusError(err, errDbusConnClosed) {
			return err
		}
		d.resetConnection(conn)
	}
}

// resetConnection resets the connection to its initial state
// (so it can be reconnected if necessary).
func (d *DbusConnManager) resetConnection(conn *systemdDbus.Conn) {
	dbusMu.Lock()
	defer dbusMu.Unlock()
	if dbusC != nil && dbusC == conn {
		dbusC.Close()
		dbusC = nil
	}
}

// isDbusError returns true if the error is a specific dbus error.
func isDbusError(err error, name string) bool {
	if err != nil {
		var derr dbus.Error
		if errors.As(err, &derr) {
			return strings.Contains(derr.Name, name)
		}
	}
	return false
}
<|endoftext|>


<commit_before>package homekit

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/brutella/hap"
	"github.com/brutella/hap/accessory"
	"github.com/cswank/quimby/internal/config"
	"github.com/cswank/quimby/internal/schema"
	"github.com/kelseyhightower/envconfig"
)

const (
	thermostatOff thermostatState = 0
	heat          thermostatState = 1
	cool          thermostatState = 2
	auto          thermostatState = 3

	on  state = true
	off state = false
)

type (
	state           bool
	thermostatState uint8

	cfg struct {
		Store          string   `envconfig:"STORE" required:"true"`
		Pin            string   `envconfig:"PIN" required:"true"`
		Port           string   `envconfig:"PORT" required:"true"`
		FurnaceHost    string   `envconfig:"FURNACE_HOST"`
		Thermostat     string   `envconfig:"THERMOSTAT" default:"home furnace"`
		Thermometer    string   `envconfig:"THERMOMETER" default:"home temperature"`
		SprinklerHost  string   `envconfig:"SPRINKLER_HOST"`
		SprinklerZones []string `envconfig:"SPRINKLER_ZONES"`
	}

	update func(schema.Message)

	Homekit struct {
		cfg     cfg
		updates map[string]update
	}
)

func (h state) String() string {
	if h {
		return "turn on"
	}

	return "turn off"
}

func (h thermostatState) String() string {
	switch h {
	case 1:
		return "heat home"
	case 2:
		return "cool home"
	default:
		return "turn off home furnace"
	}
}

func New() (*Homekit, error) {
	var c cfg
	err := envconfig.Process("HOMEKIT", &c)
	if err != nil {
		return nil, err
	}

	f := func(msg schema.Message) {
		log.Println("not implemented")
	}

	ss := make(map[string]update, len(c.SprinklerZones))
	for _, z := range c.SprinklerZones {
		ss[z] = f
	}

	h := &Homekit{
		cfg:     c,
		updates: map[string]update{},
	}

	err = h.init()
	if err != nil {
		return nil, err
	}

	go h.start()

	return h, nil
}

func (h *Homekit) Update(msg schema.Message) {
	f, ok := h.updates[msg.Sender]
	if ok {
		f(msg)
	}
}

func (h *Homekit) start() {
	bridge := accessory.NewBridge(accessory.Info{Name: "Quimby"})

	var ac []*accessory.A
	if h.cfg.FurnaceHost != "" {
		ac = append(ac, h.furnace())
	}

	if h.cfg.SprinklerHost != "" {
		ac = append(ac, h.sprinklers()...)
	}

	ac = append(ac, h.stereo())

	st := hap.NewFsStore(h.cfg.Store)
	tr, err := hap.NewServer(
		st,
		bridge.A,
		ac...,
	)

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

	tr.ListenAndServe(context.Background())
}

func (h *Homekit) stereo() *accessory.A {
	s := accessory.NewSwitch(accessory.Info{Name: "stereo"})

	s.Switch.On.OnValueRemoteUpdate(func(b bool) {
		h.sendOnOffCommand(s.A.Info.Name.String.Value(), state(b))
	})

	h.updates["stereo"] = func(msg schema.Message) {
		b, ok := msg.Value.Value.(bool)
		if ok {
			s.Switch.On.SetValue(b)
		}
	}

	return s.A
}

func (h *Homekit) sprinklers() []*accessory.A {
	out := make([]*accessory.A, len(h.cfg.SprinklerZones))
	m := make(map[string]accessory.Switch)

	for i, z := range h.cfg.SprinklerZones {
		s := accessory.NewSwitch(accessory.Info{Name: z})
		m[z] = *s

		s.Switch.On.OnValueRemoteUpdate(func(b bool) {
			h.sendOnOffCommand(s.A.Info.Name.String.Value(), state(b))
		})

		h.updates[z] = func(msg schema.Message) {
			sw, ok := m[msg.Sender]
			b, ok := msg.Value.Value.(bool)
			if ok {
				sw.Switch.On.SetValue(b)
			}
		}

		out[i] = s.A
	}

	return out
}

func (h *Homekit) sendOnOffCommand(name string, val state) {
	msg := schema.Message{Type: "command", Sender: "homekit", Body: fmt.Sprintf("%s %s", val, name)}
	h.sendCommand(msg, h.cfg.SprinklerHost)
}

func (h *Homekit) furnace() *accessory.A {
	furnace := accessory.NewThermostat(accessory.Info{Name: "Thermostat", SerialNumber: "06", Manufacturer: "16", Model: "26", Firmware: "1"})
	state := thermostatOff

	furnace.Thermostat.TargetHeatingCoolingState.OnValueRemoteUpdate(func(i int) {
		state = thermostatState(i) //TODO: figure out how to handle 'auto' state
		c := furnace.Thermostat.TargetTemperature.Float.Value()
		h.updateFurnace(c, state)
	})

	furnace.Thermostat.TargetTemperature.OnValueRemoteUpdate(func(c float64) {
		h.updateFurnace(c, state)
	})

	var i int
	h.updates[h.cfg.Thermometer] = func(msg schema.Message) {
		f, ok := msg.Value.Value.(float64)
		if ok {
			if i == 0 {
				c := (f - 32.0) / 1.8
				furnace.Thermostat.CurrentTemperature.SetValue(c)
			}
			i++
			if i == 10 {
				i = 0
			}
		}
	}

	h.updates[h.cfg.Thermostat] = func(msg schema.Message) {
		if msg.TargetValue == nil {
			return
		}

		val := *msg.TargetValue
		if strings.Index(val.Cmd, "heat home") == 0 {
			state = heat
		} else if strings.Index(val.Cmd, "cool home") == 0 {
			state = cool
		} else {
			state = thermostatOff
		}

		furnace.Thermostat.TargetHeatingCoolingState.SetValue(int(state))
		furnace.Thermostat.CurrentHeatingCoolingState.SetValue(int(state))
		if state != thermostatOff {
			f, ok := val.Value.(float64)
			if ok {
				c := (f - 32.0) / 1.8
				furnace.Thermostat.TargetTemperature.SetValue(c)
			}
		}
	}

	return furnace.A
}

func (h *Homekit) updateFurnace(c float64, state thermostatState) {
	f := float64(c*1.8 + 32.0)
	msg := schema.Message{Type: "command", Sender: "homekit"}

	switch state {
	case heat, cool:
		msg.Body = fmt.Sprintf("%s to %f F", state, f)
	case thermostatOff:
		msg.Body = "turn off furnace"
	}

	h.sendCommand(msg, h.cfg.FurnaceHost)
}

func (h *Homekit) sendCommand(msg schema.Message, host string) {
	var buf bytes.Buffer
	json.NewEncoder(&buf).Encode(msg)
	resp, err := http.Post(fmt.Sprintf("%s/gadgets", host), "application/json", &buf)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		log.Printf("unable to update %s: %d", host, resp.StatusCode)
	}
}

func (h *Homekit) init() error {
	if h.cfg.FurnaceHost != "" {
		err := h.register(h.cfg.FurnaceHost)
		if err != nil {
			return err
		}
	}

	if h.cfg.SprinklerHost != "" {
		err := h.register(h.cfg.SprinklerHost)
		if err != nil {
			return err
		}
	}
	return nil
}

func (h *Homekit) register(addr string) error {
	cfg := config.Get()

	m := map[string]string{"address": cfg.InternalAddress, "token": "n/a"}

	buf := &bytes.Buffer{}
	err := json.NewEncoder(buf).Encode(&m)
	if err != nil {
		return err
	}

	r, err := http.Post(fmt.Sprintf("%s/clients", addr), "application/json", buf)
	if err != nil {
		return err
	}

	r.Body.Close()
	if r.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected response from %s: %d", addr, r.StatusCode)
	}

	return nil
}
<commit_msg>set homekit pin and port<commit_after>package homekit

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/brutella/hap"
	"github.com/brutella/hap/accessory"
	"github.com/cswank/quimby/internal/config"
	"github.com/cswank/quimby/internal/schema"
	"github.com/kelseyhightower/envconfig"
)

const (
	thermostatOff thermostatState = 0
	heat          thermostatState = 1
	cool          thermostatState = 2
	auto          thermostatState = 3

	on  state = true
	off state = false
)

type (
	state           bool
	thermostatState uint8

	cfg struct {
		Store          string   `envconfig:"STORE" required:"true"`
		Pin            string   `envconfig:"PIN" required:"true"`
		Port           string   `envconfig:"PORT" required:"true"`
		FurnaceHost    string   `envconfig:"FURNACE_HOST"`
		Thermostat     string   `envconfig:"THERMOSTAT" default:"home furnace"`
		Thermometer    string   `envconfig:"THERMOMETER" default:"home temperature"`
		SprinklerHost  string   `envconfig:"SPRINKLER_HOST"`
		SprinklerZones []string `envconfig:"SPRINKLER_ZONES"`
	}

	update func(schema.Message)

	Homekit struct {
		cfg     cfg
		updates map[string]update
	}
)

func (h state) String() string {
	if h {
		return "turn on"
	}

	return "turn off"
}

func (h thermostatState) String() string {
	switch h {
	case 1:
		return "heat home"
	case 2:
		return "cool home"
	default:
		return "turn off home furnace"
	}
}

func New() (*Homekit, error) {
	var c cfg
	err := envconfig.Process("HOMEKIT", &c)
	if err != nil {
		return nil, err
	}

	f := func(msg schema.Message) {
		log.Println("not implemented")
	}

	ss := make(map[string]update, len(c.SprinklerZones))
	for _, z := range c.SprinklerZones {
		ss[z] = f
	}

	h := &Homekit{
		cfg:     c,
		updates: map[string]update{},
	}

	err = h.init()
	if err != nil {
		return nil, err
	}

	go h.start()

	return h, nil
}

func (h *Homekit) Update(msg schema.Message) {
	f, ok := h.updates[msg.Sender]
	if ok {
		f(msg)
	}
}

func (h *Homekit) start() {
	bridge := accessory.NewBridge(accessory.Info{Name: "Quimby"})

	var ac []*accessory.A
	if h.cfg.FurnaceHost != "" {
		ac = append(ac, h.furnace())
	}

	if h.cfg.SprinklerHost != "" {
		ac = append(ac, h.sprinklers()...)
	}

	//ac = append(ac, h.stereo())

	st := hap.NewFsStore(h.cfg.Store)
	srv, err := hap.NewServer(
		st,
		bridge.A,
		ac...,
	)

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

	srv.Pin = h.cfg.Pin
	srv.Addr = fmt.Sprintf("0.0.0.0:%s", h.cfg.Port)
	srv.ListenAndServe(context.Background())
}

func (h *Homekit) stereo() *accessory.A {
	s := accessory.NewSwitch(accessory.Info{Name: "stereo"})

	s.Switch.On.OnValueRemoteUpdate(func(b bool) {
		h.sendOnOffCommand(s.A.Info.Name.String.Value(), state(b))
	})

	h.updates["stereo"] = func(msg schema.Message) {
		b, ok := msg.Value.Value.(bool)
		if ok {
			s.Switch.On.SetValue(b)
		}
	}

	return s.A
}

func (h *Homekit) sprinklers() []*accessory.A {
	out := make([]*accessory.A, len(h.cfg.SprinklerZones))
	m := make(map[string]accessory.Switch)

	for i, z := range h.cfg.SprinklerZones {
		s := accessory.NewSwitch(accessory.Info{Name: z})
		m[z] = *s

		s.Switch.On.OnValueRemoteUpdate(func(b bool) {
			h.sendOnOffCommand(s.A.Info.Name.String.Value(), state(b))
		})

		h.updates[z] = func(msg schema.Message) {
			sw, ok := m[msg.Sender]
			b, ok := msg.Value.Value.(bool)
			if ok {
				sw.Switch.On.SetValue(b)
			}
		}

		out[i] = s.A
	}

	return out
}

func (h *Homekit) sendOnOffCommand(name string, val state) {
	msg := schema.Message{Type: "command", Sender: "homekit", Body: fmt.Sprintf("%s %s", val, name)}
	h.sendCommand(msg, h.cfg.SprinklerHost)
}

func (h *Homekit) furnace() *accessory.A {
	furnace := accessory.NewThermostat(accessory.Info{Name: "Thermostat", SerialNumber: "06", Manufacturer: "16", Model: "26", Firmware: "1"})
	state := thermostatOff

	furnace.Thermostat.TargetHeatingCoolingState.OnValueRemoteUpdate(func(i int) {
		state = thermostatState(i) //TODO: figure out how to handle 'auto' state
		c := furnace.Thermostat.TargetTemperature.Float.Value()
		h.updateFurnace(c, state)
	})

	furnace.Thermostat.TargetTemperature.OnValueRemoteUpdate(func(c float64) {
		h.updateFurnace(c, state)
	})

	var i int
	h.updates[h.cfg.Thermometer] = func(msg schema.Message) {
		f, ok := msg.Value.Value.(float64)
		if ok {
			if i == 0 {
				c := (f - 32.0) / 1.8
				furnace.Thermostat.CurrentTemperature.SetValue(c)
			}
			i++
			if i == 10 {
				i = 0
			}
		}
	}

	h.updates[h.cfg.Thermostat] = func(msg schema.Message) {
		if msg.TargetValue == nil {
			return
		}

		val := *msg.TargetValue
		if strings.Index(val.Cmd, "heat home") == 0 {
			state = heat
		} else if strings.Index(val.Cmd, "cool home") == 0 {
			state = cool
		} else {
			state = thermostatOff
		}

		furnace.Thermostat.TargetHeatingCoolingState.SetValue(int(state))
		furnace.Thermostat.CurrentHeatingCoolingState.SetValue(int(state))
		if state != thermostatOff {
			f, ok := val.Value.(float64)
			if ok {
				c := (f - 32.0) / 1.8
				furnace.Thermostat.TargetTemperature.SetValue(c)
			}
		}
	}

	return furnace.A
}

func (h *Homekit) updateFurnace(c float64, state thermostatState) {
	f := float64(c*1.8 + 32.0)
	msg := schema.Message{Type: "command", Sender: "homekit"}

	switch state {
	case heat, cool:
		msg.Body = fmt.Sprintf("%s to %f F", state, f)
	case thermostatOff:
		msg.Body = "turn off furnace"
	}

	h.sendCommand(msg, h.cfg.FurnaceHost)
}

func (h *Homekit) sendCommand(msg schema.Message, host string) {
	var buf bytes.Buffer
	json.NewEncoder(&buf).Encode(msg)
	resp, err := http.Post(fmt.Sprintf("%s/gadgets", host), "application/json", &buf)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		log.Printf("unable to update %s: %d", host, resp.StatusCode)
	}
}

func (h *Homekit) init() error {
	if h.cfg.FurnaceHost != "" {
		err := h.register(h.cfg.FurnaceHost)
		if err != nil {
			return err
		}
	}

	if h.cfg.SprinklerHost != "" {
		err := h.register(h.cfg.SprinklerHost)
		if err != nil {
			return err
		}
	}
	return nil
}

func (h *Homekit) register(addr string) error {
	cfg := config.Get()

	m := map[string]string{"address": cfg.InternalAddress, "token": "n/a"}

	buf := &bytes.Buffer{}
	err := json.NewEncoder(buf).Encode(&m)
	if err != nil {
		return err
	}

	r, err := http.Post(fmt.Sprintf("%s/clients", addr), "application/json", buf)
	if err != nil {
		return err
	}

	r.Body.Close()
	if r.StatusCode != http.StatusOK {
		return fmt.Errorf("unexpected response from %s: %d", addr, r.StatusCode)
	}

	return nil
}
<|endoftext|>