<commit_before>package weed_server

import (
	"fmt"
	"os"
	"time"

	"github.com/chrislusf/seaweedfs/weed/operation"

	"google.golang.org/grpc"

	"github.com/chrislusf/seaweedfs/weed/pb"
	"github.com/chrislusf/seaweedfs/weed/security"
	"github.com/chrislusf/seaweedfs/weed/storage/backend"
	"github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"

	"golang.org/x/net/context"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/util"
)

func (vs *VolumeServer) GetMaster() pb.ServerAddress {
	return vs.currentMaster
}

func (vs *VolumeServer) checkWithMaster() (err error) {
	for {
		for _, master := range vs.SeedMasterNodes {
			err = operation.WithMasterServerClient(false, master, vs.grpcDialOption, func(masterClient master_pb.SeaweedClient) error {
				resp, err := masterClient.GetMasterConfiguration(context.Background(), &master_pb.GetMasterConfigurationRequest{})
				if err != nil {
					return fmt.Errorf("get master %s configuration: %v", master, err)
				}
				vs.metricsAddress, vs.metricsIntervalSec = resp.MetricsAddress, int(resp.MetricsIntervalSeconds)
				backend.LoadFromPbStorageBackends(resp.StorageBackends)
				return nil
			})
			if err == nil {
				return
			} else {
				glog.V(0).Infof("checkWithMaster %s: %v", master, err)
			}
		}
		time.Sleep(1790 * time.Millisecond)
	}
}

func (vs *VolumeServer) heartbeat() {

	glog.V(0).Infof("Volume server start with seed master nodes: %v", vs.SeedMasterNodes)
	vs.store.SetDataCenter(vs.dataCenter)
	vs.store.SetRack(vs.rack)

	grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.volume")

	var err error
	var newLeader pb.ServerAddress
	for vs.isHeartbeating {
		for _, master := range vs.SeedMasterNodes {
			if newLeader != "" {
				// the new leader may actually is the same master
				// need to wait a bit before adding itself
				time.Sleep(3 * time.Second)
				master = newLeader
			}
			vs.store.MasterAddress = master
			newLeader, err = vs.doHeartbeat(master, grpcDialOption, time.Duration(vs.pulseSeconds)*time.Second)
			if err != nil {
				glog.V(0).Infof("heartbeat error: %v", err)
				time.Sleep(time.Duration(vs.pulseSeconds) * time.Second)
				newLeader = ""
				vs.store.MasterAddress = ""
			}
			if !vs.isHeartbeating {
				break
			}
		}
	}
}

func (vs *VolumeServer) StopHeartbeat() (isAlreadyStopping bool) {
	if !vs.isHeartbeating {
		return true
	}
	vs.isHeartbeating = false
	close(vs.stopChan)
	return false
}

