<commit_before>package svc

import (
	"context"
	"time"

	"github.com/nerdalize/nerd/pkg/kubevisor"

	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
)

//JobDetailsPhase is a high level description of the underlying pod
type JobDetailsPhase string

var (
	// JobDetailsPhasePending means the pod has been accepted by the system, but one or more of the containers
	// has not been started. This includes time before being bound to a node, as well as time spent
	// pulling images onto the host.
	JobDetailsPhasePending JobDetailsPhase = "Pending"
	// JobDetailsPhaseRunning means the pod has been bound to a node and all of the containers have been started.
	// At least one container is still running or is in the process of being restarted.
	JobDetailsPhaseRunning JobDetailsPhase = "Running"
	// JobDetailsPhaseSucceeded means that all containers in the pod have voluntarily terminated
	// with a container exit code of 0, and the system is not going to restart any of these containers.
	JobDetailsPhaseSucceeded JobDetailsPhase = "Succeeded"
	// JobDetailsPhaseFailed means that all containers in the pod have terminated, and at least one container has
	// terminated in a failure (exited with a non-zero exit code or was stopped by the system).
	JobDetailsPhaseFailed JobDetailsPhase = "Failed"
	// JobDetailsPhaseUnknown means that for some reason the state of the pod could not be obtained, typically due
	// to an error in communicating with the host of the pod.
	JobDetailsPhaseUnknown JobDetailsPhase = "Unknown"
)

//JobDetails tells us more about the job from a pod
type JobDetails struct {
	SeenAt         time.Time
	Phase          JobDetailsPhase
	WaitingReason  string //why the job -> pod -> container is waiting
	WaitingMessage string //explains why we're waiting
}

//ListJobItem is a job listing item
type ListJobItem struct {
	Name        string
	Image       string
	CreatedAt   time.Time
	DeletedAt   time.Time
	ActiveAt    time.Time
	CompletedAt time.Time
	FailedAt    time.Time

	Details JobDetails
}

//ListJobsInput is the input to ListJobs
type ListJobsInput struct{}

//ListJobsOutput is the output to ListJobs
type ListJobsOutput struct {
	Items []*ListJobItem
}

//ListJobs will create a job on kubernetes
func (k *Kube) ListJobs(ctx context.Context, in *ListJobsInput) (out *ListJobsOutput, err error) {
	if err = k.checkInput(ctx, in); err != nil {
		return nil, err
	}

	//Step 0: Get all the jobs under nerd-app=cli
	jobs := &jobs{}
	err = k.visor.ListResources(ctx, kubevisor.ResourceTypeJobs, jobs)
	if err != nil {
		return nil, err
	}

	//Step 1: Analyse job structure and formulate our output items
	mapping := map[types.UID]*ListJobItem{}
	for _, job := range jobs.Items {
		if len(job.Spec.Template.Spec.Containers) != 1 {
			k.logs.Debugf("skipping job '%s' in namespace '%s' as it has not just 1 container", job.Name, job.Namespace)
			continue
		}

		//@TODO if parralism is set to 0, consider "stopped"?

		c := job.Spec.Template.Spec.Containers[0]
		item := &ListJobItem{
			Name:      job.GetName(),
			Image:     c.Image,
			CreatedAt: job.CreationTimestamp.Local(),
		}

		if dt := job.GetDeletionTimestamp(); dt != nil {
			item.DeletedAt = dt.Local() //mark as deleting
		}

		if job.Status.StartTime != nil {
			item.ActiveAt = job.Status.StartTime.Local()
		}

		for _, cond := range job.Status.Conditions {
			if cond.Status != corev1.ConditionTrue {
				continue
			}

			switch cond.Type {
			case batchv1.JobComplete:
				item.CompletedAt = cond.LastTransitionTime.Local()
			case batchv1.JobFailed:
				item.FailedAt = cond.LastTransitionTime.Local()
			}
		}

		mapping[job.UID] = item
	}

	//Step 2: Get all pods under nerd-app=cli
	pods := &pods{}
	err = k.visor.ListResources(ctx, kubevisor.ResourceTypePods, pods)
	if err != nil {
		return nil, err
	}

	//Step 3: Match pods to the jobs we got earlier and augment item with pod statuses
	for _, pod := range pods.Items {
		uid, ok := pod.Labels["controller-uid"]
		if !ok {
			continue //not part of a controller
		}

		jobItem, ok := mapping[types.UID(uid)]
		if !ok {
			continue //not part of any job
		}

		//technically we can have multiple pods per job (one terminating, unkown etc) so we pick the
		//one that is created most recently
		if pod.CreationTimestamp.Local().After(jobItem.Details.SeenAt) {
			jobItem.Details.SeenAt = pod.CreationTimestamp.Local()
		}

		//the pod phase allows us to distinguish between Pending and Running
		switch pod.Status.Phase {
		case corev1.PodPending:
			jobItem.Details.Phase = JobDetailsPhasePending
		case corev1.PodRunning:
			jobItem.Details.Phase = JobDetailsPhaseRunning
		case corev1.PodFailed:
			jobItem.Details.Phase = JobDetailsPhaseFailed
		case corev1.PodSucceeded:
			jobItem.Details.Phase = JobDetailsPhaseSucceeded
		default:
			jobItem.Details.Phase = JobDetailsPhaseUnknown
		}

		//container conditions allow us to capture ErrImageNotFound
		for _, cstatus := range pod.Status.ContainerStatuses {
			if cstatus.Name != "main" { //we only care about the main container
				continue
			}

			//waiting reasons give us ErrImagePull/Backoff
			if cstatus.State.Waiting != nil {
				jobItem.Details.WaitingReason = cstatus.State.Waiting.Reason
				jobItem.Details.WaitingMessage = cstatus.State.Waiting.Message
			}
		}

	}

	//Step 4: Set in output
	out = &ListJobsOutput{}
	for _, item := range mapping {
		out.Items = append(out.Items, item)
	}

	return out, nil
}

//jobs implements the list transformer interface to allow the kubevisor the manage names for us
type jobs struct{ *batchv1.JobList }

func (jobs *jobs) Transform(fn func(in kubevisor.ManagedNames) (out kubevisor.ManagedNames)) {
	for i, j1 := range jobs.JobList.Items {
		jobs.Items[i] = *(fn(&j1).(*batchv1.Job))
	}
}

//pods implements the list transformer interface to allow the kubevisor the manage names for us
type pods struct{ *corev1.PodList }

func (pods *pods) Transform(fn func(in kubevisor.ManagedNames) (out kubevisor.ManagedNames)) {
	for i, j1 := range pods.PodList.Items {
		pods.Items[i] = *(fn(&j1).(*corev1.Pod))
	}
}
<commit_msg>added current ordering back in the mix<commit_after>package svc

import (
	"context"
	"time"

	"github.com/nerdalize/nerd/pkg/kubevisor"

	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
)

//JobDetailsPhase is a high level description of the underlying pod
type JobDetailsPhase string

var (
	// JobDetailsPhasePending means the pod has been accepted by the system, but one or more of the containers
	// has not been started. This includes time before being bound to a node, as well as time spent
	// pulling images onto the host.
	JobDetailsPhasePending JobDetailsPhase = "Pending"
	// JobDetailsPhaseRunning means the pod has been bound to a node and all of the containers have been started.
	// At least one container is still running or is in the process of being restarted.
	JobDetailsPhaseRunning JobDetailsPhase = "Running"
	// JobDetailsPhaseSucceeded means that all containers in the pod have voluntarily terminated
	// with a container exit code of 0, and the system is not going to restart any of these containers.
	JobDetailsPhaseSucceeded JobDetailsPhase = "Succeeded"
	// JobDetailsPhaseFailed means that all containers in the pod have terminated, and at least one container has
	// terminated in a failure (exited with a non-zero exit code or was stopped by the system).
	JobDetailsPhaseFailed JobDetailsPhase = "Failed"
	// JobDetailsPhaseUnknown means that for some reason the state of the pod could not be obtained, typically due
	// to an error in communicating with the host of the pod.
	JobDetailsPhaseUnknown JobDetailsPhase = "Unknown"
)

//JobDetails tells us more about the job from a pod
type JobDetails struct {
	SeenAt         time.Time
	Phase          JobDetailsPhase
	WaitingReason  string //why the job -> pod -> container is waiting
	WaitingMessage string //explains why we're waiting
}

//ListJobItem is a job listing item
type ListJobItem struct {
	Name        string
	Image       string
	CreatedAt   time.Time
	DeletedAt   time.Time
	ActiveAt    time.Time
	CompletedAt time.Time
	FailedAt    time.Time

	Details JobDetails
}

//ListJobsInput is the input to ListJobs
type ListJobsInput struct{}

//ListJobsOutput is the output to ListJobs
type ListJobsOutput struct {
	Items []*ListJobItem
}

//ListJobs will create a job on kubernetes
func (k *Kube) ListJobs(ctx context.Context, in *ListJobsInput) (out *ListJobsOutput, err error) {
	if err = k.checkInput(ctx, in); err != nil {
		return nil, err
	}

	//Step 0: Get all the jobs under nerd-app=cli
	jobs := &jobs{}
	err = k.visor.ListResources(ctx, kubevisor.ResourceTypeJobs, jobs)
	if err != nil {
		return nil, err
	}

	//Step 1: Analyse job structure and formulate our output items
	out = &ListJobsOutput{}
	mapping := map[types.UID]*ListJobItem{}
	for _, job := range jobs.Items {
		if len(job.Spec.Template.Spec.Containers) != 1 {
			k.logs.Debugf("skipping job '%s' in namespace '%s' as it has not just 1 container", job.Name, job.Namespace)
			continue
		}

		//@TODO if parralism is set to 0, consider "stopped"?

		c := job.Spec.Template.Spec.Containers[0]
		item := &ListJobItem{
			Name:      job.GetName(),
			Image:     c.Image,
			CreatedAt: job.CreationTimestamp.Local(),
		}

		if dt := job.GetDeletionTimestamp(); dt != nil {
			item.DeletedAt = dt.Local() //mark as deleting
		}

		if job.Status.StartTime != nil {
			item.ActiveAt = job.Status.StartTime.Local()
		}

		for _, cond := range job.Status.Conditions {
			if cond.Status != corev1.ConditionTrue {
				continue
			}

			switch cond.Type {
			case batchv1.JobComplete:
				item.CompletedAt = cond.LastTransitionTime.Local()
			case batchv1.JobFailed:
				item.FailedAt = cond.LastTransitionTime.Local()
			}
		}

		mapping[job.UID] = item
		out.Items = append(out.Items, item)
	}

	//Step 2: Get all pods under nerd-app=cli
	pods := &pods{}
	err = k.visor.ListResources(ctx, kubevisor.ResourceTypePods, pods)
	if err != nil {
		return nil, err
	}

	//Step 3: Match pods to the jobs we got earlier and augment details with pod information
	for _, pod := range pods.Items {
		uid, ok := pod.Labels["controller-uid"]
		if !ok {
			continue //not part of a controller
		}

		jobItem, ok := mapping[types.UID(uid)]
		if !ok {
			continue //not part of any job
		}

		//technically we can have multiple pods per job (one terminating, unkown etc) so we pick the
		//one that is created most recently
		if pod.CreationTimestamp.Local().After(jobItem.Details.SeenAt) {
			jobItem.Details.SeenAt = pod.CreationTimestamp.Local()
		}

		//the pod phase allows us to distinguish between Pending and Running
		switch pod.Status.Phase {
		case corev1.PodPending:
			jobItem.Details.Phase = JobDetailsPhasePending
		case corev1.PodRunning:
			jobItem.Details.Phase = JobDetailsPhaseRunning
		case corev1.PodFailed:
			jobItem.Details.Phase = JobDetailsPhaseFailed
		case corev1.PodSucceeded:
			jobItem.Details.Phase = JobDetailsPhaseSucceeded
		default:
			jobItem.Details.Phase = JobDetailsPhaseUnknown
		}

		//container conditions allow us to capture ErrImageNotFound
		for _, cstatus := range pod.Status.ContainerStatuses {
			if cstatus.Name != "main" { //we only care about the main container
				continue
			}

			//waiting reasons give us ErrImagePull/Backoff
			if cstatus.State.Waiting != nil {
				jobItem.Details.WaitingReason = cstatus.State.Waiting.Reason
				jobItem.Details.WaitingMessage = cstatus.State.Waiting.Message
			}
		}
	}

	return out, nil
}

//jobs implements the list transformer interface to allow the kubevisor the manage names for us
type jobs struct{ *batchv1.JobList }

func (jobs *jobs) Transform(fn func(in kubevisor.ManagedNames) (out kubevisor.ManagedNames)) {
	for i, j1 := range jobs.JobList.Items {
		jobs.Items[i] = *(fn(&j1).(*batchv1.Job))
	}
}

//pods implements the list transformer interface to allow the kubevisor the manage names for us
type pods struct{ *corev1.PodList }

