<commit_before>// +build linux

package immortal

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/immortal/xtime"
)

// ScanDir struct
type ScanDir struct {
	scandir       string
	sdir          string
	services      map[string]string
	timeMultipler time.Duration
}

// NewScanDir returns ScanDir struct
func NewScanDir(path string) (*ScanDir, error) {
	if info, err := os.Stat(path); err != nil {
		return nil, fmt.Errorf("%q no such file or directory", path)
	} else if !info.IsDir() {
		return nil, fmt.Errorf("%q is not a directory", path)
	}

	dir, err := filepath.EvalSymlinks(path)
	if err != nil {
		return nil, err
	}

	dir, err = filepath.Abs(dir)
	if err != nil {
		return nil, err
	}

	d, err := os.Open(dir)
	if err != nil {
		if os.IsPermission(err) {
			return nil, os.ErrPermission
		}
		return nil, err
	}
	defer d.Close()

	return &ScanDir{
		scandir:       dir,
		sdir:          GetSdir(),
		services:      map[string]string{},
		timeMultipler: 5,
	}, nil
}

// Start scans directory every 5 seconds
func (s *ScanDir) Start(ctl Control) {
	log.Printf("immortal scandir: %s", s.scandir)
	s.Scaner(ctl)
	ticker := time.NewTicker(time.Second * s.timeMultipler)
	for {
		select {
		case <-ticker.C:
			s.Scaner(ctl)
		}
	}
}

// Scaner searches for run.yml if file changes it will reload(stop-start)
func (s *ScanDir) Scaner(ctl Control) {
	// var services used to keep track of what services should be removed if they don't
	// exist any more
	var services []string

	find := func(path string, f os.FileInfo, err error) error {
		var (
			stop, start bool
			md5, name   string
		)
		if err != nil {
			return err
		}
		// only use .yml files
		if strings.HasSuffix(f.Name(), ".yml") {
			name = strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
			md5, err = md5sum(path)
			if err != nil {
				return err
			}
			// add service to services map or reload if file has been changed
			services = append(services, name)
			if hash, ok := s.services[name]; !ok {
				s.services[name] = md5
				start = true
			} else if hash != md5 {
				// update to new hash
				s.services[name] = md5
				stop = true
			}
			// check if file hasn't been changed since last tick (5 seconds)
			refresh := (time.Now().Unix() - xtime.Get(f).Ctime().Unix()) <= int64(s.timeMultipler)
			if refresh || start {
				if stop {
					// restart = term + start
					log.Printf("Restarting: %s\n", name)
					ctl.SendSignal(filepath.Join(s.sdir, name, "immortal.sock"), "halt")
				}
				log.Printf("Starting: %s\n", name)
				// try to start before via socket
				if _, err := ctl.SendSignal(filepath.Join(s.sdir, name, "immortal.sock"), "start"); err != nil {
					if out, err := ctl.Run(fmt.Sprintf("immortal -c %s -ctl %s", path, name)); err != nil {
						// keep retrying
						delete(s.services, name)
						log.Println(err)
					} else {
						log.Printf("%s\n", out)
					}
				}
			}
		}
		return nil
	}

	// find for .yml files
	err := filepath.Walk(s.scandir, find)
	if err != nil && !os.IsPermission(err) {
		log.Println(err)
	}

	// halts services that don't exist anymore
	for service := range s.services {
		if !inSlice(services, service) {
			delete(s.services, service)
			ctl.SendSignal(filepath.Join(s.sdir, service, "immortal.sock"), "halt")
			log.Printf("Exiting: %s\n", service)
		}
	}
}
<commit_msg>check for lock in sdir or start<commit_after>// +build linux

package immortal

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/immortal/xtime"
)

// ScanDir struct
type ScanDir struct {
	scandir       string
	sdir          string
	services      map[string]string
	timeMultipler time.Duration
}

// NewScanDir returns ScanDir struct
func NewScanDir(path string) (*ScanDir, error) {
	if info, err := os.Stat(path); err != nil {
		return nil, fmt.Errorf("%q no such file or directory", path)
	} else if !info.IsDir() {
		return nil, fmt.Errorf("%q is not a directory", path)
	}

	dir, err := filepath.EvalSymlinks(path)
	if err != nil {
		return nil, err
	}

	dir, err = filepath.Abs(dir)
	if err != nil {
		return nil, err
	}

	d, err := os.Open(dir)
	if err != nil {
		if os.IsPermission(err) {
			return nil, os.ErrPermission
		}
		return nil, err
	}
	defer d.Close()

	return &ScanDir{
		scandir:       dir,
		sdir:          GetSdir(),
		services:      map[string]string{},
		timeMultipler: 5,
	}, nil
}

// Start scans directory every 5 seconds
func (s *ScanDir) Start(ctl Control) {
	log.Printf("immortal scandir: %s", s.scandir)
	s.Scaner(ctl)
	ticker := time.NewTicker(time.Second * s.timeMultipler)
	for {
		select {
		case <-ticker.C:
			s.Scaner(ctl)
		}
	}
}

// Scaner searches for run.yml if file changes it will reload(stop-start)
func (s *ScanDir) Scaner(ctl Control) {
	// var services used to keep track of what services should be removed if they don't
	// exist any more
	var services []string

	find := func(path string, f os.FileInfo, err error) error {
		var (
			stop, start bool
			md5, name   string
		)
		if err != nil {
			return err
		}
		// only use .yml files
		if strings.HasSuffix(f.Name(), ".yml") {
			name = strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
			md5, err = md5sum(path)
			if err != nil {
				return err
			}
			// add service to services map or reload if file has been changed
			services = append(services, name)
			if hash, ok := s.services[name]; !ok || !isFile(filepath.Join(s.sdir, name, "lock")) {
				s.services[name] = md5
				start = true
			} else if hash != md5 {
				// update to new hash
				s.services[name] = md5
				stop = true
			}
			// check if file hasn't been changed since last tick (5 seconds)
			refresh := (time.Now().Unix() - xtime.Get(f).Ctime().Unix()) <= int64(s.timeMultipler)
			if refresh || start {
				if stop {
					// restart = term + start
					log.Printf("Restarting: %s\n", name)
					ctl.SendSignal(filepath.Join(s.sdir, name, "immortal.sock"), "halt")
				}
				log.Printf("Starting: %s\n", name)
				// try to start before via socket
				if _, err := ctl.SendSignal(filepath.Join(s.sdir, name, "immortal.sock"), "start"); err != nil {
					if out, err := ctl.Run(fmt.Sprintf("immortal -c %s -ctl %s", path, name)); err != nil {
						// keep retrying
						delete(s.services, name)
						log.Println(err)
					} else {
						log.Printf("%s\n", out)
					}
				}
			}
		}
		return nil
	}

	// find for .yml files
	err := filepath.Walk(s.scandir, find)
	if err != nil && !os.IsPermission(err) {
		log.Println(err)
	}

	// halts services that don't exist anymore
	for service := range s.services {
		if !inSlice(services, service) {
			delete(s.services, service)
			ctl.SendSignal(filepath.Join(s.sdir, service, "immortal.sock"), "halt")
			log.Printf("Exiting: %s\n", service)
		}
	}
}
<|endoftext|>


<commit_before>package scenario_test

import "testing"
import "github.com/32bitkid/scenario"

func callbackShouldExecute(s *scenario.S, method func(interface{}) *scenario.S) {
	executed := false
	fn := func() { executed = true }

	method(fn)

	if !executed {
		s.Fatal("Callback was not executed")
	}

}

func TestWhen(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.When)
}

func TestThen(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.Then)
}

func TestGiven(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.Given)
}

func TestAnd(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.And)
}

func TestStepsCanGetTheCurrentScenario(t *testing.T) {
	currentScenario := scenario.Start(t)

	fn := func(injectedScenario *scenario.S) {
		if injectedScenario != currentScenario {
			t.Fatal("Didn't get the expected scenario")
		}
	}

	currentScenario.Given(fn)
}

func TestStepsCanGetOtherDependencies(t *testing.T) {
	type Context struct{}
	ctx := &Context{}

	s := scenario.Start(t)
	s.With(ctx)
	s.Then(func(injectedContext *Context) {
		if ctx != injectedContext {
			t.Fatal("Didn't get the expected dependency")
		}
	})
}

func TestExecutionOrder(t *testing.T) {

	expected := []string{"Given", "AndGiven", "When", "AndWhen", "Then", "AndThen"}
	var actual []string

	inject := func(s string) func() {
		return func() {
			actual = append(actual, s)
		}
	}

	s := scenario.Start(t)
	s.Given(inject("Given"))
	s.And(inject("AndGiven"))
	s.When(inject("When"))
	s.And(inject("AndWhen"))
	s.Then(inject("Then"))
	s.And(inject("AndThen"))

	if len(expected) != len(actual) {
		t.Fatal("Expected %d invocations, but got %d instead", len(expected), len(actual))
	}

	for i, expectedValue := range expected {
		if actual[i] != expectedValue {
			t.Fatal("Expected \"%s\", but got \"%s\" instead", expectedValue, actual[i])
		}
	}
}

func TestReturnValueOfStepsShouldGetPutInResolver(t *testing.T) {
	foo := &struct{ string }{"foo"}
	s := scenario.Start(t)
	s.Given(func() *struct{ string } { return foo })
	s.Then(func(injectedfoo *struct{ string }) {
		if injectedfoo != foo {
			t.Fatal()
		}
	})
}
<commit_msg>Adding tests for assignable types<commit_after>package scenario_test

import "testing"
import "github.com/32bitkid/scenario"

func callbackShouldExecute(s *scenario.S, method func(interface{}) *scenario.S) {
	executed := false
	fn := func() { executed = true }

	method(fn)

	if !executed {
		s.Fatal("Callback was not executed")
	}

}

func TestWhen(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.When)
}

func TestThen(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.Then)
}

func TestGiven(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.Given)
}

func TestAnd(t *testing.T) {
	s := scenario.Start(t)
	callbackShouldExecute(s, s.And)
}

func TestStepsCanGetTheCurrentScenario(t *testing.T) {
	currentScenario := scenario.Start(t)

	fn := func(injectedScenario *scenario.S) {
		if injectedScenario != currentScenario {
			t.Fatal("Didn't get the expected scenario")
		}
	}

	currentScenario.Given(fn)
}

func TestStepsCanGetOtherDependencies(t *testing.T) {
	type Context struct{}
	ctx := &Context{}

	s := scenario.Start(t)
	s.With(ctx)
	s.Then(func(injectedContext *Context) {
		if ctx != injectedContext {
			t.Fatal("Didn't get the expected dependency")
		}
	})
}

func TestExecutionOrder(t *testing.T) {

	expected := []string{"Given", "AndGiven", "When", "AndWhen", "Then", "AndThen"}
	var actual []string

	inject := func(s string) func() {
		return func() {
			actual = append(actual, s)
		}
	}

	s := scenario.Start(t)
	s.Given(inject("Given"))
	s.And(inject("AndGiven"))
	s.When(inject("When"))
	s.And(inject("AndWhen"))
	s.Then(inject("Then"))
	s.And(inject("AndThen"))

	if len(expected) != len(actual) {
		t.Fatal("Expected %d invocations, but got %d instead", len(expected), len(actual))
	}

	for i, expectedValue := range expected {
		if actual[i] != expectedValue {
			t.Fatal("Expected \"%s\", but got \"%s\" instead", expectedValue, actual[i])
		}
	}
}