func (vs *VolumeServer) doHeartbeat(masterAddress pb.ServerAddress, grpcDialOption grpc.DialOption, sleepInterval time.Duration) (newLeader pb.ServerAddress, err error) {

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	grpcConection, err := pb.GrpcDial(ctx, masterAddress.ToGrpcAddress(), grpcDialOption)
	if err != nil {
		return "", fmt.Errorf("fail to dial %s : %v", masterAddress, err)
	}
	defer grpcConection.Close()

	client := master_pb.NewSeaweedClient(grpcConection)
	stream, err := client.SendHeartbeat(ctx)
	if err != nil {
		glog.V(0).Infof("SendHeartbeat to %s: %v", masterAddress, err)
		return "", err
	}
	glog.V(0).Infof("Heartbeat to: %v", masterAddress)
	vs.currentMaster = masterAddress

	doneChan := make(chan error, 1)

	go func() {
		for {
			in, err := stream.Recv()
			if err != nil {
				doneChan <- err
				return
			}
			if len(in.DuplicatedUuids) > 0 {
				var duplictedDir []string
				for _, loc := range vs.store.Locations {
					for _, uuid := range in.DuplicatedUuids {
						if uuid == loc.DirectoryUuid {
							duplictedDir = append(duplictedDir, loc.Directory)
						}
					}
				}
				glog.Errorf("Shut down Volume Server due to duplicated volume directories: %v", duplictedDir)
				os.Exit(1)
			}
			if in.GetVolumeSizeLimit() != 0 && vs.store.GetVolumeSizeLimit() != in.GetVolumeSizeLimit() {
				vs.store.SetVolumeSizeLimit(in.GetVolumeSizeLimit())
				if vs.store.MaybeAdjustVolumeMax() {
					if err = stream.Send(vs.store.CollectHeartbeat()); err != nil {
						glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", vs.currentMaster, err)
						return
					}
				}
			}
			if in.GetLeader() != "" && string(vs.currentMaster) != in.GetLeader() {
				glog.V(0).Infof("Volume Server found a new master newLeader: %v instead of %v", in.GetLeader(), vs.currentMaster)
				newLeader = pb.ServerAddress(in.GetLeader())
				doneChan <- nil
				return
			}
		}
	}()

	if err = stream.Send(vs.store.CollectHeartbeat()); err != nil {
		glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
		return "", err
	}

	if err = stream.Send(vs.store.CollectErasureCodingHeartbeat()); err != nil {
		glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
		return "", err
	}

	volumeTickChan := time.Tick(sleepInterval)
	ecShardTickChan := time.Tick(17 * sleepInterval)

	for {
		select {
		case volumeMessage := <-vs.store.NewVolumesChan:
			deltaBeat := &master_pb.Heartbeat{
				NewVolumes: []*master_pb.VolumeShortInformationMessage{
					&volumeMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d adds volume %d", vs.store.Ip, vs.store.Port, volumeMessage.Id)
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case ecShardMessage := <-vs.store.NewEcShardsChan:
			deltaBeat := &master_pb.Heartbeat{
				NewEcShards: []*master_pb.VolumeEcShardInformationMessage{
					&ecShardMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d adds ec shard %d:%d", vs.store.Ip, vs.store.Port, ecShardMessage.Id,
				erasure_coding.ShardBits(ecShardMessage.EcIndexBits).ShardIds())
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case volumeMessage := <-vs.store.DeletedVolumesChan:
			deltaBeat := &master_pb.Heartbeat{
				DeletedVolumes: []*master_pb.VolumeShortInformationMessage{
					&volumeMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d deletes volume %d", vs.store.Ip, vs.store.Port, volumeMessage.Id)
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case ecShardMessage := <-vs.store.DeletedEcShardsChan:
			deltaBeat := &master_pb.Heartbeat{
				DeletedEcShards: []*master_pb.VolumeEcShardInformationMessage{
					&ecShardMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d deletes ec shard %d:%d", vs.store.Ip, vs.store.Port, ecShardMessage.Id,
				erasure_coding.ShardBits(ecShardMessage.EcIndexBits).ShardIds())
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case <-volumeTickChan:
			glog.V(4).Infof("volume server %s:%d heartbeat", vs.store.Ip, vs.store.Port)
			vs.store.MaybeAdjustVolumeMax()
			if err = stream.Send(vs.store.CollectHeartbeat()); err != nil {
				glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
				return "", err
			}
		case <-ecShardTickChan:
			glog.V(4).Infof("volume server %s:%d ec heartbeat", vs.store.Ip, vs.store.Port)
			if err = stream.Send(vs.store.CollectErasureCodingHeartbeat()); err != nil {
				glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
				return "", err
			}
		case err = <-doneChan:
			return
		case <-vs.stopChan:
			var volumeMessages []*master_pb.VolumeInformationMessage
			emptyBeat := &master_pb.Heartbeat{
				Ip:           vs.store.Ip,
				Port:         uint32(vs.store.Port),
				PublicUrl:    vs.store.PublicUrl,
				MaxFileKey:   uint64(0),
				DataCenter:   vs.store.GetDataCenter(),
				Rack:         vs.store.GetRack(),
				Volumes:      volumeMessages,
				HasNoVolumes: len(volumeMessages) == 0,
			}
			glog.V(1).Infof("volume server %s:%d stops and deletes all volumes", vs.store.Ip, vs.store.Port)
			if err = stream.Send(emptyBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
			return
		}
	}
}
<commit_msg>fix typo<commit_after>package weed_server

import (
	"fmt"
	"os"
	"time"

	"github.com/chrislusf/seaweedfs/weed/operation"

	"google.golang.org/grpc"

	"github.com/chrislusf/seaweedfs/weed/pb"
	"github.com/chrislusf/seaweedfs/weed/security"
	"github.com/chrislusf/seaweedfs/weed/storage/backend"
	"github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"

	"golang.org/x/net/context"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/util"
)

func (vs *VolumeServer) GetMaster() pb.ServerAddress {
	return vs.currentMaster
}

func (vs *VolumeServer) checkWithMaster() (err error) {
	for {
		for _, master := range vs.SeedMasterNodes {
			err = operation.WithMasterServerClient(false, master, vs.grpcDialOption, func(masterClient master_pb.SeaweedClient) error {
				resp, err := masterClient.GetMasterConfiguration(context.Background(), &master_pb.GetMasterConfigurationRequest{})
				if err != nil {
					return fmt.Errorf("get master %s configuration: %v", master, err)
				}
				vs.metricsAddress, vs.metricsIntervalSec = resp.MetricsAddress, int(resp.MetricsIntervalSeconds)
				backend.LoadFromPbStorageBackends(resp.StorageBackends)
				return nil
			})
			if err == nil {
				return
			} else {
				glog.V(0).Infof("checkWithMaster %s: %v", master, err)
			}
		}
		time.Sleep(1790 * time.Millisecond)
	}
}

func (vs *VolumeServer) heartbeat() {

	glog.V(0).Infof("Volume server start with seed master nodes: %v", vs.SeedMasterNodes)
	vs.store.SetDataCenter(vs.dataCenter)
	vs.store.SetRack(vs.rack)

	grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.volume")

	var err error
	var newLeader pb.ServerAddress
	for vs.isHeartbeating {
		for _, master := range vs.SeedMasterNodes {
			if newLeader != "" {
				// the new leader may actually is the same master
				// need to wait a bit before adding itself
				time.Sleep(3 * time.Second)
				master = newLeader
			}
			vs.store.MasterAddress = master
			newLeader, err = vs.doHeartbeat(master, grpcDialOption, time.Duration(vs.pulseSeconds)*time.Second)
			if err != nil {
				glog.V(0).Infof("heartbeat error: %v", err)
				time.Sleep(time.Duration(vs.pulseSeconds) * time.Second)
				newLeader = ""
				vs.store.MasterAddress = ""
			}
			if !vs.isHeartbeating {
				break
			}
		}
	}
}

func (vs *VolumeServer) StopHeartbeat() (isAlreadyStopping bool) {
	if !vs.isHeartbeating {
		return true
	}
	vs.isHeartbeating = false
	close(vs.stopChan)
	return false
}

func (vs *VolumeServer) doHeartbeat(masterAddress pb.ServerAddress, grpcDialOption grpc.DialOption, sleepInterval time.Duration) (newLeader pb.ServerAddress, err error) {

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	grpcConection, err := pb.GrpcDial(ctx, masterAddress.ToGrpcAddress(), grpcDialOption)
	if err != nil {
		return "", fmt.Errorf("fail to dial %s : %v", masterAddress, err)
	}
	defer grpcConection.Close()

	client := master_pb.NewSeaweedClient(grpcConection)
	stream, err := client.SendHeartbeat(ctx)
	if err != nil {
		glog.V(0).Infof("SendHeartbeat to %s: %v", masterAddress, err)
		return "", err
	}
	glog.V(0).Infof("Heartbeat to: %v", masterAddress)
	vs.currentMaster = masterAddress

	doneChan := make(chan error, 1)

	go func() {
		for {
			in, err := stream.Recv()
			if err != nil {
				doneChan <- err
				return
			}
			if len(in.DuplicatedUuids) > 0 {
				var duplicateDir []string
				for _, loc := range vs.store.Locations {
					for _, uuid := range in.DuplicatedUuids {
						if uuid == loc.DirectoryUuid {
							duplicateDir = append(duplicateDir, loc.Directory)
						}
					}
				}
				glog.Errorf("Shut down Volume Server due to duplicate volume directories: %v", duplicateDir)
				os.Exit(1)
			}
			if in.GetVolumeSizeLimit() != 0 && vs.store.GetVolumeSizeLimit() != in.GetVolumeSizeLimit() {
				vs.store.SetVolumeSizeLimit(in.GetVolumeSizeLimit())
				if vs.store.MaybeAdjustVolumeMax() {
					if err = stream.Send(vs.store.CollectHeartbeat()); err != nil {
						glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", vs.currentMaster, err)
						return
					}
				}
			}
			if in.GetLeader() != "" && string(vs.currentMaster) != in.GetLeader() {
				glog.V(0).Infof("Volume Server found a new master newLeader: %v instead of %v", in.GetLeader(), vs.currentMaster)
				newLeader = pb.ServerAddress(in.GetLeader())
				doneChan <- nil
				return
			}
		}
	}()

	if err = stream.Send(vs.store.CollectHeartbeat()); err != nil {
		glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
		return "", err
	}

	if err = stream.Send(vs.store.CollectErasureCodingHeartbeat()); err != nil {
		glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
		return "", err
	}

	volumeTickChan := time.Tick(sleepInterval)
	ecShardTickChan := time.Tick(17 * sleepInterval)

	for {
		select {
		case volumeMessage := <-vs.store.NewVolumesChan:
			deltaBeat := &master_pb.Heartbeat{
				NewVolumes: []*master_pb.VolumeShortInformationMessage{
					&volumeMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d adds volume %d", vs.store.Ip, vs.store.Port, volumeMessage.Id)
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case ecShardMessage := <-vs.store.NewEcShardsChan:
			deltaBeat := &master_pb.Heartbeat{
				NewEcShards: []*master_pb.VolumeEcShardInformationMessage{
					&ecShardMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d adds ec shard %d:%d", vs.store.Ip, vs.store.Port, ecShardMessage.Id,
				erasure_coding.ShardBits(ecShardMessage.EcIndexBits).ShardIds())
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case volumeMessage := <-vs.store.DeletedVolumesChan:
			deltaBeat := &master_pb.Heartbeat{
				DeletedVolumes: []*master_pb.VolumeShortInformationMessage{
					&volumeMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d deletes volume %d", vs.store.Ip, vs.store.Port, volumeMessage.Id)
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case ecShardMessage := <-vs.store.DeletedEcShardsChan:
			deltaBeat := &master_pb.Heartbeat{
				DeletedEcShards: []*master_pb.VolumeEcShardInformationMessage{
					&ecShardMessage,
				},
			}
			glog.V(0).Infof("volume server %s:%d deletes ec shard %d:%d", vs.store.Ip, vs.store.Port, ecShardMessage.Id,
				erasure_coding.ShardBits(ecShardMessage.EcIndexBits).ShardIds())
			if err = stream.Send(deltaBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
		case <-volumeTickChan:
			glog.V(4).Infof("volume server %s:%d heartbeat", vs.store.Ip, vs.store.Port)
			vs.store.MaybeAdjustVolumeMax()
			if err = stream.Send(vs.store.CollectHeartbeat()); err != nil {
				glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
				return "", err
			}
		case <-ecShardTickChan:
			glog.V(4).Infof("volume server %s:%d ec heartbeat", vs.store.Ip, vs.store.Port)
			if err = stream.Send(vs.store.CollectErasureCodingHeartbeat()); err != nil {
				glog.V(0).Infof("Volume Server Failed to talk with master %s: %v", masterAddress, err)
				return "", err
			}
		case err = <-doneChan:
			return
		case <-vs.stopChan:
			var volumeMessages []*master_pb.VolumeInformationMessage
			emptyBeat := &master_pb.Heartbeat{
				Ip:           vs.store.Ip,
				Port:         uint32(vs.store.Port),
				PublicUrl:    vs.store.PublicUrl,
				MaxFileKey:   uint64(0),
				DataCenter:   vs.store.GetDataCenter(),
				Rack:         vs.store.GetRack(),
				Volumes:      volumeMessages,
				HasNoVolumes: len(volumeMessages) == 0,
			}
			glog.V(1).Infof("volume server %s:%d stops and deletes all volumes", vs.store.Ip, vs.store.Port)
			if err = stream.Send(emptyBeat); err != nil {
				glog.V(0).Infof("Volume Server Failed to update to master %s: %v", masterAddress, err)
				return "", err
			}
			return
		}
	}
}
<|endoftext|>


<commit_before>// Alexandria
//
// Copyright (C) 2015,2016  Colin Benner
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"os"
	"runtime/pprof"
	"strings"

	flag "github.com/ogier/pflag"

	. "github.com/yzhs/alexandria-go"
)

func printStats() {
	stats := ComputeStatistics()
	n := stats.Num()
	size := float32(stats.Size()) / 1024.0
	fmt.Printf("The library contains %v scrolls with a total size of %.1f kiB.\n", n, size)
}

func main() {
	var index, profile, stats, version bool
	flag.BoolVarP(&index, "index", "i", false, "\tUpdate the index")
	flag.BoolVarP(&stats, "stats", "S", false, "\tPrint some statistics")
	flag.BoolVarP(&version, "version", "v", false, "\tShow version")
	flag.BoolVar(&profile, "profile", false, "\tEnable profiler")
	flag.Parse()

	InitConfig()

	if profile {
		f, err := os.Create("alexandria.prof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	switch {
	case index:
		GenerateIndex()
	case stats:
		printStats()
	case version:
		fmt.Println(NAME, VERSION)
	default:
		results, err := FindScrolls(strings.Join(os.Args[1:], " "))
		if err != nil {
			panic(err)
		}
		fmt.Printf("There are %d matching scrolls.\n", len(results.Ids))
		for _, id := range results.Ids {
			fmt.Println("file://" + Config.CacheDirectory + string(id) + ".png")
		}
	}
}
<commit_msg>Make sure that the cli compiles all scrolls<commit_after>// Alexandria
//
// Copyright (C) 2015,2016  Colin Benner
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"os"
	"runtime/pprof"
	"strings"

	flag "github.com/ogier/pflag"

	. "github.com/yzhs/alexandria-go"
)

func printStats() {
	stats := ComputeStatistics()
	n := stats.Num()
	size := float32(stats.Size()) / 1024.0
	fmt.Printf("The library contains %v scrolls with a total size of %.1f kiB.\n", n, size)
}

func main() {
	var index, profile, stats, version bool
	flag.BoolVarP(&index, "index", "i", false, "\tUpdate the index")
	flag.BoolVarP(&stats, "stats", "S", false, "\tPrint some statistics")
	flag.BoolVarP(&version, "version", "v", false, "\tShow version")
	flag.BoolVar(&profile, "profile", false, "\tEnable profiler")
	flag.Parse()

	InitConfig()
	Config.MaxResults = 1e9

	if profile {
		f, err := os.Create("alexandria.prof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	switch {
	case index:
		GenerateIndex()
	case stats:
		printStats()
	case version:
		fmt.Println(NAME, VERSION)
	default:
		results, err := FindScrolls(strings.Join(os.Args[1:], " "))
		if err != nil {
			panic(err)
		}
		fmt.Printf("There are %d matching scrolls.\n", len(results.Ids))
		for _, id := range results.Ids {
			fmt.Println("file://" + Config.CacheDirectory + string(id) + ".png")
		}
	}
}
<|endoftext|>


<commit_before>package handlers

import (
	"net/http"
	"time"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/user"

	"github.com/icco/natnatnat/models"
	"github.com/pilu/traffic"
)

type ArchiveData struct {
	Years   map[int]Year
	Posts   *[]models.Entry
	IsAdmin bool
}

// TODO(icco): Rewrite to fix map iteration problems.
type Year map[time.Month]Month
type Month []Day
type Day []int64

var months = [12]time.Month{
	time.January,
	time.February,
	time.March,
	time.April,
	time.May,
	time.June,
	time.July,
	time.August,
	time.September,
	time.October,
	time.November,
	time.December,
}

func ArchiveHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)

	entries, err := models.AllPosts(c)
	if err != nil {
		log.Errorf(c, err.Error())
		http.Error(w, err.Error(), 500)
		return
	}
	log.Infof(c, "Retrieved data: %d.", len(*entries))

	years := make(map[int]Year)

	oldest := (*entries)[len(*entries)-1].Datetime
	newest := (*entries)[0].Datetime

	log.Infof(c, "Oldest: %v, Newest: %v", oldest, newest)

	// for year := oldest.Year(); year <= newest.Year(); year += 1 {
	// 	years[year] = make(Year)
	// 	log.Infof(c, "Adding %d.", year)
	// 	for _, month := range months {
	// 		if year < newest.Year() || (year == newest.Year() && month <= newest.Month()) {
	// 			years[year][month] = make([]Day, daysIn(month, year))
	// 			log.Debugf(c, "Adding %d/%d - %d days.", year, month, len(years[year][month]))
	// 		}
	// 	}
	// }

	q := models.ArchivePageQuery()
	t := q.Run(c)
	for {
		var p models.Entry
		_, err := t.Next(&p)
		if err == datastore.Done {
			break // No further entities match the query.
		}

		if err != nil {
			log.Errorf(c, "Error fetching next Entry: %v", err)
			break
		}

		year := p.Datetime.Year()
		month := p.Datetime.Month()
		day := p.Datetime.Day()
		log.Infof(c, "Trying post id %d", p.Id)

		if years[year] == nil {
			years[year] = make(Year)
			log.Errorf(c, "%d isn't a valid year.", year)
		}

		if years[year][month] == nil {
			log.Errorf(c, "%d/%d isn't a valid month.", year, month)
			years[year][month] = make([]Day, daysIn(month, year))
		}

		if years[year][month][day] == nil {
			log.Infof(c, "Making %d/%d/%d", year, month, day)
			years[year][month][day] = make(Day, 0)
		}

		log.Infof(c, "Appending %d/%d/%d: %+v", year, month, day, years[year][month][day])
		years[year][month][day] = append(years[year][month][day], p.Id)
	}
	log.Infof(c, "Added posts.")

	data := &ArchiveData{Years: years, IsAdmin: user.IsAdmin(c), Posts: entries}
	w.Render("archive", data)
}

// daysIn returns the number of days in a month for a given year.
func daysIn(m time.Month, year int) int {
	// This is equivalent to time.daysIn(m, year).
	return time.Date(year, m+1, 0, 0, 0, 0, 0, time.UTC).Day()
}
<commit_msg>no idea still<commit_after>package handlers

import (
	"net/http"
	"time"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/user"

	"github.com/icco/natnatnat/models"
	"github.com/pilu/traffic"
)

type ArchiveData struct {
	Years   *map[int]Year
	Posts   *[]models.Entry
	IsAdmin bool
}

// TODO(icco): Rewrite to fix map iteration problems.
type Year map[time.Month]Month
type Month []Day
type Day []int64

var months = [12]time.Month{
	time.January,
	time.February,
	time.March,
	time.April,
	time.May,
	time.June,
	time.July,
	time.August,
	time.September,
	time.October,
	time.November,
	time.December,
}

func ArchiveHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)

	entries, err := models.AllPosts(c)
	if err != nil {
		log.Errorf(c, err.Error())
		http.Error(w, err.Error(), 500)
		return
	}
	log.Infof(c, "Retrieved data: %d.", len(*entries))

	years := make(map[int]Year)

	oldest := (*entries)[len(*entries)-1].Datetime
	newest := (*entries)[0].Datetime

	log.Infof(c, "Oldest: %v, Newest: %v", oldest, newest)

	// for year := oldest.Year(); year <= newest.Year(); year += 1 {
	// 	years[year] = make(Year)
	// 	log.Infof(c, "Adding %d.", year)
	// 	for _, month := range months {
	// 		if year < newest.Year() || (year == newest.Year() && month <= newest.Month()) {
	// 			years[year][month] = make([]Day, daysIn(month, year))
	// 			log.Debugf(c, "Adding %d/%d - %d days.", year, month, len(years[year][month]))
	// 		}
	// 	}
	// }

	q := models.ArchivePageQuery()
	t := q.Run(c)
	for {
		var p models.Entry
		_, err := t.Next(&p)
		if err == datastore.Done {
			break // No further entities match the query.
		}

		if err != nil {
			log.Errorf(c, "Error fetching next Entry: %v", err)
			break
		}

		year := p.Datetime.Year()
		month := p.Datetime.Month()
		day := p.Datetime.Day()
		log.Infof(c, "Trying post id %d", p.Id)

		if years[year] == nil {
			years[year] = make(Year)
			log.Errorf(c, "%d isn't a valid year.", year)
		}

		if years[year][month] == nil {
			log.Errorf(c, "%d/%d isn't a valid month.", year, month)
			years[year][month] = make([]Day, daysIn(month, year))
		}

		if years[year][month][day] == nil {
			log.Infof(c, "Making %d/%d/%d", year, month, day)
			years[year][month][day] = make(Day, 0)
		}

		// log.Infof(c, "Appending %d/%d/%d: %+v", year, month, day, years[year][month][day])
		years[year][month][day] = append(years[year][month][day], p.Id)
	}
	log.Infof(c, "Added posts.")

	data := &ArchiveData{Years: &years, IsAdmin: user.IsAdmin(c), Posts: &[]models.Entry{}}
	w.Render("archive", data)
}

// daysIn returns the number of days in a month for a given year.
func daysIn(m time.Month, year int) int {
	// This is equivalent to time.daysIn(m, year).
	return time.Date(year, m+1, 0, 0, 0, 0, 0, time.UTC).Day()
}
<|endoftext|>


<commit_before>package console

import (
	"fmt"
	"strings"

	"github.com/jasonsoft/log"
)

// Console is an instance of the console logger
type Console struct {
}

func New() *Console {
	return &Console{}
}

// Run starts the logger consuming on the returned channed
func (c *Console) Run() chan<- *log.Entry {
	// in a big high traffic app, set a higher buffer
	ch := make(chan *log.Entry, 3000)

	go func(entries <-chan *log.Entry) {
		var e *log.Entry
		for e = range entries {
			msg := FormatFunc(e)
			println(msg)
			e.Consumed()
		}
	}(ch)

	return ch
}

func FormatFunc(entry *log.Entry) string {
	time := entry.Timestamp.Format("2006-01-02T15:04:05.999Z")
	level := entry.Level.String()

	strFields := ""
	for key, value := range entry.Fields {

		switch value.(type) {
		case string:
			strFields += value.(string)
		default:
			strFields += fmt.Sprintf("%#v ", value)
		}

		strFields += fmt.Sprintf("%s=%s ", key, value)
	}

	var result string
	if entry.Line > 0 && len(entry.File) > 0 {
		result = fmt.Sprintf("time=\"%s\" level=%s msg=\"%s\" line=\"%d\" file=\"%s\"  ", time, level, entry.Message, entry.Line, entry.File)

	} else {
		result = fmt.Sprintf("time=\"%s\" level=%s msg=\"%s\" ", time, level, entry.Message)

	}

	if len(strFields) > 0 {
		result += strings.TrimSpace(strFields)
	}

	return result
}
<commit_msg><commit_after>package console

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/jasonsoft/log"
)

const (
	base10 = 10
)

// Console is an instance of the console logger
type Console struct {
}

func New() *Console {
	return &Console{}
}

// Run starts the logger consuming on the returned channed
func (c *Console) Run() chan<- *log.Entry {
	// in a big high traffic app, set a higher buffer
	ch := make(chan *log.Entry, 3000)

	go func(entries <-chan *log.Entry) {
		var e *log.Entry
		for e = range entries {
			msg := FormatFunc(e)
			println(msg)
			e.Consumed()
		}
	}(ch)

	return ch
}

func FormatFunc(entry *log.Entry) string {
	time := entry.Timestamp.Format("2006-01-02T15:04:05.999Z")
	level := entry.Level.String()

	builder := strings.Builder{}

	if entry.Line > 0 && len(entry.File) > 0 {
		builder.WriteString(fmt.Sprintf("time=\"%s\" level=%s msg=\"%s\" line=\"%d\" file=\"%s\" ", time, level, entry.Message, entry.Line, entry.File))
	} else {
		builder.WriteString(fmt.Sprintf("time=\"%s\" level=%s msg=\"%s\" ", time, level, entry.Message))
	}

	// custom fields to string
	var b []byte
	for key, value := range entry.Fields {
		b = append(b, key...)
		b = append(b, "="...)
		switch t := value.(type) {
		case string:
			b = append(b, t...)
		case int:
			b = strconv.AppendInt(b, int64(t), base10)
		case int8:
			b = strconv.AppendInt(b, int64(t), base10)
		case int16:
			b = strconv.AppendInt(b, int64(t), base10)
		case int32:
			b = strconv.AppendInt(b, int64(t), base10)
		case int64:
			b = strconv.AppendInt(b, t, base10)
		case uint:
			b = strconv.AppendUint(b, uint64(t), base10)
		case uint8:
			b = strconv.AppendUint(b, uint64(t), base10)
		case uint16:
			b = strconv.AppendUint(b, uint64(t), base10)
		case uint32:
			b = strconv.AppendUint(b, uint64(t), base10)
		case uint64:
			b = strconv.AppendUint(b, t, base10)
		case float32:
			b = strconv.AppendFloat(b, float64(t), 'f', -1, 32)
		case float64:
			b = strconv.AppendFloat(b, t, 'f', -1, 64)
		case bool:
			b = strconv.AppendBool(b, t)
		default:
			b = append(b, fmt.Sprintf("%#v", value)...)
		}
		builder.Write(b)
	}

	return builder.String()
}
<|endoftext|>


<commit_before>package topgun_test

import (
	"bytes"
	"fmt"
	"time"

	gclient "code.cloudfoundry.org/garden/client"
	gconn "code.cloudfoundry.org/garden/client/connection"
	_ "github.com/lib/pq"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("[#129726125] Hijacked containers", func() {
	var (
		gClient gclient.Client

		containerHandle string
	)

	BeforeEach(func() {
		Deploy("deployments/single-vm.yml")

		gClient = gclient.New(gconn.New("tcp", fmt.Sprintf("%s:7777", atcIP)))
	})

	getContainer := func() (h hijackedContainerResult) {
		containers := flyTable("containers")

		for _, c := range containers {
			if c["build #"] == "1" {
				containerHandle = c["handle"]
				h.flyContainerExists = true

				break
			}
		}

		_, err := gClient.Lookup(containerHandle)
		if err == nil {
			h.gardenContainerExists = true
		}

		return
	}

	It("does not delete hijacked build containers from the database, and sets a 5 minute TTL on the container in garden", func() {
		By("setting the pipeline that has a build")
		fly("set-pipeline", "-n", "-c", "pipelines/task-waiting.yml", "-p", "hijacked-containers-test")

		By("triggering the build")
		fly("unpause-pipeline", "-p", "hijacked-containers-test")
		buildSession := spawnFly("trigger-job", "-w", "-j", "hijacked-containers-test/simple-job")
		Eventually(buildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))

		By("hijacking into the build container")
		hijackSession := spawnFlyInteractive(
			bytes.NewBufferString("3\n"),
			"hijack",
			"-j", "hijacked-containers-test/simple-job",
			"-b", "1",
			"-s", "simple-task",
			"touch", "/tmp/stop-waiting",
			"and", "sleep", "3600",
		)

		By("triggering a new build")
		<-buildSession.Exited
		buildSession = spawnFly("trigger-job", "-w", "-j", "hijacked-containers-test/simple-job")
		Eventually(buildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))
		<-spawnFlyInteractive(
			bytes.NewBufferString("3\n"),
			"hijack",
			"-j", "hijacked-containers-test/simple-job",
			"-b", "2",
			"-s", "simple-task",
			"touch", "/tmp/stop-waiting",
		).Exited

		By("verifying the hijacked container exists via fly and Garden")
		Consistently(getContainer, 2*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{true, true}))

		By("unhijacking and seeing the container removed via fly/Garden after 5 minutes")
		hijackSession.Terminate()
		<-hijackSession.Exited

		Eventually(getContainer, 10*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{false, false}))
	})

	It("does not delete hijacked one-off build containers from the database, and sets a 5 minute TTL on the container in garden", func() {
		By("triggering a one-off build")
		buildSession := spawnFly("execute", "-c", "tasks/wait.yml")
		Eventually(buildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))

		By("hijacking into the build container")
		hijackSession := spawnFlyInteractive(
			bytes.NewBufferString("3\n"),
			"hijack",
			"-b", "1",
			"touch", "/tmp/stop-waiting",
			"and", "sleep", "3600",
		)

		By("waiting for build to finish")
		<-buildSession.Exited

		By("verifying the hijacked container exists via fly and Garden")
		Consistently(getContainer, 2*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{true, true}))

		By("unhijacking and seeing the container removed via fly/Garden after 5 minutes")
		hijackSession.Terminate()
		<-hijackSession.Exited

		Eventually(getContainer, 10*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{false, false}))
	})
})

type hijackedContainerResult struct {
	flyContainerExists    bool
	gardenContainerExists bool
}
<commit_msg>add test for hijacked resource containers<commit_after>package topgun_test

import (
	"bytes"
	"fmt"
	"time"

	gclient "code.cloudfoundry.org/garden/client"
	gconn "code.cloudfoundry.org/garden/client/connection"
	_ "github.com/lib/pq"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("[#129726125] Hijacked containers", func() {
	var (
		gClient gclient.Client

		containerHandle string
	)

	BeforeEach(func() {
		Deploy("deployments/single-vm.yml")

		gClient = gclient.New(gconn.New("tcp", fmt.Sprintf("%s:7777", atcIP)))
	})

	getContainer := func(condition, value string) func() hijackedContainerResult {
		return func() (h hijackedContainerResult) {
			containers := flyTable("containers")

			for _, c := range containers {
				if c[condition] == value {
					containerHandle = c["handle"]
					h.flyContainerExists = true

					break
				}
			}

			_, err := gClient.Lookup(containerHandle)
			if err == nil {
				h.gardenContainerExists = true
			}

			return
		}
	}

	It("does not delete hijacked build containers from the database, and sets a 5 minute TTL on the container in garden", func() {
		By("setting the pipeline that has a build")
		fly("set-pipeline", "-n", "-c", "pipelines/task-waiting.yml", "-p", "hijacked-containers-test")

		By("triggering the build")
		fly("unpause-pipeline", "-p", "hijacked-containers-test")
		buildSession := spawnFly("trigger-job", "-w", "-j", "hijacked-containers-test/simple-job")
		Eventually(buildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))

		By("hijacking into the build container")
		hijackSession := spawnFlyInteractive(
			bytes.NewBufferString("3\n"),
			"hijack",
			"-j", "hijacked-containers-test/simple-job",
			"-b", "1",
			"-s", "simple-task",
			"touch", "/tmp/stop-waiting",
			"and", "sleep", "3600",
		)

		By("triggering a new build")
		<-buildSession.Exited
		buildSession = spawnFly("trigger-job", "-w", "-j", "hijacked-containers-test/simple-job")
		Eventually(buildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))
		<-spawnFlyInteractive(
			bytes.NewBufferString("3\n"),
			"hijack",
			"-j", "hijacked-containers-test/simple-job",
			"-b", "2",
			"-s", "simple-task",
			"touch", "/tmp/stop-waiting",
		).Exited

		By("verifying the hijacked container exists via fly and Garden")
		Consistently(getContainer("build #", "1"), 2*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{true, true}))

		By("unhijacking and seeing the container removed via fly/Garden after 5 minutes")
		hijackSession.Terminate()
		<-hijackSession.Exited

		Eventually(getContainer("build #", "1"), 10*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{false, false}))
	})

	It("does not delete hijacked one-off build containers from the database, and sets a 5 minute TTL on the container in garden", func() {
		By("triggering a one-off build")
		buildSession := spawnFly("execute", "-c", "tasks/wait.yml")
		Eventually(buildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))

		By("hijacking into the build container")
		hijackSession := spawnFlyInteractive(
			bytes.NewBufferString("3\n"),
			"hijack",
			"-b", "1",
			"touch", "/tmp/stop-waiting",
			"and", "sleep", "3600",
		)

		By("waiting for build to finish")
		<-buildSession.Exited

		By("verifying the hijacked container exists via fly and Garden")
		Consistently(getContainer("build #", "1"), 2*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{true, true}))

		By("unhijacking and seeing the container removed via fly/Garden after 5 minutes")
		hijackSession.Terminate()
		<-hijackSession.Exited

		Eventually(getContainer("build #", "1"), 10*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{false, false}))
	})

	It("does not delete hijacked resource containers from the database, and sets a 5 minute TTL on the container in garden", func() {
		By("setting the pipeline that has a build")
		fly("set-pipeline", "-n", "-c", "pipelines/get-task.yml", "-p", "hijacked-resource-test")
		fly("unpause-pipeline", "-p", "hijacked-resource-test")

		By("checking resource")
		fly("check-resource", "-r", "hijacked-resource-test/tick-tock")

		By("hijacking into the build container")
		hijackSession := spawnFlyInteractive(
			bytes.NewBufferString("3\n"),
			"hijack",
			"-c", "hijacked-resource-test/tick-tock",
			"sleep", "3600",
		)

		By("reconfiguring pipeline without resource")
		fly("set-pipeline", "-n", "-c", "pipelines/task-waiting.yml", "-p", "hijacked-resource-test")

		By("verifying the hijacked container exists via fly and Garden")
		Consistently(getContainer("type", "check"), 2*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{true, true}))

		By("unhijacking and seeing the container removed via fly/Garden after 5 minutes")
		hijackSession.Terminate()
		<-hijackSession.Exited

		Eventually(getContainer("type", "check"), 10*time.Minute, 30*time.Second).Should(Equal(hijackedContainerResult{false, false}))
	})
})