func (pods *pods) Transform(fn func(in kubevisor.ManagedNames) (out kubevisor.ManagedNames)) {
	for i, j1 := range pods.PodList.Items {
		pods.Items[i] = *(fn(&j1).(*corev1.Pod))
	}
}
<|endoftext|>


<commit_before>// Basic sequence quality package
package seq
// Copyright ©2011 Dan Kortschak <dan.kortschak@adelaide.edu.au>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

import (
	"github.com/kortschak/BioGo/bio"
	"github.com/kortschak/BioGo/featgroup"
	"github.com/kortschak/BioGo/interval"
	"github.com/kortschak/BioGo/util"
	"math"
)

type Quality struct {
	ID       string
	Qual     []int8
	Offset   int
	Strand   int8
	Circular bool
}

func NewQuality(id string, seq []int8) *Quality {
	return &Quality{
		ID:       id,
		Qual:     seq,
		Offset:   0,
		Strand:   1,
		Circular: false,
	}
}

func (self *Quality) Len() int {
	return len(self.Qual)
}

func (self *Quality) Start() int {
	return self.Offset
}

func (self *Quality) End() int {
	return self.Offset + len(self.Qual)
}

func (self *Quality) Trunc(start, end int) (q *Quality, err error) {
	var ts []int8

	if start < self.Offset || end < self.Offset ||
		start > len(self.Qual)+self.Offset || end > len(self.Qual)+self.Offset {
		return nil, bio.NewError("Start or end position out of range.", 0, self)
	}

	if start <= end {
		ts = append([]int8{}, self.Qual[start-self.Offset:end-self.Offset]...)
	} else if self.Circular {
		ts = make([]int8, len(self.Qual)-start-self.Offset, len(self.Qual)+end-start)
		copy(ts, self.Qual[start-self.Offset:])
		ts = append(ts, self.Qual[:end-self.Offset]...)
	} else {
		return nil, bio.NewError("Start position greater than end position for non-circular molecule.", 0, self)
	}

	return &Quality{
		ID:       self.ID,
		Qual:     ts,
		Offset:   start,
		Strand:   self.Strand,
		Circular: false,
	}, nil
}

func (self *Quality) Reverse() *Quality {
	rs := make([]int8, len(self.Qual))

	for i, j := 0, len(self.Qual)-1; i < j; i, j = i+1, j-1 {
		rs[i], rs[j] = self.Qual[j], self.Qual[i]
	}

	return &Quality{
		ID:       self.ID,
		Qual:     rs,
		Offset:   0,
		Strand:   -self.Strand,
		Circular: self.Circular,
	}
}

func (self *Quality) Join(q *Quality, where int) (err error) {
	if self.Circular {
		return bio.NewError("Cannot join circular molecule.", 0, self)
	}
	switch where {
	case Prepend:
		ts := make([]int8, len(q.Qual), len(q.Qual)+len(self.Qual))
		copy(ts, q.Qual)
		self.Qual = append(ts, self.Qual...)
	case Append:
		self.Qual = append(self.Qual, q.Qual...)
	}

	return
}

func (self *Quality) Stitch(f *featgroup.FeatureGroup) (q *Quality, err error) {
	t := interval.NewTree()
	var i *interval.Interval

	for _, feature := range *f {
		if i, err = interval.New("", feature.Start, feature.End, 0, nil); err != nil {
			return nil, err
		} else {
			t.Insert(i)
		}
	}

	tq := []int8{}
	if span, err := interval.New("", self.Start(), self.End(), 0, nil); err != nil {
		panic("Seq.End() < Seq.Start()")
	} else {
		f, _ := t.Flatten(span, 0, 0)
		for _, seg := range f {
			tq = append(tq, self.Qual[util.Max(seg.Start()-self.Offset, 0):util.Min(seg.End()-self.Offset, len(self.Qual))]...)
		}
	}

	self.Qual = tq
	self.Offset = 0

	return self, nil
}
func SangerToSolexa(q int8) int8 {
	return int8(10 * math.Log10(math.Pow(10, float64(q)/10)-1))
}

func SolexaToSanger(q int8) int8 {
	return int8(10 * math.Log10(math.Pow(10, float64(q)/10)+1))
}

// Return the quality as a Sanger quality string
func (self *Quality) String() string {
	qs := make([]byte, 0, len(self.Qual))
	for _, q := range self.Qual {
		if q <= 93 {
			q += 33
		}
		qs = append(qs, byte(q))
	}
	return string(qs)
}
<commit_msg>Godoc error.<commit_after>package seq
// Copyright ©2011 Dan Kortschak <dan.kortschak@adelaide.edu.au>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

import (
	"github.com/kortschak/BioGo/bio"
	"github.com/kortschak/BioGo/featgroup"
	"github.com/kortschak/BioGo/interval"
	"github.com/kortschak/BioGo/util"
	"math"
)

type Quality struct {
	ID       string
	Qual     []int8
	Offset   int
	Strand   int8
	Circular bool
}

func NewQuality(id string, seq []int8) *Quality {
	return &Quality{
		ID:       id,
		Qual:     seq,
		Offset:   0,
		Strand:   1,
		Circular: false,
	}
}

func (self *Quality) Len() int {
	return len(self.Qual)
}

func (self *Quality) Start() int {
	return self.Offset
}

func (self *Quality) End() int {
	return self.Offset + len(self.Qual)
}

func (self *Quality) Trunc(start, end int) (q *Quality, err error) {
	var ts []int8

	if start < self.Offset || end < self.Offset ||
		start > len(self.Qual)+self.Offset || end > len(self.Qual)+self.Offset {
		return nil, bio.NewError("Start or end position out of range.", 0, self)
	}

	if start <= end {
		ts = append([]int8{}, self.Qual[start-self.Offset:end-self.Offset]...)
	} else if self.Circular {
		ts = make([]int8, len(self.Qual)-start-self.Offset, len(self.Qual)+end-start)
		copy(ts, self.Qual[start-self.Offset:])
		ts = append(ts, self.Qual[:end-self.Offset]...)
	} else {
		return nil, bio.NewError("Start position greater than end position for non-circular molecule.", 0, self)
	}

	return &Quality{
		ID:       self.ID,
		Qual:     ts,
		Offset:   start,
		Strand:   self.Strand,
		Circular: false,
	}, nil
}

func (self *Quality) Reverse() *Quality {
	rs := make([]int8, len(self.Qual))

	for i, j := 0, len(self.Qual)-1; i < j; i, j = i+1, j-1 {
		rs[i], rs[j] = self.Qual[j], self.Qual[i]
	}

	return &Quality{
		ID:       self.ID,
		Qual:     rs,
		Offset:   0,
		Strand:   -self.Strand,
		Circular: self.Circular,
	}
}

func (self *Quality) Join(q *Quality, where int) (err error) {
	if self.Circular {
		return bio.NewError("Cannot join circular molecule.", 0, self)
	}
	switch where {
	case Prepend:
		ts := make([]int8, len(q.Qual), len(q.Qual)+len(self.Qual))
		copy(ts, q.Qual)
		self.Qual = append(ts, self.Qual...)
	case Append:
		self.Qual = append(self.Qual, q.Qual...)
	}

	return
}

func (self *Quality) Stitch(f *featgroup.FeatureGroup) (q *Quality, err error) {
	t := interval.NewTree()
	var i *interval.Interval

	for _, feature := range *f {
		if i, err = interval.New("", feature.Start, feature.End, 0, nil); err != nil {
			return nil, err
		} else {
			t.Insert(i)
		}
	}

	tq := []int8{}
	if span, err := interval.New("", self.Start(), self.End(), 0, nil); err != nil {
		panic("Seq.End() < Seq.Start()")
	} else {
		f, _ := t.Flatten(span, 0, 0)
		for _, seg := range f {
			tq = append(tq, self.Qual[util.Max(seg.Start()-self.Offset, 0):util.Min(seg.End()-self.Offset, len(self.Qual))]...)
		}
	}

	self.Qual = tq
	self.Offset = 0

	return self, nil
}
func SangerToSolexa(q int8) int8 {
	return int8(10 * math.Log10(math.Pow(10, float64(q)/10)-1))
}

func SolexaToSanger(q int8) int8 {
	return int8(10 * math.Log10(math.Pow(10, float64(q)/10)+1))
}

// Return the quality as a Sanger quality string
func (self *Quality) String() string {
	qs := make([]byte, 0, len(self.Qual))
	for _, q := range self.Qual {
		if q <= 93 {
			q += 33
		}
		qs = append(qs, byte(q))
	}
	return string(qs)
}
<|endoftext|>


<commit_before>package bitcoin