func TestReturnValueOfStepsShouldGetPutInResolver(t *testing.T) {
	foo := &struct{ string }{"foo"}
	s := scenario.Start(t)
	s.Given(func() *struct{ string } { return foo })
	s.Then(func(injectedfoo *struct{ string }) {
		if injectedfoo != foo {
			t.Fatal()
		}
	})
}

  type foo interface { bar() }
  type baz struct {}
  func (b baz) bar() {
  }

func TestCompatableTypesFromResolver(t *testing.T) {

  b := &baz{}
  s := scenario.Start(t)
  s.Given(func() *baz { return b })
  s.Then(func(f foo) {
    if(f != b) {
      t.Fatal("Asked for a foo, but didn't get baz")
    }
  })
}<|endoftext|>


<commit_before>// Monte Carlo simulation of VO2 system
package percolation

import (
	"os"
	"math"
	"fmt"
)

const MonteCarloValidateError = "Monte Carlo input parameters are invalid"

type MonteCarlo struct {
	// Minimum value of random flip acceptance probability (must be > 0).
	etaMinimum float64
	// How many total steps should be taken in the simulation?
	totalSteps int
	// Number of steps to take between snapshots of the grid.
	// If recordInterval is <= 0, only snapshot the final grid.
	recordInterval int
}

// Build a MonteCarlo from the JSON file at filePath.
func MonteCarloFromFile(filePath string) (*MonteCarlo, os.Error) {
	mc := new(MonteCarlo)
	err := CopyFromFile(filePath, mc)
	if err != nil {
		return nil, err
	}
	if !mc.validate() {
		return nil, fmt.Errorf(MonteCarloValidateError)
	}
	return mc, nil
}

// Build a MonteCarlo from the given JSON string.
func MonteCarloFromString(jsonData string) (*MonteCarlo, os.Error) {
	mc := new(MonteCarlo)
	err := CopyFromString(jsonData, mc)
	if err != nil {
		return nil, err
	}
	if !mc.validate() {
		return nil, fmt.Errorf(MonteCarloValidateError)
	}
	return mc, nil
}

// Do the fields of mc have acceptable values?
func (mc *MonteCarlo) validate() bool {
	return mc.etaMinimum > 0 && mc.totalSteps > 0
}

// Make a random perturbation on the Grid g.  If this perturbation leads to a
// negative energy change, accept it.  If it leads to a positive energy change,
// accept it with a random probability.  Return true if and only if the
// perturbation is accepted.
func (mc *MonteCarlo) Step(e *Energetics, g *Grid) bool {
	// choose a random site
	xf, yf := RandomIntPair(g.Lx(), g.Ly())
	// calculate the energy change due to flipping (xf, yf)
	energyChange := e.SiteFlipEnergy(g, xf, yf)
	// going to lower energy: accept it
	if energyChange < 0 {
		g.Toggle(xf, yf)
		return true
	}
	// gaining energy: accept if eta + etaMinimum <= e^(-beta*energyChange)
	log_eta := math.Log(RandomFloat() + mc.etaMinimum)
	acceptFactor := e.LogBoltzmann(energyChange)
	if log_eta <= acceptFactor {
		g.Toggle(xf, yf)
		return true
	}
	return false
}

// Run a simulation, starting from a random grid and taking steps equal to
// mc.totalSteps.  Return a slice containg each recorded grid.
// May also want to return a slice of the times when each grid was recorded.
func (mc *MonteCarlo) Simulate(e *Energetics) []*Grid {

}
<commit_msg>d'oh! unbroke build<commit_after>// Monte Carlo simulation of VO2 system
package percolation

import (
	"os"
	"math"
	"fmt"
)

const MonteCarloValidateError = "Monte Carlo input parameters are invalid"

type MonteCarlo struct {
	// Minimum value of random flip acceptance probability (must be > 0).
	etaMinimum float64
	// How many total steps should be taken in the simulation?
	totalSteps int
	// Number of steps to take between snapshots of the grid.
	// If recordInterval is <= 0, only snapshot the final grid.
	recordInterval int
}

// Build a MonteCarlo from the JSON file at filePath.
func MonteCarloFromFile(filePath string) (*MonteCarlo, os.Error) {
	mc := new(MonteCarlo)
	err := CopyFromFile(filePath, mc)
	if err != nil {
		return nil, err
	}
	if !mc.validate() {
		return nil, fmt.Errorf(MonteCarloValidateError)
	}
	return mc, nil
}

// Build a MonteCarlo from the given JSON string.
func MonteCarloFromString(jsonData string) (*MonteCarlo, os.Error) {
	mc := new(MonteCarlo)
	err := CopyFromString(jsonData, mc)
	if err != nil {
		return nil, err
	}
	if !mc.validate() {
		return nil, fmt.Errorf(MonteCarloValidateError)
	}
	return mc, nil
}

// Do the fields of mc have acceptable values?
func (mc *MonteCarlo) validate() bool {
	return mc.etaMinimum > 0 && mc.totalSteps > 0
}

// Make a random perturbation on the Grid g.  If this perturbation leads to a
// negative energy change, accept it.  If it leads to a positive energy change,
// accept it with a random probability.  Return true if and only if the
// perturbation is accepted.
func (mc *MonteCarlo) Step(e *Energetics, g *Grid) bool {
	// choose a random site
	xf, yf := RandomIntPair(g.Lx(), g.Ly())
	// calculate the energy change due to flipping (xf, yf)
	energyChange := e.SiteFlipEnergy(g, xf, yf)
	// going to lower energy: accept it
	if energyChange < 0 {
		g.Toggle(xf, yf)
		return true
	}
	// gaining energy: accept if eta + etaMinimum <= e^(-beta*energyChange)
	log_eta := math.Log(RandomFloat() + mc.etaMinimum)
	acceptFactor := e.LogBoltzmann(energyChange)
	if log_eta <= acceptFactor {
		g.Toggle(xf, yf)
		return true
	}
	return false
}

// Run a simulation, starting from a random grid and taking steps equal to
// mc.totalSteps.  Return a slice containg each recorded grid.
// May also want to return a slice of the times when each grid was recorded.
func (mc *MonteCarlo) Simulate(e *Energetics) []*Grid {
	return nil
}
<|endoftext|>


<commit_before>package redlot

import (
	"errors"
	"strconv"
	"time"

	"github.com/syndtr/goleveldb/leveldb/util"
)

func encodeKvKey(key []byte) (buf []byte) {
	buf = append(buf, typeKV)
	buf = append(buf, key...)
	return
}

func decodeKvKey(buf []byte) (key []byte) {
	if len(buf) < 4 {
		return nil
	}
	return buf[1:]
}

// Get a value by a key.
// Args: key string
func Get(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return "", errNosArgs
	}

	v, err := db.Get(encodeKvKey(args[0]), nil)
	return string(v), err
}

// Set a value by a key.
// Args: key string, value any
func Set(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	// fmt.Printf("SET %s %s\n", args[0], args[1])
	return nil, db.Put(encodeKvKey(args[0]), args[1], nil)
}

// Del will delete a value by a key.
// Args: key string
func Del(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}
	return nil, db.Delete(encodeKvKey(args[0]), nil)
}

// Exists will check key is exists.
// Args: key string
func Exists(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	ret, err := db.Has(encodeKvKey(args[0]), nil)
	if ret {
		return int64(1), err
	}
	return int64(0), err
}

// Expire the key after timeout.
// Args: key string, seconds int
func Expire(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	key := encodeKvKey(args[0])
	has, _ := db.Has(key, nil)
	if has {
		ttl := strToInt64(string(args[1]))
		if ttl < 1 {
			return nil, errors.New("TTL must > 0, you set to " + string(args[1]))
		}
		bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
		if meta.Put(key, bs, nil) == nil {
			return int64(1), nil
		}
	}
	return int64(0), nil
}

// Setx will set a value by the key and expire it after timeout.
// Args: key string, value any, seconds int
func Setx(args [][]byte) (interface{}, error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}
	key := encodeKvKey(args[0])

	ttl := strToInt64(string(args[2]))
	if ttl < 1 {
		return nil, errors.New("TTL must > 0, you set to " + string(args[2]))
	}
	bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
	meta.Put(key, bs, nil)

	return nil, db.Put(key, args[1], nil)
}

// TTL will return the lifetime of the key.
// Args: key string
func TTL(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	key := encodeKvKey(args[0])
	b, _ := meta.Get(key, nil)
	if len(b) < 1 {
		return int64(-1), nil
	}
	ttl := int64(bytesToUint64(b)) - time.Now().UTC().Unix()
	if ttl < 0 {
		ttl = -1
		meta.Delete(key, nil)
		db.Delete(key, nil)
	}
	return ttl, nil
}

// Keys will list keys in the range.
// Args: start_key string, end_key string, limit_number int
func Keys(args [][]byte) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encodeKvKey(args[0])
	ke := encodeKvKey(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var keys []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	for iter.Next() {
		k := decodeKvKey(iter.Key())
		keys = append(keys, string(k))
		limit--
		if limit == 0 {
			break
		}
	}
	iter.Release()
	err := iter.Error()
	return keys, err
}

// Scan will list KV pair that keys in the range.
// Args: start_key string, end_key string, limit_number int
func Scan(args [][]byte) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encodeKvKey(args[0])
	ke := encodeKvKey(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var ret []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	for iter.Next() {
		k := decodeKvKey(iter.Key())
		ret = append(ret, string(k))
		ret = append(ret, string(iter.Value()))
		limit--
		if limit == 0 {
			break
		}
	}
	iter.Release()
	err := iter.Error()
	return ret, err
}
<commit_msg>Refactor Scan method.<commit_after>package redlot

import (
	"errors"
	"strconv"
	"time"

	"github.com/syndtr/goleveldb/leveldb/util"
)

func encodeKvKey(key []byte) (buf []byte) {
	buf = append(buf, typeKV)
	buf = append(buf, key...)
	return
}

func decodeKvKey(buf []byte) (key []byte) {
	if len(buf) < 4 {
		return nil
	}
	return buf[1:]
}

// Get a value by a key.
// Args: key string
func Get(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return "", errNosArgs
	}

	v, err := db.Get(encodeKvKey(args[0]), nil)
	return string(v), err
}

// Set a value by a key.
// Args: key string, value any
func Set(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	// fmt.Printf("SET %s %s\n", args[0], args[1])
	return nil, db.Put(encodeKvKey(args[0]), args[1], nil)
}

// Del will delete a value by a key.
// Args: key string
func Del(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}
	return nil, db.Delete(encodeKvKey(args[0]), nil)
}

// Exists will check key is exists.
// Args: key string
func Exists(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	ret, err := db.Has(encodeKvKey(args[0]), nil)
	if ret {
		return int64(1), err
	}
	return int64(0), err
}

// Expire the key after timeout.
// Args: key string, seconds int
func Expire(args [][]byte) (interface{}, error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	key := encodeKvKey(args[0])
	has, _ := db.Has(key, nil)
	if has {
		ttl := strToInt64(string(args[1]))
		if ttl < 1 {
			return nil, errors.New("TTL must > 0, you set to " + string(args[1]))
		}
		bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
		if meta.Put(key, bs, nil) == nil {
			return int64(1), nil
		}
	}
	return int64(0), nil
}