type hijackedContainerResult struct {
	flyContainerExists    bool
	gardenContainerExists bool
}
<|endoftext|>


<commit_before>
package main

import (
	"fmt"
)

type Fetcher interface {
	// Fetch returns the body of URL and
	// a slice of URLs found on that page.
	Fetch(url string) (body string, urls []string, err error)
}

// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher) {
	// TODO: Fetch URLs in parallel.
	// TODO: Don't fetch the same URL twice.
	// This implementation doesn't do either:
	if depth <= 0 {
		return
	}
	body, urls, err := fetcher.Fetch(url)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("found: %s %q\n", url, body)
	for _, u := range urls {
		Crawl(u, depth-1, fetcher)
	}
	return
}

func main() {
	Crawl("http://golang.org/", 4, fetcher)
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
	body string
	urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
	if res, ok := f[url]; ok {
		return res.body, res.urls, nil
	}
	return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
	"http://golang.org/": &fakeResult{
		"The Go Programming Language",
		[]string{
			"http://golang.org/pkg/",
			"http://golang.org/cmd/",
		},
	},
	"http://golang.org/pkg/": &fakeResult{
		"Packages",
		[]string{
			"http://golang.org/",
			"http://golang.org/cmd/",
			"http://golang.org/pkg/fmt/",
			"http://golang.org/pkg/os/",
		},
	},
	"http://golang.org/pkg/fmt/": &fakeResult{
		"Package fmt",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
	"http://golang.org/pkg/os/": &fakeResult{
		"Package os",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
}
<commit_msg>Parallelized URL fetching in the Web Crawler exercise<commit_after>
package main

import (
	"fmt"
)

type Fetcher interface {
	Fetch(url string) (body string, urls []string, err error)
}

func Crawl(url string, depth int, fetcher Fetcher, ch chan string) {

	defer close(ch)

	if depth <= 0 {
		return
	}

	body, urls, err := fetcher.Fetch(url)

	if err != nil {
		ch <- fmt.Sprintln(err)
		return
	}

	ch <- fmt.Sprintf("found: %s %q\n", url, body)

	chans := make([]chan string, len(urls))
	for i, u := range urls {
		chans[i] = make(chan string)
		go Crawl(u, depth-1, fetcher, chans[i])
	}

	for i := range chans {
		for s := range chans[i] {
			ch <- s
		}
	}

	return
}

func main() {
	ch := make(chan string)
	go Crawl("http://golang.org/", 4, fetcher, ch)
	for s := range ch {
		fmt.Print(s)
	}
}

// fakeFetcher is a Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
	body string
	urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
	if res, ok := f[url]; ok {
		return res.body, res.urls, nil
	}
	return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
	"http://golang.org/": &fakeResult{
		"The Go Programming Language",
		[]string{
			"http://golang.org/pkg/",
			"http://golang.org/cmd/",
		},
	},
	"http://golang.org/pkg/": &fakeResult{
		"Packages",
		[]string{
			"http://golang.org/",
			"http://golang.org/cmd/",
			"http://golang.org/pkg/fmt/",
			"http://golang.org/pkg/os/",
		},
	},
	"http://golang.org/pkg/fmt/": &fakeResult{
		"Package fmt",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
	"http://golang.org/pkg/os/": &fakeResult{
		"Package os",
		[]string{
			"http://golang.org/",
			"http://golang.org/pkg/",
		},
	},
}
<|endoftext|>


<commit_before>// Package rescuetime provides a Golang library for the RescueTime API
package rescuetime

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"time"

	simplejson "github.com/bitly/go-simplejson"
)

const (
	analyticDataURL string = "https://www.rescuetime.com/anapi/data"
	dailySummaryURL string = "https://www.rescuetime.com/anapi/daily_summary_feed"
)

// RescueTime contains the user's API key
type RescueTime struct {
	APIKey string
}

// DailySummary is a users summary for a single day
type DailySummary struct {
	AllDistractingDurationFormatted             string  `json:"all_distracting_duration_formatted"`
	AllDistractingHours                         float64 `json:"all_distracting_hours"`
	AllDistractingPercentage                    float64 `json:"all_distracting_percentage"`
	AllProductiveDurationFormatted              string  `json:"all_productive_duration_formatted"`
	AllProductiveHours                          float64 `json:"all_productive_hours"`
	AllProductivePercentage                     float64 `json:"all_productive_percentage"`
	BusinessDurationFormatted                   string  `json:"business_duration_formatted"`
	BusinessHours                               float64 `json:"business_hours"`
	BusinessPercentage                          float64 `json:"business_percentage"`
	CommunicationAndSchedulingDurationFormatted string  `json:"communication_and_scheduling_duration_formatted"`
	CommunicationAndSchedulingHours             float64 `json:"communication_and_scheduling_hours"`
	CommunicationAndSchedulingPercentage        float64 `json:"communication_and_scheduling_percentage"`
	Date                                        string  `json:"date"`
	DesignAndCompositionDurationFormatted       string  `json:"design_and_composition_duration_formatted"`
	DesignAndCompositionHours                   float64 `json:"design_and_composition_hours"`
	DesignAndCompositionPercentage              float64 `json:"design_and_composition_percentage"`
	DistractingDurationFormatted                string  `json:"distracting_duration_formatted"`
	DistractingHours                            float64 `json:"distracting_hours"`
	DistractingPercentage                       float64 `json:"distracting_percentage"`
	EntertainmentDurationFormatted              string  `json:"entertainment_duration_formatted"`
	EntertainmentHours                          float64 `json:"entertainment_hours"`
	EntertainmentPercentage                     float64 `json:"entertainment_percentage"`
	ID                                          float64 `json:"id"`
	NeutralDurationFormatted                    string  `json:"neutral_duration_formatted"`
	NeutralHours                                float64 `json:"neutral_hours"`
	NeutralPercentage                           float64 `json:"neutral_percentage"`
	NewsDurationFormatted                       string  `json:"news_duration_formatted"`
	NewsHours                                   float64 `json:"news_hours"`
	NewsPercentage                              float64 `json:"news_percentage"`
	ProductiveDurationFormatted                 string  `json:"productive_duration_formatted"`
	ProductiveHours                             float64 `json:"productive_hours"`
	ProductivePercentage                        float64 `json:"productive_percentage"`
	ProductivityPulse                           float64 `json:"productivity_pulse"`
	ReferenceAndLearningDurationFormatted       string  `json:"reference_and_learning_duration_formatted"`
	ReferenceAndLearningHours                   float64 `json:"reference_and_learning_hours"`
	ReferenceAndLearningPercentage              float64 `json:"reference_and_learning_percentage"`
	ShoppingDurationFormatted                   string  `json:"shopping_duration_formatted"`
	ShoppingHours                               float64 `json:"shopping_hours"`
	ShoppingPercentage                          float64 `json:"shopping_percentage"`
	SocialNetworkingDurationFormatted           string  `json:"social_networking_duration_formatted"`
	SocialNetworkingHours                       float64 `json:"social_networking_hours"`
	SocialNetworkingPercentage                  float64 `json:"social_networking_percentage"`
	SoftwareDevelopmentDurationFormatted        string  `json:"software_development_duration_formatted"`
	SoftwareDevelopmentHours                    float64 `json:"software_development_hours"`
	SoftwareDevelopmentPercentage               float64 `json:"software_development_percentage"`
	TotalDurationFormatted                      string  `json:"total_duration_formatted"`
	TotalHours                                  float64 `json:"total_hours"`
	UncategorizedDurationFormatted              string  `json:"uncategorized_duration_formatted"`
	UncategorizedHours                          float64 `json:"uncategorized_hours"`
	UncategorizedPercentage                     float64 `json:"uncategorized_percentage"`
	UtilitiesDurationFormatted                  string  `json:"utilities_duration_formatted"`
	UtilitiesHours                              float64 `json:"utilities_hours"`
	UtilitiesPercentage                         float64 `json:"utilities_percentage"`
	VeryDistractingDurationFormatted            string  `json:"very_distracting_duration_formatted"`
	VeryDistractingHours                        float64 `json:"very_distracting_hours"`
	VeryDistractingPercentage                   float64 `json:"very_distracting_percentage"`
	VeryProductiveDurationFormatted             string  `json:"very_productive_duration_formatted"`
	VeryProductiveHours                         float64 `json:"very_productive_hours"`
	VeryProductivePercentage                    float64 `json:"very_productive_percentage"`
}

// AnalyticDataQueryParameters is used to provide parameters to the Analytic Data API
type AnalyticDataQueryParameters struct {
	Perspective    string `field_name:"perspective"`
	ResolutionTime string `field_name:"resolution_time"`
	RestrictGroup  string `field_name:"restrict_group"`
	RestrictBegin  string `field_name:"restrict_begin"`
	RestrictEnd    string `field_name:"restrict_end"`
	RestrictKind   string `field_name:"restrict_kind"`
	RestrictThing  string `field_name:"restrict_thing"`
	RestrictThingy string `field_name:"restrict_thingy"`
}

// AnalyticData describes an Analytic Data API result
type AnalyticData struct {
	Notes      string                       `json:"notes"`
	RowHeaders []string                     `json:"row_headers"`
	Rows       []Row                        `json:"rows"`
	Parameters *AnalyticDataQueryParameters `json:"-,omitempty"`
}

// Row is a single row in an Analytic Data API result
type Row struct {
	Date             time.Time
	Rank             int
	TimeSpentSeconds int
	NumberOfPeople   int
	Person           string
	Activity         string
	Category         string
	Productivity     int
}

func structToMap(i interface{}) (values url.Values) {
	values = url.Values{}
	iVal := reflect.ValueOf(i).Elem()
	typ := iVal.Type()
	for i := 0; i < iVal.NumField(); i++ {
		f := iVal.Field(i)
		// Convert each type into a string for the url.Values string map
		var v string
		switch f.Interface().(type) {
		case int, int8, int16, int32, int64:
			v = strconv.FormatInt(f.Int(), 10)
		case uint, uint8, uint16, uint32, uint64:
			v = strconv.FormatUint(f.Uint(), 10)
		case float32:
			v = strconv.FormatFloat(f.Float(), 'f', 4, 32)
		case float64:
			v = strconv.FormatFloat(f.Float(), 'f', 4, 64)
		case []byte:
			v = string(f.Bytes())
		case string:
			v = f.String()
		}
		if v == "" {
			continue
		}
		values.Set(typ.Field(i).Tag.Get("field_name"), v)
	}
	return
}

func (r *RescueTime) buildURL(baseURL string, urlValues url.Values) (string, error) {
	parsedURL, err := url.Parse(baseURL)
	if err != nil {
		return "", err
	}
	urlValues.Set("key", r.APIKey)
	urlValues.Set("format", "json")
	parsedURL.RawQuery = urlValues.Encode()
	return parsedURL.String(), nil
}

var titlingRegex = regexp.MustCompile("[0-9A-Za-z]+")

func titleCase(src string) string {
	byteSrc := []byte(src)
	chunks := titlingRegex.FindAll(byteSrc, -1)
	for idx, val := range chunks {
		chunks[idx] = bytes.Title(val)
	}
	return string(bytes.Join(chunks, nil))
}

func (r *RescueTime) getResponse(getURL string) ([]byte, error) {
	if r.APIKey == "" {
		return nil, errors.New("Please provide API key")
	}
	response, err := http.Get(getURL)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	return contents, nil
}

// GetAnalyticData makes a request to the Analytic Data API with the provided (if any) arguments.
// If a timezone is given, all dates will be located in the given timezone.
func (r *RescueTime) GetAnalyticData(timezone string, parameters *AnalyticDataQueryParameters) (AnalyticData, error) {
	var rtd AnalyticData

	params := structToMap(parameters)

	builtURL, err := r.buildURL(analyticDataURL, params)
	if err != nil {
		return rtd, err
	}

	contents, err := r.getResponse(builtURL)
	if err != nil {
		return rtd, err
	}
	currentJSON, err := simplejson.NewJson(contents)
	if err != nil {
		return rtd, err
	}

	data := AnalyticData{
		Parameters: parameters,
	}

	var notes string
	notes = fmt.Sprintf("%s", currentJSON.Get("notes").MustString())
	data.Notes = notes

	var rowHeaders []string
	headersMap := make(map[int]string)
	headerRegex := regexp.MustCompile("[^A-Za-z0-9]+")
	for i, s := range currentJSON.Get("row_headers").MustStringArray() {
		rowHeaders = append(rowHeaders, s)
		headersMap[i] = headerRegex.ReplaceAllString(titleCase(s), "")
	}
	data.RowHeaders = rowHeaders

	var toAppend []Row
	for _, entry := range currentJSON.Get("rows").MustArray() {
		var aRow Row
		for index, column := range entry.([]interface{}) {
			thisHeader := headersMap[index]
			field := reflect.ValueOf(&aRow).Elem().FieldByName(thisHeader)
			switch field.Interface().(type) {
			case int, int8, int16, int32, int64:
				intValue, err := column.(json.Number).Int64()
				if err != nil {
					return data, err
				}
				field.SetInt(intValue)
			case time.Time:
				parsed, err := time.Parse("2006-01-02T15:04:05", column.(string))
				if err != nil {
					return rtd, err
				}
				if timezone != "" {
					location, err := time.LoadLocation(timezone)
					if err != nil {
						return rtd, err
					}
					parsed = parsed.In(location)
				}
				field.Set(reflect.ValueOf(parsed))
			default:
				field.Set(reflect.ValueOf(column))
			}
		}
		toAppend = append(toAppend, aRow)
	}
	data.Rows = toAppend
	return data, nil
}

// GetDailySummary returns the daily summary for the user.
func (r *RescueTime) GetDailySummary() ([]DailySummary, error) {
	var summaries []DailySummary
	builtURL, err := r.buildURL(dailySummaryURL, url.Values{})
	if err != nil {
		return summaries, err
	}
	contents, err := r.getResponse(builtURL)
	if err != nil {
		return summaries, err
	}
	var keys []DailySummary
	err = json.Unmarshal(contents, &keys)
	if err != nil {
		return summaries, err
	}
	return keys, nil
}
<commit_msg>un-export Row<commit_after>// Package rescuetime provides a Golang library for the RescueTime API
package rescuetime

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"time"

	simplejson "github.com/bitly/go-simplejson"
)