import (
	"sync"
	"time"

	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"github.com/OpenBazaar/wallet-interface"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("transaction-listener")

type TransactionListener struct {
	db        repo.Datastore
	broadcast chan repo.Notifier
	*sync.Mutex
}

func NewTransactionListener(db repo.Datastore, broadcast chan repo.Notifier) *TransactionListener {
	l := &TransactionListener{db, broadcast, new(sync.Mutex)}
	return l
}

func (l *TransactionListener) OnTransactionReceived(cb wallet.TransactionCallback) {
	l.Lock()
	defer l.Unlock()
	for _, output := range cb.Outputs {
		contract, state, funded, records, err := l.db.Sales().GetByPaymentAddress(output.Address)
		if err == nil && state != pb.OrderState_PROCESSING_ERROR {
			l.processSalePayment(cb.Txid, output, contract, state, funded, records)
			continue
		}
		contract, state, funded, records, err = l.db.Purchases().GetByPaymentAddress(output.Address)
		if err == nil {
			l.processPurchasePayment(cb.Txid, output, contract, state, funded, records)
			continue
		}
	}
	for _, input := range cb.Inputs {
		isForSale := true
		contract, state, funded, records, err := l.db.Sales().GetByPaymentAddress(input.LinkedAddress)
		if err != nil {
			contract, state, funded, records, err = l.db.Purchases().GetByPaymentAddress(input.LinkedAddress)
			if err != nil {
				continue
			}
			isForSale = false
		}
		if isForSale && contract.BuyerOrder.Payment.Method == pb.Order_Payment_ADDRESS_REQUEST {
			continue
		}

		orderId, err := calcOrderId(contract.BuyerOrder)
		if err != nil {
			continue
		}

		outpointHash, err := chainhash.NewHash(input.OutpointHash)
		if err != nil {
			continue
		}

		fundsReleased := true
		for i, r := range records {
			if r.Txid == outpointHash.String() && r.Index == input.OutpointIndex {
				records[i].Spent = true
			}
			if records[i].Value > 0 && !records[i].Spent {
				fundsReleased = false
			}
		}

		record := &wallet.TransactionRecord{
			Timestamp: time.Now(),
			Txid:      cb.Txid,
			Index:     input.OutpointIndex,
			Value:     -input.Value,
			Address:   input.LinkedAddress.String(),
		}
		records = append(records, record)
		if isForSale {
			l.db.Sales().UpdateFunding(orderId, funded, records)
			// This is a dispute payout. We should set the order state.
			if state == pb.OrderState_DECIDED && len(records) > 0 && fundsReleased {
				if contract.DisputeAcceptance == nil && contract != nil && contract.BuyerOrder != nil && contract.BuyerOrder.BuyerID != nil {
					accept := new(pb.DisputeAcceptance)
					ts, _ := ptypes.TimestampProto(time.Now())
					accept.Timestamp = ts
					accept.ClosedBy = contract.BuyerOrder.BuyerID.PeerID
					contract.DisputeAcceptance = accept
					buyerHandle := contract.BuyerOrder.BuyerID.Handle

					n := repo.DisputeAcceptedNotification{
						repo.NewNotificationID(),
						"disputeAccepted",
						orderId,
						repo.Thumbnail{contract.VendorListings[0].Item.Images[0].Tiny, contract.VendorListings[0].Item.Images[0].Small},
						accept.ClosedBy,
						buyerHandle,
						accept.ClosedBy,
					}

					l.broadcast <- n
					l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
				}
				l.db.Sales().Put(orderId, *contract, pb.OrderState_RESOLVED, false)
			}
		} else {
			l.db.Purchases().UpdateFunding(orderId, funded, records)
			if state == pb.OrderState_DECIDED && len(records) > 0 && fundsReleased {
				if contract.DisputeAcceptance == nil && contract != nil && len(contract.VendorListings) > 0 && contract.VendorListings[0].VendorID != nil {
					accept := new(pb.DisputeAcceptance)
					ts, _ := ptypes.TimestampProto(time.Now())
					accept.Timestamp = ts
					accept.ClosedBy = contract.VendorListings[0].VendorID.PeerID
					contract.DisputeAcceptance = accept
					vendorHandle := contract.VendorListings[0].VendorID.Handle
					var buyer string
					if contract.BuyerOrder != nil && contract.BuyerOrder.BuyerID != nil {
						buyer = contract.BuyerOrder.BuyerID.PeerID
					}

					n := repo.DisputeAcceptedNotification{
						repo.NewNotificationID(),
						"disputeAccepted",
						orderId,
						repo.Thumbnail{contract.VendorListings[0].Item.Images[0].Tiny, contract.VendorListings[0].Item.Images[0].Small},
						accept.ClosedBy,
						vendorHandle,
						buyer,
					}

					l.broadcast <- n
					l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
				}
				l.db.Purchases().Put(orderId, *contract, pb.OrderState_RESOLVED, false)
			}
		}
	}

}

func (l *TransactionListener) processSalePayment(txid string, output wallet.TransactionOutput, contract *pb.RicardianContract, state pb.OrderState, funded bool, records []*wallet.TransactionRecord) {
	funding := output.Value
	for _, r := range records {
		funding += r.Value
		// If we have already seen this transaction for some reason, just return
		if r.Txid == txid {
			return
		}
	}
	orderId, err := calcOrderId(contract.BuyerOrder)
	if err != nil {
		return
	}
	if !funded {
		requestedAmount := int64(contract.BuyerOrder.Payment.Amount)
		if funding >= requestedAmount {
			log.Debugf("Received payment for order %s", orderId)
			funded = true

			if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation != nil { // Confirmed orders go to AWAITING_FULFILLMENT
				l.db.Sales().Put(orderId, *contract, pb.OrderState_AWAITING_FULFILLMENT, false)
			} else if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation == nil { // Unconfirmed orders go into PENDING
				l.db.Sales().Put(orderId, *contract, pb.OrderState_PENDING, false)
			}
			l.adjustInventory(contract)

			n := repo.OrderNotification{
				BuyerHandle: contract.BuyerOrder.BuyerID.Handle,
				BuyerID:     contract.BuyerOrder.BuyerID.PeerID,
				ID:          repo.NewNotificationID(),
				ListingType: contract.VendorListings[0].Metadata.ContractType.String(),
				OrderId:     orderId,
				Price: repo.ListingPrice{
					Amount:           contract.BuyerOrder.Payment.Amount,
					CoinDivisibility: contract.VendorListings[0].Metadata.CoinDivisibility,
					CurrencyCode:     contract.VendorListings[0].Metadata.AcceptedCurrencies[0],
					PriceModifier:    contract.VendorListings[0].Metadata.PriceModifier,
				},
				Slug:      contract.VendorListings[0].Slug,
				Thumbnail: repo.Thumbnail{contract.VendorListings[0].Item.Images[0].Tiny, contract.VendorListings[0].Item.Images[0].Small},
				Title:     contract.VendorListings[0].Item.Title,
				Type:      "order",
			}

			l.broadcast <- n
			l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
		}
	}

	record := &wallet.TransactionRecord{
		Timestamp: time.Now(),
		Txid:      txid,
		Index:     output.Index,
		Value:     output.Value,
		Address:   output.Address.String(),
	}
	records = append(records, record)
	l.db.Sales().UpdateFunding(orderId, funded, records)

	// Save tx metadata
	var thumbnail string
	var title string
	if contract.VendorListings[0].Item != nil && len(contract.VendorListings[0].Item.Images) > 0 {
		thumbnail = contract.VendorListings[0].Item.Images[0].Tiny
		title = contract.VendorListings[0].Item.Title
	}
	bumpable := false
	if contract.BuyerOrder.Payment.Method != pb.Order_Payment_MODERATED {
		bumpable = true
	}
	l.db.TxMetadata().Put(repo.Metadata{txid, "", title, orderId, thumbnail, bumpable})
}

func (l *TransactionListener) processPurchasePayment(txid string, output wallet.TransactionOutput, contract *pb.RicardianContract, state pb.OrderState, funded bool, records []*wallet.TransactionRecord) {
	funding := output.Value
	for _, r := range records {
		funding += r.Value
		// If we have already seen this transaction for some reason, just return
		if r.Txid == txid {
			return
		}
	}
	orderId, err := calcOrderId(contract.BuyerOrder)
	if err != nil {
		return
	}
	if !funded {
		requestedAmount := int64(contract.BuyerOrder.Payment.Amount)
		if funding >= requestedAmount {
			log.Debugf("Payment for purchase %s detected", orderId)
			funded = true
			if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation != nil { // Confirmed orders go to AWAITING_FULFILLMENT
				l.db.Purchases().Put(orderId, *contract, pb.OrderState_AWAITING_FULFILLMENT, false)
			} else if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation == nil { // Unconfirmed go into PENDING
				l.db.Purchases().Put(orderId, *contract, pb.OrderState_PENDING, false)
			}
		}
		n := repo.PaymentNotification{
			repo.NewNotificationID(),
			"payment",
			orderId,
			uint64(funding),
		}
		l.broadcast <- n
		l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
	}

	record := &wallet.TransactionRecord{
		Txid:      txid,
		Index:     output.Index,
		Value:     output.Value,
		Address:   output.Address.String(),
		Timestamp: time.Now(),
	}
	records = append(records, record)
	l.db.Purchases().UpdateFunding(orderId, funded, records)
}

func (l *TransactionListener) adjustInventory(contract *pb.RicardianContract) {
	inventoryUpdated := false
	for _, item := range contract.BuyerOrder.Items {
		listing, err := core.ParseContractForListing(item.ListingHash, contract)
		if err != nil {
			continue
		}
		variant, err := core.GetSelectedSku(listing, item.Options)
		if err != nil {
			continue
		}
		c, err := l.db.Inventory().GetSpecific(listing.Slug, variant)
		if err != nil {
			continue
		}
		q := int64(core.GetOrderQuantity(listing, item))
		newCount := c - q
		if c < 0 {
			newCount = -1
		} else if newCount < 0 {
			newCount = 0
		}
		if (c == 0) || (c > 0 && c-q < 0) {
			orderId, err := calcOrderId(contract.BuyerOrder)
			if err != nil {
				continue
			}
			log.Warningf("Order %s purchased more inventory for %s than we have on hand", orderId, listing.Slug)
			l.broadcast <- repo.PremarshalledNotifier{[]byte(`{"warning": "order ` + orderId + ` exceeded on hand inventory for ` + listing.Slug + `"`)}
		}
		l.db.Inventory().Put(listing.Slug, variant, newCount)
		inventoryUpdated = true
		if newCount >= 0 {
			log.Debugf("Adjusting inventory for %s:%d to %d\n", listing.Slug, variant, newCount)
		}
	}

	if inventoryUpdated && core.Node != nil {
		core.Node.PublishInventory()
	}
}

func calcOrderId(order *pb.Order) (string, error) {
	ser, err := proto.Marshal(order)
	if err != nil {
		return "", err
	}
	id, err := core.EncodeMultihash(ser)
	if err != nil {
		return "", err
	}
	return id.B58String(), nil
}
<commit_msg>[#1188] Use BuyerOrder.Payment.Coin to indicate order socket's currency<commit_after>package bitcoin

import (
	"sync"
	"time"

	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"github.com/OpenBazaar/wallet-interface"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("transaction-listener")

type TransactionListener struct {
	db        repo.Datastore
	broadcast chan repo.Notifier
	*sync.Mutex
}

func NewTransactionListener(db repo.Datastore, broadcast chan repo.Notifier) *TransactionListener {
	l := &TransactionListener{db, broadcast, new(sync.Mutex)}
	return l
}

func (l *TransactionListener) OnTransactionReceived(cb wallet.TransactionCallback) {
	l.Lock()
	defer l.Unlock()
	for _, output := range cb.Outputs {
		contract, state, funded, records, err := l.db.Sales().GetByPaymentAddress(output.Address)
		if err == nil && state != pb.OrderState_PROCESSING_ERROR {
			l.processSalePayment(cb.Txid, output, contract, state, funded, records)
			continue
		}
		contract, state, funded, records, err = l.db.Purchases().GetByPaymentAddress(output.Address)
		if err == nil {
			l.processPurchasePayment(cb.Txid, output, contract, state, funded, records)
			continue
		}
	}
	for _, input := range cb.Inputs {
		isForSale := true
		contract, state, funded, records, err := l.db.Sales().GetByPaymentAddress(input.LinkedAddress)
		if err != nil {
			contract, state, funded, records, err = l.db.Purchases().GetByPaymentAddress(input.LinkedAddress)
			if err != nil {
				continue
			}
			isForSale = false
		}
		if isForSale && contract.BuyerOrder.Payment.Method == pb.Order_Payment_ADDRESS_REQUEST {
			continue
		}

		orderId, err := calcOrderId(contract.BuyerOrder)
		if err != nil {
			continue
		}

		outpointHash, err := chainhash.NewHash(input.OutpointHash)
		if err != nil {
			continue
		}

		fundsReleased := true
		for i, r := range records {
			if r.Txid == outpointHash.String() && r.Index == input.OutpointIndex {
				records[i].Spent = true
			}
			if records[i].Value > 0 && !records[i].Spent {
				fundsReleased = false
			}
		}

		record := &wallet.TransactionRecord{
			Timestamp: time.Now(),
			Txid:      cb.Txid,
			Index:     input.OutpointIndex,
			Value:     -input.Value,
			Address:   input.LinkedAddress.String(),
		}
		records = append(records, record)
		if isForSale {
			l.db.Sales().UpdateFunding(orderId, funded, records)
			// This is a dispute payout. We should set the order state.
			if state == pb.OrderState_DECIDED && len(records) > 0 && fundsReleased {
				if contract.DisputeAcceptance == nil && contract != nil && contract.BuyerOrder != nil && contract.BuyerOrder.BuyerID != nil {
					accept := new(pb.DisputeAcceptance)
					ts, _ := ptypes.TimestampProto(time.Now())
					accept.Timestamp = ts
					accept.ClosedBy = contract.BuyerOrder.BuyerID.PeerID
					contract.DisputeAcceptance = accept
					buyerHandle := contract.BuyerOrder.BuyerID.Handle

					n := repo.DisputeAcceptedNotification{
						repo.NewNotificationID(),
						"disputeAccepted",
						orderId,
						repo.Thumbnail{contract.VendorListings[0].Item.Images[0].Tiny, contract.VendorListings[0].Item.Images[0].Small},
						accept.ClosedBy,
						buyerHandle,
						accept.ClosedBy,
					}

					l.broadcast <- n
					l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
				}
				l.db.Sales().Put(orderId, *contract, pb.OrderState_RESOLVED, false)
			}
		} else {
			l.db.Purchases().UpdateFunding(orderId, funded, records)
			if state == pb.OrderState_DECIDED && len(records) > 0 && fundsReleased {
				if contract.DisputeAcceptance == nil && contract != nil && len(contract.VendorListings) > 0 && contract.VendorListings[0].VendorID != nil {
					accept := new(pb.DisputeAcceptance)
					ts, _ := ptypes.TimestampProto(time.Now())
					accept.Timestamp = ts
					accept.ClosedBy = contract.VendorListings[0].VendorID.PeerID
					contract.DisputeAcceptance = accept
					vendorHandle := contract.VendorListings[0].VendorID.Handle
					var buyer string
					if contract.BuyerOrder != nil && contract.BuyerOrder.BuyerID != nil {
						buyer = contract.BuyerOrder.BuyerID.PeerID
					}

					n := repo.DisputeAcceptedNotification{
						repo.NewNotificationID(),
						"disputeAccepted",
						orderId,
						repo.Thumbnail{contract.VendorListings[0].Item.Images[0].Tiny, contract.VendorListings[0].Item.Images[0].Small},
						accept.ClosedBy,
						vendorHandle,
						buyer,
					}

					l.broadcast <- n
					l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
				}
				l.db.Purchases().Put(orderId, *contract, pb.OrderState_RESOLVED, false)
			}
		}
	}

}

func (l *TransactionListener) processSalePayment(txid string, output wallet.TransactionOutput, contract *pb.RicardianContract, state pb.OrderState, funded bool, records []*wallet.TransactionRecord) {
	funding := output.Value
	for _, r := range records {
		funding += r.Value
		// If we have already seen this transaction for some reason, just return
		if r.Txid == txid {
			return
		}
	}
	orderId, err := calcOrderId(contract.BuyerOrder)
	if err != nil {
		return
	}
	if !funded {
		requestedAmount := int64(contract.BuyerOrder.Payment.Amount)
		if funding >= requestedAmount {
			log.Debugf("Received payment for order %s", orderId)
			funded = true

			if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation != nil { // Confirmed orders go to AWAITING_FULFILLMENT
				l.db.Sales().Put(orderId, *contract, pb.OrderState_AWAITING_FULFILLMENT, false)
			} else if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation == nil { // Unconfirmed orders go into PENDING
				l.db.Sales().Put(orderId, *contract, pb.OrderState_PENDING, false)
			}
			l.adjustInventory(contract)

			n := repo.OrderNotification{
				BuyerHandle: contract.BuyerOrder.BuyerID.Handle,
				BuyerID:     contract.BuyerOrder.BuyerID.PeerID,
				ID:          repo.NewNotificationID(),
				ListingType: contract.VendorListings[0].Metadata.ContractType.String(),
				OrderId:     orderId,
				Price: repo.ListingPrice{
					Amount:           contract.BuyerOrder.Payment.Amount,
					CoinDivisibility: contract.VendorListings[0].Metadata.CoinDivisibility,
					CurrencyCode:     contract.BuyerOrder.Payment.Coin,
					PriceModifier:    contract.VendorListings[0].Metadata.PriceModifier,
				},
				Slug:      contract.VendorListings[0].Slug,
				Thumbnail: repo.Thumbnail{contract.VendorListings[0].Item.Images[0].Tiny, contract.VendorListings[0].Item.Images[0].Small},
				Title:     contract.VendorListings[0].Item.Title,
				Type:      "order",
			}

			l.broadcast <- n
			l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
		}
	}

	record := &wallet.TransactionRecord{
		Timestamp: time.Now(),
		Txid:      txid,
		Index:     output.Index,
		Value:     output.Value,
		Address:   output.Address.String(),
	}
	records = append(records, record)
	l.db.Sales().UpdateFunding(orderId, funded, records)

	// Save tx metadata
	var thumbnail string
	var title string
	if contract.VendorListings[0].Item != nil && len(contract.VendorListings[0].Item.Images) > 0 {
		thumbnail = contract.VendorListings[0].Item.Images[0].Tiny
		title = contract.VendorListings[0].Item.Title
	}
	bumpable := false
	if contract.BuyerOrder.Payment.Method != pb.Order_Payment_MODERATED {
		bumpable = true
	}
	l.db.TxMetadata().Put(repo.Metadata{txid, "", title, orderId, thumbnail, bumpable})
}

func (l *TransactionListener) processPurchasePayment(txid string, output wallet.TransactionOutput, contract *pb.RicardianContract, state pb.OrderState, funded bool, records []*wallet.TransactionRecord) {
	funding := output.Value
	for _, r := range records {
		funding += r.Value
		// If we have already seen this transaction for some reason, just return
		if r.Txid == txid {
			return
		}
	}
	orderId, err := calcOrderId(contract.BuyerOrder)
	if err != nil {
		return
	}
	if !funded {
		requestedAmount := int64(contract.BuyerOrder.Payment.Amount)
		if funding >= requestedAmount {
			log.Debugf("Payment for purchase %s detected", orderId)
			funded = true
			if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation != nil { // Confirmed orders go to AWAITING_FULFILLMENT
				l.db.Purchases().Put(orderId, *contract, pb.OrderState_AWAITING_FULFILLMENT, false)
			} else if state == pb.OrderState_AWAITING_PAYMENT && contract.VendorOrderConfirmation == nil { // Unconfirmed go into PENDING
				l.db.Purchases().Put(orderId, *contract, pb.OrderState_PENDING, false)
			}
		}
		n := repo.PaymentNotification{
			repo.NewNotificationID(),
			"payment",
			orderId,
			uint64(funding),
		}
		l.broadcast <- n
		l.db.Notifications().PutRecord(repo.NewNotification(n, time.Now(), false))
	}

	record := &wallet.TransactionRecord{
		Txid:      txid,
		Index:     output.Index,
		Value:     output.Value,
		Address:   output.Address.String(),
		Timestamp: time.Now(),
	}
	records = append(records, record)
	l.db.Purchases().UpdateFunding(orderId, funded, records)
}

func (l *TransactionListener) adjustInventory(contract *pb.RicardianContract) {
	inventoryUpdated := false
	for _, item := range contract.BuyerOrder.Items {
		listing, err := core.ParseContractForListing(item.ListingHash, contract)
		if err != nil {
			continue
		}
		variant, err := core.GetSelectedSku(listing, item.Options)
		if err != nil {
			continue
		}
		c, err := l.db.Inventory().GetSpecific(listing.Slug, variant)
		if err != nil {
			continue
		}
		q := int64(core.GetOrderQuantity(listing, item))
		newCount := c - q
		if c < 0 {
			newCount = -1
		} else if newCount < 0 {
			newCount = 0
		}
		if (c == 0) || (c > 0 && c-q < 0) {
			orderId, err := calcOrderId(contract.BuyerOrder)
			if err != nil {
				continue
			}
			log.Warningf("Order %s purchased more inventory for %s than we have on hand", orderId, listing.Slug)
			l.broadcast <- repo.PremarshalledNotifier{[]byte(`{"warning": "order ` + orderId + ` exceeded on hand inventory for ` + listing.Slug + `"`)}
		}
		l.db.Inventory().Put(listing.Slug, variant, newCount)
		inventoryUpdated = true
		if newCount >= 0 {
			log.Debugf("Adjusting inventory for %s:%d to %d\n", listing.Slug, variant, newCount)
		}
	}

	if inventoryUpdated && core.Node != nil {
		core.Node.PublishInventory()
	}
}

func calcOrderId(order *pb.Order) (string, error) {
	ser, err := proto.Marshal(order)
	if err != nil {
		return "", err
	}
	id, err := core.EncodeMultihash(ser)
	if err != nil {
		return "", err
	}
	return id.B58String(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"net/smtp"
	"fmt"
)

func SendEmail(to string, subject string, body string) {
	config, _ := Configuration()
  from := config.Email
	pass := config.Password
	cc := config.Email
	fmt.Println("Report User or Comment to " + from)
	msg := "From: " + from + "\n" +
		"To: " + from + "\n" +
    "Cc: " + cc + "\n" +
		"Subject: " + subject + "\n\n" +
		body

	smtp.SendMail("smtp.gmail.com:587",
		smtp.PlainAuth("", from, pass, "smtp.gmail.com"),
		from, []string{to}, []byte(msg))
}
<commit_msg>fix bug reporting<commit_after>package main

import (
	"net/smtp"
)

func SendEmail(to string, subject string, body string) {
	config, _ := Configuration()
  from := config.Email
	pass := config.Password
	cc := config.Email

	msg := "From: " + from + "\n" +
		"To: " + from + "\n" +
    "Cc: " + cc + "\n" +
		"Subject: " + subject + "\n\n" +
		body

	smtp.SendMail("smtp.gmail.com:587",
		smtp.PlainAuth("", from, pass, "smtp.gmail.com"),
		from, []string{from}, []byte(msg))
}
<|endoftext|>


<commit_before>package dhcp4

import (
	"code.google.com/p/go.net/ipv4"
	"net"
)

type serveIfConn struct {
	ifIndex int
	conn    *ipv4.PacketConn
	cm      *ipv4.ControlMessage
}

func (s *serveIfConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
	n, s.cm, addr, err = s.conn.ReadFrom(b)
	if s.cm != nil && s.cm.IfIndex != s.ifIndex { // Filter all other interfaces
		n = 0 // Packets < 240 are filtered in Serve().
	}
	return
}

func (s *serveIfConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
	return s.conn.WriteTo(b, s.cm, addr)
}

// ServeIf does the same job as Serve(), but listens and responds on the
// specified network interface (by index).  It also doubles as an example of
// how to leverage the dhcp4.ServeConn interface.
//
// If your target only has one interface, use Serve(). ServeIf() requires an
// import outside the std library.  Serving DHCP over multiple interfaces will
// require your own dhcp4.ServeConn, as listening to broadcasts utilises all
// interfaces (so you cannot have more than on listener).
func ServeIf(ifIndex int, conn net.PacketConn, handler Handler) error {
	p := ipv4.NewPacketConn(conn)
	if err := p.SetControlMessage(ipv4.FlagInterface, true); err != nil {
		return err
	}
	return Serve(&serveIfConn{ifIndex: ifIndex, conn: p}, handler)
}

// ListenAndServe listens on the UDP network address addr and then calls
// Serve with handler to handle requests on incoming packets.
// i.e. ListenAndServeIf("eth0",handler)
func ListenAndServeIf(interfaceName string, handler Handler) error {
	iface, err := net.InterfaceByName(interfaceName)
	if err != nil {
		return err
	}
	l, err := net.ListenPacket("udp4", ":67")
	if err != nil {
		return err
	}
	defer l.Close()
	return ServeIf(iface.Index, l, handler)
}
<commit_msg>Update net/ipv4 import with new paths.<commit_after>package dhcp4

import (
	"net"

	"golang.org/x/net/ipv4"
)

type serveIfConn struct {
	ifIndex int
	conn    *ipv4.PacketConn
	cm      *ipv4.ControlMessage
}

func (s *serveIfConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
	n, s.cm, addr, err = s.conn.ReadFrom(b)
	if s.cm != nil && s.cm.IfIndex != s.ifIndex { // Filter all other interfaces
		n = 0 // Packets < 240 are filtered in Serve().
	}
	return
}

func (s *serveIfConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
	return s.conn.WriteTo(b, s.cm, addr)
}

// ServeIf does the same job as Serve(), but listens and responds on the
// specified network interface (by index).  It also doubles as an example of
// how to leverage the dhcp4.ServeConn interface.
//
// If your target only has one interface, use Serve(). ServeIf() requires an
// import outside the std library.  Serving DHCP over multiple interfaces will
// require your own dhcp4.ServeConn, as listening to broadcasts utilises all
// interfaces (so you cannot have more than on listener).
func ServeIf(ifIndex int, conn net.PacketConn, handler Handler) error {
	p := ipv4.NewPacketConn(conn)
	if err := p.SetControlMessage(ipv4.FlagInterface, true); err != nil {
		return err
	}
	return Serve(&serveIfConn{ifIndex: ifIndex, conn: p}, handler)
}

// ListenAndServe listens on the UDP network address addr and then calls
// Serve with handler to handle requests on incoming packets.
// i.e. ListenAndServeIf("eth0",handler)
func ListenAndServeIf(interfaceName string, handler Handler) error {
	iface, err := net.InterfaceByName(interfaceName)
	if err != nil {
		return err
	}
	l, err := net.ListenPacket("udp4", ":67")
	if err != nil {
		return err
	}
	defer l.Close()
	return ServeIf(iface.Index, l, handler)
}
<|endoftext|>


<commit_before>// +build !linux

/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package cm

import (
	"k8s.io/kubernetes/pkg/kubelet/dockertools"
)

type unsupportedContainerManager struct {
}

func NewContainerManager(_ string, _ dockertools.DockerInterface) ContainerManager {
	return &unsupportedContainerManager{}
}

func (m *unsupportedContainerManager) Start() error {
	return fmt.Errorf("Container Manager is unsupported in this build")
}
<commit_msg>Fix build break on non-Linux OS introduced in 87aaf4c0<commit_after>// +build !linux

/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package cm

import (
	"fmt"
	"k8s.io/kubernetes/pkg/kubelet/dockertools"
)

type unsupportedContainerManager struct {
}

func NewContainerManager(_ string, _ dockertools.DockerInterface) ContainerManager {
	return &unsupportedContainerManager{}
}

func (m *unsupportedContainerManager) Start() error {
	return fmt.Errorf("Container Manager is unsupported in this build")
}
<|endoftext|>


<commit_before>// This file was generated by counterfeiter
package fake_gatherer

import (
	"sync"

	"github.com/cloudfoundry-incubator/executor"
	"github.com/cloudfoundry-incubator/rep/gatherer"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
)

type FakeSnapshot struct {
	ListContainersStub        func(tags executor.Tags) []executor.Container
	listContainersMutex       sync.RWMutex
	listContainersArgsForCall []struct {
		tags executor.Tags
	}
	listContainersReturns struct {
		result1 []executor.Container
	}
	GetContainerStub        func(guid string) (*executor.Container, bool)
	getContainerMutex       sync.RWMutex
	getContainerArgsForCall []struct {
		guid string
	}
	getContainerReturns struct {
		result1 *executor.Container
		result2 bool
	}
	ActualLRPsStub        func() []models.ActualLRP
	actualLRPsMutex       sync.RWMutex
	actualLRPsArgsForCall []struct{}
	actualLRPsReturns     struct {
		result1 []models.ActualLRP
	}
	TasksStub        func() []models.Task
	tasksMutex       sync.RWMutex
	tasksArgsForCall []struct{}
	tasksReturns     struct {
		result1 []models.Task
	}
	LookupTaskStub        func(guid string) (models.Task, bool, error)
	lookupTaskMutex       sync.RWMutex
	lookupTaskArgsForCall []struct {
		guid string
	}
	lookupTaskReturns struct {
		result1 models.Task
		result2 bool
		result3 error
	}
}

func (fake *FakeSnapshot) ListContainers(tags executor.Tags) []executor.Container {
	fake.listContainersMutex.Lock()
	fake.listContainersArgsForCall = append(fake.listContainersArgsForCall, struct {
		tags executor.Tags
	}{tags})
	fake.listContainersMutex.Unlock()
	if fake.ListContainersStub != nil {
		return fake.ListContainersStub(tags)
	} else {
		return fake.listContainersReturns.result1
	}
}

func (fake *FakeSnapshot) ListContainersCallCount() int {
	fake.listContainersMutex.RLock()
	defer fake.listContainersMutex.RUnlock()
	return len(fake.listContainersArgsForCall)
}

func (fake *FakeSnapshot) ListContainersArgsForCall(i int) executor.Tags {
	fake.listContainersMutex.RLock()
	defer fake.listContainersMutex.RUnlock()
	return fake.listContainersArgsForCall[i].tags
}

func (fake *FakeSnapshot) ListContainersReturns(result1 []executor.Container) {
	fake.ListContainersStub = nil
	fake.listContainersReturns = struct {
		result1 []executor.Container
	}{result1}
}

func (fake *FakeSnapshot) GetContainer(guid string) (*executor.Container, bool) {
	fake.getContainerMutex.Lock()
	fake.getContainerArgsForCall = append(fake.getContainerArgsForCall, struct {
		guid string
	}{guid})
	fake.getContainerMutex.Unlock()
	if fake.GetContainerStub != nil {
		return fake.GetContainerStub(guid)
	} else {
		return fake.getContainerReturns.result1, fake.getContainerReturns.result2
	}
}

func (fake *FakeSnapshot) GetContainerCallCount() int {
	fake.getContainerMutex.RLock()
	defer fake.getContainerMutex.RUnlock()
	return len(fake.getContainerArgsForCall)
}

func (fake *FakeSnapshot) GetContainerArgsForCall(i int) string {
	fake.getContainerMutex.RLock()
	defer fake.getContainerMutex.RUnlock()
	return fake.getContainerArgsForCall[i].guid
}

func (fake *FakeSnapshot) GetContainerReturns(result1 *executor.Container, result2 bool) {
	fake.GetContainerStub = nil
	fake.getContainerReturns = struct {
		result1 *executor.Container
		result2 bool
	}{result1, result2}
}

func (fake *FakeSnapshot) ActualLRPs() []models.ActualLRP {
	fake.actualLRPsMutex.Lock()
	fake.actualLRPsArgsForCall = append(fake.actualLRPsArgsForCall, struct{}{})
	fake.actualLRPsMutex.Unlock()
	if fake.ActualLRPsStub != nil {
		return fake.ActualLRPsStub()
	} else {
		return fake.actualLRPsReturns.result1
	}
}

func (fake *FakeSnapshot) ActualLRPsCallCount() int {
	fake.actualLRPsMutex.RLock()
	defer fake.actualLRPsMutex.RUnlock()
	return len(fake.actualLRPsArgsForCall)
}

func (fake *FakeSnapshot) ActualLRPsReturns(result1 []models.ActualLRP) {
	fake.ActualLRPsStub = nil
	fake.actualLRPsReturns = struct {
		result1 []models.ActualLRP
	}{result1}
}

func (fake *FakeSnapshot) Tasks() []models.Task {
	fake.tasksMutex.Lock()
	fake.tasksArgsForCall = append(fake.tasksArgsForCall, struct{}{})
	fake.tasksMutex.Unlock()
	if fake.TasksStub != nil {
		return fake.TasksStub()
	} else {
		return fake.tasksReturns.result1
	}
}

func (fake *FakeSnapshot) TasksCallCount() int {
	fake.tasksMutex.RLock()
	defer fake.tasksMutex.RUnlock()
	return len(fake.tasksArgsForCall)
}

func (fake *FakeSnapshot) TasksReturns(result1 []models.Task) {
	fake.TasksStub = nil
	fake.tasksReturns = struct {
		result1 []models.Task
	}{result1}
}

func (fake *FakeSnapshot) LookupTask(guid string) (models.Task, bool, error) {
	fake.lookupTaskMutex.Lock()
	fake.lookupTaskArgsForCall = append(fake.lookupTaskArgsForCall, struct {
		guid string
	}{guid})
	fake.lookupTaskMutex.Unlock()
	if fake.LookupTaskStub != nil {
		return fake.LookupTaskStub(guid)
	} else {
		return fake.lookupTaskReturns.result1, fake.lookupTaskReturns.result2, fake.lookupTaskReturns.result3
	}
}

func (fake *FakeSnapshot) LookupTaskCallCount() int {
	fake.lookupTaskMutex.RLock()
	defer fake.lookupTaskMutex.RUnlock()
	return len(fake.lookupTaskArgsForCall)
}

func (fake *FakeSnapshot) LookupTaskArgsForCall(i int) string {
	fake.lookupTaskMutex.RLock()
	defer fake.lookupTaskMutex.RUnlock()
	return fake.lookupTaskArgsForCall[i].guid
}

func (fake *FakeSnapshot) LookupTaskReturns(result1 models.Task, result2 bool, result3 error) {
	fake.LookupTaskStub = nil
	fake.lookupTaskReturns = struct {
		result1 models.Task
		result2 bool
		result3 error
	}{result1, result2, result3}
}

var _ gatherer.Snapshot = new(FakeSnapshot)
<commit_msg>Remove unused gatherer (and fake gatherer)<commit_after><|endoftext|>


<commit_before>package system

import (
	"fmt"

	"github.com/dmtar/pit/config"
	"github.com/gorilla/sessions"
	"gopkg.in/mgo.v2"
)

type Application struct {
	Store   *sessions.CookieStore
	db      *mgo.Database
	session *mgo.Session
}

func (application *Application) Init() {
	secret := []byte(config.Secret)
	application.Store = sessions.NewCookieStore(secret)
	go application.CreateIndexes()
}

func (application *Application) CreateIndexes() {
	var err error
	application.session, err = mgo.Dial("localhost")
	if err != nil {
		check(fmt.Errorf("Can't connect to mongo, go error: %v", err))
	}
	application.db = application.session.DB("pit")

	application.createIndexesOnPictures()
	application.createIndexesOnAlbums()
	application.createIndexesOnNotifications()

}

func (application *Application) createIndexesOnPictures() {
	var err error
	collection := application.db.C("fs.files")
	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"$2dsphere:metadata.location"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.tags"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.album"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.user"},
		Background: true,
	})
	check(err)
}

func (application *Application) createIndexesOnAlbums() {
	var err error
	collection := application.db.C("albums")
	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"$2dsphere:location"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.tags"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"data_range.start"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"data_range.end"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"user"},
		Background: true,
	})
	check(err)
}