// Setx will set a value by the key and expire it after timeout.
// Args: key string, value any, seconds int
func Setx(args [][]byte) (interface{}, error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}
	key := encodeKvKey(args[0])

	ttl := strToInt64(string(args[2]))
	if ttl < 1 {
		return nil, errors.New("TTL must > 0, you set to " + string(args[2]))
	}
	bs := uint64ToBytes(uint64(time.Now().UTC().Unix() + ttl))
	meta.Put(key, bs, nil)

	return nil, db.Put(key, args[1], nil)
}

// TTL will return the lifetime of the key.
// Args: key string
func TTL(args [][]byte) (interface{}, error) {
	if len(args) < 1 {
		return int64(-1), errNosArgs
	}

	key := encodeKvKey(args[0])
	b, _ := meta.Get(key, nil)
	if len(b) < 1 {
		return int64(-1), nil
	}
	ttl := int64(bytesToUint64(b)) - time.Now().UTC().Unix()
	if ttl < 0 {
		ttl = -1
		meta.Delete(key, nil)
		db.Delete(key, nil)
	}
	return ttl, nil
}

// Keys will list keys in the range.
// Args: start_key string, end_key string, limit_number int
func Keys(args [][]byte) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encodeKvKey(args[0])
	ke := encodeKvKey(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var keys []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	for iter.Next() {
		k := decodeKvKey(iter.Key())
		keys = append(keys, string(k))
		limit--
		if limit == 0 {
			break
		}
	}
	iter.Release()
	err := iter.Error()
	return keys, err
}

func scan(args [][]byte, reverse bool) ([]string, error) {
	if len(args) < 3 {
		return []string{}, errNosArgs
	}

	ks := encodeKvKey(args[0])
	ke := encodeKvKey(args[1])
	limit, _ := strconv.Atoi(string(args[2]))

	var ret []string
	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	if reverse {
		iter.Seek(ke)
		for iter.Prev() {
			k := decodeKvKey(iter.Key())
			ret = append(ret, string(k))
			ret = append(ret, string(iter.Value()))
			limit--
			if limit == 0 {
				break
			}
		}
	} else {
		for iter.Next() {
			k := decodeKvKey(iter.Key())
			ret = append(ret, string(k))
			ret = append(ret, string(iter.Value()))
			limit--
			if limit == 0 {
				break
			}
		}
	}
	iter.Release()
	err := iter.Error()
	return ret, err
}

// Scan will list KV pair that keys in the range.
// Args: start_key string, end_key string, limit_number int
func Scan(args [][]byte) ([]string, error) {
	return scan(args, false)
}
<|endoftext|>


<commit_before>//
// daemon.go
//
package srnd
import (
  "log"
  "net"
  "strconv"
  "strings"
  "net/textproto"
  "time"
)

type NNTPDaemon struct {
  instance_name string
  bind_addr string
  conf *SRNdConfig
  store *ArticleStore
  database Database
  mod Moderation
  listener net.Listener
  debug bool
  sync_on_start bool
  running bool
  // http frontend
  frontend Frontend

  // nntp feeds map, feed, isoutbound
  feeds map[NNTPConnection]bool
  infeed chan *NNTPMessage
  // channel to load messages to infeed given their message id
  infeed_load chan string
  // channel for broadcasting a message to all feeds given their message id
  send_all_feeds chan string
}

func (self *NNTPDaemon) End() {
  self.listener.Close()
}

// register a new connection
// can be either inbound or outbound
func (self *NNTPDaemon) newConnection(conn net.Conn, inbound bool, policy *FeedPolicy) NNTPConnection {
  feed := NNTPConnection{conn, textproto.NewConn(conn), inbound, self.debug, new(ConnectionInfo), policy, make(chan *NNTPMessage, 64),  make(chan string, 512)}
  self.feeds[feed] = ! inbound
  return feed
}

func (self *NNTPDaemon) persistFeed(conf FeedConfig) {
  for {
    if self.running {

      var conn net.Conn
      var err error
      proxy_type := strings.ToLower(conf.proxy_type)

      if proxy_type ==  "" || proxy_type == "none" {
        // connect out without proxy
        log.Println("dial out to ", conf.addr)
        conn, err = net.Dial("tcp", conf.addr)
        if err != nil {
          log.Println("cannot connect to outfeed", conf.addr, err)
					time.Sleep(5)
          continue
        }
      } else if proxy_type == "socks4a" {
        // connect via socks4a
        log.Println("dial out via proxy", conf.proxy_addr)
        conn, err = net.Dial("tcp", conf.proxy_addr)
        if err != nil {
          log.Println("cannot connect to proxy", conf.proxy_addr)
					time.Sleep(5)
          continue
        }
        // generate request
        idx := strings.LastIndex(conf.addr, ":")
        if idx == -1 {
          log.Fatal("invalid outfeed address")
        }
        var port uint64
        addr := conf.addr[:idx]
        port, err = strconv.ParseUint(conf.addr[idx+1:], 10, 16)
        if port >= 25536 {
          log.Fatal("bad proxy port" , port)
        }
        var proxy_port uint16
        proxy_port = uint16(port)
        proxy_ident := "srndv2"
        req_len := len(addr) + 1 + len(proxy_ident) + 1 + 8

        req := make([]byte, req_len)
        // pack request
        req[0] = '\x04'
        req[1] = '\x01'
        req[2] = byte(proxy_port & 0xff00 >> 8)
        req[3] = byte(proxy_port & 0x00ff)
        req[7] = '\x01'
        idx = 8

        proxy_ident_b := []byte(proxy_ident)
        addr_b := []byte(addr)

        var bi int
        for bi = range proxy_ident_b {
          req[idx] = proxy_ident_b[bi]
          idx += 1
        }
        idx += 1
        for bi = range addr_b {
          req[idx] = addr_b[bi]
          idx += 1
        }

        // send request
        conn.Write(req)
        resp := make([]byte, 8)

        // receive response
        conn.Read(resp)
        if resp[1] == '\x5a' {
          // success
          log.Println("connected to", conf.addr)
        } else {
          log.Println("failed to connect to", conf.addr)
					time.Sleep(5)
          continue
        }
      }
      policy := &conf.policy
      nntp := self.newConnection(conn, false, policy)
      nntp.HandleOutbound(self)
      log.Println("remove outfeed")
      delete(self.feeds, nntp)
    }
  }
  time.Sleep(1 * time.Second)
}

// sync every article to all feeds
func (self *NNTPDaemon) syncAll() {
  log.Println("sync all feeds")
  chnl := make(chan string, 128)
  go self.store.IterateAllArticles(chnl)
  for {
    select {
    case msgid := <- chnl:
      for feed, use := range self.feeds {
        if use {
          feed.sync <- msgid
        }
      }
    }
  }
}

// run daemon
func (self *NNTPDaemon) Run() {
  err := self.Bind()
  if err != nil {
    log.Println("failed to bind:", err)
    return
  }
  defer self.listener.Close()

  // we are now running
  self.running = true

  // persist outfeeds
  for idx := range self.conf.feeds {
    go self.persistFeed(self.conf.feeds[idx])
  }

  // start accepting incoming connections
  go self.acceptloop()

  if self.sync_on_start {
    go self.syncAll()
  }
  // if we have no frontend this does nothing
  if self.frontend != nil {
    go self.pollfrontend()
  }
  self.pollfeeds()

}

func (self *NNTPDaemon) pollfrontend() {
  for {
    select {
    case nntp := <- self.frontend.NewPostsChan():
      // new post from frontend
      // ammend path
      nntp.Path = self.instance_name + "!" + nntp.Path
      // tell infeed that we got one
      self.infeed <- nntp
    case msgid := <- self.infeed_load:
      // load temp message
      // this deletes the temp file
      nntp := self.store.ReadTempMessage(msgid)
      if nntp == nil {
        log.Println("invalid message", msgid)
        break
      }
      // rewrite path header
      nntp.Path = self.instance_name +"!" + nntp.Path
      // offer infeed
      self.infeed <- nntp

    }
  }
}

func (self *NNTPDaemon) pollfeeds() {
  chnl := self.frontend.PostsChan()
  for {
    select {
    case msgid := <- self.send_all_feeds:
      // send all feeds
      nntp := self.store.GetMessage(msgid)
      if nntp == nil {
        log.Printf("failed to load %s for federation", msgid)
      } else {
        for feed , use := range self.feeds {
          if use && feed.policy != nil {
            if feed.policy.AllowsNewsgroup(nntp.Newsgroup) {
              feed.send <- nntp
            }
          }
        }
      }
      break
    case nntp := <- self.infeed:
      // register article
      self.database.RegisterArticle(nntp)
      // check for validity
      if nntp.Verify() {
        // store article
        self.store.StorePost(nntp)
        // tell frontend
        chnl <- nntp
        // queue to all outfeeds
        self.send_all_feeds <- nntp.MessageID
        // do any moderation events
        nntp.DoModeration(&self.mod)
      } else {
        log.Printf("%s has invalid signature", nntp.MessageID)
      }

      break
    }
  }
}

func (self *NNTPDaemon) acceptloop() {
  for {
    // accept
    conn, err := self.listener.Accept()
    if err != nil {
      log.Fatal(err)
    }
    // make a new inbound nntp connection handler
    nntp := self.newConnection(conn, true, nil)
    go self.RunInbound(nntp)
  }
}

func (self *NNTPDaemon) RunInbound(nntp NNTPConnection) {
  nntp.HandleInbound(self)
  delete(self.feeds, nntp)
}

// bind to address
func (self *NNTPDaemon) Bind() error {
  listener , err := net.Listen("tcp", self.bind_addr)
  if err != nil {
    log.Println("failed to bind to", self.bind_addr, err)
    return err
  }
  self.listener = listener
  log.Println("SRNd NNTPD bound at", listener.Addr())
  return nil
}

// load configuration
// bind to interface
func (self *NNTPDaemon) Init() bool {
  CheckConfig()
  log.Println("load config")
  self.conf = ReadConf()
  if self.conf == nil {
    log.Println("cannot load config")
    return false
  }
  self.infeed = make(chan *NNTPMessage, 64)
  self.infeed_load = make(chan string, 256)
  self.send_all_feeds = make(chan string, 64)
  self.feeds = make(map[NNTPConnection]bool)

  db_host := self.conf.database["host"]
  db_port := self.conf.database["port"]
  db_user := self.conf.database["user"]
  db_passwd := self.conf.database["password"]

  self.database = NewDatabase(self.conf.database["type"], self.conf.database["schema"], db_host, db_port, db_user, db_passwd)
  self.database.CreateTables()

  self.store = new(ArticleStore)
  self.store.directory = self.conf.store["store_dir"]
  self.store.temp = self.conf.store["incoming_dir"]
  self.store.database = self.database
  self.store.Init()

  self.sync_on_start = self.conf.daemon["sync_on_start"] == "1"
  if self.sync_on_start {
    log.Println("sync on start")
  }
  self.bind_addr = self.conf.daemon["bind"]
  self.debug = self.conf.daemon["log"] == "debug"
  self.instance_name = self.conf.daemon["instance_name"]
  if self.debug {
    log.Println("debug mode activated")
  }

  // initialize moderation engine
  self.mod.Init(self)

  // do we enable the frontend?
  if self.conf.frontend["enable"] == "1" {
    log.Printf("frontend %s enabled", self.conf.frontend["name"])
    self.frontend = NewHTTPFrontend(self, self.conf.frontend)
    go self.frontend.Mainloop()
  }

  return true
}
<commit_msg>properly sleep for dial out failure<commit_after>//
// daemon.go
//
package srnd
import (
  "log"
  "net"
  "strconv"
  "strings"
  "net/textproto"
  "time"
)