const (
	analyticDataURL string = "https://www.rescuetime.com/anapi/data"
	dailySummaryURL string = "https://www.rescuetime.com/anapi/daily_summary_feed"
)

// RescueTime contains the user's API key
type RescueTime struct {
	APIKey string
}

// DailySummary is a users summary for a single day
type DailySummary struct {
	AllDistractingDurationFormatted             string  `json:"all_distracting_duration_formatted"`
	AllDistractingHours                         float64 `json:"all_distracting_hours"`
	AllDistractingPercentage                    float64 `json:"all_distracting_percentage"`
	AllProductiveDurationFormatted              string  `json:"all_productive_duration_formatted"`
	AllProductiveHours                          float64 `json:"all_productive_hours"`
	AllProductivePercentage                     float64 `json:"all_productive_percentage"`
	BusinessDurationFormatted                   string  `json:"business_duration_formatted"`
	BusinessHours                               float64 `json:"business_hours"`
	BusinessPercentage                          float64 `json:"business_percentage"`
	CommunicationAndSchedulingDurationFormatted string  `json:"communication_and_scheduling_duration_formatted"`
	CommunicationAndSchedulingHours             float64 `json:"communication_and_scheduling_hours"`
	CommunicationAndSchedulingPercentage        float64 `json:"communication_and_scheduling_percentage"`
	Date                                        string  `json:"date"`
	DesignAndCompositionDurationFormatted       string  `json:"design_and_composition_duration_formatted"`
	DesignAndCompositionHours                   float64 `json:"design_and_composition_hours"`
	DesignAndCompositionPercentage              float64 `json:"design_and_composition_percentage"`
	DistractingDurationFormatted                string  `json:"distracting_duration_formatted"`
	DistractingHours                            float64 `json:"distracting_hours"`
	DistractingPercentage                       float64 `json:"distracting_percentage"`
	EntertainmentDurationFormatted              string  `json:"entertainment_duration_formatted"`
	EntertainmentHours                          float64 `json:"entertainment_hours"`
	EntertainmentPercentage                     float64 `json:"entertainment_percentage"`
	ID                                          float64 `json:"id"`
	NeutralDurationFormatted                    string  `json:"neutral_duration_formatted"`
	NeutralHours                                float64 `json:"neutral_hours"`
	NeutralPercentage                           float64 `json:"neutral_percentage"`
	NewsDurationFormatted                       string  `json:"news_duration_formatted"`
	NewsHours                                   float64 `json:"news_hours"`
	NewsPercentage                              float64 `json:"news_percentage"`
	ProductiveDurationFormatted                 string  `json:"productive_duration_formatted"`
	ProductiveHours                             float64 `json:"productive_hours"`
	ProductivePercentage                        float64 `json:"productive_percentage"`
	ProductivityPulse                           float64 `json:"productivity_pulse"`
	ReferenceAndLearningDurationFormatted       string  `json:"reference_and_learning_duration_formatted"`
	ReferenceAndLearningHours                   float64 `json:"reference_and_learning_hours"`
	ReferenceAndLearningPercentage              float64 `json:"reference_and_learning_percentage"`
	ShoppingDurationFormatted                   string  `json:"shopping_duration_formatted"`
	ShoppingHours                               float64 `json:"shopping_hours"`
	ShoppingPercentage                          float64 `json:"shopping_percentage"`
	SocialNetworkingDurationFormatted           string  `json:"social_networking_duration_formatted"`
	SocialNetworkingHours                       float64 `json:"social_networking_hours"`
	SocialNetworkingPercentage                  float64 `json:"social_networking_percentage"`
	SoftwareDevelopmentDurationFormatted        string  `json:"software_development_duration_formatted"`
	SoftwareDevelopmentHours                    float64 `json:"software_development_hours"`
	SoftwareDevelopmentPercentage               float64 `json:"software_development_percentage"`
	TotalDurationFormatted                      string  `json:"total_duration_formatted"`
	TotalHours                                  float64 `json:"total_hours"`
	UncategorizedDurationFormatted              string  `json:"uncategorized_duration_formatted"`
	UncategorizedHours                          float64 `json:"uncategorized_hours"`
	UncategorizedPercentage                     float64 `json:"uncategorized_percentage"`
	UtilitiesDurationFormatted                  string  `json:"utilities_duration_formatted"`
	UtilitiesHours                              float64 `json:"utilities_hours"`
	UtilitiesPercentage                         float64 `json:"utilities_percentage"`
	VeryDistractingDurationFormatted            string  `json:"very_distracting_duration_formatted"`
	VeryDistractingHours                        float64 `json:"very_distracting_hours"`
	VeryDistractingPercentage                   float64 `json:"very_distracting_percentage"`
	VeryProductiveDurationFormatted             string  `json:"very_productive_duration_formatted"`
	VeryProductiveHours                         float64 `json:"very_productive_hours"`
	VeryProductivePercentage                    float64 `json:"very_productive_percentage"`
}