func (application *Application) createIndexesOnNotifications() {
	var err error
	collection := application.db.C("notifications")
	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"user"},
		Background: true,
	})
	check(err)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>Add index on users.<commit_after>package system

import (
	"fmt"

	"github.com/dmtar/pit/config"
	"github.com/gorilla/sessions"
	"gopkg.in/mgo.v2"
)

type Application struct {
	Store   *sessions.CookieStore
	db      *mgo.Database
	session *mgo.Session
}

func (application *Application) Init() {
	secret := []byte(config.Secret)
	application.Store = sessions.NewCookieStore(secret)
	go application.CreateIndexes()
}

func (application *Application) CreateIndexes() {
	var err error
	application.session, err = mgo.Dial("localhost")
	if err != nil {
		check(fmt.Errorf("Can't connect to mongo, go error: %v", err))
	}
	application.db = application.session.DB("pit")

	application.createIndexesOnPictures()
	application.createIndexesOnAlbums()
	application.createIndexesOnNotifications()
	application.createIndexesOnUsers()

}

func (application *Application) createIndexesOnPictures() {
	var err error
	collection := application.db.C("fs.files")
	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"$2dsphere:metadata.location"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.tags"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.album"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.user"},
		Background: true,
	})
	check(err)
}

func (application *Application) createIndexesOnAlbums() {
	var err error
	collection := application.db.C("albums")
	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"$2dsphere:location"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"metadata.tags"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"data_range.start"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"data_range.end"},
		Background: true,
	})
	check(err)

	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"user"},
		Background: true,
	})
	check(err)
}