type NNTPDaemon struct {
  instance_name string
  bind_addr string
  conf *SRNdConfig
  store *ArticleStore
  database Database
  mod Moderation
  listener net.Listener
  debug bool
  sync_on_start bool
  running bool
  // http frontend
  frontend Frontend

  // nntp feeds map, feed, isoutbound
  feeds map[NNTPConnection]bool
  infeed chan *NNTPMessage
  // channel to load messages to infeed given their message id
  infeed_load chan string
  // channel for broadcasting a message to all feeds given their message id
  send_all_feeds chan string
}

func (self *NNTPDaemon) End() {
  self.listener.Close()
}

// register a new connection
// can be either inbound or outbound
func (self *NNTPDaemon) newConnection(conn net.Conn, inbound bool, policy *FeedPolicy) NNTPConnection {
  feed := NNTPConnection{conn, textproto.NewConn(conn), inbound, self.debug, new(ConnectionInfo), policy, make(chan *NNTPMessage, 64),  make(chan string, 512)}
  self.feeds[feed] = ! inbound
  return feed
}

func (self *NNTPDaemon) persistFeed(conf FeedConfig) {
  for {
    if self.running {

      var conn net.Conn
      var err error
      proxy_type := strings.ToLower(conf.proxy_type)

      if proxy_type ==  "" || proxy_type == "none" {
        // connect out without proxy
        log.Println("dial out to ", conf.addr)
        conn, err = net.Dial("tcp", conf.addr)
        if err != nil {
          log.Println("cannot connect to outfeed", conf.addr, err)
					time.Sleep(time.Second)
          continue
        }
      } else if proxy_type == "socks4a" {
        // connect via socks4a
        log.Println("dial out via proxy", conf.proxy_addr)
        conn, err = net.Dial("tcp", conf.proxy_addr)
        if err != nil {
          log.Println("cannot connect to proxy", conf.proxy_addr)
					time.Sleep(time.Second)
          continue
        }
        // generate request
        idx := strings.LastIndex(conf.addr, ":")
        if idx == -1 {
          log.Fatal("invalid outfeed address")
        }
        var port uint64
        addr := conf.addr[:idx]
        port, err = strconv.ParseUint(conf.addr[idx+1:], 10, 16)
        if port >= 25536 {
          log.Fatal("bad proxy port" , port)
        }
        var proxy_port uint16
        proxy_port = uint16(port)
        proxy_ident := "srndv2"
        req_len := len(addr) + 1 + len(proxy_ident) + 1 + 8

        req := make([]byte, req_len)
        // pack request
        req[0] = '\x04'
        req[1] = '\x01'
        req[2] = byte(proxy_port & 0xff00 >> 8)
        req[3] = byte(proxy_port & 0x00ff)
        req[7] = '\x01'
        idx = 8

        proxy_ident_b := []byte(proxy_ident)
        addr_b := []byte(addr)

        var bi int
        for bi = range proxy_ident_b {
          req[idx] = proxy_ident_b[bi]
          idx += 1
        }
        idx += 1
        for bi = range addr_b {
          req[idx] = addr_b[bi]
          idx += 1
        }

        // send request
        conn.Write(req)
        resp := make([]byte, 8)

        // receive response
        conn.Read(resp)
        if resp[1] == '\x5a' {
          // success
          log.Println("connected to", conf.addr)
        } else {
          log.Println("failed to connect to", conf.addr)
					time.Sleep(5)
          continue
        }
      }
      policy := &conf.policy
      nntp := self.newConnection(conn, false, policy)
      nntp.HandleOutbound(self)
      log.Println("remove outfeed")
      delete(self.feeds, nntp)
    }
  }
  time.Sleep(1 * time.Second)
}

// sync every article to all feeds
func (self *NNTPDaemon) syncAll() {
  log.Println("sync all feeds")
  chnl := make(chan string, 128)
  go self.store.IterateAllArticles(chnl)
  for {
    select {
    case msgid := <- chnl:
      for feed, use := range self.feeds {
        if use {
          feed.sync <- msgid
        }
      }
    }
  }
}

// run daemon
func (self *NNTPDaemon) Run() {
  err := self.Bind()
  if err != nil {
    log.Println("failed to bind:", err)
    return
  }
  defer self.listener.Close()

  // we are now running
  self.running = true

  // persist outfeeds
  for idx := range self.conf.feeds {
    go self.persistFeed(self.conf.feeds[idx])
  }

  // start accepting incoming connections
  go self.acceptloop()

  if self.sync_on_start {
    go self.syncAll()
  }
  // if we have no frontend this does nothing
  if self.frontend != nil {
    go self.pollfrontend()
  }
  self.pollfeeds()

}

func (self *NNTPDaemon) pollfrontend() {
  for {
    select {
    case nntp := <- self.frontend.NewPostsChan():
      // new post from frontend
      // ammend path
      nntp.Path = self.instance_name + "!" + nntp.Path
      // tell infeed that we got one
      self.infeed <- nntp
    case msgid := <- self.infeed_load:
      // load temp message
      // this deletes the temp file
      nntp := self.store.ReadTempMessage(msgid)
      if nntp == nil {
        log.Println("invalid message", msgid)
        break
      }
      // rewrite path header
      nntp.Path = self.instance_name +"!" + nntp.Path
      // offer infeed
      self.infeed <- nntp

    }
  }
}

func (self *NNTPDaemon) pollfeeds() {
  chnl := self.frontend.PostsChan()
  for {
    select {
    case msgid := <- self.send_all_feeds:
      // send all feeds
      nntp := self.store.GetMessage(msgid)
      if nntp == nil {
        log.Printf("failed to load %s for federation", msgid)
      } else {
        for feed , use := range self.feeds {
          if use && feed.policy != nil {
            if feed.policy.AllowsNewsgroup(nntp.Newsgroup) {
              feed.send <- nntp
            }
          }
        }
      }
      break
    case nntp := <- self.infeed:
      // register article
      self.database.RegisterArticle(nntp)
      // check for validity
      if nntp.Verify() {
        // store article
        self.store.StorePost(nntp)
        // tell frontend
        chnl <- nntp
        // queue to all outfeeds
        self.send_all_feeds <- nntp.MessageID
        // do any moderation events
        nntp.DoModeration(&self.mod)
      } else {
        log.Printf("%s has invalid signature", nntp.MessageID)
      }

      break
    }
  }
}

func (self *NNTPDaemon) acceptloop() {
  for {
    // accept
    conn, err := self.listener.Accept()
    if err != nil {
      log.Fatal(err)
    }
    // make a new inbound nntp connection handler
    nntp := self.newConnection(conn, true, nil)
    go self.RunInbound(nntp)
  }
}

func (self *NNTPDaemon) RunInbound(nntp NNTPConnection) {
  nntp.HandleInbound(self)
  delete(self.feeds, nntp)
}

// bind to address
func (self *NNTPDaemon) Bind() error {
  listener , err := net.Listen("tcp", self.bind_addr)
  if err != nil {
    log.Println("failed to bind to", self.bind_addr, err)
    return err
  }
  self.listener = listener
  log.Println("SRNd NNTPD bound at", listener.Addr())
  return nil
}

// load configuration
// bind to interface
func (self *NNTPDaemon) Init() bool {
  CheckConfig()
  log.Println("load config")
  self.conf = ReadConf()
  if self.conf == nil {
    log.Println("cannot load config")
    return false
  }
  self.infeed = make(chan *NNTPMessage, 64)
  self.infeed_load = make(chan string, 256)
  self.send_all_feeds = make(chan string, 64)
  self.feeds = make(map[NNTPConnection]bool)

  db_host := self.conf.database["host"]
  db_port := self.conf.database["port"]
  db_user := self.conf.database["user"]
  db_passwd := self.conf.database["password"]

  self.database = NewDatabase(self.conf.database["type"], self.conf.database["schema"], db_host, db_port, db_user, db_passwd)
  self.database.CreateTables()

  self.store = new(ArticleStore)
  self.store.directory = self.conf.store["store_dir"]
  self.store.temp = self.conf.store["incoming_dir"]
  self.store.database = self.database
  self.store.Init()

  self.sync_on_start = self.conf.daemon["sync_on_start"] == "1"
  if self.sync_on_start {
    log.Println("sync on start")
  }
  self.bind_addr = self.conf.daemon["bind"]
  self.debug = self.conf.daemon["log"] == "debug"
  self.instance_name = self.conf.daemon["instance_name"]
  if self.debug {
    log.Println("debug mode activated")
  }

  // initialize moderation engine
  self.mod.Init(self)

  // do we enable the frontend?
  if self.conf.frontend["enable"] == "1" {
    log.Printf("frontend %s enabled", self.conf.frontend["name"])
    self.frontend = NewHTTPFrontend(self, self.conf.frontend)
    go self.frontend.Mainloop()
  }

  return true
}
<|endoftext|>


<commit_before>package vkutil

import (
	"context"
	"net/url"

	"github.com/zhuharev/vk"
)

type poolsClient struct {
	client *Api
}

func newPoolsClient(client *Api) *poolsClient {
	return &poolsClient{
		client: client,
	}
}

func (p *poolsClient) GetByID(ctx context.Context, ownerID, poolID int) (*Poll, error) {
	params := url.Values{
		"owner_id": {toString(ownerID)},
		"poll_id":  {toString(poolID)},
	}

	var res PoolResponse

	err := p.client.VkApi.RequestTypedContext(ctx, vk.MethodPoolsGetByID, params, &res)
	if err != nil {
		return nil, err
	}

	return &res.Response, nil
}

func (p *poolsClient) GetVoters(ctx context.Context, ownerID, pollID int, answerIDs []int, offset, count int) (map[int][]int, error) {
	params := url.Values{
		"owner_id":   {toString(ownerID)},
		"poll_id":    {toString(pollID)},
		"answer_ids": {arrIntToString(answerIDs)},
		"offset":     {toString(offset)},
		"count":      {toString(count)},
	}

	var res PollVoters

	err := p.client.VkApi.RequestTypedContext(ctx, vk.MethodPoolsGetByID, params, &res)
	if err != nil {
		return nil, err
	}

	// convert to map
	m := make(map[int][]int)

	for _, r := range res.Response {
		m[r.AnswerID] = append(m[r.AnswerID], r.Users.Items...)
	}

	return m, nil
}

func (p *poolsClient) GetAllVoters(ctx context.Context, ownerID, poolID int, answerIDs []int) (map[int][]int, error) {
	var (
		offset int
		count  int = 1000

		res map[int][]int
	)

	for {
		m, err := p.GetVoters(ctx, ownerID, poolID, answerIDs, offset, count)
		if err != nil {
			return m, err
		}

		// isEmpty
		var mapHasValues bool
		for _, arr := range m {
			if len(arr) != 0 {
				mapHasValues = true

				break
			}
		}

		res = joinMaps(res, m)

		// если в ответе нет ID-шников пользователей, считаем что мы дошли до конца и возвращаем результат
		if !mapHasValues {
			return res, nil
		}

		offset += count
	}
}

type PoolResponse struct {
	Response Poll `json:"response"`
}