// AnalyticDataQueryParameters is used to provide parameters to the Analytic Data API
type AnalyticDataQueryParameters struct {
	Perspective    string `field_name:"perspective"`
	ResolutionTime string `field_name:"resolution_time"`
	RestrictGroup  string `field_name:"restrict_group"`
	RestrictBegin  string `field_name:"restrict_begin"`
	RestrictEnd    string `field_name:"restrict_end"`
	RestrictKind   string `field_name:"restrict_kind"`
	RestrictThing  string `field_name:"restrict_thing"`
	RestrictThingy string `field_name:"restrict_thingy"`
}

// AnalyticData describes an Analytic Data API result
type AnalyticData struct {
	Notes      string                       `json:"notes"`
	RowHeaders []string                     `json:"row_headers"`
	Rows       []row                        `json:"rows"`
	Parameters *AnalyticDataQueryParameters `json:"-,omitempty"`
}

// Row is a single row in an Analytic Data API result
type row struct {
	Date             time.Time
	Rank             int
	TimeSpentSeconds int
	NumberOfPeople   int
	Person           string
	Activity         string
	Category         string
	Productivity     int
}

func structToMap(i interface{}) (values url.Values) {
	values = url.Values{}
	iVal := reflect.ValueOf(i).Elem()
	typ := iVal.Type()
	for i := 0; i < iVal.NumField(); i++ {
		f := iVal.Field(i)
		// Convert each type into a string for the url.Values string map
		var v string
		switch f.Interface().(type) {
		case int, int8, int16, int32, int64:
			v = strconv.FormatInt(f.Int(), 10)
		case uint, uint8, uint16, uint32, uint64:
			v = strconv.FormatUint(f.Uint(), 10)
		case float32:
			v = strconv.FormatFloat(f.Float(), 'f', 4, 32)
		case float64:
			v = strconv.FormatFloat(f.Float(), 'f', 4, 64)
		case []byte:
			v = string(f.Bytes())
		case string:
			v = f.String()
		}
		if v == "" {
			continue
		}
		values.Set(typ.Field(i).Tag.Get("field_name"), v)
	}
	return
}