func (application *Application) createIndexesOnUsers() {
	var err error
	collection := application.db.C("users")
	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"email"},
		Background: true,
		Unique:     true,
	})
	check(err)
}

func (application *Application) createIndexesOnNotifications() {
	var err error
	collection := application.db.C("notifications")
	err = collection.EnsureIndex(mgo.Index{
		Key:        []string{"user"},
		Background: true,
	})
	check(err)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package logic

import (
	"sync"

	log "github.com/cihub/seelog"
	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/protocol"
)

type Rule interface {
	Uuid() string
	Name() string
	SetUuid(string)
	CondState() bool
	SetCondState(bool)
	RunEnter()
	RunExit()
	AddExitAction(Action)
	AddEnterAction(Action)
	AddCondition(RuleCondition)
	Conditions() []RuleCondition
}

type rule struct {
	Name_         string          `json:"name"`
	Uuid_         string          `json:"uuid"`
	Conditions_   []RuleCondition `json:"conditions"`
	EnterActions_ []string        `json:"enterActions"`
	ExitActions_  []string        `json:"exitActions"`
	enterActions_ []Action
	exitActions_  []Action
	condState     bool
	sync.RWMutex
	nodes *protocol.Nodes
}

func (r *rule) Uuid() string {
	r.RLock()
	defer r.RUnlock()
	return r.Uuid_
}
func (r *rule) Name() string {
	r.RLock()
	defer r.RUnlock()
	return r.Name_
}
func (r *rule) SetUuid(uuid string) {
	r.Lock()
	r.Uuid_ = uuid
	r.Unlock()
}
func (r *rule) CondState() bool {
	r.RLock()
	defer r.RUnlock()
	return r.condState
}
func (r *rule) Conditions() []RuleCondition {
	r.RLock()
	defer r.RUnlock()
	return r.Conditions_
}
func (r *rule) SetCondState(cond bool) {
	r.RLock()
	r.condState = cond
	r.RUnlock()
}
func (r *rule) RunEnter() {
	for _, a := range r.enterActions_ {
		a.Run()
	}
}
func (r *rule) RunExit() {
	for _, a := range r.exitActions_ {
		a.Run()
	}
}
func (r *rule) AddExitAction(a Action) {
	if a == nil {
		log.Error("Error adding ExitAction. Action is nil")
		return
	}
	r.Lock()
	r.exitActions_ = append(r.exitActions_, a)
	r.ExitActions_ = append(r.ExitActions_, a.Uuid())
	r.Unlock()
}
func (r *rule) AddEnterAction(a Action) {
	if a == nil {
		log.Error("Error adding EnterAction. Action is nil")
		return
	}
	r.Lock()
	r.enterActions_ = append(r.enterActions_, a)
	r.EnterActions_ = append(r.EnterActions_, a.Uuid())
	r.Unlock()
}
func (r *rule) AddCondition(a RuleCondition) {
	r.Lock()
	r.Conditions_ = append(r.Conditions_, a)
	r.Unlock()
}
<commit_msg>Added cancel calls<commit_after>package logic

import (
	"sync"

	log "github.com/cihub/seelog"
	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/protocol"
)

type Rule interface {
	Uuid() string
	Name() string
	SetUuid(string)
	CondState() bool
	SetCondState(bool)
	RunEnter()
	RunExit()
	AddExitAction(Action)
	AddEnterAction(Action)
	AddCondition(RuleCondition)
	Conditions() []RuleCondition
}

type rule struct {
	Name_         string          `json:"name"`
	Uuid_         string          `json:"uuid"`
	Conditions_   []RuleCondition `json:"conditions"`
	EnterActions_ []string        `json:"enterActions"`
	ExitActions_  []string        `json:"exitActions"`
	enterActions_ []Action
	exitActions_  []Action
	condState     bool
	sync.RWMutex
	nodes *protocol.Nodes
}

func (r *rule) Uuid() string {
	r.RLock()
	defer r.RUnlock()
	return r.Uuid_
}
func (r *rule) Name() string {
	r.RLock()
	defer r.RUnlock()
	return r.Name_
}
func (r *rule) SetUuid(uuid string) {
	r.Lock()
	r.Uuid_ = uuid
	r.Unlock()
}
func (r *rule) CondState() bool {
	r.RLock()
	defer r.RUnlock()
	return r.condState
}
func (r *rule) Conditions() []RuleCondition {
	r.RLock()
	defer r.RUnlock()
	return r.Conditions_
}
func (r *rule) SetCondState(cond bool) {
	r.RLock()
	r.condState = cond
	r.RUnlock()
}
func (r *rule) RunEnter() {
	for _, a := range r.exitActions_ {
		a.Cancel()
	}
	for _, a := range r.enterActions_ {
		a.Run()
	}
}
func (r *rule) RunExit() {
	for _, a := range r.enterActions_ {
		a.Cancel()
	}
	for _, a := range r.exitActions_ {
		a.Run()
	}
}
func (r *rule) AddExitAction(a Action) {
	if a == nil {
		log.Error("Error adding ExitAction. Action is nil")
		return
	}
	r.Lock()
	r.exitActions_ = append(r.exitActions_, a)
	r.ExitActions_ = append(r.ExitActions_, a.Uuid())
	r.Unlock()
}
func (r *rule) AddEnterAction(a Action) {
	if a == nil {
		log.Error("Error adding EnterAction. Action is nil")
		return
	}
	r.Lock()
	r.enterActions_ = append(r.enterActions_, a)
	r.EnterActions_ = append(r.EnterActions_, a.Uuid())
	r.Unlock()
}
func (r *rule) AddCondition(a RuleCondition) {
	r.Lock()
	r.Conditions_ = append(r.Conditions_, a)
	r.Unlock()
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"

	"github.com/iwannay/log"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// D alias DB
type D = gorm.DB

var (
	db        *D
	debugMode bool
)

func CreateDB(dialect string, dsn string) (err error) {
	switch dialect {
	case "sqlite3":
		return createSqlite(dsn)
	case "mysql":
		db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
			PrepareStmt: true,
		})
		return
	case "postgres":
		db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
			PrepareStmt: true,
		})
		return
	}
	return fmt.Errorf("unknow database type %s", dialect)
}