type Poll struct {
	Multiple      bool   `json:"multiple"`
	EndDate       int    `json:"end_date"`
	Closed        bool   `json:"closed"`
	IsBoard       bool   `json:"is_board"`
	CanEdit       bool   `json:"can_edit"`
	CanVote       bool   `json:"can_vote"`
	CanReport     bool   `json:"can_report"`
	CanShare      bool   `json:"can_share"`
	Created       int    `json:"created"`
	ID            int    `json:"id"`
	OwnerID       int    `json:"owner_id"`
	Question      string `json:"question"`
	Votes         int    `json:"votes"`
	DisableUnvote bool   `json:"disable_unvote"`
	Anonymous     bool   `json:"anonymous"`
	Friends       []struct {
		ID int `json:"id"`
	} `json:"friends"`
	AnswerIds []int  `json:"answer_ids"`
	EmbedHash string `json:"embed_hash"`
	Answers   []struct {
		ID    int    `json:"id"`
		Rate  int    `json:"rate"`
		Text  string `json:"text"`
		Votes int    `json:"votes"`
	} `json:"answers"`
	Background struct {
		Angle  int    `json:"angle"`
		Color  string `json:"color"`
		ID     int    `json:"id"`
		Name   string `json:"name"`
		Points []struct {
			Color    string `json:"color"`
			Position int    `json:"position"`
		} `json:"points"`
		Type string `json:"type"`
	} `json:"background"`
}

type PollVoters struct {
	Response []struct {
		AnswerID int `json:"answer_id"`
		Users    struct {
			Count int   `json:"count"`
			Items []int `json:"items"`
		} `json:"users"`
	} `json:"response"`
}
<commit_msg>Change rate type<commit_after>package vkutil

import (
	"context"
	"net/url"

	"github.com/zhuharev/vk"
)

type poolsClient struct {
	client *Api
}

func newPoolsClient(client *Api) *poolsClient {
	return &poolsClient{
		client: client,
	}
}

func (p *poolsClient) GetByID(ctx context.Context, ownerID, poolID int) (*Poll, error) {
	params := url.Values{
		"owner_id": {toString(ownerID)},
		"poll_id":  {toString(poolID)},
	}

	var res PoolResponse

	err := p.client.VkApi.RequestTypedContext(ctx, vk.MethodPoolsGetByID, params, &res)
	if err != nil {
		return nil, err
	}

	return &res.Response, nil
}

func (p *poolsClient) GetVoters(ctx context.Context, ownerID, pollID int, answerIDs []int, offset, count int) (map[int][]int, error) {
	params := url.Values{
		"owner_id":   {toString(ownerID)},
		"poll_id":    {toString(pollID)},
		"answer_ids": {arrIntToString(answerIDs)},
		"offset":     {toString(offset)},
		"count":      {toString(count)},
	}

	var res PollVoters

	err := p.client.VkApi.RequestTypedContext(ctx, vk.MethodPoolsGetByID, params, &res)
	if err != nil {
		return nil, err
	}

	// convert to map
	m := make(map[int][]int)

	for _, r := range res.Response {
		m[r.AnswerID] = append(m[r.AnswerID], r.Users.Items...)
	}

	return m, nil
}

func (p *poolsClient) GetAllVoters(ctx context.Context, ownerID, poolID int, answerIDs []int) (map[int][]int, error) {
	var (
		offset int
		count  int = 1000

		res map[int][]int
	)

	for {
		m, err := p.GetVoters(ctx, ownerID, poolID, answerIDs, offset, count)
		if err != nil {
			return m, err
		}

		// isEmpty
		var mapHasValues bool
		for _, arr := range m {
			if len(arr) != 0 {
				mapHasValues = true

				break
			}
		}

		res = joinMaps(res, m)

		// если в ответе нет ID-шников пользователей, считаем что мы дошли до конца и возвращаем результат
		if !mapHasValues {
			return res, nil
		}

		offset += count
	}
}

type PoolResponse struct {
	Response Poll `json:"response"`
}

type Poll struct {
	Multiple      bool   `json:"multiple"`
	EndDate       int    `json:"end_date"`
	Closed        bool   `json:"closed"`
	IsBoard       bool   `json:"is_board"`
	CanEdit       bool   `json:"can_edit"`
	CanVote       bool   `json:"can_vote"`
	CanReport     bool   `json:"can_report"`
	CanShare      bool   `json:"can_share"`
	Created       int    `json:"created"`
	ID            int    `json:"id"`
	OwnerID       int    `json:"owner_id"`
	Question      string `json:"question"`
	Votes         int    `json:"votes"`
	DisableUnvote bool   `json:"disable_unvote"`
	Anonymous     bool   `json:"anonymous"`
	Friends       []struct {
		ID int `json:"id"`
	} `json:"friends"`
	AnswerIds []int  `json:"answer_ids"`
	EmbedHash string `json:"embed_hash"`
	Answers   []struct {
		ID    int     `json:"id"`
		Rate  float64 `json:"rate"`
		Text  string  `json:"text"`
		Votes int     `json:"votes"`
	} `json:"answers"`
	Background struct {
		Angle  int    `json:"angle"`
		Color  string `json:"color"`
		ID     int    `json:"id"`
		Name   string `json:"name"`
		Points []struct {
			Color    string `json:"color"`
			Position int    `json:"position"`
		} `json:"points"`
		Type string `json:"type"`
	} `json:"background"`
}

type PollVoters struct {
	Response []struct {
		AnswerID int `json:"answer_id"`
		Users    struct {
			Count int   `json:"count"`
			Items []int `json:"items"`
		} `json:"users"`
	} `json:"response"`
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
)

// pow computes z to the (nonnegative integer) power i.
func pow(z complex128, i int) complex128 {
	if i < 0 {
		panic("negative power")
	}

	var res complex128 = 1

	for i > 0 {
		res *= z
		i--
	}

	return res
}

// A Function can be evaluated at a complex point.
type Function interface {
	// evaluate computes the value of the function at z.
	Evaluate(z complex128) complex128
}

// A poly is a (complex) polynomial.
type poly []complex128

// Degree returns the degree of the polynomial.
//
// The degree of the zero polynomial is 0.
func (f poly) Degree() int {
	if len(f) == 0 {
		return 0
	}

	var deg int

	for i, v := range f {
		if v != 0 {
			deg = i
		}
	}

	return deg
}

// Normalise returns a new poly with any excess zeroes culled from the end.
func (f poly) Normalise() poly {
	deg := f.Degree()

	if deg == 0 && len(f) > 0 && f[0] == 0 {
		return poly([]complex128{})
	}

	if deg < len(f) {
		return f[:deg+1]
	}

	return f
}

// IsConstant checks whether the (normalised) polynomial is constant.
func (f poly) IsConstant() bool {
	return len(f) <= 1
}

func (f poly) Add(g poly) poly {
	deg1 := f.Degree()
	deg2 := g.Degree()
	var max_deg int

	if deg1 >= deg2 {
		max_deg = deg1
	} else {
		max_deg = deg2
	}

	res := make([]complex128, max_deg+1)

	for i := range res {
		var fi, gi complex128

		if i >= len(f) {
			fi = 0
		} else {
			fi = f[i]
		}

		if i >= len(g) {
			gi = 0
		} else {
			gi = g[i]
		}

		res[i] = fi + gi
	}

	return poly(res)
}

func (f poly) Negative() poly {
	res := make([]complex128, len(f))

	for i := range res {
		res[i] = -f[i]
	}

	return res
}

func (f poly) Subtract(g poly) poly {
	return f.Add(g.Negative())
}

func (f poly) Multiply(g poly) poly {
	deg := f.Degree() + g.Degree()

	res := make([]complex128, deg+1)

	for i := range res {
		for j := 0; j <= i; j++ {
			var fj, gi_j complex128

			if j >= len(f) {
				fj = 0
			} else {
				fj = f[j]
			}

			if i-j >= len(g) {
				gi_j = 0
			} else {
				gi_j = g[i-j]
			}

			res[i] += fj * gi_j
		}
	}

	return res
}

func (f poly) Equal(g poly) bool {
	deg1 := f.Degree()
	deg2 := g.Degree()

	if deg1 != deg2 {
		return false
	}

	f = f.Normalise()
	g = g.Normalise()

	for i := range f {
		if f[i] != g[i] {
			return false
		}
	}

	return true
}

func (f poly) String() string {
	b := new(bytes.Buffer)

	if len(f) == 0 {
		return "0"
	}

	fmt.Fprint(b, f[0])

	if len(f) >= 2 {
		if f[1] != 0 {
			fmt.Fprintf(b, " + %vt", f[1])
		}
	} else {
		return b.String()
	}

	for i, z := range f[2:] {
		if z != 0 {
			fmt.Fprintf(b, " + %vt^%v", z, i+2)
		}
	}

	return b.String()
}

func (f poly) Evaluate(z complex128) complex128 {
	var res complex128

	for i, coeff := range f {
		res += coeff * pow(z, i)
	}

	return res
}

// NewPoly returns a Function coefficients coeffs, starting with the constant term.
func NewPoly(coeffs ...complex128) Function {
	return poly(coeffs)
}

// A rat is a rational function.
type rat struct {
	numerator   poly
	denominator poly
}

func (f rat) Evaluate(z complex128) complex128 {
	num := f.numerator.Evaluate(z)
	denom := f.denominator.Evaluate(z)
	return num / denom
}
<commit_msg>Do more normalising<commit_after>package main

import (
	"bytes"
	"fmt"
)

// pow computes z to the (nonnegative integer) power i.
func pow(z complex128, i int) complex128 {
	if i < 0 {
		panic("negative power")
	}

	var res complex128 = 1

	for i > 0 {
		res *= z
		i--
	}

	return res
}

// A Function can be evaluated at a complex point.
type Function interface {
	// evaluate computes the value of the function at z.
	Evaluate(z complex128) complex128
}

// A poly is a (complex) polynomial.
type poly []complex128

// Degree returns the degree of the polynomial.
//
// The degree of the zero polynomial is 0.
func (f poly) Degree() int {
	if len(f) == 0 {
		return 0
	}

	var deg int

	for i, v := range f {
		if v != 0 {
			deg = i
		}
	}

	return deg
}

// Normalise returns a new poly with any excess zeroes culled from the end.
//
// The normalised form of zero is {0}, not {}.
func (f poly) Normalise() poly {
	deg := f.Degree()

	if len(f) == 0 {
		return poly([]complex128{0})
	}

	if deg < len(f) {
		return f[:deg+1]
	}

	return f
}

// IsConstant checks whether the (normalised) polynomial is constant.
func (f poly) IsConstant() bool {
	return len(f) <= 1
}

func (f poly) Add(g poly) poly {
	deg1 := f.Degree()
	deg2 := g.Degree()
	var max_deg int

	if deg1 >= deg2 {
		max_deg = deg1
	} else {
		max_deg = deg2
	}

	res := make([]complex128, max_deg+1)

	for i := range res {
		var fi, gi complex128

		if i >= len(f) {
			fi = 0
		} else {
			fi = f[i]
		}

		if i >= len(g) {
			gi = 0
		} else {
			gi = g[i]
		}

		res[i] = fi + gi
	}

	return poly(res)
}

func (f poly) Negative() poly {
	res := make([]complex128, len(f))

	for i := range res {
		res[i] = -f[i]
	}

	return res
}