func (r *RescueTime) buildURL(baseURL string, urlValues url.Values) (string, error) {
	parsedURL, err := url.Parse(baseURL)
	if err != nil {
		return "", err
	}
	urlValues.Set("key", r.APIKey)
	urlValues.Set("format", "json")
	parsedURL.RawQuery = urlValues.Encode()
	return parsedURL.String(), nil
}

var titlingRegex = regexp.MustCompile("[0-9A-Za-z]+")

func titleCase(src string) string {
	byteSrc := []byte(src)
	chunks := titlingRegex.FindAll(byteSrc, -1)
	for idx, val := range chunks {
		chunks[idx] = bytes.Title(val)
	}
	return string(bytes.Join(chunks, nil))
}

func (r *RescueTime) getResponse(getURL string) ([]byte, error) {
	if r.APIKey == "" {
		return nil, errors.New("Please provide API key")
	}
	response, err := http.Get(getURL)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	return contents, nil
}

// GetAnalyticData makes a request to the Analytic Data API with the provided (if any) arguments.
// If a timezone is given, all dates will be located in the given timezone.
func (r *RescueTime) GetAnalyticData(timezone string, parameters *AnalyticDataQueryParameters) (AnalyticData, error) {
	var rtd AnalyticData

	params := structToMap(parameters)

	builtURL, err := r.buildURL(analyticDataURL, params)
	if err != nil {
		return rtd, err
	}

	contents, err := r.getResponse(builtURL)
	if err != nil {
		return rtd, err
	}
	currentJSON, err := simplejson.NewJson(contents)
	if err != nil {
		return rtd, err
	}

	data := AnalyticData{
		Parameters: parameters,
	}

	var notes string
	notes = fmt.Sprintf("%s", currentJSON.Get("notes").MustString())
	data.Notes = notes

	var rowHeaders []string
	headersMap := make(map[int]string)
	headerRegex := regexp.MustCompile("[^A-Za-z0-9]+")
	for i, s := range currentJSON.Get("row_headers").MustStringArray() {
		rowHeaders = append(rowHeaders, s)
		headersMap[i] = headerRegex.ReplaceAllString(titleCase(s), "")
	}
	data.RowHeaders = rowHeaders

	var toAppend []Row
	for _, entry := range currentJSON.Get("rows").MustArray() {
		var aRow row
		for index, column := range entry.([]interface{}) {
			thisHeader := headersMap[index]
			field := reflect.ValueOf(&aRow).Elem().FieldByName(thisHeader)
			switch field.Interface().(type) {
			case int, int8, int16, int32, int64:
				intValue, err := column.(json.Number).Int64()
				if err != nil {
					return data, err
				}
				field.SetInt(intValue)
			case time.Time:
				parsed, err := time.Parse("2006-01-02T15:04:05", column.(string))
				if err != nil {
					return rtd, err
				}
				if timezone != "" {
					location, err := time.LoadLocation(timezone)
					if err != nil {
						return rtd, err
					}
					parsed = parsed.In(location)
				}
				field.Set(reflect.ValueOf(parsed))
			default:
				field.Set(reflect.ValueOf(column))
			}
		}
		toAppend = append(toAppend, aRow)
	}
	data.Rows = toAppend
	return data, nil
}

// GetDailySummary returns the daily summary for the user.
func (r *RescueTime) GetDailySummary() ([]DailySummary, error) {
	var summaries []DailySummary
	builtURL, err := r.buildURL(dailySummaryURL, url.Values{})
	if err != nil {
		return summaries, err
	}
	contents, err := r.getResponse(builtURL)
	if err != nil {
		return summaries, err
	}
	var keys []DailySummary
	err = json.Unmarshal(contents, &keys)
	if err != nil {
		return summaries, err
	}
	return keys, nil
}
<|endoftext|>


<commit_before>package utils

import (
	"errors"
	"fmt"

	e "github.com/techjanitor/pram-get/errors"
)

var (
	ErrUserNotConfirmed error = errors.New("Account not confirmed")
	ErrUserBanned       error = errors.New("Account banned")
	ErrUserLocked       error = errors.New("Account locked")
	userdataWorker      *userWorker
)

// struct for database insert worker
type userWorker struct {
	queue chan *User
}

// user struct
type User struct {
	Id              uint   `json:"id"`
	Name            string `json:"name"`
	Email           string `json:"email"`
	Group           uint   `json:"group"`
	IsConfirmed     bool   `json:"-"`
	IsLocked        bool   `json:"-"`
	IsBanned        bool   `json:"-"`
	IsAuthenticated bool   `json:"-"`
}

func init() {
	// make worker channel
	userdataWorker = &userWorker{
		make(chan *User, 64),
	}

	go func() {

		// Get Database handle
		db, err := GetDb()
		if err != nil {
			return
		}

		// prepare query for users table
		ps1, err := db.Prepare("SELECT usergroup_id,user_name,user_email,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?")
		if err != nil {
			return
		}

		// range through tasks channel
		for u := range userdataWorker.queue {

			// input data
			err = ps1.QueryRow(u.Id).Scan(&u.Group, &u.Name, &u.Email, &u.IsConfirmed, &u.IsLocked, &u.IsBanned)
			if err != nil {
				return
			}

			userdataWorker.queue <- u

		}

	}()

}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 || u.Id == 1 {
		return e.ErrInvalidParam
	}

	userdataWorker.queue <- u

	fmt.Printf("%s\n", u)

	fmt.Printf("%s\n", <-userdataWorker.queue)

	// if account is not confirmed
	if !u.IsConfirmed {
		return ErrUserNotConfirmed
	}

	// if locked
	if u.IsLocked {
		return ErrUserLocked
	}

	// if banned
	if u.IsBanned {
		return ErrUserBanned
	}

	// mark authenticated
	u.IsAuthenticated = true

	return

}
<commit_msg>test async user info<commit_after>package utils

import (
	"errors"
	"fmt"

	e "github.com/techjanitor/pram-get/errors"
)

var (
	ErrUserNotConfirmed error = errors.New("Account not confirmed")
	ErrUserBanned       error = errors.New("Account banned")
	ErrUserLocked       error = errors.New("Account locked")
	userdataWorker      *userWorker
)

// struct for database insert worker
type userWorker struct {
	send    chan *User
	receive chan *User
}

// user struct
type User struct {
	Id              uint   `json:"id"`
	Name            string `json:"name"`
	Email           string `json:"email"`
	Group           uint   `json:"group"`
	IsConfirmed     bool   `json:"-"`
	IsLocked        bool   `json:"-"`
	IsBanned        bool   `json:"-"`
	IsAuthenticated bool   `json:"-"`
}

func init() {
	// make worker channel
	userdataWorker = &userWorker{
		make(chan *User, 64),
		make(chan *User, 64),
	}

	go func() {

		// Get Database handle
		db, err := GetDb()
		if err != nil {
			return
		}

		// prepare query for users table
		ps1, err := db.Prepare("SELECT usergroup_id,user_name,user_email,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?")
		if err != nil {
			return
		}

		// range through tasks channel
		for u := range userdataWorker.send {

			// input data
			err = ps1.QueryRow(u.Id).Scan(&u.Group, &u.Name, &u.Email, &u.IsConfirmed, &u.IsLocked, &u.IsBanned)
			if err != nil {
				return
			}

			userdataWorker.receive <- u

		}

	}()

}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 || u.Id == 1 {
		return e.ErrInvalidParam
	}

	userdataWorker.send <- u

	fmt.Printf("%s\n", u)

	fmt.Printf("%s\n", <-userdataWorker.receive)

	// if account is not confirmed
	if !u.IsConfirmed {
		return ErrUserNotConfirmed
	}

	// if locked
	if u.IsLocked {
		return ErrUserLocked
	}

	// if banned
	if u.IsBanned {
		return ErrUserBanned
	}

	// mark authenticated
	u.IsAuthenticated = true

	return

}
<|endoftext|>


<commit_before>package couchdb

import (
	"net/url"
	"reflect"
	"testing"
)

// quote()
var quoteTests = []struct {
	in  url.Values
	out url.Values
}{
	{
		url.Values{"key": []string{"value"}},
		url.Values{"key": []string{"\"value\""}},
	},
	{
		url.Values{"descending": []string{"true"}},
		url.Values{"descending": []string{"\"true\""}},
	},
}

func TestQuote(t *testing.T) {
	for _, tt := range quoteTests {
		actual := quote(tt.in)
		if !reflect.DeepEqual(actual, tt.out) {
			t.Errorf("quote(%v): expected %v, actual %v", tt.in, tt.out, actual)
		}
	}
}

// mimeType()
var mimeTypeTests = []struct {
	in  string
	out string
}{
	{"image.jpg", "image/jpeg"},
	{"presentation.pdf", "application/pdf"},
	{"file.text", "text/plain; charset=utf-8"},
	{"archive.zip", "application/zip"},
	{"movie.avi", "video/x-msvideo"},
}

func TestMimeType(t *testing.T) {
	for _, tt := range mimeTypeTests {
		actual := mimeType(tt.in)
		if actual != tt.out {
			t.Errorf("mimeType(%s): expected %s, actual %s", tt.in, tt.out, actual)
		}
	}
}
<commit_msg>make quote table test prettier<commit_after>package couchdb

import (
	"net/url"
	"reflect"
	"testing"
)

// quote()
var quoteTests = []struct {
	in  url.Values
	out url.Values
}{
	{
		url.Values{"key": {`value`}},
		url.Values{"key": {`"value"`}},
	},
	{
		url.Values{"descending": {`true`}},
		url.Values{"descending": {`"true"`}},
	},
}

func TestQuote(t *testing.T) {
	for _, tt := range quoteTests {
		actual := quote(tt.in)
		if !reflect.DeepEqual(actual, tt.out) {
			t.Errorf("quote(%v): expected %v, actual %v", tt.in, tt.out, actual)
		}
	}
}

// mimeType()
var mimeTypeTests = []struct {
	in  string
	out string
}{
	{"image.jpg", "image/jpeg"},
	{"presentation.pdf", "application/pdf"},
	{"file.text", "text/plain; charset=utf-8"},
	{"archive.zip", "application/zip"},
	{"movie.avi", "video/x-msvideo"},
}

func TestMimeType(t *testing.T) {
	for _, tt := range mimeTypeTests {
		actual := mimeType(tt.in)
		if actual != tt.out {
			t.Errorf("mimeType(%s): expected %s, actual %s", tt.in, tt.out, actual)
		}
	}
}
<|endoftext|>


<commit_before>package ddns

import (
	"testing"
)

func Test_backendHas(t *testing.T) {
	hash := backendHash("www.163.com")
	/* must compatible with Python zlib.crc32('www.163.com') or binascii.crc32('www.163.com') */
	if (hash != 832174588) {
		t.Error("test func *backendHash* error")
	}
}
<commit_msg>update test case<commit_after>package ddns

import (
	"testing"
)