func createSqlite(dsn string) error {
	var err error
	if dsn == "" {
		return errors.New("sqlite:db file cannot empty")
	}

	dbDir := filepath.Dir(filepath.Clean(dsn))
	err = os.MkdirAll(dbDir, 0755)
	if err != nil {
		return fmt.Errorf("sqlite: makedir failed %s", err)
	}
	db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{})
	if err == nil {
		d, err := db.DB()
		if err != nil {
			panic(err)
		}
		d.SetMaxOpenConns(1)
	}
	return err
}

func DB() *D {
	if db == nil {
		panic("you must call CreateDb first")
	}
	if debugMode {
		return db.Debug()
	}
	return db
}

func Transactions(fn func(tx *gorm.DB) error) error {
	if fn == nil {
		return errors.New("fn is nil")
	}
	tx := DB().Begin()
	defer func() {
		if err := recover(); err != nil {
			DB().Rollback()
		}
	}()

	if fn(tx) != nil {
		tx.Rollback()
	}
	return tx.Commit().Error
}

func InitModel(driverName string, dsn string, debug bool) error {
	if driverName == "" || dsn == "" {
		return errors.New("driverName and dsn cannot empty")
	}

	if err := CreateDB(driverName, dsn); err != nil {
		return err
	}
	debugMode = debug
	AutoMigrate()
	return nil
}

func AutoMigrate() {
	if err := DB().AutoMigrate(&Node{}, &Group{}, &User{}, &Event{}, &JobHistory{}); err != nil {
		log.Fatal(err)
	}
	if err := DB().FirstOrCreate(&SuperGroup).Error; err != nil {
		log.Fatal(err)
	}
}
<commit_msg>修复sqlite automigrate异常<commit_after>package models

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"

	"github.com/iwannay/log"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// D alias DB
type D = gorm.DB

var (
	db        *D
	debugMode bool
)

func CreateDB(dialect string, dsn string) (err error) {
	switch dialect {
	case "sqlite3":
		return createSqlite(dsn)
	case "mysql":
		db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
			PrepareStmt:                              true,
			DisableForeignKeyConstraintWhenMigrating: true,
		})
		return
	case "postgres":
		db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
			PrepareStmt:                              true,
			DisableForeignKeyConstraintWhenMigrating: true,
		})
		return
	}
	return fmt.Errorf("unknow database type %s", dialect)
}

func createSqlite(dsn string) error {
	var err error
	if dsn == "" {
		return errors.New("sqlite:db file cannot empty")
	}

	dbDir := filepath.Dir(filepath.Clean(dsn))
	err = os.MkdirAll(dbDir, 0755)
	if err != nil {
		return fmt.Errorf("sqlite: makedir failed %s", err)
	}
	db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,
	})
	if err == nil {
		d, err := db.DB()
		if err != nil {
			panic(err)
		}
		d.SetMaxOpenConns(1)
	}
	return err
}

func DB() *D {
	if db == nil {
		panic("you must call CreateDb first")
	}
	if debugMode {
		return db.Debug()
	}
	return db
}

func Transactions(fn func(tx *gorm.DB) error) error {
	if fn == nil {
		return errors.New("fn is nil")
	}
	tx := DB().Begin()
	defer func() {
		if err := recover(); err != nil {
			DB().Rollback()
		}
	}()

	if fn(tx) != nil {
		tx.Rollback()
	}
	return tx.Commit().Error
}

func InitModel(driverName string, dsn string, debug bool) error {
	if driverName == "" || dsn == "" {
		return errors.New("driverName and dsn cannot empty")
	}

	if err := CreateDB(driverName, dsn); err != nil {
		return err
	}
	debugMode = debug
	AutoMigrate()
	return nil
}

func AutoMigrate() {
	if err := DB().AutoMigrate(&Node{}, &Group{}, &User{}, &Event{}, &JobHistory{}); err != nil {
		log.Fatal(err)
	}
	if err := DB().FirstOrCreate(&SuperGroup).Error; err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package vagrant

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/url"
	"strconv"
	"time"

	"koding/db/models"
	"koding/db/mongodb/modelhelper"
	"koding/kites/kloud/api/vagrantapi"
	puser "koding/kites/kloud/scripts/provisionklient/userdata"
	"koding/kites/kloud/stackplan"
	"koding/kites/kloud/utils"

	"github.com/satori/go.uuid"
	"gopkg.in/mgo.v2/bson"
)

// VagrantResource represents vagrant_instance Terraform resource.
type VagrantResource struct {
	Build map[string]map[string]interface{} `hcl:"vagrant_instance"`
}

func (s *Stack) updateCredential(cred *stackplan.Credential) {
	meta := cred.Meta.(*VagrantMeta)
	meta.SetDefaults()
}

type Tunnel struct {
	Name    string
	KiteURL string
}

func (s *Stack) newTunnel(resourceName string) *Tunnel {
	t := &Tunnel{
		Name:    utils.RandString(12),
		KiteURL: s.TunnelURL.String(),
	}

	if m, ok := s.Builder.Machines[resourceName]; ok {
		t.Name = m.Uid
	}

	return t
}

// InjectVagrantData sets default properties for vagrant_instance Terraform template.
//
// TODO(rjeczalik): move out hostQueryString outside this method.
func (s *Stack) InjectVagrantData() (string, stackplan.KiteMap, error) {
	// TODO(rjeczalik): add ByProvider to stackplan.Credentials
	for _, c := range s.Builder.Credentials {
		if c.Provider == "vagrant" {
			s.Credential = c
			break
		}
	}

	if s.Credential == nil {
		return "", nil, errors.New("vagrant credential not found")
	}

	s.updateCredential(s.Credential)

	t := s.Builder.Template
	meta := s.Credential.Meta.(*VagrantMeta)

	s.Log.Debug("Injecting vagrant credentials: %# v", meta)

	if err := t.InjectVariables(s.Credential.Provider, s.Credential.Meta); err != nil {
		return "", nil, err
	}

	var res VagrantResource

	if err := t.DecodeResource(&res); err != nil {
		return "", nil, err
	}

	if len(res.Build) == 0 {
		return "", nil, errors.New("no vagrant instances specified")
	}

	kiteIDs := make(stackplan.KiteMap)

	uids := s.Builder.MachineUIDs()

	s.Log.Debug("machine uids (%d): %v", len(uids), uids)

	klientURL, err := s.Session.Userdata.LookupKlientURL()
	if err != nil {
		return "", nil, err
	}

	// queryString is taken from jCredentialData.meta.queryString,
	// for debugging purposes it can be overwritten in the template,
	// however if template has multiple machines, all of them
	// are required to overwrite the queryString to the same value
	// to match current implementation of terraformplugins/vagrant
	// provider.
	//
	// Otherwise we fail early to show problem with the template.
	var queryString string
	for resourceName, box := range res.Build {
		kiteID := uuid.NewV4().String()

		kiteKey, err := s.Session.Userdata.Keycreator.Create(s.Req.Username, kiteID)
		if err != nil {
			return "", nil, err
		}

		// set kontrolURL if not provided via template
		kontrolURL := s.Session.Userdata.Keycreator.KontrolURL
		if k, ok := box["kontrolURL"].(string); ok {
			kontrolURL = k
		} else {
			box["kontrolURL"] = kontrolURL
		}

		if q, ok := box["queryString"].(string); ok {
			q = utils.QueryString(q)
			if queryString != "" && queryString != q {
				return "", nil, fmt.Errorf("mismatched queryString provided for multiple instances; want %q, got %q", queryString, q)
			}
			queryString = q
		} else {
			box["queryString"] = "${var.vagrant_queryString}"
			queryString = meta.QueryString
		}

		// set default filePath to relative <stackdir>/<boxname>; for
		// default configured klient it resolves to ~/.vagrant.d/<stackdir>/<boxname>
		if _, ok := box["filePath"]; !ok {
			uid, ok := uids[resourceName]
			if !ok {
				// For Plan call we return random uid as it won't be returned
				// as a part of meta; the filePath is inserted into meta by
				// the apply method.
				uid = resourceName + "-" + utils.RandString(6)
			}
			box["filePath"] = "koding/${var.koding_group_slug}/" + uid
		}

		// set default CPU number
		if _, ok := box["cpus"]; !ok {
			box["cpus"] = "${var.vagrant_cpus}"
		}

		// set default RAM in MiB
		if _, ok := box["memory"]; !ok {
			box["memory"] = "${var.vagrant_memory}"
		}

		// set default box type
		if _, ok := box["box"]; !ok {
			box["box"] = "${var.vagrant_box}"
		}

		ports, ok := box["forwarded_ports"].([]interface{})
		if !ok {
			ports = make([]interface{}, 0)
		}

		// klient kite port
		kitePort := &vagrantapi.ForwardedPort{
			HostPort:  2200,
			GuestPort: 56789,
		}

		// tlsproxy port
		kitesPort := &vagrantapi.ForwardedPort{
			HostPort:  2201,
			GuestPort: 56790,
		}

		ports = append(ports, kitePort, kitesPort)

		box["forwarded_ports"] = ports
		box["username"] = s.Req.Username

		tunnel := s.newTunnel(resourceName)

		s.Builder.BuildUserData(box, resourceName)

		if b, ok := box["debug"].(bool); ok && b {
			s.Debug = true
		}

		data := puser.Value{
			Username:        s.Req.Username,
			Groups:          []string{"sudo"},
			Hostname:        s.Req.Username, // no typo here. hostname = username
			KiteKey:         kiteKey,
			LatestKlientURL: klientURL,
			TunnelName:      tunnel.Name,
			TunnelKiteURL:   tunnel.KiteURL,
			KontrolURL:      kontrolURL,
		}

		// pass the values as a JSON encoded as bae64. Our script will decode
		// and unmarshall and use it inside the Vagrant box
		val, err := json.Marshal(&data)
		if err != nil {
			return "", nil, err
		}

		// Compressing the provision data isn't doing any serious optimizations,
		// it's just here so the debug output does not take half a screen.
		//
		// The provisionclient handles both compressed and uncompressed JSONs.
		var buf bytes.Buffer
		if cw, err := gzip.NewWriterLevel(&buf, 9); err == nil {
			if _, err = io.Copy(cw, bytes.NewReader(val)); err == nil && cw.Close() == nil {
				s.Log.Debug("using compressed provision data: %d vs %d", len(val), len(buf.Bytes()))

				val = buf.Bytes()
			}
		}

		box["provisionData"] = base64.StdEncoding.EncodeToString(val)
		kiteIDs[resourceName] = kiteID
		res.Build[resourceName] = box
	}

	t.Resource["vagrant_instance"] = res.Build

	if err := t.Flush(); err != nil {
		return "", nil, err
	}

	return queryString, kiteIDs, nil
}

func (s *Stack) machinesFromTemplate(t *stackplan.Template) (stackplan.Machines, error) {
	var res VagrantResource
	if err := t.DecodeResource(&res); err != nil {
		return nil, err
	}

	machines := make(stackplan.Machines, len(res.Build))

	for label, box := range res.Build {
		m := &stackplan.Machine{
			Provider:   "vagrant",
			Label:      label,
			Attributes: make(map[string]string),
		}

		if cpus, ok := box["cpus"].(string); ok && !stackplan.IsVariable(cpus) {
			m.Attributes["cpus"] = cpus
		}
		if mem, ok := box["memory"].(string); ok && !stackplan.IsVariable(mem) {
			m.Attributes["memory"] = mem
		}
		if typ, ok := box["box"].(string); ok && !stackplan.IsVariable(typ) {
			m.Attributes["box"] = typ
		}

		if _, ok := machines[label]; ok {
			return nil, errors.New("duplicate instance labels: " + label)
		}

		machines[label] = m
	}

	return machines, nil
}

func (s *Stack) updateMachines(machines stackplan.Machines, jMachines map[string]*models.Machine) error {
	for label, machine := range jMachines {
		s.Log.Debug("Updating machine with %q label and %q provider", label, machine.Provider)

		tf, ok := machines[label]
		if !ok {
			return fmt.Errorf("machine label '%s' doesn't exist in terraform output", label)
		}

		if tf.Provider == "vagrant" {
			if err := updateVagrant(tf, machine.ObjectId, s.Credential.Identifier); err != nil {
				return err
			}
		}
	}

	return nil
}