func (f poly) Subtract(g poly) poly {
	return f.Add(g.Negative())
}

func (f poly) Multiply(g poly) poly {
	deg := f.Degree() + g.Degree()

	res := make([]complex128, deg+1)

	for i := range res {
		for j := 0; j <= i; j++ {
			var fj, gi_j complex128

			if j >= len(f) {
				fj = 0
			} else {
				fj = f[j]
			}

			if i-j >= len(g) {
				gi_j = 0
			} else {
				gi_j = g[i-j]
			}

			res[i] += fj * gi_j
		}
	}

	return res
}

func (f poly) Equal(g poly) bool {
	deg1 := f.Degree()
	deg2 := g.Degree()

	if deg1 != deg2 {
		return false
	}

	f = f.Normalise()
	g = g.Normalise()

	for i := range f {
		if f[i] != g[i] {
			return false
		}
	}

	return true
}

func (f poly) String() string {
	b := new(bytes.Buffer)

	f = f.Normalise()
	fmt.Fprint(b, f[0])

	if len(f) >= 2 {
		if f[1] != 0 {
			fmt.Fprintf(b, " + %vt", f[1])
		}
	} else {
		return b.String()
	}

	for i, z := range f[2:] {
		if z != 0 {
			fmt.Fprintf(b, " + %vt^%v", z, i+2)
		}
	}

	return b.String()
}

func (f poly) Evaluate(z complex128) complex128 {
	var res complex128

	for i, coeff := range f {
		res += coeff * pow(z, i)
	}

	return res
}

// NewPoly returns a poly with coefficients coeffs, starting with the constant term.
func NewPoly(coeffs ...complex128) poly {
	return poly(coeffs).Normalise()
}

// A rat is a rational function.
type rat struct {
	numerator   poly
	denominator poly
}

func (f rat) Evaluate(z complex128) complex128 {
	num := f.numerator.Evaluate(z)
	denom := f.denominator.Evaluate(z)
	return num / denom
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
)

// pow computes z to the (nonnegative integer) power i.
func pow(z complex128, i int) complex128 {
	if i < 0 {
		panic("negative power")
	}

	var res complex128 = 1

	for i > 0 {
		res *= z
		i--
	}

	return res
}

// A Function can be evaluated at a complex point.
type Function interface {
	// evaluate computes the value of the function at z.
	Evaluate(z complex128) complex128
}

// A poly is a (complex) polynomial.
type poly []complex128

// Degree returns the degree of the polynomial.
//
// The degree of the zero polynomial is 0.
func (f poly) Degree() int {
	if len(f) == 0 {
		return 0
	}

	var deg int

	for i, v := range f {
		if v != 0 {
			deg = i
		}
	}

	return deg
}

// Normalise returns a new poly with any excess zeroes culled from the end.
func (f poly) Normalise() poly {
	deg := f.Degree()

	if deg == 0 && len(f) > 0 && f[0] == 0 {
		return poly([]complex128{})
	}

	if deg < len(f) {
		return f[:deg+1]
	}

	return f
}

// IsConstant checks whether the (normalised) polynomial is constant.
func (f poly) IsConstant() bool {
	return len(f) <= 1
}

func (f poly) Add(g poly) poly {
	deg1 := f.Degree()
	deg2 := g.Degree()
	var max_deg int

	if deg1 >= deg2 {
		max_deg = deg1
	} else {
		max_deg = deg2
	}

	res := make([]complex128, max_deg)

	for i := range res {
		var fi, gi complex128

		if i >= len(f) {
			fi = 0
		} else {
			fi = f[i]
		}

		if i >= len(g) {
			gi = 0
		} else {
			gi = g[i]
		}

		res[i] = fi + gi
	}

	return poly(res)
}

func (f poly) Negative() poly {
	res := make([]complex128, len(f))

	for i := range res {
		res[i] = -f[i]
	}

	return res
}

func (f poly) Subtract(g poly) poly {
	return f.Add(g.Negative())
}

func (f poly) Multiply(g poly) poly {
	deg := f.Degree() + g.Degree()

	res := make([]complex128, deg)

	for i := range res {
		for j := 0; j <= i; j++ {
			var fj, gi_j complex128

			if j >= len(f) {
				fj = 0
			} else {
				fj = f[j]
			}

			if i-j >= len(g) {
				gi_j = 0
			} else {
				gi_j = g[i-j]
			}

			res[i] += fj * gi_j
		}
	}

	return res
}

func (f poly) Equal(g poly) bool {
	deg1 := f.Degree()
	deg2 := g.Degree()

	if deg1 != deg2 {
		return false
	}

	if deg1 < len(f) {
		f = f[:deg1+1]
	}

	for i := range f {
		if f[i] != g[i] {
			return false
		}
	}

	return true
}

func (f poly) String() string {
	var b bytes.Buffer

	if len(f) == 0 {
		return "0"
	}

	b.WriteString(fmt.Sprint(f[0]))

	if len(f) >= 2 {
		part := fmt.Sprintf(" + %vt", f[1])
		b.WriteString(part)
	} else {
		return b.String()
	}

	for i, z := range f[2:] {
		part := fmt.Sprintf(" + %vt^%v", z, i+2)
		b.WriteString(part)
	}

	return b.String()
}

func (f poly) Evaluate(z complex128) complex128 {
	var res complex128

	for i, coeff := range f {
		res += coeff * pow(z, i)
	}

	return res
}

// NewPoly returns a Function coefficients coeffs, starting with the constant term.
func NewPoly(coeffs ...complex128) Function {
	return poly(coeffs)
}

// A rat is a rational function.
type rat struct {
	numerator   poly
	denominator poly
}

func (f rat) Evaluate(z complex128) complex128 {
	num := f.numerator.Evaluate(z)
	denom := f.denominator.Evaluate(z)
	return num / denom
}
<commit_msg>Tidy up poly.String()<commit_after>package main

import (
	"bytes"
	"fmt"
)

// pow computes z to the (nonnegative integer) power i.
func pow(z complex128, i int) complex128 {
	if i < 0 {
		panic("negative power")
	}

	var res complex128 = 1

	for i > 0 {
		res *= z
		i--
	}

	return res
}

// A Function can be evaluated at a complex point.
type Function interface {
	// evaluate computes the value of the function at z.
	Evaluate(z complex128) complex128
}

// A poly is a (complex) polynomial.
type poly []complex128

// Degree returns the degree of the polynomial.
//
// The degree of the zero polynomial is 0.
func (f poly) Degree() int {
	if len(f) == 0 {
		return 0
	}

	var deg int

	for i, v := range f {
		if v != 0 {
			deg = i
		}
	}

	return deg
}

// Normalise returns a new poly with any excess zeroes culled from the end.
func (f poly) Normalise() poly {
	deg := f.Degree()

	if deg == 0 && len(f) > 0 && f[0] == 0 {
		return poly([]complex128{})
	}

	if deg < len(f) {
		return f[:deg+1]
	}

	return f
}

// IsConstant checks whether the (normalised) polynomial is constant.
func (f poly) IsConstant() bool {
	return len(f) <= 1
}

func (f poly) Add(g poly) poly {
	deg1 := f.Degree()
	deg2 := g.Degree()
	var max_deg int

	if deg1 >= deg2 {
		max_deg = deg1
	} else {
		max_deg = deg2
	}

	res := make([]complex128, max_deg)

	for i := range res {
		var fi, gi complex128

		if i >= len(f) {
			fi = 0
		} else {
			fi = f[i]
		}

		if i >= len(g) {
			gi = 0
		} else {
			gi = g[i]
		}

		res[i] = fi + gi
	}

	return poly(res)
}

func (f poly) Negative() poly {
	res := make([]complex128, len(f))

	for i := range res {
		res[i] = -f[i]
	}

	return res
}

func (f poly) Subtract(g poly) poly {
	return f.Add(g.Negative())
}

func (f poly) Multiply(g poly) poly {
	deg := f.Degree() + g.Degree()

	res := make([]complex128, deg)

	for i := range res {
		for j := 0; j <= i; j++ {
			var fj, gi_j complex128

			if j >= len(f) {
				fj = 0
			} else {
				fj = f[j]
			}

			if i-j >= len(g) {
				gi_j = 0
			} else {
				gi_j = g[i-j]
			}

			res[i] += fj * gi_j
		}
	}

	return res
}

func (f poly) Equal(g poly) bool {
	deg1 := f.Degree()
	deg2 := g.Degree()

	if deg1 != deg2 {
		return false
	}

	if deg1 < len(f) {
		f = f[:deg1+1]
	}

	for i := range f {
		if f[i] != g[i] {
			return false
		}
	}

	return true
}

func (f poly) String() string {
	b := new(bytes.Buffer)

	if len(f) == 0 {
		return "0"
	}

	fmt.Fprint(b, f[0])

	if len(f) >= 2 {
		if f[1] != 0 {
			fmt.Fprintf(b, " + %vt", f[1])
		}
	} else {
		return b.String()
	}

	for i, z := range f[2:] {
		if z != 0 {
			fmt.Fprintf(b, " + %vt^%v", z, i+2)
		}
	}

	return b.String()
}

func (f poly) Evaluate(z complex128) complex128 {
	var res complex128

	for i, coeff := range f {
		res += coeff * pow(z, i)
	}

	return res
}

// NewPoly returns a Function coefficients coeffs, starting with the constant term.
func NewPoly(coeffs ...complex128) Function {
	return poly(coeffs)
}

// A rat is a rational function.
type rat struct {
	numerator   poly
	denominator poly
}

func (f rat) Evaluate(z complex128) complex128 {
	num := f.numerator.Evaluate(z)
	denom := f.denominator.Evaluate(z)
	return num / denom
}
<|endoftext|>


<commit_before>package moxxiConf

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"text/template"
)

func CreateMux(handlers []HandlerConfig, l *log.Logger) *http.ServeMux {
	mux := http.NewServeMux()
	for _, handler := range handlers {
		switch handler.handlerType {
		case "json":
			mux.HandleFunc(handler.handlerRoute, ChunkedJSONHandler(handler, l))
		case "form":
			mux.HandleFunc(handler.handlerRoute, FormHandler(handler, l))
		case "static":
			mux.HandleFunc(handler.handlerRoute, StaticHandler(handler, l))
		}
	}
	return mux
}

// FormHandler - creates and returns a Handler for both Query and Form requests
func FormHandler(config HandlerConfig, l *log.Logger) http.HandlerFunc {
	confWriter := confWrite(config)
	// log.Printf("\n%#v\n", config)

	return func(w http.ResponseWriter, r *http.Request) {

		if extErr := r.ParseForm(); extErr != nil {
			http.Error(w, extErr.Error(), http.StatusBadRequest)
			return
		}

		if r.Form.Get("host") == "" {
			pkgErr := &NewErr{Code: ErrNoHostname}
			http.Error(w, pkgErr.Error(), http.StatusPreconditionFailed)
			log.Println(pkgErr.LogError(r))
			return
		}
		host := r.Form.Get("host")

		if r.Form.Get("ip") == "" {
			pkgErr := &NewErr{Code: ErrNoIP}
			http.Error(w, pkgErr.Error(), http.StatusPreconditionFailed)
			log.Println(pkgErr.LogError(r))
			return
		}

		tls := parseCheckbox(r.Form.Get("tls"))

		port, err := strconv.Atoi(r.Form.Get("port"))
		if err != nil {
			port = 80
		}

		vhost := siteParams{
			IntHost:      host,
			IntIP:        r.Form.Get("ip"),
			Encrypted:    tls,
			IntPort:      port,
			StripHeaders: r.Form["header"],
		}

		vhost, pkgErr := confCheck(vhost, config)
		if pkgErr != nil {
			http.Error(w, pkgErr.Error(), http.StatusPreconditionFailed)
			log.Println(pkgErr.LogError(r))
			return
		}

		if vhost, pkgErr = confWriter(vhost); pkgErr != nil {
			http.Error(w, pkgErr.Error(), http.StatusInternalServerError)
			log.Println(pkgErr.LogError(r))
			return
		}

		if extErr := config.resTempl.Execute(w, []siteParams{vhost}); extErr != nil {
			http.Error(w, extErr.Error(), http.StatusInternalServerError)
			log.Println(extErr.Error())
			return
		}
		return
	}
}