func Test_backendHas(t *testing.T) {
	//hash := backendHash("www.163.com")
	hash := backendHash("Hello234")
	/* must compatible with Python zlib.crc32('www.163.com') or binascii.crc32('www.163.com') */
	if (hash != 832174588) {
		t.Error("%s", hash)
		t.Error("test func *backendHash* error")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
)

func TestLoadExistingPage(t *testing.T) {
	title := "TestPage"
	p, err := loadPage(title)
	if err != nil {
		t.Fatal(err)
	}
	if p.Title != "TestPage" {
		t.Fatalf("expected TestPage, got %s", p.Title)
	}
}

func TestLoadNonExistingPage(t *testing.T) {
	title := "DOESNOTEXIST"
	_, err := loadPage(title)
	if err == nil {
		t.Fatalf("expecting error, received %s", err)
	}
}

func TestGetAllPages(t *testing.T) {
	// getAllPageLinks will fill in the []Pages struct slice.
	p, err := getAllPageLinks()
	if err != nil {
		t.Fatalf("expected nil, received %s", err)
	}
	if len(p) < 1 {
		t.Fatalf("expected pages, received 0: %d", len(p))
	}

}

func TestPageInPagesTrue(t *testing.T) {
	// getAllPageLinks will fill in the []Pages struct slice.
	getAllPageLinks()
	p, _ := loadPage("TestPage")
	if !pageInPages(p) {
		t.Fatalf("expected true, received false. %s", p.Title)
	}

}
<commit_msg>Fixing utils test<commit_after>package main

import (
	"testing"
)

func TestLoadExistingPage(t *testing.T) {
	title := "TestPage"
	p, err := loadPage(title)
	if err != nil {
		t.Fatal(err)
	}
	if p.Title != "TestPage" {
		t.Fatalf("expected TestPage, got %s", p.Title)
	}
}

func TestLoadNonExistingPage(t *testing.T) {
	title := "DOESNOTEXIST"
	_, err := loadPage(title)
	if err == nil {
		t.Fatalf("expecting error, received %s", err)
	}
}

func TestGetAllPages(t *testing.T) {
	// getAllPageLinks will fill in the []Pages struct slice.
	p, err := getAllPageLinks()
	if err != nil {
		t.Fatalf("expected nil, received %s", err)
	}
	if len(p) < 1 {
		t.Fatalf("expected pages, received 0: %d", len(p))
	}

}

func TestPageInPagesTrue(t *testing.T) {
	// getAllPageLinks will fill in the []Pages struct slice.
	_, err := getAllPageLinks()
	if err != nil {
		t.Fatalf("expected pages, received error response. %s", err)
	}

	p, _ := loadPage("TestPage")
	if !pageInPages(p) {
		t.Fatalf("expected true, received false. %s", p.Title)
	}

}
<|endoftext|>


<commit_before>// Copyright 2016-2020 The Libsacloud 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 libsacloud

// Version バージョン
const Version = "2.9.0"
<commit_msg>Bump to v2.9.1<commit_after>// Copyright 2016-2020 The Libsacloud 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 libsacloud

// Version バージョン
const Version = "2.9.1"
<|endoftext|>


<commit_before>package values

// Tuple is a structure that holds exactly two values.
// You can read the values, but not change them
type Tuple[T, U any] struct {
	first  T
	second U
}

// Tup creates a new tuple with the first parameter being the first
// element in the tuple and the second being the second
func NewTuple[T, U any](first T, second U) Tuple[T, U] {
	return Tuple[T, U]{
		first:  first,
		second: second,
	}
}

// First gets the first element of the tuple
func First[T, U any](t Tuple[T, U]) T {
	return t.first
}

// Second gets the second element of the given tuple
func Second[T, U any](t Tuple[T, U]) U {
	return t.second
}
<commit_msg>new tuple methods<commit_after>package values

// Tuple is a structure that holds exactly two values.
// You can read the values, but not change them
type Tuple[T, U any] struct {
	first  T
	second U
}

// Tup creates a new tuple with the first parameter being the first
// element in the tuple and the second being the second
func NewTuple[T, U any](first T, second U) Tuple[T, U] {
	return Tuple[T, U]{
		first:  first,
		second: second,
	}
}

// First gets the first element of the tuple
func (tup *Tuple[T, U]) GetFirst() T {
	return tup.first
}

func (tup *Tuple[T, U]) SetFirst(val T) {
	tup.first = val
}

func (tup *Tuple[T, U]) SetSecond(val U) {
	tup.second = val
}

// Second gets the second element of the given tuple
func (tup *Tuple[T, U]) GetSecond() U {
	return tup.second
}
<|endoftext|>


<commit_before>package vault

import (
	"context"
	"encoding/base64"
	"encoding/hex"
	"fmt"

	"github.com/hashicorp/vault/helper/pgpkeys"
	"github.com/hashicorp/vault/shamir"
)

// InitParams keeps the init function from being littered with too many
// params, that's it!
type InitParams struct {
	BarrierConfig   *SealConfig
	RecoveryConfig  *SealConfig
	RootTokenPGPKey string
}

// InitResult is used to provide the key parts back after
// they are generated as part of the initialization.
type InitResult struct {
	SecretShares   [][]byte
	RecoveryShares [][]byte
	RootToken      string
}

// Initialized checks if the Vault is already initialized
func (c *Core) Initialized(ctx context.Context) (bool, error) {
	// Check the barrier first
	init, err := c.barrier.Initialized(ctx)
	if err != nil {
		c.logger.Error("core: barrier init check failed", "error", err)
		return false, err
	}
	if !init {
		c.logger.Info("core: security barrier not initialized")
		return false, nil
	}

	// Verify the seal configuration
	sealConf, err := c.seal.BarrierConfig(ctx)
	if err != nil {
		return false, err
	}
	if sealConf == nil {
		return false, fmt.Errorf("core: barrier reports initialized but no seal configuration found")
	}

	if c.seal.RecoveryKeySupported(ctx) {
		sealConf, err = c.seal.RecoveryConfig(ctx)
		if err != nil {
			return false, err
		}
		if sealConf == nil {
			return false, fmt.Errorf("core: barrier reports initialized but no recovery seal configuration found")
		}
	}

	return true, nil
}

func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) {
	// Generate a master key
	masterKey, err := c.barrier.GenerateKey()
	if err != nil {
		return nil, nil, fmt.Errorf("key generation failed: %v", err)
	}

	// Return the master key if only a single key part is used
	var unsealKeys [][]byte
	if sc.SecretShares == 1 {
		unsealKeys = append(unsealKeys, masterKey)
	} else {
		// Split the master key using the Shamir algorithm
		shares, err := shamir.Split(masterKey, sc.SecretShares, sc.SecretThreshold)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to generate barrier shares: %v", err)
		}
		unsealKeys = shares
	}

	// If we have PGP keys, perform the encryption
	if len(sc.PGPKeys) > 0 {
		hexEncodedShares := make([][]byte, len(unsealKeys))
		for i, _ := range unsealKeys {
			hexEncodedShares[i] = []byte(hex.EncodeToString(unsealKeys[i]))
		}
		_, encryptedShares, err := pgpkeys.EncryptShares(hexEncodedShares, sc.PGPKeys)
		if err != nil {
			return nil, nil, err
		}
		unsealKeys = encryptedShares
	}

	return masterKey, unsealKeys, nil
}

// Initialize is used to initialize the Vault with the given
// configurations.
func (c *Core) Initialize(ctx context.Context, initParams *InitParams) (*InitResult, error) {
	barrierConfig := initParams.BarrierConfig
	recoveryConfig := initParams.RecoveryConfig

	if c.seal.RecoveryKeySupported(ctx) {
		if recoveryConfig == nil {
			return nil, fmt.Errorf("recovery configuration must be supplied")
		}

		if recoveryConfig.SecretShares < 1 {
			return nil, fmt.Errorf("recovery configuration must specify a positive number of shares")
		}

		// Check if the seal configuration is valid
		if err := recoveryConfig.Validate(); err != nil {
			c.logger.Error("core: invalid recovery configuration", "error", err)
			return nil, fmt.Errorf("invalid recovery configuration: %v", err)
		}
	}

	// Check if the seal configuration is valid
	if err := barrierConfig.Validate(); err != nil {
		c.logger.Error("core: invalid seal configuration", "error", err)
		return nil, fmt.Errorf("invalid seal configuration: %v", err)
	}

	// Avoid an initialization race
	c.stateLock.Lock()
	defer c.stateLock.Unlock()

	// Check if we are initialized
	init, err := c.Initialized(ctx)
	if err != nil {
		return nil, err
	}
	if init {
		return nil, ErrAlreadyInit
	}

	err = c.seal.Init(ctx)
	if err != nil {
		c.logger.Error("core: failed to initialize seal", "error", err)
		return nil, fmt.Errorf("error initializing seal: %v", err)
	}

	barrierKey, barrierUnsealKeys, err := c.generateShares(barrierConfig)
	if err != nil {
		c.logger.Error("core: error generating shares", "error", err)
		return nil, err
	}

	// Initialize the barrier
	if err := c.barrier.Initialize(ctx, barrierKey); err != nil {
		c.logger.Error("core: failed to initialize barrier", "error", err)
		return nil, fmt.Errorf("failed to initialize barrier: %v", err)
	}
	if c.logger.IsInfo() {
		c.logger.Info("core: security barrier initialized", "shares", barrierConfig.SecretShares, "threshold", barrierConfig.SecretThreshold)
	}

	// Unseal the barrier
	if err := c.barrier.Unseal(ctx, barrierKey); err != nil {
		c.logger.Error("core: failed to unseal barrier", "error", err)
		return nil, fmt.Errorf("failed to unseal barrier: %v", err)
	}

	// Ensure the barrier is re-sealed
	defer func() {
		// Defers are LIFO so we need to run this here too to ensure the stop
		// happens before sealing. preSeal also stops, so we just make the
		// stopping safe against multiple calls.
		if err := c.barrier.Seal(); err != nil {
			c.logger.Error("core: failed to seal barrier", "error", err)
		}
	}()

	err = c.seal.SetBarrierConfig(ctx, barrierConfig)
	if err != nil {
		c.logger.Error("core: failed to save barrier configuration", "error", err)
		return nil, fmt.Errorf("barrier configuration saving failed: %v", err)
	}

	// If we are storing shares, pop them out of the returned results and push
	// them through the seal
	if barrierConfig.StoredShares > 0 {
		var keysToStore [][]byte
		for i := 0; i < barrierConfig.StoredShares; i++ {
			keysToStore = append(keysToStore, barrierUnsealKeys[0])
			barrierUnsealKeys = barrierUnsealKeys[1:]
		}
		if err := c.seal.SetStoredKeys(ctx, keysToStore); err != nil {
			c.logger.Error("core: failed to store keys", "error", err)
			return nil, fmt.Errorf("failed to store keys: %v", err)
		}
	}

	results := &InitResult{
		SecretShares: barrierUnsealKeys,
	}

	// Perform initial setup
	if err := c.setupCluster(ctx); err != nil {
		c.logger.Error("core: cluster setup failed during init", "error", err)
		return nil, err
	}
	if err := c.postUnseal(); err != nil {
		c.logger.Error("core: post-unseal setup failed during init", "error", err)
		return nil, err
	}

	// Save the configuration regardless, but only generate a key if it's not
	// disabled. When using recovery keys they are stored in the barrier, so
	// this must happen post-unseal.
	if c.seal.RecoveryKeySupported(ctx) {
		err = c.seal.SetRecoveryConfig(ctx, recoveryConfig)
		if err != nil {
			c.logger.Error("core: failed to save recovery configuration", "error", err)
			return nil, fmt.Errorf("recovery configuration saving failed: %v", err)
		}

		if recoveryConfig.SecretShares > 0 {
			recoveryKey, recoveryUnsealKeys, err := c.generateShares(recoveryConfig)
			if err != nil {
				c.logger.Error("core: failed to generate recovery shares", "error", err)
				return nil, err
			}

			err = c.seal.SetRecoveryKey(ctx, recoveryKey)
			if err != nil {
				return nil, err
			}

			results.RecoveryShares = recoveryUnsealKeys
		}
	}

	// Generate a new root token
	rootToken, err := c.tokenStore.rootToken(ctx)
	if err != nil {
		c.logger.Error("core: root token generation failed", "error", err)
		return nil, err
	}
	results.RootToken = rootToken.ID
	c.logger.Info("core: root token generated")

	if initParams.RootTokenPGPKey != "" {
		_, encryptedVals, err := pgpkeys.EncryptShares([][]byte{[]byte(results.RootToken)}, []string{initParams.RootTokenPGPKey})
		if err != nil {
			c.logger.Error("core: root token encryption failed", "error", err)
			return nil, err
		}
		results.RootToken = base64.StdEncoding.EncodeToString(encryptedVals[0])
	}

	// Prepare to re-seal
	if err := c.preSeal(); err != nil {
		c.logger.Error("core: pre-seal teardown failed", "error", err)
		return nil, err
	}

	return results, nil
}