func updateVagrant(tf *stackplan.Machine, machineId bson.ObjectId, credential string) error {
	machine := bson.M{
		"provider":           tf.Provider,
		"queryString":        tf.QueryString,
		"credential":         credential,
		"ipAddress":          tf.Attributes["ipAddress"],
		"meta.filePath":      tf.Attributes["filePath"],
		"meta.box":           tf.Attributes["box"],
		"meta.hostname":      tf.Attributes["hostname"],
		"meta.klientHostURL": tf.Attributes["klientHostURL"],
		"status.modifiedAt":  time.Now().UTC(),
		"status.state":       tf.State.String(),
		"status.reason":      tf.StateReason,
	}

	if u, err := url.Parse(tf.RegisterURL); tf.RegisterURL != "" && err == nil {
		u.Path = "/klient/kite"
		machine["meta.klientGuestURL"] = u.String()
		machine["domain"] = u.Host
	}

	if n, err := strconv.Atoi(tf.Attributes["memory"]); err == nil {
		machine["meta.memory"] = n
	}

	if n, err := strconv.Atoi(tf.Attributes["cpus"]); err == nil {
		machine["meta.cpus"] = n
	}

	return modelhelper.UpdateMachine(machineId, bson.M{"$set": machine})
}
<commit_msg>provider/vagrant: missing resource error<commit_after>package vagrant

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/url"
	"strconv"
	"time"

	"koding/db/models"
	"koding/db/mongodb/modelhelper"
	"koding/kites/kloud/api/vagrantapi"
	puser "koding/kites/kloud/scripts/provisionklient/userdata"
	"koding/kites/kloud/stackplan"
	"koding/kites/kloud/utils"

	"github.com/satori/go.uuid"
	"gopkg.in/mgo.v2/bson"
)

// VagrantResource represents vagrant_instance Terraform resource.
type VagrantResource struct {
	Build map[string]map[string]interface{} `hcl:"vagrant_instance"`
}

func (s *Stack) updateCredential(cred *stackplan.Credential) {
	meta := cred.Meta.(*VagrantMeta)
	meta.SetDefaults()
}

type Tunnel struct {
	Name    string
	KiteURL string
}

func (s *Stack) newTunnel(resourceName string) *Tunnel {
	t := &Tunnel{
		Name:    utils.RandString(12),
		KiteURL: s.TunnelURL.String(),
	}

	if m, ok := s.Builder.Machines[resourceName]; ok {
		t.Name = m.Uid
	}

	return t
}

// InjectVagrantData sets default properties for vagrant_instance Terraform template.
//
// TODO(rjeczalik): move out hostQueryString outside this method.
func (s *Stack) InjectVagrantData() (string, stackplan.KiteMap, error) {
	// TODO(rjeczalik): add ByProvider to stackplan.Credentials
	for _, c := range s.Builder.Credentials {
		if c.Provider == "vagrant" {
			s.Credential = c
			break
		}
	}

	if s.Credential == nil {
		return "", nil, errors.New("vagrant credential not found")
	}

	s.updateCredential(s.Credential)

	t := s.Builder.Template
	meta := s.Credential.Meta.(*VagrantMeta)

	s.Log.Debug("Injecting vagrant credentials: %# v", meta)

	if err := t.InjectVariables(s.Credential.Provider, s.Credential.Meta); err != nil {
		return "", nil, err
	}

	var res VagrantResource

	if err := t.DecodeResource(&res); err != nil {
		return "", nil, err
	}

	if len(res.Build) == 0 {
		return "", nil, errors.New("no vagrant instances specified")
	}

	kiteIDs := make(stackplan.KiteMap)

	uids := s.Builder.MachineUIDs()

	s.Log.Debug("machine uids (%d): %v", len(uids), uids)

	klientURL, err := s.Session.Userdata.LookupKlientURL()
	if err != nil {
		return "", nil, err
	}

	// queryString is taken from jCredentialData.meta.queryString,
	// for debugging purposes it can be overwritten in the template,
	// however if template has multiple machines, all of them
	// are required to overwrite the queryString to the same value
	// to match current implementation of terraformplugins/vagrant
	// provider.
	//
	// Otherwise we fail early to show problem with the template.
	var queryString string
	for resourceName, box := range res.Build {
		kiteID := uuid.NewV4().String()

		kiteKey, err := s.Session.Userdata.Keycreator.Create(s.Req.Username, kiteID)
		if err != nil {
			return "", nil, err
		}

		// set kontrolURL if not provided via template
		kontrolURL := s.Session.Userdata.Keycreator.KontrolURL
		if k, ok := box["kontrolURL"].(string); ok {
			kontrolURL = k
		} else {
			box["kontrolURL"] = kontrolURL
		}

		if q, ok := box["queryString"].(string); ok {
			q = utils.QueryString(q)
			if queryString != "" && queryString != q {
				return "", nil, fmt.Errorf("mismatched queryString provided for multiple instances; want %q, got %q", queryString, q)
			}
			queryString = q
		} else {
			box["queryString"] = "${var.vagrant_queryString}"
			queryString = meta.QueryString
		}

		// set default filePath to relative <stackdir>/<boxname>; for
		// default configured klient it resolves to ~/.vagrant.d/<stackdir>/<boxname>
		if _, ok := box["filePath"]; !ok {
			uid, ok := uids[resourceName]
			if !ok {
				// For Plan call we return random uid as it won't be returned
				// as a part of meta; the filePath is inserted into meta by
				// the apply method.
				uid = resourceName + "-" + utils.RandString(6)
			}
			box["filePath"] = "koding/${var.koding_group_slug}/" + uid
		}

		// set default CPU number
		if _, ok := box["cpus"]; !ok {
			box["cpus"] = "${var.vagrant_cpus}"
		}

		// set default RAM in MiB
		if _, ok := box["memory"]; !ok {
			box["memory"] = "${var.vagrant_memory}"
		}

		// set default box type
		if _, ok := box["box"]; !ok {
			box["box"] = "${var.vagrant_box}"
		}

		ports, ok := box["forwarded_ports"].([]interface{})
		if !ok {
			ports = make([]interface{}, 0)
		}

		// klient kite port
		kitePort := &vagrantapi.ForwardedPort{
			HostPort:  2200,
			GuestPort: 56789,
		}

		// tlsproxy port
		kitesPort := &vagrantapi.ForwardedPort{
			HostPort:  2201,
			GuestPort: 56790,
		}

		ports = append(ports, kitePort, kitesPort)

		box["forwarded_ports"] = ports
		box["username"] = s.Req.Username

		tunnel := s.newTunnel(resourceName)

		s.Builder.BuildUserData(box, resourceName)

		if b, ok := box["debug"].(bool); ok && b {
			s.Debug = true
		}

		data := puser.Value{
			Username:        s.Req.Username,
			Groups:          []string{"sudo"},
			Hostname:        s.Req.Username, // no typo here. hostname = username
			KiteKey:         kiteKey,
			LatestKlientURL: klientURL,
			TunnelName:      tunnel.Name,
			TunnelKiteURL:   tunnel.KiteURL,
			KontrolURL:      kontrolURL,
		}

		// pass the values as a JSON encoded as bae64. Our script will decode
		// and unmarshall and use it inside the Vagrant box
		val, err := json.Marshal(&data)
		if err != nil {
			return "", nil, err
		}

		// Compressing the provision data isn't doing any serious optimizations,
		// it's just here so the debug output does not take half a screen.
		//
		// The provisionclient handles both compressed and uncompressed JSONs.
		var buf bytes.Buffer
		if cw, err := gzip.NewWriterLevel(&buf, 9); err == nil {
			if _, err = io.Copy(cw, bytes.NewReader(val)); err == nil && cw.Close() == nil {
				s.Log.Debug("using compressed provision data: %d vs %d", len(val), len(buf.Bytes()))

				val = buf.Bytes()
			}
		}

		box["provisionData"] = base64.StdEncoding.EncodeToString(val)
		kiteIDs[resourceName] = kiteID
		res.Build[resourceName] = box
	}

	t.Resource["vagrant_instance"] = res.Build

	if err := t.Flush(); err != nil {
		return "", nil, err
	}

	return queryString, kiteIDs, nil
}

func (s *Stack) machinesFromTemplate(t *stackplan.Template) (stackplan.Machines, error) {
	var res VagrantResource
	if err := t.DecodeResource(&res); err != nil {
		return nil, err
	}

	machines := make(stackplan.Machines, len(res.Build))

	for label, box := range res.Build {
		m := &stackplan.Machine{
			Provider:   "vagrant",
			Label:      label,
			Attributes: make(map[string]string),
		}

		if cpus, ok := box["cpus"].(string); ok && !stackplan.IsVariable(cpus) {
			m.Attributes["cpus"] = cpus
		}
		if mem, ok := box["memory"].(string); ok && !stackplan.IsVariable(mem) {
			m.Attributes["memory"] = mem
		}
		if typ, ok := box["box"].(string); ok && !stackplan.IsVariable(typ) {
			m.Attributes["box"] = typ
		}

		if _, ok := machines[label]; ok {
			return nil, errors.New("duplicate instance labels: " + label)
		}

		machines[label] = m
	}

	return machines, nil
}

func (s *Stack) updateMachines(machines stackplan.Machines, jMachines map[string]*models.Machine) error {
	for label, machine := range jMachines {
		s.Log.Debug("Updating machine with %q label and %q provider", label, machine.Provider)

		tf, ok := machines[label]
		if !ok {
			return fmt.Errorf("machine label '%s' doesn't exist in terraform output", label)
		}

		if tf.Provider == "vagrant" {
			if err := updateVagrant(tf, machine.ObjectId, s.Credential.Identifier); err != nil {
				return stackplan.ResError(err, "jMachine")
			}
		}
	}

	return nil
}

func updateVagrant(tf *stackplan.Machine, machineId bson.ObjectId, credential string) error {
	machine := bson.M{
		"provider":           tf.Provider,
		"queryString":        tf.QueryString,
		"credential":         credential,
		"ipAddress":          tf.Attributes["ipAddress"],
		"meta.filePath":      tf.Attributes["filePath"],
		"meta.box":           tf.Attributes["box"],
		"meta.hostname":      tf.Attributes["hostname"],
		"meta.klientHostURL": tf.Attributes["klientHostURL"],
		"status.modifiedAt":  time.Now().UTC(),
		"status.state":       tf.State.String(),
		"status.reason":      tf.StateReason,
	}

	if u, err := url.Parse(tf.RegisterURL); tf.RegisterURL != "" && err == nil {
		u.Path = "/klient/kite"
		machine["meta.klientGuestURL"] = u.String()
		machine["domain"] = u.Host
	}

	if n, err := strconv.Atoi(tf.Attributes["memory"]); err == nil {
		machine["meta.memory"] = n
	}

	if n, err := strconv.Atoi(tf.Attributes["cpus"]); err == nil {
		machine["meta.cpus"] = n
	}

	return modelhelper.UpdateMachine(machineId, bson.M{"$set": machine})
}
<|endoftext|>


<commit_before>package matchers

var (
	TypeJpeg = newType("jpg", "image/jpeg")
	TypePng  = newType("png", "image/png")
	TypeGif  = newType("gif", "image/gif")
	TypeWebp = newType("webp", "image/webp")
	TypeCR2  = newType("cr2", "image/x-canon-cr2")
	TypeTiff = newType("tif", "image/tiff")
	TypeBmp  = newType("bmp", "image/bmp")
	TypeJxr  = newType("jxr", "image/vnd.ms-photo")
	TypePsd  = newType("psd", "image/vnd.adobe.photoshop")
	TypeIco  = newType("ico", "image/x-icon")
)

var Image = Map{
	TypeJpeg: Jpeg,
	TypePng:  Png,
	TypeGif:  Gif,
	TypeWebp: Webp,
	TypeCR2:  CR2,
	TypeTiff: Tiff,
	TypeBmp:  Bmp,
	TypeJxr:  Jxr,
	TypePsd:  Psd,
	TypeIco:  Ico,
}

func Jpeg(buf []byte) bool {
	return len(buf) > 2 &&
		buf[0] == 0xFF &&
		buf[1] == 0xD8 &&
		buf[2] == 0xFF
}

func Png(buf []byte) bool {
	return len(buf) > 3 &&
		buf[0] == 0x89 && buf[1] == 0x50 &&
		buf[2] == 0x4E && buf[3] == 0x47
}

func Gif(buf []byte) bool {
	return len(buf) > 2 &&
		buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46
}

func Webp(buf []byte) bool {
	return len(buf) > 11 &&
		buf[8] == 0x57 && buf[9] == 0x45 &&
		buf[10] == 0x42 && buf[11] == 0x50
}

func CR2(buf []byte) bool {
	return len(buf) > 9 &&
		((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) ||
			(buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A)) &&
		buf[8] == 0x43 && buf[9] == 0x52
}

func Tiff(buf []byte) bool {
	return len(buf) > 3 &&
		((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) ||
			(buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A))
}