// JSONHandler - creates and returns a Handler for JSON body requests
func ChunkedJSONHandler(config HandlerConfig, l *log.Logger) http.HandlerFunc {

	var tStart, tEnd, tBody, tError *template.Template

	for _, each := range config.resTempl.Templates() {
		switch each.Name() {
		case "start":
			tStart = each
		case "end":
			tEnd = each
		case "body":
			tBody = each
		case "error":
			tError = each
		}
	}

	if tStart == nil || tEnd == nil || tBody == nil || tError == nil {
		return JSONHandler(config, l)
	}

	confWriter := confWrite(config)

	return func(w http.ResponseWriter, r *http.Request) {

		var emptyInterface interface{}
		tStart.Execute(w, emptyInterface)

		decoder := json.NewDecoder(r.Body)
		var v struct {
			host           string
			ip             string
			port           int
			tls            bool
			blockedHeaders []string
		}

		for decoder.More() {
			err := decoder.Decode(&v)
			if err != nil {
				continue
			}

			vhost := siteParams{
				IntHost:      v.host,
				IntIP:        v.ip,
				Encrypted:    v.tls,
				IntPort:      v.port,
				StripHeaders: v.blockedHeaders,
			}

			confConfig, err := confCheck(vhost, config)
			if err != nil {
				tError.Execute(w, vhost)
			}

			// #TODO# maybe change the style of siteParams to include myError?
			if confConfig, err := confWriter(confConfig); err != nil {
				log.Println(err.LogError(r))
				erredConfig := struct {
					ExtHost      string
					IntHost      string
					IntIP        string
					IntPort      int
					Encrypted    bool
					StripHeaders []string
					myError      string
				}{
					ExtHost:      confConfig.ExtHost,
					IntHost:      confConfig.IntHost,
					IntIP:        confConfig.IntIP,
					IntPort:      confConfig.IntPort,
					Encrypted:    confConfig.Encrypted,
					StripHeaders: confConfig.StripHeaders,
					myError:      err.Error(),
				}
				if err := tError.Execute(w, erredConfig); err != nil {
					log.Println(err.Error())
				}
			}

			if err = tBody.Execute(w, confConfig); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				log.Println(err.Error())
				return
			}
		}
		tEnd.Execute(w, emptyInterface)
	}
}

func JSONHandler(config HandlerConfig, l *log.Logger) http.HandlerFunc {
	confWriter := confWrite(config)
	return func(w http.ResponseWriter, r *http.Request) {
		var v []struct {
			host           string
			ip             string
			port           int
			tls            bool
			blockedHeaders []string
		}
		var responseConfig []siteParams

		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(&v)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
		for _, each := range v {

			vhost := siteParams{
				IntHost:      each.host,
				IntIP:        each.ip,
				Encrypted:    each.tls,
				IntPort:      each.port,
				StripHeaders: each.blockedHeaders,
			}

			confConfig, err := confCheck(vhost, config)
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
			}

			confConfig, err = confCheck(vhost, config)
			if err != nil {
				http.Error(w, err.Error(), http.StatusPreconditionFailed)
				log.Println(err.LogError(r))
				return
			}

			if confConfig, err = confWriter(confConfig); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				log.Println(err.LogError(r))
				return
			}

			responseConfig = append(responseConfig, confConfig)
		}

		if err := config.resTempl.Execute(w, responseConfig); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Println(err.Error())
			return
		}
	}
}

// StaticHandler - creates and returns a Handler to simply respond with a static response to every request
func StaticHandler(config HandlerConfig, l *log.Logger) http.HandlerFunc {
	res, err := ioutil.ReadFile(config.resFile)
	if err != nil {
		log.Printf("bad static response file %s - %v", config.resFile, err)
		return func(w http.ResponseWriter, r *http.Request) {
			http.Error(w, "no data", http.StatusInternalServerError)
		}
	}

	return func(w http.ResponseWriter, r *http.Request) {
		if _, err := w.Write(res); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
}
<commit_msg>rewrote json handler<commit_after>package moxxiConf

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"text/template"
)

func CreateMux(handlers []HandlerConfig, l *log.Logger) *http.ServeMux {
	mux := http.NewServeMux()
	for _, handler := range handlers {
		switch handler.handlerType {
		case "json":
			mux.HandleFunc(handler.handlerRoute, JSONHandler(handler, l))
		case "form":
			mux.HandleFunc(handler.handlerRoute, FormHandler(handler, l))
		case "static":
			mux.HandleFunc(handler.handlerRoute, StaticHandler(handler, l))
		}
	}
	return mux
}

// FormHandler - creates and returns a Handler for both Query and Form requests
func FormHandler(config HandlerConfig, l *log.Logger) http.HandlerFunc {
	confWriter := confWrite(config)
	// log.Printf("\n%#v\n", config)

	return func(w http.ResponseWriter, r *http.Request) {

		if extErr := r.ParseForm(); extErr != nil {
			http.Error(w, extErr.Error(), http.StatusBadRequest)
			return
		}

		if r.Form.Get("host") == "" {
			pkgErr := &NewErr{Code: ErrNoHostname}
			http.Error(w, pkgErr.Error(), http.StatusPreconditionFailed)
			log.Println(pkgErr.LogError(r))
			return
		}
		host := r.Form.Get("host")

		if r.Form.Get("ip") == "" {
			pkgErr := &NewErr{Code: ErrNoIP}
			http.Error(w, pkgErr.Error(), http.StatusPreconditionFailed)
			log.Println(pkgErr.LogError(r))
			return
		}

		tls := parseCheckbox(r.Form.Get("tls"))

		port, err := strconv.Atoi(r.Form.Get("port"))
		if err != nil {
			port = 80
		}

		vhost := siteParams{
			IntHost:      host,
			IntIP:        r.Form.Get("ip"),
			Encrypted:    tls,
			IntPort:      port,
			StripHeaders: r.Form["header"],
		}

		vhost, pkgErr := confCheck(vhost, config)
		if pkgErr != nil {
			http.Error(w, pkgErr.Error(), http.StatusPreconditionFailed)
			log.Println(pkgErr.LogError(r))
			return
		}

		if vhost, pkgErr = confWriter(vhost); pkgErr != nil {
			http.Error(w, pkgErr.Error(), http.StatusInternalServerError)
			log.Println(pkgErr.LogError(r))
			return
		}

		if extErr := config.resTempl.Execute(w, []siteParams{vhost}); extErr != nil {
			http.Error(w, extErr.Error(), http.StatusInternalServerError)
			log.Println(extErr.Error())
			return
		}
		return
	}
}

// JSONHandler - creates and returns a Handler for JSON body requests
func JSONHandler(config HandlerConfig, l *log.Logger) http.HandlerFunc {

	var tStart, tEnd, tBody *template.Template

	for _, each := range config.resTempl.Templates() {
		switch each.Name() {
		case "start":
			tStart = each
		case "end":
			tEnd = each
		case "body":
			tBody = each
		}
	}

	if tStart == nil || tEnd == nil || tBody == nil {
		return InvalidHandler("bad template", http.StatusInternalServerError)
	}

	confWriter := confWrite(config)

	return func(w http.ResponseWriter, r *http.Request) {

		var emptyInterface interface{}
		type locSiteParams struct {
			ExtHost      string
			IntHost      string
			IntIP        string
			IntPort      int
			Encrypted    bool
			StripHeaders []string
			ErrorString  string
			Error        Err
		}

		tStart.Execute(w, emptyInterface)

		decoder := json.NewDecoder(r.Body)

		for decoder.More() {
			var v siteParams
			if err := decoder.Decode(&v); err != nil {
				continue
			}

			v, err := confCheck(v, config)
			if err == nil {
				v, err = confWriter(v)
			}

			var vPlus = struct {
				ExtHost      string
				IntHost      string
				IntIP        string
				IntPort      int
				Encrypted    bool
				StripHeaders []string
				Error        string
			}{
				ExtHost:      v.ExtHost,
				IntHost:      v.IntHost,
				IntIP:        v.IntIP,
				IntPort:      v.IntPort,
				Encrypted:    v.Encrypted,
				StripHeaders: v.StripHeaders,
			}

			if err != nil {
				log.Println(err.LogError(r))
				vPlus.Error = err.Error()
			}

			if err := tBody.Execute(w, vPlus); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				log.Println(err.Error())
				return
			}
		}
		tEnd.Execute(w, emptyInterface)
	}
}

// StaticHandler - creates and returns a Handler to simply respond with a static response to every request
func StaticHandler(config HandlerConfig, l *log.Logger) http.HandlerFunc {
	res, err := ioutil.ReadFile(config.resFile)
	if err != nil {
		log.Printf("bad static response file %s - %v", config.resFile, err)
		return InvalidHandler("no data", http.StatusInternalServerError)
	}

	return func(w http.ResponseWriter, r *http.Request) {
		if _, err := w.Write(res); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
}

func InvalidHandler(msg string, code int) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, msg, code)
	}
}
<|endoftext|>


<commit_before>package db

import (
	sq "github.com/Masterminds/squirrel"
)

//go:generate counterfeiter . ContainerRepository

type ContainerRepository interface {
	FindOrphanedContainers() ([]CreatingContainer, []CreatedContainer, []DestroyingContainer, error)
	DestroyFailedContainers() (int, error)
	FindDestroyingContainers(workerName string) ([]string, error)
	RemoveDestroyingContainers(workerName string, currentHandles []string) (int, error)
}

type containerRepository struct {
	conn Conn
}

func NewContainerRepository(conn Conn) ContainerRepository {
	return &containerRepository{
		conn: conn,
	}
}

func (repository *containerRepository) FindDestroyingContainers(workerName string) ([]string, error) {
	handles := []string{}

	query, args, err := psql.Select("handle").From("containers").
		Where(
			sq.And{
				sq.Eq{
					"state":       ContainerStateDestroying,
					"worker_name": workerName,
				},
				sq.NotEq{
					"discontinued": true,
				},
			},
		).ToSql()

	rows, err := repository.conn.Query(query, args...)
	if err != nil {
		return nil, err
	}
	defer Close(rows)

	for rows.Next() {
		var handle = "handle"
		columns := []interface{}{&handle}

		err = rows.Scan(columns...)
		if err != nil {
			return nil, err
		}
		handles = append(handles, handle)
	}

	return handles, nil
}