// UnsealWithStoredKeys performs auto-unseal using stored keys.
func (c *Core) UnsealWithStoredKeys(ctx context.Context) error {
	if !c.seal.StoredKeysSupported(ctx) {
		return nil
	}

	sealed, err := c.Sealed()
	if err != nil {
		c.logger.Error("core: error checking sealed status in auto-unseal", "error", err)
		return fmt.Errorf("error checking sealed status in auto-unseal: %s", err)
	}
	if !sealed {
		return nil
	}

	c.logger.Info("core: stored unseal keys supported, attempting fetch")
	keys, err := c.seal.GetStoredKeys(ctx)
	if err != nil {
		c.logger.Error("core: fetching stored unseal keys failed", "error", err)
		return &NonFatalError{Err: fmt.Errorf("fetching stored unseal keys failed: %v", err)}
	}
	if len(keys) == 0 {
		c.logger.Warn("core: stored unseal key(s) supported but none found")
	} else {
		unsealed := false
		keysUsed := 0
		for _, key := range keys {
			unsealed, err = c.Unseal(key)
			if err != nil {
				c.logger.Error("core: unseal with stored unseal key failed", "error", err)
				return &NonFatalError{Err: fmt.Errorf("unseal with stored key failed: %v", err)}
			}
			keysUsed += 1
			if unsealed {
				break
			}
		}
		if !unsealed {
			if c.logger.IsWarn() {
				c.logger.Warn("core: stored unseal key(s) used but Vault not unsealed yet", "stored_keys_used", keysUsed)
			}
		} else {
			if c.logger.IsInfo() {
				c.logger.Info("core: successfully unsealed with stored key(s)", "stored_keys_used", keysUsed)
			}
		}
	}

	return nil
}
<commit_msg>Don't check recovery seal in Initialized()<commit_after>package vault

import (
	"context"
	"encoding/base64"
	"encoding/hex"
	"fmt"

	"github.com/hashicorp/vault/helper/pgpkeys"
	"github.com/hashicorp/vault/shamir"
)

// InitParams keeps the init function from being littered with too many
// params, that's it!
type InitParams struct {
	BarrierConfig   *SealConfig
	RecoveryConfig  *SealConfig
	RootTokenPGPKey string
}

// InitResult is used to provide the key parts back after
// they are generated as part of the initialization.
type InitResult struct {
	SecretShares   [][]byte
	RecoveryShares [][]byte
	RootToken      string
}

// Initialized checks if the Vault is already initialized
func (c *Core) Initialized(ctx context.Context) (bool, error) {
	// Check the barrier first
	init, err := c.barrier.Initialized(ctx)
	if err != nil {
		c.logger.Error("core: barrier init check failed", "error", err)
		return false, err
	}
	if !init {
		c.logger.Info("core: security barrier not initialized")
		return false, nil
	}

	// Verify the seal configuration
	sealConf, err := c.seal.BarrierConfig(ctx)
	if err != nil {
		return false, err
	}
	if sealConf == nil {
		return false, fmt.Errorf("core: barrier reports initialized but no seal configuration found")
	}

	return true, nil
}

func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) {
	// Generate a master key
	masterKey, err := c.barrier.GenerateKey()
	if err != nil {
		return nil, nil, fmt.Errorf("key generation failed: %v", err)
	}

	// Return the master key if only a single key part is used
	var unsealKeys [][]byte
	if sc.SecretShares == 1 {
		unsealKeys = append(unsealKeys, masterKey)
	} else {
		// Split the master key using the Shamir algorithm
		shares, err := shamir.Split(masterKey, sc.SecretShares, sc.SecretThreshold)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to generate barrier shares: %v", err)
		}
		unsealKeys = shares
	}

	// If we have PGP keys, perform the encryption
	if len(sc.PGPKeys) > 0 {
		hexEncodedShares := make([][]byte, len(unsealKeys))
		for i, _ := range unsealKeys {
			hexEncodedShares[i] = []byte(hex.EncodeToString(unsealKeys[i]))
		}
		_, encryptedShares, err := pgpkeys.EncryptShares(hexEncodedShares, sc.PGPKeys)
		if err != nil {
			return nil, nil, err
		}
		unsealKeys = encryptedShares
	}

	return masterKey, unsealKeys, nil
}

// Initialize is used to initialize the Vault with the given
// configurations.
func (c *Core) Initialize(ctx context.Context, initParams *InitParams) (*InitResult, error) {
	barrierConfig := initParams.BarrierConfig
	recoveryConfig := initParams.RecoveryConfig

	if c.seal.RecoveryKeySupported(ctx) {
		if recoveryConfig == nil {
			return nil, fmt.Errorf("recovery configuration must be supplied")
		}

		if recoveryConfig.SecretShares < 1 {
			return nil, fmt.Errorf("recovery configuration must specify a positive number of shares")
		}

		// Check if the seal configuration is valid
		if err := recoveryConfig.Validate(); err != nil {
			c.logger.Error("core: invalid recovery configuration", "error", err)
			return nil, fmt.Errorf("invalid recovery configuration: %v", err)
		}
	}

	// Check if the seal configuration is valid
	if err := barrierConfig.Validate(); err != nil {
		c.logger.Error("core: invalid seal configuration", "error", err)
		return nil, fmt.Errorf("invalid seal configuration: %v", err)
	}

	// Avoid an initialization race
	c.stateLock.Lock()
	defer c.stateLock.Unlock()

	// Check if we are initialized
	init, err := c.Initialized(ctx)
	if err != nil {
		return nil, err
	}
	if init {
		return nil, ErrAlreadyInit
	}

	err = c.seal.Init(ctx)
	if err != nil {
		c.logger.Error("core: failed to initialize seal", "error", err)
		return nil, fmt.Errorf("error initializing seal: %v", err)
	}

	barrierKey, barrierUnsealKeys, err := c.generateShares(barrierConfig)
	if err != nil {
		c.logger.Error("core: error generating shares", "error", err)
		return nil, err
	}

	// Initialize the barrier
	if err := c.barrier.Initialize(ctx, barrierKey); err != nil {
		c.logger.Error("core: failed to initialize barrier", "error", err)
		return nil, fmt.Errorf("failed to initialize barrier: %v", err)
	}
	if c.logger.IsInfo() {
		c.logger.Info("core: security barrier initialized", "shares", barrierConfig.SecretShares, "threshold", barrierConfig.SecretThreshold)
	}

	// Unseal the barrier
	if err := c.barrier.Unseal(ctx, barrierKey); err != nil {
		c.logger.Error("core: failed to unseal barrier", "error", err)
		return nil, fmt.Errorf("failed to unseal barrier: %v", err)
	}

	// Ensure the barrier is re-sealed
	defer func() {
		// Defers are LIFO so we need to run this here too to ensure the stop
		// happens before sealing. preSeal also stops, so we just make the
		// stopping safe against multiple calls.
		if err := c.barrier.Seal(); err != nil {
			c.logger.Error("core: failed to seal barrier", "error", err)
		}
	}()

	err = c.seal.SetBarrierConfig(ctx, barrierConfig)
	if err != nil {
		c.logger.Error("core: failed to save barrier configuration", "error", err)
		return nil, fmt.Errorf("barrier configuration saving failed: %v", err)
	}

	// If we are storing shares, pop them out of the returned results and push
	// them through the seal
	if barrierConfig.StoredShares > 0 {
		var keysToStore [][]byte
		for i := 0; i < barrierConfig.StoredShares; i++ {
			keysToStore = append(keysToStore, barrierUnsealKeys[0])
			barrierUnsealKeys = barrierUnsealKeys[1:]
		}
		if err := c.seal.SetStoredKeys(ctx, keysToStore); err != nil {
			c.logger.Error("core: failed to store keys", "error", err)
			return nil, fmt.Errorf("failed to store keys: %v", err)
		}
	}

	results := &InitResult{
		SecretShares: barrierUnsealKeys,
	}

	// Perform initial setup
	if err := c.setupCluster(ctx); err != nil {
		c.logger.Error("core: cluster setup failed during init", "error", err)
		return nil, err
	}
	if err := c.postUnseal(); err != nil {
		c.logger.Error("core: post-unseal setup failed during init", "error", err)
		return nil, err
	}

	// Save the configuration regardless, but only generate a key if it's not
	// disabled. When using recovery keys they are stored in the barrier, so
	// this must happen post-unseal.
	if c.seal.RecoveryKeySupported(ctx) {
		err = c.seal.SetRecoveryConfig(ctx, recoveryConfig)
		if err != nil {
			c.logger.Error("core: failed to save recovery configuration", "error", err)
			return nil, fmt.Errorf("recovery configuration saving failed: %v", err)
		}

		if recoveryConfig.SecretShares > 0 {
			recoveryKey, recoveryUnsealKeys, err := c.generateShares(recoveryConfig)
			if err != nil {
				c.logger.Error("core: failed to generate recovery shares", "error", err)
				return nil, err
			}

			err = c.seal.SetRecoveryKey(ctx, recoveryKey)
			if err != nil {
				return nil, err
			}

			results.RecoveryShares = recoveryUnsealKeys
		}
	}

	// Generate a new root token
	rootToken, err := c.tokenStore.rootToken(ctx)
	if err != nil {
		c.logger.Error("core: root token generation failed", "error", err)
		return nil, err
	}
	results.RootToken = rootToken.ID
	c.logger.Info("core: root token generated")

	if initParams.RootTokenPGPKey != "" {
		_, encryptedVals, err := pgpkeys.EncryptShares([][]byte{[]byte(results.RootToken)}, []string{initParams.RootTokenPGPKey})
		if err != nil {
			c.logger.Error("core: root token encryption failed", "error", err)
			return nil, err
		}
		results.RootToken = base64.StdEncoding.EncodeToString(encryptedVals[0])
	}

	// Prepare to re-seal
	if err := c.preSeal(); err != nil {
		c.logger.Error("core: pre-seal teardown failed", "error", err)
		return nil, err
	}

	return results, nil
}

// UnsealWithStoredKeys performs auto-unseal using stored keys.
func (c *Core) UnsealWithStoredKeys(ctx context.Context) error {
	if !c.seal.StoredKeysSupported(ctx) {
		return nil
	}

	sealed, err := c.Sealed()
	if err != nil {
		c.logger.Error("core: error checking sealed status in auto-unseal", "error", err)
		return fmt.Errorf("error checking sealed status in auto-unseal: %s", err)
	}
	if !sealed {
		return nil
	}

	c.logger.Info("core: stored unseal keys supported, attempting fetch")
	keys, err := c.seal.GetStoredKeys(ctx)
	if err != nil {
		c.logger.Error("core: fetching stored unseal keys failed", "error", err)
		return &NonFatalError{Err: fmt.Errorf("fetching stored unseal keys failed: %v", err)}
	}
	if len(keys) == 0 {
		c.logger.Warn("core: stored unseal key(s) supported but none found")
	} else {
		unsealed := false
		keysUsed := 0
		for _, key := range keys {
			unsealed, err = c.Unseal(key)
			if err != nil {
				c.logger.Error("core: unseal with stored unseal key failed", "error", err)
				return &NonFatalError{Err: fmt.Errorf("unseal with stored key failed: %v", err)}
			}
			keysUsed += 1
			if unsealed {
				break
			}
		}
		if !unsealed {
			if c.logger.IsWarn() {
				c.logger.Warn("core: stored unseal key(s) used but Vault not unsealed yet", "stored_keys_used", keysUsed)
			}
		} else {
			if c.logger.IsInfo() {
				c.logger.Info("core: successfully unsealed with stored key(s)", "stored_keys_used", keysUsed)
			}
		}
	}

	return nil
}
<|endoftext|>