func Bmp(buf []byte) bool {
	return len(buf) > 1 &&
		buf[0] == 0x42 &&
		buf[1] == 0x4D
}

func Jxr(buf []byte) bool {
	return len(buf) > 2 &&
		buf[0] == 0x49 &&
		buf[1] == 0x49 &&
		buf[2] == 0xBC
}

func Psd(buf []byte) bool {
	return len(buf) > 3 &&
		buf[0] == 0x38 && buf[1] == 0x42 &&
		buf[2] == 0x50 && buf[3] == 0x53
}

func Ico(buf []byte) bool {
	return len(buf) > 3 &&
		buf[0] == 0x00 && buf[1] == 0x00 &&
		buf[2] == 0x01 && buf[3] == 0x00
}
<commit_msg>jpeg2000 support<commit_after>package matchers

var (
	TypeJpeg     = newType("jpg", "image/jpeg")
	TypeJpeg2000 = newType("jp2", "image/jpegjp2")
	TypePng      = newType("png", "image/png")
	TypeGif      = newType("gif", "image/gif")
	TypeWebp     = newType("webp", "image/webp")
	TypeCR2      = newType("cr2", "image/x-canon-cr2")
	TypeTiff     = newType("tif", "image/tiff")
	TypeBmp      = newType("bmp", "image/bmp")
	TypeJxr      = newType("jxr", "image/vnd.ms-photo")
	TypePsd      = newType("psd", "image/vnd.adobe.photoshop")
	TypeIco      = newType("ico", "image/x-icon")
)

var Image = Map{
	TypeJpeg:     Jpeg,
	TypeJpeg2000: Jpeg2000,
	TypePng:      Png,
	TypeGif:      Gif,
	TypeWebp:     Webp,
	TypeCR2:      CR2,
	TypeTiff:     Tiff,
	TypeBmp:      Bmp,
	TypeJxr:      Jxr,
	TypePsd:      Psd,
	TypeIco:      Ico,
}

func Jpeg(buf []byte) bool {
	return len(buf) > 2 &&
		buf[0] == 0xFF &&
		buf[1] == 0xD8 &&
		buf[2] == 0xFF
}

func Jpeg2000(buf []byte) bool {
	return len(buf) > 12 &&
		buf[0] == 0x0 &&
		buf[1] == 0x0 &&
		buf[2] == 0x0 &&
		buf[3] == 0xC &&
		buf[4] == 0x6A &&
		buf[5] == 0x50 &&
		buf[6] == 0x20 &&
		buf[7] == 0x20 &&
		buf[8] == 0xD &&
		buf[9] == 0xA &&
		buf[10] == 0x87 &&
		buf[11] == 0xA &&
		buf[12] == 0x0
}

func Png(buf []byte) bool {
	return len(buf) > 3 &&
		buf[0] == 0x89 && buf[1] == 0x50 &&
		buf[2] == 0x4E && buf[3] == 0x47
}

func Gif(buf []byte) bool {
	return len(buf) > 2 &&
		buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46
}

func Webp(buf []byte) bool {
	return len(buf) > 11 &&
		buf[8] == 0x57 && buf[9] == 0x45 &&
		buf[10] == 0x42 && buf[11] == 0x50
}

func CR2(buf []byte) bool {
	return len(buf) > 9 &&
		((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) ||
			(buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A)) &&
		buf[8] == 0x43 && buf[9] == 0x52
}

func Tiff(buf []byte) bool {
	return len(buf) > 3 &&
		((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) ||
			(buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A))
}

func Bmp(buf []byte) bool {
	return len(buf) > 1 &&
		buf[0] == 0x42 &&
		buf[1] == 0x4D
}

func Jxr(buf []byte) bool {
	return len(buf) > 2 &&
		buf[0] == 0x49 &&
		buf[1] == 0x49 &&
		buf[2] == 0xBC
}

func Psd(buf []byte) bool {
	return len(buf) > 3 &&
		buf[0] == 0x38 && buf[1] == 0x42 &&
		buf[2] == 0x50 && buf[3] == 0x53
}

func Ico(buf []byte) bool {
	return len(buf) > 3 &&
		buf[0] == 0x00 && buf[1] == 0x00 &&
		buf[2] == 0x01 && buf[3] == 0x00
}
<|endoftext|>


<commit_before>// +build !confonly

package http

import (
	"bufio"
	"context"
	"encoding/base64"
	"io"
	"net/http"
	"strings"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/session"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/common/task"
	"v2ray.com/core/features/policy"
	"v2ray.com/core/transport"
	"v2ray.com/core/transport/internet"
)

// Client is a inbound handler for HTTP protocol
type Client struct {
	serverPicker  protocol.ServerPicker
	policyManager policy.Manager
}

// NewClient create a new http client based on the given config.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
	serverList := protocol.NewServerList()
	for _, rec := range config.Server {
		s, err := protocol.NewServerSpecFromPB(*rec)
		if err != nil {
			return nil, newError("failed to get server spec").Base(err)
		}
		serverList.AddServer(s)
	}
	if serverList.Size() == 0 {
		return nil, newError("0 target server")
	}

	v := core.MustFromContext(ctx)
	return &Client{
		serverPicker:  protocol.NewRoundRobinServerPicker(serverList),
		policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
	}, nil
}

// Process implements proxy.Outbound.Process. We first create a socket tunnel via HTTP CONNECT method, then redirect all inbound traffic to that tunnel.
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
	outbound := session.OutboundFromContext(ctx)
	if outbound == nil || !outbound.Target.IsValid() {
		return newError("target not specified.")
	}
	destination := outbound.Target

	if destination.Network == net.Network_UDP {
		return newError("UDP is not supported by HTTP outbound")
	}

	var server *protocol.ServerSpec
	var conn internet.Connection

	if err := retry.ExponentialBackoff(5, 100).On(func() error {
		server = c.serverPicker.PickServer()
		dest := server.Destination()
		rawConn, err := dialer.Dial(ctx, dest)
		if err != nil {
			return err
		}
		conn = rawConn

		return nil
	}); err != nil {
		return newError("failed to find an available destination").Base(err)
	}

	defer func() {
		if err := conn.Close(); err != nil {
			newError("failed to closed connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
		}
	}()

	p := c.policyManager.ForLevel(0)

	user := server.PickUser()
	if user != nil {
		p = c.policyManager.ForLevel(user.Level)
	}

	if err := setUpHTTPTunnel(conn, &destination, user); err != nil {
		return err
	}

	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle)

	requestFunc := func() error {
		defer timer.SetTimeout(p.Timeouts.DownlinkOnly)
		return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))
	}
	responseFunc := func() error {
		defer timer.SetTimeout(p.Timeouts.UplinkOnly)
		bc := bufio.NewReader(conn)
		resp, err := http.ReadResponse(bc, nil)
		if err != nil {
			return err
		}
		if resp.StatusCode != http.StatusOK {
			return newError(resp.Status)
		}
		return buf.Copy(buf.NewReader(bc), link.Writer, buf.UpdateActivity(timer))
	}

	var responseDonePost = task.OnSuccess(responseFunc, task.Close(link.Writer))
	if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
		return newError("connection ends").Base(err)
	}

	return nil
}

// setUpHTTPTunnel will create a socket tunnel via HTTP CONNECT method
func setUpHTTPTunnel(writer io.Writer, destination *net.Destination, user *protocol.MemoryUser) error {
	var headers []string
	destNetAddr := destination.NetAddr()
	headers = append(headers, "CONNECT "+destNetAddr+" HTTP/1.1")
	headers = append(headers, "Host: "+destNetAddr)
	if user != nil && user.Account != nil {
		account := user.Account.(*Account)
		auth := account.GetUsername() + ":" + account.GetPassword()
		headers = append(headers, "Proxy-Authorization: Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
	}
	headers = append(headers, "Proxy-Connection: Keep-Alive")

	b := buf.New()
	b.WriteString(strings.Join(headers, "\r\n") + "\r\n\r\n")
	if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
		return err
	}

	return nil
}

func init() {
	common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewClient(ctx, config.(*ClientConfig))
	}))
}
<commit_msg>Optimize HTTP tunnel setup in TFO environment<commit_after>// +build !confonly

package http

import (
	"bufio"
	"io"
	"context"
	"encoding/base64"
	"net/http"
	"strings"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/session"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/common/task"
	"v2ray.com/core/features/policy"
	"v2ray.com/core/transport"
	"v2ray.com/core/transport/internet"
)

// Client is a inbound handler for HTTP protocol
type Client struct {
	serverPicker  protocol.ServerPicker
	policyManager policy.Manager
}

// NewClient create a new http client based on the given config.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
	serverList := protocol.NewServerList()
	for _, rec := range config.Server {
		s, err := protocol.NewServerSpecFromPB(*rec)
		if err != nil {
			return nil, newError("failed to get server spec").Base(err)
		}
		serverList.AddServer(s)
	}
	if serverList.Size() == 0 {
		return nil, newError("0 target server")
	}

	v := core.MustFromContext(ctx)
	return &Client{
		serverPicker:  protocol.NewRoundRobinServerPicker(serverList),
		policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
	}, nil
}

// Process implements proxy.Outbound.Process. We first create a socket tunnel via HTTP CONNECT method, then redirect all inbound traffic to that tunnel.
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
	outbound := session.OutboundFromContext(ctx)
	if outbound == nil || !outbound.Target.IsValid() {
		return newError("target not specified.")
	}
	destination := outbound.Target

	if destination.Network == net.Network_UDP {
		return newError("UDP is not supported by HTTP outbound")
	}

	var server *protocol.ServerSpec
	var conn internet.Connection

	if err := retry.ExponentialBackoff(5, 100).On(func() error {
		server = c.serverPicker.PickServer()
		dest := server.Destination()
		rawConn, err := dialer.Dial(ctx, dest)
		if err != nil {
			return err
		}
		conn = rawConn

		return nil
	}); err != nil {
		return newError("failed to find an available destination").Base(err)
	}

	defer func() {
		if err := conn.Close(); err != nil {
			newError("failed to closed connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
		}
	}()

	p := c.policyManager.ForLevel(0)

	user := server.PickUser()
	if user != nil {
		p = c.policyManager.ForLevel(user.Level)
	}

	conn = setUpHTTPTunnel(conn, &destination, user)

	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, p.Timeouts.ConnectionIdle)

	requestFunc := func() error {
		defer timer.SetTimeout(p.Timeouts.DownlinkOnly)
		return buf.Copy(link.Reader, buf.NewWriter(conn), buf.UpdateActivity(timer))
	}
	responseFunc := func() error {
		defer timer.SetTimeout(p.Timeouts.UplinkOnly)
		bc := bufio.NewReader(conn)
		resp, err := http.ReadResponse(bc, nil)
		if err != nil {
			return err
		}
		if resp.StatusCode != http.StatusOK {
			return newError(resp.Status)
		}
		return buf.Copy(buf.NewReader(bc), link.Writer, buf.UpdateActivity(timer))
	}

	var responseDonePost = task.OnSuccess(responseFunc, task.Close(link.Writer))
	if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
		return newError("connection ends").Base(err)
	}

	return nil
}

type tunnelConn struct {
	internet.Connection
	header *buf.Buffer
}

// setUpHTTPTunnel will create a socket tunnel via HTTP CONNECT method
func setUpHTTPTunnel(conn internet.Connection, destination *net.Destination, user *protocol.MemoryUser) *tunnelConn {
	var headers []string
	destNetAddr := destination.NetAddr()
	headers = append(headers, "CONNECT "+destNetAddr+" HTTP/1.1")
	headers = append(headers, "Host: "+destNetAddr)
	if user != nil && user.Account != nil {
		account := user.Account.(*Account)
		auth := account.GetUsername() + ":" + account.GetPassword()
		headers = append(headers, "Proxy-Authorization: Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
	}
	headers = append(headers, "Proxy-Connection: Keep-Alive")

	b := buf.New()
	b.WriteString(strings.Join(headers, "\r\n") + "\r\n\r\n")
	return &tunnelConn {
		Connection: conn,
		header:     b,
	}
}

func (c *tunnelConn) Write(b []byte) (n int, err error) {
	if c.header == nil {
		return c.Connection.Write(b)
	}
	buffer := c.header
	lenheader := c.header.Len()
	// Concate header and b
	_, err = buffer.Write(b)
	if err != nil {
		c.header.Resize(0, lenheader)
		return 0, err
	}
	// Write buffer
	nc, err := io.Copy(c.Connection, buffer)
	if int32(nc) < lenheader {
		c.header.Resize(int32(nc), lenheader)
		return 0, err
	}
	c.header.Release()
	c.header = nil
	n = int(nc) - int(lenheader)
	if err != nil {
		return n, err
	}
	// Write trailing bytes
	if n < len(b) {
		var nw int
		nw, err = c.Connection.Write(b[:n])
		n += nw
	}
	return n, err
}

func init() {
	common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewClient(ctx, config.(*ClientConfig))
	}))
}
<|endoftext|>