func (repository *containerRepository) RemoveDestroyingContainers(workerName string, handles []string) (int, error) {
	rows, err := psql.Delete("containers").
		Where(
			sq.And{
				sq.Eq{
					"worker_name": workerName,
				},
				sq.NotEq{
					"handle": handles,
				},
				sq.Eq{
					"state": ContainerStateDestroying,
				},
			},
		).RunWith(repository.conn).
		Exec()

	if err != nil {
		return 0, err
	}

	affected, err := rows.RowsAffected()
	if err != nil {
		return 0, err
	}

	return int(affected), nil
}

func (repository *containerRepository) FindOrphanedContainers() ([]CreatingContainer, []CreatedContainer, []DestroyingContainer, error) {
	query, args, err := selectContainers("c").
		LeftJoin("builds b ON b.id = c.build_id").
		LeftJoin("containers icc ON icc.id = c.image_check_container_id").
		LeftJoin("containers igc ON igc.id = c.image_get_container_id").
		Where(sq.Or{
			sq.Eq{
				"c.build_id":                                nil,
				"c.image_check_container_id":                nil,
				"c.image_get_container_id":                  nil,
				"c.worker_resource_config_check_session_id": nil,
			},
			sq.And{
				sq.NotEq{"c.build_id": nil},
				sq.Eq{"b.interceptible": false},
			},
			sq.And{
				sq.NotEq{"c.image_check_container_id": nil},
				sq.NotEq{"icc.state": ContainerStateCreating},
			},
			sq.And{
				sq.NotEq{"c.image_get_container_id": nil},
				sq.NotEq{"igc.state": ContainerStateCreating},
			},
		}).
		ToSql()
	if err != nil {
		return nil, nil, nil, err
	}

	rows, err := repository.conn.Query(query, args...)
	if err != nil {
		return nil, nil, nil, err
	}

	defer Close(rows)

	creatingContainers := []CreatingContainer{}
	createdContainers := []CreatedContainer{}
	destroyingContainers := []DestroyingContainer{}

	var (
		creatingContainer   CreatingContainer
		createdContainer    CreatedContainer
		destroyingContainer DestroyingContainer
	)

	for rows.Next() {
		creatingContainer, createdContainer, destroyingContainer, _, err = scanContainer(rows, repository.conn)
		if err != nil {
			return nil, nil, nil, err
		}

		if creatingContainer != nil {
			creatingContainers = append(creatingContainers, creatingContainer)
		}

		if createdContainer != nil {
			createdContainers = append(createdContainers, createdContainer)
		}

		if destroyingContainer != nil {
			destroyingContainers = append(destroyingContainers, destroyingContainer)
		}
	}

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

	return creatingContainers, createdContainers, destroyingContainers, nil
}

func selectContainers(asOptional ...string) sq.SelectBuilder {
	columns := []string{"id", "handle", "worker_name", "hijacked", "discontinued", "state"}
	columns = append(columns, containerMetadataColumns...)

	table := "containers"
	if len(asOptional) > 0 {
		as := asOptional[0]

		for i, c := range columns {
			columns[i] = as + "." + c
		}

		table += " " + as
	}

	return psql.Select(columns...).From(table)
}

func scanContainer(row sq.RowScanner, conn Conn) (CreatingContainer, CreatedContainer, DestroyingContainer, FailedContainer, error) {
	var (
		id             int
		handle         string
		workerName     string
		isDiscontinued bool
		isHijacked     bool
		state          string

		metadata ContainerMetadata
	)

	columns := []interface{}{&id, &handle, &workerName, &isHijacked, &isDiscontinued, &state}
	columns = append(columns, metadata.ScanTargets()...)

	err := row.Scan(columns...)
	if err != nil {
		return nil, nil, nil, nil, err
	}

	switch state {
	case ContainerStateCreating:
		return newCreatingContainer(
			id,
			handle,
			workerName,
			metadata,
			conn,
		), nil, nil, nil, nil
	case ContainerStateCreated:
		return nil, newCreatedContainer(
			id,
			handle,
			workerName,
			metadata,
			isHijacked,
			conn,
		), nil, nil, nil
	case ContainerStateDestroying:
		return nil, nil, newDestroyingContainer(
			id,
			handle,
			workerName,
			metadata,
			isDiscontinued,
			conn,
		), nil, nil
	case ContainerStateFailed:
		return nil, nil, nil, newFailedContainer(
			id,
			handle,
			workerName,
			metadata,
			conn,
		), nil
	}

	return nil, nil, nil, nil, nil
}

func (repository *containerRepository) DestroyFailedContainers() (int, error) {
	query, args, err := psql.Select("c.id").
		From("containers c").
		LeftJoin("builds b ON b.id = c.build_id").
		LeftJoin("containers icc ON icc.id = c.image_check_container_id").
		LeftJoin("containers igc ON igc.id = c.image_get_container_id").
		Where(sq.Eq{"c.state": ContainerStateFailed}).
		ToSql()
	if err != nil {
		return 0, err
	}

	result, err := sq.Delete("containers").
		Where("id IN ("+query+")", args...).
		RunWith(repository.conn).
		Exec()
	if err != nil {
		return 0, err
	}

	failedContainersLen, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return int(failedContainersLen), nil
}
<commit_msg>Simplify DestroyFailedContainers query<commit_after>package db

import (
	sq "github.com/Masterminds/squirrel"
)

//go:generate counterfeiter . ContainerRepository

type ContainerRepository interface {
	FindOrphanedContainers() ([]CreatingContainer, []CreatedContainer, []DestroyingContainer, error)
	DestroyFailedContainers() (int, error)
	FindDestroyingContainers(workerName string) ([]string, error)
	RemoveDestroyingContainers(workerName string, currentHandles []string) (int, error)
}

type containerRepository struct {
	conn Conn
}

func NewContainerRepository(conn Conn) ContainerRepository {
	return &containerRepository{
		conn: conn,
	}
}

func (repository *containerRepository) FindDestroyingContainers(workerName string) ([]string, error) {
	handles := []string{}

	query, args, err := psql.Select("handle").From("containers").
		Where(
			sq.And{
				sq.Eq{
					"state":       ContainerStateDestroying,
					"worker_name": workerName,
				},
				sq.NotEq{
					"discontinued": true,
				},
			},
		).ToSql()

	rows, err := repository.conn.Query(query, args...)
	if err != nil {
		return nil, err
	}
	defer Close(rows)

	for rows.Next() {
		var handle = "handle"
		columns := []interface{}{&handle}

		err = rows.Scan(columns...)
		if err != nil {
			return nil, err
		}
		handles = append(handles, handle)
	}

	return handles, nil
}

func (repository *containerRepository) RemoveDestroyingContainers(workerName string, handles []string) (int, error) {
	rows, err := psql.Delete("containers").
		Where(
			sq.And{
				sq.Eq{
					"worker_name": workerName,
				},
				sq.NotEq{
					"handle": handles,
				},
				sq.Eq{
					"state": ContainerStateDestroying,
				},
			},
		).RunWith(repository.conn).
		Exec()

	if err != nil {
		return 0, err
	}

	affected, err := rows.RowsAffected()
	if err != nil {
		return 0, err
	}

	return int(affected), nil
}

func (repository *containerRepository) FindOrphanedContainers() ([]CreatingContainer, []CreatedContainer, []DestroyingContainer, error) {
	query, args, err := selectContainers("c").
		LeftJoin("builds b ON b.id = c.build_id").
		LeftJoin("containers icc ON icc.id = c.image_check_container_id").
		LeftJoin("containers igc ON igc.id = c.image_get_container_id").
		Where(sq.Or{
			sq.Eq{
				"c.build_id":                                nil,
				"c.image_check_container_id":                nil,
				"c.image_get_container_id":                  nil,
				"c.worker_resource_config_check_session_id": nil,
			},
			sq.And{
				sq.NotEq{"c.build_id": nil},
				sq.Eq{"b.interceptible": false},
			},
			sq.And{
				sq.NotEq{"c.image_check_container_id": nil},
				sq.NotEq{"icc.state": ContainerStateCreating},
			},
			sq.And{
				sq.NotEq{"c.image_get_container_id": nil},
				sq.NotEq{"igc.state": ContainerStateCreating},
			},
		}).
		ToSql()
	if err != nil {
		return nil, nil, nil, err
	}

	rows, err := repository.conn.Query(query, args...)
	if err != nil {
		return nil, nil, nil, err
	}

	defer Close(rows)

	creatingContainers := []CreatingContainer{}
	createdContainers := []CreatedContainer{}
	destroyingContainers := []DestroyingContainer{}

	var (
		creatingContainer   CreatingContainer
		createdContainer    CreatedContainer
		destroyingContainer DestroyingContainer
	)

	for rows.Next() {
		creatingContainer, createdContainer, destroyingContainer, _, err = scanContainer(rows, repository.conn)
		if err != nil {
			return nil, nil, nil, err
		}

		if creatingContainer != nil {
			creatingContainers = append(creatingContainers, creatingContainer)
		}

		if createdContainer != nil {
			createdContainers = append(createdContainers, createdContainer)
		}

		if destroyingContainer != nil {
			destroyingContainers = append(destroyingContainers, destroyingContainer)
		}
	}

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

	return creatingContainers, createdContainers, destroyingContainers, nil
}

func selectContainers(asOptional ...string) sq.SelectBuilder {
	columns := []string{"id", "handle", "worker_name", "hijacked", "discontinued", "state"}
	columns = append(columns, containerMetadataColumns...)

	table := "containers"
	if len(asOptional) > 0 {
		as := asOptional[0]

		for i, c := range columns {
			columns[i] = as + "." + c
		}

		table += " " + as
	}

	return psql.Select(columns...).From(table)
}

func scanContainer(row sq.RowScanner, conn Conn) (CreatingContainer, CreatedContainer, DestroyingContainer, FailedContainer, error) {
	var (
		id             int
		handle         string
		workerName     string
		isDiscontinued bool
		isHijacked     bool
		state          string

		metadata ContainerMetadata
	)

	columns := []interface{}{&id, &handle, &workerName, &isHijacked, &isDiscontinued, &state}
	columns = append(columns, metadata.ScanTargets()...)

	err := row.Scan(columns...)
	if err != nil {
		return nil, nil, nil, nil, err
	}

	switch state {
	case ContainerStateCreating:
		return newCreatingContainer(
			id,
			handle,
			workerName,
			metadata,
			conn,
		), nil, nil, nil, nil
	case ContainerStateCreated:
		return nil, newCreatedContainer(
			id,
			handle,
			workerName,
			metadata,
			isHijacked,
			conn,
		), nil, nil, nil
	case ContainerStateDestroying:
		return nil, nil, newDestroyingContainer(
			id,
			handle,
			workerName,
			metadata,
			isDiscontinued,
			conn,
		), nil, nil
	case ContainerStateFailed:
		return nil, nil, nil, newFailedContainer(
			id,
			handle,
			workerName,
			metadata,
			conn,
		), nil
	}

	return nil, nil, nil, nil, nil
}

func (repository *containerRepository) DestroyFailedContainers() (int, error) {
	result, err := sq.Delete("containers").
		Where(sq.Eq{"containers.state": ContainerStateFailed}).
		PlaceholderFormat(sq.Dollar).
		RunWith(repository.conn).
		Exec()
	if err != nil {
		return 0, err
	}

	failedContainersLen, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return int(failedContainersLen), nil
}
<|endoftext|>


<commit_before><commit_msg>more fixes for worker process<commit_after><|endoftext|>