<commit_before>package jobs

import (
	"context"
	"time"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/couchdb/mango"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/realtime"
)

type (
	// Trigger interface is used to represent a trigger.
	Trigger interface {
		permissions.Validable
		Type() string
		Infos() *TriggerInfos
		// Schedule should return a channel on which the trigger can send job
		// requests when it decides to.
		Schedule() <-chan *JobRequest
		// Unschedule should be used to clean the trigger states and should close
		// the returns jobs channel.
		Unschedule()
	}

	// Scheduler interface is used to represent a scheduler that is responsible
	// to listen respond to triggers jobs requests and send them to the broker.
	Scheduler interface {
		StartScheduler(broker Broker) error
		ShutdownScheduler(ctx context.Context) error
		AddTrigger(trigger Trigger) error
		GetTrigger(domain, id string) (Trigger, error)
		DeleteTrigger(domain, id string) error
		GetAllTriggers(domain string) ([]Trigger, error)
		RebuildRedis(domain string) error
	}

	// TriggerInfos is a struct containing all the options of a trigger.
	TriggerInfos struct {
		TID          string        `json:"_id,omitempty"`
		TRev         string        `json:"_rev,omitempty"`
		Domain       string        `json:"domain"`
		Type         string        `json:"type"`
		WorkerType   string        `json:"worker"`
		Arguments    string        `json:"arguments"`
		Debounce     string        `json:"debounce"`
		Options      *JobOptions   `json:"options"`
		Message      Message       `json:"message"`
		CurrentState *TriggerState `json:"current_state,omitempty"`
	}

	// TriggerState represent the current state of the trigger
	TriggerState struct {
		TID                 string     `json:"trigger_id"`
		Status              State      `json:"status"`
		LastSuccess         *time.Time `json:"last_success,omitempty"`
		LastSuccessfulJobID string     `json:"last_successful_job_id,omitempty"`
		LastExecution       *time.Time `json:"last_execution,omitempty"`
		LastExecutedJobID   string     `json:"last_executed_job_id,omitempty"`
		LastFailure         *time.Time `json:"last_failure,omitempty"`
		LastFailedJobID     string     `json:"last_failed_job_id,omitempty"`
		LastError           string     `json:"last_error,omitempty"`
		LastManualExecution *time.Time `json:"last_manual_execution,omitempty"`
		LastManualJobID     string     `json:"last_manual_job_id,omitempty"`
	}
)

// NewTrigger creates the trigger associates with the specified trigger
// options.
func NewTrigger(infos *TriggerInfos) (Trigger, error) {
	switch infos.Type {
	case "@at":
		return NewAtTrigger(infos)
	case "@in":
		return NewInTrigger(infos)
	case "@cron":
		return NewCronTrigger(infos)
	case "@every":
		return NewEveryTrigger(infos)
	case "@event":
		return NewEventTrigger(infos)
	default:
		return nil, ErrUnknownTrigger
	}
}

// ID implements the couchdb.Doc interface
func (t *TriggerInfos) ID() string { return t.TID }

// Rev implements the couchdb.Doc interface
func (t *TriggerInfos) Rev() string { return t.TRev }

// DocType implements the couchdb.Doc interface
func (t *TriggerInfos) DocType() string { return consts.Triggers }

// Clone implements the couchdb.Doc interface
func (t *TriggerInfos) Clone() couchdb.Doc {
	cloned := *t
	if t.Options != nil {
		tmp := *t.Options
		cloned.Options = &tmp
	}
	if t.Message != nil {
		tmp := t.Message
		t.Message = make([]byte, len(tmp))
		copy(t.Message[:], tmp)
	}
	return &cloned
}

// JobRequest returns a job request associated with the scheduler informations.
func (t *TriggerInfos) JobRequest() *JobRequest {
	return &JobRequest{
		Domain:     t.Domain,
		WorkerType: t.WorkerType,
		TriggerID:  t.ID(),
		Message:    t.Message,
		Options:    t.Options,
	}
}

// JobRequestWithEvent returns a job request associated with the scheduler
// informations associated to the specified realtime event.
func (t *TriggerInfos) JobRequestWithEvent(event *realtime.Event) (*JobRequest, error) {
	evt, err := NewEvent(event)
	if err != nil {
		return nil, err
	}
	req := t.JobRequest()
	req.Event = evt
	return req, nil
}

// SetID implements the couchdb.Doc interface
func (t *TriggerInfos) SetID(id string) { t.TID = id }

// SetRev implements the couchdb.Doc interface
func (t *TriggerInfos) SetRev(rev string) { t.TRev = rev }

// Valid implements the permissions.Validable interface
func (t *TriggerInfos) Valid(key, value string) bool {
	switch key {
	case "worker":
		return t.WorkerType == value
	}
	return false
}

// GetJobs returns the jobs launched by the given trigger.
func GetJobs(t Trigger, limit int) ([]*Job, error) {
	triggerInfos := t.Infos()
	db := couchdb.SimpleDatabasePrefix(triggerInfos.Domain)
	if limit <= 0 || limit > 50 {
		limit = 50
	}
	var jobs []*Job
	req := &couchdb.FindRequest{
		UseIndex: "by-trigger-id",
		Selector: mango.Equal("trigger_id", triggerInfos.ID()),
		Sort: mango.SortBy{
			{Field: "trigger_id", Direction: mango.Desc},
			{Field: "queued_at", Direction: mango.Desc},
		},
		Limit: limit,
	}
	err := couchdb.FindDocs(db, consts.Jobs, req, &jobs)
	if err != nil {
		return nil, err
	}
	return jobs, nil
}

// GetTriggerState returns the state of the trigger, calculated from the last
// launched
func GetTriggerState(t Trigger) (*TriggerState, error) {
	js, err := GetJobs(t, 0)
	if err != nil {
		return nil, err
	}

	var state TriggerState

	state.Status = Done
	state.TID = t.ID()

	// jobs are ordered from the oldest to most recent job
	for i := len(js) - 1; i >= 0; i-- {
		j := js[i]
		startedAt := &j.StartedAt
		switch j.State {
		case Errored:
			state.LastFailure = startedAt
			state.LastFailedJobID = j.ID()
			state.LastError = j.Error
		case Done:
			state.LastSuccess = startedAt
			state.LastSuccessfulJobID = j.ID()
		}
		if j.Manual && (j.State == Done || j.State == Errored) {
			state.LastManualExecution = startedAt
			state.LastManualJobID = j.ID()
		}
		state.LastExecution = startedAt
		state.LastExecutedJobID = j.ID()
		state.Status = j.State
	}

	return &state, nil
}

var _ couchdb.Doc = &TriggerInfos{}
<commit_msg>Undo removed comment<commit_after>package jobs

import (
	"context"
	"time"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/couchdb/mango"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/realtime"
)

type (
	// Trigger interface is used to represent a trigger.
	Trigger interface {
		permissions.Validable
		Type() string
		Infos() *TriggerInfos
		// Schedule should return a channel on which the trigger can send job
		// requests when it decides to.
		Schedule() <-chan *JobRequest
		// Unschedule should be used to clean the trigger states and should close
		// the returns jobs channel.
		Unschedule()
	}

	// Scheduler interface is used to represent a scheduler that is responsible
	// to listen respond to triggers jobs requests and send them to the broker.
	Scheduler interface {
		StartScheduler(broker Broker) error
		ShutdownScheduler(ctx context.Context) error
		AddTrigger(trigger Trigger) error
		GetTrigger(domain, id string) (Trigger, error)
		DeleteTrigger(domain, id string) error
		GetAllTriggers(domain string) ([]Trigger, error)
		RebuildRedis(domain string) error
	}

	// TriggerInfos is a struct containing all the options of a trigger.
	TriggerInfos struct {
		TID          string        `json:"_id,omitempty"`
		TRev         string        `json:"_rev,omitempty"`
		Domain       string        `json:"domain"`
		Type         string        `json:"type"`
		WorkerType   string        `json:"worker"`
		Arguments    string        `json:"arguments"`
		Debounce     string        `json:"debounce"`
		Options      *JobOptions   `json:"options"`
		Message      Message       `json:"message"`
		CurrentState *TriggerState `json:"current_state,omitempty"`
	}

	// TriggerState represent the current state of the trigger
	TriggerState struct {
		TID                 string     `json:"trigger_id"`
		Status              State      `json:"status"`
		LastSuccess         *time.Time `json:"last_success,omitempty"`
		LastSuccessfulJobID string     `json:"last_successful_job_id,omitempty"`
		LastExecution       *time.Time `json:"last_execution,omitempty"`
		LastExecutedJobID   string     `json:"last_executed_job_id,omitempty"`
		LastFailure         *time.Time `json:"last_failure,omitempty"`
		LastFailedJobID     string     `json:"last_failed_job_id,omitempty"`
		LastError           string     `json:"last_error,omitempty"`
		LastManualExecution *time.Time `json:"last_manual_execution,omitempty"`
		LastManualJobID     string     `json:"last_manual_job_id,omitempty"`
	}
)

// NewTrigger creates the trigger associates with the specified trigger
// options.
func NewTrigger(infos *TriggerInfos) (Trigger, error) {
	switch infos.Type {
	case "@at":
		return NewAtTrigger(infos)
	case "@in":
		return NewInTrigger(infos)
	case "@cron":
		return NewCronTrigger(infos)
	case "@every":
		return NewEveryTrigger(infos)
	case "@event":
		return NewEventTrigger(infos)
	default:
		return nil, ErrUnknownTrigger
	}
}

// ID implements the couchdb.Doc interface
func (t *TriggerInfos) ID() string { return t.TID }

// Rev implements the couchdb.Doc interface
func (t *TriggerInfos) Rev() string { return t.TRev }

// DocType implements the couchdb.Doc interface
func (t *TriggerInfos) DocType() string { return consts.Triggers }

// Clone implements the couchdb.Doc interface
func (t *TriggerInfos) Clone() couchdb.Doc {
	cloned := *t
	if t.Options != nil {
		tmp := *t.Options
		cloned.Options = &tmp
	}
	if t.Message != nil {
		tmp := t.Message
		t.Message = make([]byte, len(tmp))
		copy(t.Message[:], tmp)
	}
	return &cloned
}

// JobRequest returns a job request associated with the scheduler informations.
func (t *TriggerInfos) JobRequest() *JobRequest {
	return &JobRequest{
		Domain:     t.Domain,
		WorkerType: t.WorkerType,
		TriggerID:  t.ID(),
		Message:    t.Message,
		Options:    t.Options,
	}
}

// JobRequestWithEvent returns a job request associated with the scheduler
// informations associated to the specified realtime event.
func (t *TriggerInfos) JobRequestWithEvent(event *realtime.Event) (*JobRequest, error) {
	evt, err := NewEvent(event)
	if err != nil {
		return nil, err
	}
	req := t.JobRequest()
	req.Event = evt
	return req, nil
}

// SetID implements the couchdb.Doc interface
func (t *TriggerInfos) SetID(id string) { t.TID = id }

// SetRev implements the couchdb.Doc interface
func (t *TriggerInfos) SetRev(rev string) { t.TRev = rev }

// Valid implements the permissions.Validable interface
func (t *TriggerInfos) Valid(key, value string) bool {
	switch key {
	case "worker":
		return t.WorkerType == value
	}
	return false
}

// GetJobs returns the jobs launched by the given trigger.
func GetJobs(t Trigger, limit int) ([]*Job, error) {
	triggerInfos := t.Infos()
	db := couchdb.SimpleDatabasePrefix(triggerInfos.Domain)
	if limit <= 0 || limit > 50 {
		limit = 50
	}
	var jobs []*Job
	req := &couchdb.FindRequest{
		UseIndex: "by-trigger-id",
		Selector: mango.Equal("trigger_id", triggerInfos.ID()),
		Sort: mango.SortBy{
			{Field: "trigger_id", Direction: mango.Desc},
			{Field: "queued_at", Direction: mango.Desc},
		},
		Limit: limit,
	}
	err := couchdb.FindDocs(db, consts.Jobs, req, &jobs)
	if err != nil {
		return nil, err
	}
	return jobs, nil
}

// GetTriggerState returns the state of the trigger, calculated from the last
// launched jobs.
func GetTriggerState(t Trigger) (*TriggerState, error) {
	js, err := GetJobs(t, 0)
	if err != nil {
		return nil, err
	}

	var state TriggerState

	state.Status = Done
	state.TID = t.ID()

	// jobs are ordered from the oldest to most recent job
	for i := len(js) - 1; i >= 0; i-- {
		j := js[i]
		startedAt := &j.StartedAt
		switch j.State {
		case Errored:
			state.LastFailure = startedAt
			state.LastFailedJobID = j.ID()
			state.LastError = j.Error
		case Done:
			state.LastSuccess = startedAt
			state.LastSuccessfulJobID = j.ID()
		}
		if j.Manual && (j.State == Done || j.State == Errored) {
			state.LastManualExecution = startedAt
			state.LastManualJobID = j.ID()
		}
		state.LastExecution = startedAt
		state.LastExecutedJobID = j.ID()
		state.Status = j.State
	}

	return &state, nil
}

var _ couchdb.Doc = &TriggerInfos{}
<|endoftext|>


<commit_before>package main

// Version is the tagged version or "dev"
var Version = "v0.1.19"

// BuildDate is the date of the release build or ""
var BuildDate = ""
<commit_msg>version bump: 0.1.20<commit_after>package main

// Version is the tagged version or "dev"
var Version = "0.1.20"

// BuildDate is the date of the release build or ""
var BuildDate = ""
<|endoftext|>


<commit_before>package consul

import (
	"crypto/tls"
	"fmt"
	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/consul/structs"
	"github.com/inconshreveable/muxado"
	"github.com/ugorji/go/codec"
	"io"
	"math/rand"
	"net"
	"strings"
	"time"
)

type RPCType byte

const (
	rpcConsul RPCType = iota
	rpcRaft
	rpcMultiplex
	rpcTLS
)

const (
	maxQueryTime = 600 * time.Second
)

// listen is used to listen for incoming RPC connections
func (s *Server) listen() {
	for {
		// Accept a connection
		conn, err := s.rpcListener.Accept()
		if err != nil {
			if s.shutdown {
				return
			}
			s.logger.Printf("[ERR] consul.rpc: failed to accept RPC conn: %v", err)
			continue
		}

		// Track this client
		s.rpcClientLock.Lock()
		s.rpcClients[conn] = struct{}{}
		s.rpcClientLock.Unlock()

		go s.handleConn(conn, false)
		metrics.IncrCounter([]string{"consul", "rpc", "accept_conn"}, 1)
	}
}

// handleConn is used to determine if this is a Raft or
// Consul type RPC connection and invoke the correct handler
func (s *Server) handleConn(conn net.Conn, isTLS bool) {
	// Read a single byte
	buf := make([]byte, 1)
	if _, err := conn.Read(buf); err != nil {
		s.logger.Printf("[ERR] consul.rpc: failed to read byte: %v", err)
		conn.Close()
		return
	}

	// Enforce TLS if VerifyIncoming is set
	if s.config.VerifyIncoming && !isTLS && RPCType(buf[0]) != rpcTLS {
		s.logger.Printf("[WARN] consul.rpc: Non-TLS connection attempted with VerifyIncoming set")
		conn.Close()
		return
	}

	// Switch on the byte
	switch RPCType(buf[0]) {
	case rpcConsul:
		s.handleConsulConn(conn)

	case rpcRaft:
		metrics.IncrCounter([]string{"consul", "rpc", "raft_handoff"}, 1)
		s.raftLayer.Handoff(conn)

	case rpcMultiplex:
		s.handleMultiplex(conn)

	case rpcTLS:
		if s.rpcTLS == nil {
			s.logger.Printf("[WARN] consul.rpc: TLS connection attempted, server not configured for TLS")
			conn.Close()
			return
		}
		conn = tls.Server(conn, s.rpcTLS)
		s.handleConn(conn, true)

	default:
		s.logger.Printf("[ERR] consul.rpc: unrecognized RPC byte: %v", buf[0])
		conn.Close()
		return
	}
}

// handleMultiplex is used to multiplex a single incoming connection
func (s *Server) handleMultiplex(conn net.Conn) {
	defer conn.Close()
	server := muxado.Server(conn)
	for {
		sub, err := server.Accept()
		if err != nil {
			if !strings.Contains(err.Error(), "closed") {
				s.logger.Printf("[ERR] consul.rpc: multiplex conn accept failed: %v", err)
			}
			return
		}
		go s.handleConsulConn(sub)
	}
}

// handleConsulConn is used to service a single Consul RPC connection
func (s *Server) handleConsulConn(conn net.Conn) {
	defer func() {
		conn.Close()
		s.rpcClientLock.Lock()
		delete(s.rpcClients, conn)
		s.rpcClientLock.Unlock()
	}()

	rpcCodec := codec.GoRpc.ServerCodec(conn, &codec.MsgpackHandle{})
	for !s.shutdown {
		if err := s.rpcServer.ServeRequest(rpcCodec); err != nil {
			if err != io.EOF {
				s.logger.Printf("[ERR] consul.rpc: RPC error: %v (%v)", err, conn)
			}
			return
		}
	}
}

// forward is used to forward to a remote DC or to forward to the local leader
// Returns a bool of if forwarding was performed, as well as any error
func (s *Server) forward(method string, info structs.RPCInfo, args interface{}, reply interface{}) (bool, error) {
	// Handle DC forwarding
	dc := info.RequestDatacenter()
	if dc != s.config.Datacenter {
		err := s.forwardDC(method, dc, args, reply)
		return true, err
	}

	// Check if we can allow a stale read
	if info.IsRead() && info.AllowStaleRead() {
		return false, nil
	}

	// Handle leader forwarding
	if !s.IsLeader() {
		err := s.forwardLeader(method, args, reply)
		return true, err
	}
	return false, nil
}

// forwardLeader is used to forward an RPC call to the leader, or fail if no leader
func (s *Server) forwardLeader(method string, args interface{}, reply interface{}) error {
	leader := s.raft.Leader()
	if leader == nil {
		return structs.ErrNoLeader
	}
	return s.connPool.RPC(leader, method, args, reply)
}

// forwardDC is used to forward an RPC call to a remote DC, or fail if no servers
func (s *Server) forwardDC(method, dc string, args interface{}, reply interface{}) error {
	// Bail if we can't find any servers
	s.remoteLock.RLock()
	servers := s.remoteConsuls[dc]
	if len(servers) == 0 {
		s.remoteLock.RUnlock()
		s.logger.Printf("[WARN] consul.rpc: RPC request for DC '%s', no path found", dc)
		return structs.ErrNoDCPath
	}

	// Select a random addr
	offset := rand.Int31() % int32(len(servers))
	server := servers[offset]
	s.remoteLock.RUnlock()

	// Forward to remote Consul
	metrics.IncrCounter([]string{"consul", "rpc", "cross-dc", dc}, 1)
	return s.connPool.RPC(server, method, args, reply)
}

// raftApply is used to encode a message, run it through raft, and return
// the FSM response along with any errors
func (s *Server) raftApply(t structs.MessageType, msg interface{}) (interface{}, error) {
	buf, err := structs.Encode(t, msg)
	if err != nil {
		return nil, fmt.Errorf("Failed to encode request: %v", err)
	}

	future := s.raft.Apply(buf, 0)
	if err := future.Error(); err != nil {
		return nil, err
	}

	return future.Response(), nil
}

// blockingRPC is used for queries that need to wait for a
// minimum index. This is used to block and wait for changes.
func (s *Server) blockingRPC(b *structs.BlockingQuery, tables MDBTables, run func() (uint64, error)) error {
	var timeout <-chan time.Time
	var notifyCh chan struct{}

	// Fast path non-blocking
	if b.MinQueryIndex == 0 {
		goto RUN_QUERY
	}

	// Sanity check that we have tables to block on
	if len(tables) == 0 {
		panic("no tables to block on")
	}

	// Restrict the max query time
	if b.MaxQueryTime > maxQueryTime {
		b.MaxQueryTime = maxQueryTime
	}

	// Ensure a time limit is set if we have an index
	if b.MinQueryIndex > 0 && b.MaxQueryTime == 0 {
		b.MaxQueryTime = maxQueryTime
	}

	// Setup a query timeout
	if b.MaxQueryTime > 0 {
		timeout = time.After(b.MaxQueryTime)
	}

	// Setup a notification channel for changes
SETUP_NOTIFY:
	if b.MinQueryIndex > 0 {
		notifyCh = make(chan struct{}, 1)
		s.fsm.State().Watch(tables, notifyCh)
	}

	// Run the query function
RUN_QUERY:
	idx, err := run()

	// Check for minimum query time
	if err == nil && idx <= b.MinQueryIndex {
		select {
		case <-notifyCh:
			goto SETUP_NOTIFY
		case <-timeout:
		}
	}
	return err
}

// setQueryMeta is used to populate the QueryMeta data for an RPC call
func (s *Server) setQueryMeta(m *structs.QueryMeta) {
	if s.IsLeader() {
		m.LastContact = 0
		m.KnownLeader = true
	} else {
		m.LastContact = time.Now().Sub(s.raft.LastContact())
		m.KnownLeader = (s.raft.Leader() != nil)
	}
}
<commit_msg>consul: Adding a method to enforce consistent read<commit_after>package consul

import (
	"crypto/tls"
	"fmt"
	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/consul/structs"
	"github.com/inconshreveable/muxado"
	"github.com/ugorji/go/codec"
	"io"
	"math/rand"
	"net"
	"strings"
	"time"
)

type RPCType byte

const (
	rpcConsul RPCType = iota
	rpcRaft
	rpcMultiplex
	rpcTLS
)

const (
	maxQueryTime = 600 * time.Second
)

// listen is used to listen for incoming RPC connections
func (s *Server) listen() {
	for {
		// Accept a connection
		conn, err := s.rpcListener.Accept()
		if err != nil {
			if s.shutdown {
				return
			}
			s.logger.Printf("[ERR] consul.rpc: failed to accept RPC conn: %v", err)
			continue
		}

		// Track this client
		s.rpcClientLock.Lock()
		s.rpcClients[conn] = struct{}{}
		s.rpcClientLock.Unlock()

		go s.handleConn(conn, false)
		metrics.IncrCounter([]string{"consul", "rpc", "accept_conn"}, 1)
	}
}

// handleConn is used to determine if this is a Raft or
// Consul type RPC connection and invoke the correct handler
func (s *Server) handleConn(conn net.Conn, isTLS bool) {
	// Read a single byte
	buf := make([]byte, 1)
	if _, err := conn.Read(buf); err != nil {
		s.logger.Printf("[ERR] consul.rpc: failed to read byte: %v", err)
		conn.Close()
		return
	}

	// Enforce TLS if VerifyIncoming is set
	if s.config.VerifyIncoming && !isTLS && RPCType(buf[0]) != rpcTLS {
		s.logger.Printf("[WARN] consul.rpc: Non-TLS connection attempted with VerifyIncoming set")
		conn.Close()
		return
	}

	// Switch on the byte
	switch RPCType(buf[0]) {
	case rpcConsul:
		s.handleConsulConn(conn)

	case rpcRaft:
		metrics.IncrCounter([]string{"consul", "rpc", "raft_handoff"}, 1)
		s.raftLayer.Handoff(conn)

	case rpcMultiplex:
		s.handleMultiplex(conn)

	case rpcTLS:
		if s.rpcTLS == nil {
			s.logger.Printf("[WARN] consul.rpc: TLS connection attempted, server not configured for TLS")
			conn.Close()
			return
		}
		conn = tls.Server(conn, s.rpcTLS)
		s.handleConn(conn, true)

	default:
		s.logger.Printf("[ERR] consul.rpc: unrecognized RPC byte: %v", buf[0])
		conn.Close()
		return
	}
}

// handleMultiplex is used to multiplex a single incoming connection
func (s *Server) handleMultiplex(conn net.Conn) {
	defer conn.Close()
	server := muxado.Server(conn)
	for {
		sub, err := server.Accept()
		if err != nil {
			if !strings.Contains(err.Error(), "closed") {
				s.logger.Printf("[ERR] consul.rpc: multiplex conn accept failed: %v", err)
			}
			return
		}
		go s.handleConsulConn(sub)
	}
}

// handleConsulConn is used to service a single Consul RPC connection
func (s *Server) handleConsulConn(conn net.Conn) {
	defer func() {
		conn.Close()
		s.rpcClientLock.Lock()
		delete(s.rpcClients, conn)
		s.rpcClientLock.Unlock()
	}()

	rpcCodec := codec.GoRpc.ServerCodec(conn, &codec.MsgpackHandle{})
	for !s.shutdown {
		if err := s.rpcServer.ServeRequest(rpcCodec); err != nil {
			if err != io.EOF {
				s.logger.Printf("[ERR] consul.rpc: RPC error: %v (%v)", err, conn)
			}
			return
		}
	}
}

// forward is used to forward to a remote DC or to forward to the local leader
// Returns a bool of if forwarding was performed, as well as any error
func (s *Server) forward(method string, info structs.RPCInfo, args interface{}, reply interface{}) (bool, error) {
	// Handle DC forwarding
	dc := info.RequestDatacenter()
	if dc != s.config.Datacenter {
		err := s.forwardDC(method, dc, args, reply)
		return true, err
	}

	// Check if we can allow a stale read
	if info.IsRead() && info.AllowStaleRead() {
		return false, nil
	}

	// Handle leader forwarding
	if !s.IsLeader() {
		err := s.forwardLeader(method, args, reply)
		return true, err
	}
	return false, nil
}

// forwardLeader is used to forward an RPC call to the leader, or fail if no leader
func (s *Server) forwardLeader(method string, args interface{}, reply interface{}) error {
	leader := s.raft.Leader()
	if leader == nil {
		return structs.ErrNoLeader
	}
	return s.connPool.RPC(leader, method, args, reply)
}

// forwardDC is used to forward an RPC call to a remote DC, or fail if no servers
func (s *Server) forwardDC(method, dc string, args interface{}, reply interface{}) error {
	// Bail if we can't find any servers
	s.remoteLock.RLock()
	servers := s.remoteConsuls[dc]
	if len(servers) == 0 {
		s.remoteLock.RUnlock()
		s.logger.Printf("[WARN] consul.rpc: RPC request for DC '%s', no path found", dc)
		return structs.ErrNoDCPath
	}

	// Select a random addr
	offset := rand.Int31() % int32(len(servers))
	server := servers[offset]
	s.remoteLock.RUnlock()

	// Forward to remote Consul
	metrics.IncrCounter([]string{"consul", "rpc", "cross-dc", dc}, 1)
	return s.connPool.RPC(server, method, args, reply)
}

// raftApply is used to encode a message, run it through raft, and return
// the FSM response along with any errors
func (s *Server) raftApply(t structs.MessageType, msg interface{}) (interface{}, error) {
	buf, err := structs.Encode(t, msg)
	if err != nil {
		return nil, fmt.Errorf("Failed to encode request: %v", err)
	}

	future := s.raft.Apply(buf, 0)
	if err := future.Error(); err != nil {
		return nil, err
	}

	return future.Response(), nil
}

// blockingRPC is used for queries that need to wait for a
// minimum index. This is used to block and wait for changes.
func (s *Server) blockingRPC(b *structs.BlockingQuery, tables MDBTables, run func() (uint64, error)) error {
	var timeout <-chan time.Time
	var notifyCh chan struct{}

	// Fast path non-blocking
	if b.MinQueryIndex == 0 {
		goto RUN_QUERY
	}

	// Sanity check that we have tables to block on
	if len(tables) == 0 {
		panic("no tables to block on")
	}

	// Restrict the max query time
	if b.MaxQueryTime > maxQueryTime {
		b.MaxQueryTime = maxQueryTime
	}

	// Ensure a time limit is set if we have an index
	if b.MinQueryIndex > 0 && b.MaxQueryTime == 0 {
		b.MaxQueryTime = maxQueryTime
	}

	// Setup a query timeout
	if b.MaxQueryTime > 0 {
		timeout = time.After(b.MaxQueryTime)
	}

	// Setup a notification channel for changes
SETUP_NOTIFY:
	if b.MinQueryIndex > 0 {
		notifyCh = make(chan struct{}, 1)
		s.fsm.State().Watch(tables, notifyCh)
	}

	// Run the query function
RUN_QUERY:
	idx, err := run()

	// Check for minimum query time
	if err == nil && idx <= b.MinQueryIndex {
		select {
		case <-notifyCh:
			goto SETUP_NOTIFY
		case <-timeout:
		}
	}
	return err
}

// setQueryMeta is used to populate the QueryMeta data for an RPC call
func (s *Server) setQueryMeta(m *structs.QueryMeta) {
	if s.IsLeader() {
		m.LastContact = 0
		m.KnownLeader = true
	} else {
		m.LastContact = time.Now().Sub(s.raft.LastContact())
		m.KnownLeader = (s.raft.Leader() != nil)
	}
}

// consistentRead is used to ensure we do not perform a stale
// read. This is done by verifying leadership before the read.
func (s *Server) consistentRead() error {
	defer metrics.MeasureSince([]string{"consul", "rpc", "consistentRead"}, time.Now())
	future := s.raft.VerifyLeader()
	return future.Error()
}
<|endoftext|>


<commit_before>package adcom1

// CategoryTaxonomy identifies the taxonomy in effect when content categories are listed.
type CategoryTaxonomy int64

// CategoryTaxonomy options.
//
// Values of 500+ hold vendor-specific codes.
const (
	CatTaxIABContent1   CategoryTaxonomy = 1 // 1	IAB Content Category Taxonomy 1.0.
	CatTaxIABContent20  CategoryTaxonomy = 2 // 2	IAB Content Category Taxonomy 2.0: www.iab.com/guidelines/taxonomy
	CatTaxIABProduct1   CategoryTaxonomy = 3 // 3	IAB Ad Product Taxonomy 1.0.
	CatTaxIABAudience11 CategoryTaxonomy = 4 // 4	IAB Audience Taxonomy 1.1.
	CatTaxIABContent21  CategoryTaxonomy = 5 // 5	IAB Content Category Taxonomy 2.1.
	CatTaxIABContent22  CategoryTaxonomy = 6 // 6	IAB Content Category Taxonomy 2.2
)
<commit_msg>native1: constant naming: "Xxx 1.0" -> "Xxx10"<commit_after>package adcom1

// CategoryTaxonomy identifies the taxonomy in effect when content categories are listed.
type CategoryTaxonomy int64

// CategoryTaxonomy options.
//
// Values of 500+ hold vendor-specific codes.
const (
	CatTaxIABContent10  CategoryTaxonomy = 1 // 1	IAB Content Category Taxonomy 1.0.
	CatTaxIABContent20  CategoryTaxonomy = 2 // 2	IAB Content Category Taxonomy 2.0: www.iab.com/guidelines/taxonomy
	CatTaxIABProduct10  CategoryTaxonomy = 3 // 3	IAB Ad Product Taxonomy 1.0.
	CatTaxIABAudience11 CategoryTaxonomy = 4 // 4	IAB Audience Taxonomy 1.1.
	CatTaxIABContent21  CategoryTaxonomy = 5 // 5	IAB Content Category Taxonomy 2.1.
	CatTaxIABContent22  CategoryTaxonomy = 6 // 6	IAB Content Category Taxonomy 2.2
)
<|endoftext|>


<commit_before>package zclwrite

import (
	"bytes"
	"testing"

	"github.com/zclconf/go-zcl/zcl"
)

func TestRoundTrip(t *testing.T) {
	tests := []string{
		``,
		`foo = 1
`,
		`
foobar = 1
baz    = 1
`,
		`
# this file is awesome

# tossed salads and scrambled eggs
foobar = 1
baz    = 1

# and they all lived happily ever after
`,
	}

	for _, test := range tests {
		t.Run(test, func(t *testing.T) {
			src := []byte(test)
			file, diags := parse(src, "", zcl.Pos{Line: 1, Column: 1})
			if len(diags) != 0 {
				for _, diag := range diags {
					t.Logf(" - %s", diag.Error())
				}
				t.Fatalf("unexpected diagnostics")
			}

			wr := &bytes.Buffer{}
			n, err := file.WriteTo(wr)
			if n != len(test) {
				t.Errorf("wrong number of bytes %d; want %d", n, len(test))
			}
			if err != nil {
				t.Fatalf("error from WriteTo")
			}

			result := wr.Bytes()

			if !bytes.Equal(result, src) {
				t.Errorf("wrong result\nresult:\n%s\ninput:\n%s", result, src)
			}
		})
	}
}
<commit_msg>zclwrite: formatting round-trip test<commit_after>package zclwrite

import (
	"bytes"
	"testing"

	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/function"
	"github.com/zclconf/go-cty/cty/function/stdlib"
	"github.com/zclconf/go-zcl/zcl"
	"github.com/zclconf/go-zcl/zcl/zclsyntax"
)

func TestRoundTripVerbatim(t *testing.T) {
	tests := []string{
		``,
		`foo = 1
`,
		`
foobar = 1
baz    = 1
`,
		`
# this file is awesome

# tossed salads and scrambled eggs
foobar = 1
baz    = 1

# and they all lived happily ever after
`,
	}

	for _, test := range tests {
		t.Run(test, func(t *testing.T) {
			src := []byte(test)
			file, diags := parse(src, "", zcl.Pos{Line: 1, Column: 1})
			if len(diags) != 0 {
				for _, diag := range diags {
					t.Logf(" - %s", diag.Error())
				}
				t.Fatalf("unexpected diagnostics")
			}

			wr := &bytes.Buffer{}
			n, err := file.WriteTo(wr)
			if n != len(test) {
				t.Errorf("wrong number of bytes %d; want %d", n, len(test))
			}
			if err != nil {
				t.Fatalf("error from WriteTo")
			}

			result := wr.Bytes()

			if !bytes.Equal(result, src) {
				t.Errorf("wrong result\nresult:\n%s\ninput:\n%s", result, src)
			}
		})
	}
}

func TestRoundTripFormat(t *testing.T) {
	// The goal of this test is to verify that the formatter doesn't change
	// the semantics of any expressions when it adds and removes whitespace.
	// String templates are the primary area of concern here, but we also
	// test some other things for completeness sake.
	//
	// The tests here must define zero or more attributes, which will be
	// extract with JustAttributes and evaluated both before and after
	// formatting.

	tests := []string{
		"",
		"\n\n\n",
		"a=1\n",
		"a=\"hello\"\n",
		"a=\"${hello} world\"\n",
		"a=upper(\"hello\")\n",
		"a=upper(hello)\n",
		"a=[1,2,3,4,five]\n",
		"a={greeting=hello}\n",
		"a={\ngreeting=hello\n}\n",
		"a={\ngreeting=hello}\n",
		"a={greeting=hello\n}\n",
		"a={greeting=hello,number=five,sarcastic=\"${upper(hello)}\"\n}\n",
		"a={\ngreeting=hello\nnumber=five\nsarcastic=\"${upper(hello)}\"\n}\n",
		"a=<<EOT\nhello\nEOT\n\n",
		"a=[<<EOT\nhello\nEOT\n]\n",
		"a=[\n<<EOT\nhello\nEOT\n]\n",
		"a=[\n]\n",
		"a=1\nb=2\nc=3\n",
		"a=\"${\n5\n}\"\n",
	}

	ctx := &zcl.EvalContext{
		Variables: map[string]cty.Value{
			"hello": cty.StringVal("hello"),
			"five":  cty.NumberIntVal(5),
		},
		Functions: map[string]function.Function{
			"upper": stdlib.UpperFunc,
		},
	}

	for _, test := range tests {
		t.Run(test, func(t *testing.T) {

			attrsAsObj := func(src []byte, phase string) cty.Value {
				t.Logf("source %s:\n%s", phase, src)
				f, diags := zclsyntax.ParseConfig(src, "", zcl.Pos{Line: 1, Column: 1})
				if len(diags) != 0 {
					for _, diag := range diags {
						t.Logf(" - %s", diag.Error())
					}
					t.Fatalf("unexpected diagnostics in parse %s", phase)
				}

				attrs, diags := f.Body.JustAttributes()
				if len(diags) != 0 {
					for _, diag := range diags {
						t.Logf(" - %s", diag.Error())
					}
					t.Fatalf("unexpected diagnostics in JustAttributes %s", phase)
				}

				vals := map[string]cty.Value{}
				for k, attr := range attrs {
					val, diags := attr.Expr.Value(ctx)
					if len(diags) != 0 {
						for _, diag := range diags {
							t.Logf(" - %s", diag.Error())
						}
						t.Fatalf("unexpected diagnostics evaluating %s", phase)
					}
					vals[k] = val
				}
				return cty.ObjectVal(vals)
			}

			src := []byte(test)
			before := attrsAsObj(src, "before")

			formatted := Format(src)
			after := attrsAsObj(formatted, "after")

			if !after.RawEquals(before) {
				t.Errorf("mismatching after format\nbefore: %#v\nafter:  %#v", before, after)
			}
		})
	}

}
<|endoftext|>


<commit_before>package v3

import (
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"

	archive_helpers "code.cloudfoundry.org/archiver/extractor/test_helper"
	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/random_name"
	. "github.com/cloudfoundry/cf-acceptance-tests/helpers/v3_helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = V3Describe("buildpack", func() {
	var (
		appName       string
		appGuid       string
		buildpackName string
		packageGuid   string
		spaceGuid     string
		token         string
	)

	BeforeEach(func() {
		appName = random_name.CATSRandomName("APP")
		spaceGuid = GetSpaceGuidFromName(context.RegularUserContext().Space)
		appGuid = CreateApp(appName, spaceGuid, "{}")
		packageGuid = CreatePackage(appGuid)
		token = GetAuthToken()
		uploadUrl := fmt.Sprintf("%s%s/v3/packages/%s/upload", config.Protocol(), config.ApiEndpoint, packageGuid)
		UploadPackage(uploadUrl, assets.NewAssets().DoraZip, token)
		WaitForPackageToBeReady(packageGuid)

		buildpackName = random_name.CATSRandomName("BPK")
		buildpackZip := createBuildpack()

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-buildpack", buildpackName, buildpackZip, "999").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
	})

	AfterEach(func() {
		FetchRecentLogs(appGuid, token, config)

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
		DeleteApp(appGuid)
	})

	It("Stages with a user specified admin buildpack", func() {
		StageBuildpackPackage(packageGuid, buildpackName)
		Eventually(func() *Session {
			return FetchRecentLogs(appGuid, token, config)
		}, 1*time.Minute, 10*time.Second).Should(Say("STAGED WITH CUSTOM BUILDPACK"))
	})

	It("Downloads the correct user specified git buildpack", func() {
		StageBuildpackPackage(packageGuid, "https://github.com/cloudfoundry/example-git-buildpack")

		Eventually(func() *Session {
			return FetchRecentLogs(appGuid, token, config)
		}, 3*time.Minute, 10*time.Second).Should(Say("I'm a buildpack!"))
	})

	It("uses buildpack cache for staging", func() {
		firstDropletGuid := StageBuildpackPackage(packageGuid, buildpackName)
		dropletPath := fmt.Sprintf("/v3/droplets/%s", firstDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - cache not found"))

		// Wait for buildpack cache to be uploaded to blobstore.
		time.Sleep(SLEEP_TIMEOUT)

		secondDropletGuid := StageBuildpackPackage(packageGuid, buildpackName)
		dropletPath = fmt.Sprintf("/v3/droplets/%s", secondDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			if strings.Contains(string(result.Out.Contents()), "cache not found") {
				Fail("cache was not found")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - here's a cache"))

		Expect(secondDropletGuid).NotTo(Equal(firstDropletGuid))
	})
})

func createBuildpack() string {
	tmpPath, err := ioutil.TempDir("", "buildpack-cats")
	Expect(err).ToNot(HaveOccurred())

	buildpackArchivePath := path.Join(tmpPath, "buildpack.zip")

	archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
		{
			Name: "bin/compile",
			Body: `#!/usr/bin/env bash

echo "STAGED WITH CUSTOM BUILDPACK"

mkdir -p $1 $2
if [ -f "$2/cached-file" ]; then
cp $2/cached-file $1/content
else
echo "cache not found" > $1/content
fi

content=$(cat $1/content)
echo "web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done" > $1/Procfile

echo "here's a cache" > $2/cached-file
`,
		},
		{
			Name: "bin/detect",
			Body: `#!/bin/bash
echo no
exit 1
`,
		},
		{
			Name: "bin/release",
			Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
  PATH: bin:/usr/local/bin:/usr/bin:/bin
  FROM_BUILD_PACK: "yes"
default_process_types:
  web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done
EOF
`,
		},
	})

	return buildpackArchivePath
}
<commit_msg>Fix internet dependent test in V3 buildpack test [#128468117]<commit_after>package v3

import (
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"

	archive_helpers "code.cloudfoundry.org/archiver/extractor/test_helper"
	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/random_name"
	. "github.com/cloudfoundry/cf-acceptance-tests/helpers/v3_helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = V3Describe("buildpack", func() {
	var (
		appName       string
		appGuid       string
		buildpackName string
		packageGuid   string
		spaceGuid     string
		token         string
	)

	BeforeEach(func() {
		appName = random_name.CATSRandomName("APP")
		spaceGuid = GetSpaceGuidFromName(context.RegularUserContext().Space)
		appGuid = CreateApp(appName, spaceGuid, "{}")
		packageGuid = CreatePackage(appGuid)
		token = GetAuthToken()
		uploadUrl := fmt.Sprintf("%s%s/v3/packages/%s/upload", config.Protocol(), config.ApiEndpoint, packageGuid)
		UploadPackage(uploadUrl, assets.NewAssets().DoraZip, token)
		WaitForPackageToBeReady(packageGuid)

		buildpackName = random_name.CATSRandomName("BPK")
		buildpackZip := createBuildpack()

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-buildpack", buildpackName, buildpackZip, "999").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
	})

	AfterEach(func() {
		FetchRecentLogs(appGuid, token, config)

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})
		DeleteApp(appGuid)
	})

	It("Stages with a user specified admin buildpack", func() {
		StageBuildpackPackage(packageGuid, buildpackName)
		Eventually(func() *Session {
			return FetchRecentLogs(appGuid, token, config)
		}, 1*time.Minute, 10*time.Second).Should(Say("STAGED WITH CUSTOM BUILDPACK"))
	})

	It("Downloads the correct user specified git buildpack", func() {
		config = helpers.LoadConfig()
		if !config.IncludeInternetDependent {
			Skip("Skipping this test because config.IncludeInternetDependent is set to false.")
		}
		StageBuildpackPackage(packageGuid, "https://github.com/cloudfoundry/example-git-buildpack")

		Eventually(func() *Session {
			return FetchRecentLogs(appGuid, token, config)
		}, 3*time.Minute, 10*time.Second).Should(Say("I'm a buildpack!"))
	})

	It("uses buildpack cache for staging", func() {
		firstDropletGuid := StageBuildpackPackage(packageGuid, buildpackName)
		dropletPath := fmt.Sprintf("/v3/droplets/%s", firstDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - cache not found"))

		// Wait for buildpack cache to be uploaded to blobstore.
		time.Sleep(SLEEP_TIMEOUT)

		secondDropletGuid := StageBuildpackPackage(packageGuid, buildpackName)
		dropletPath = fmt.Sprintf("/v3/droplets/%s", secondDropletGuid)
		Eventually(func() *Session {
			result := cf.Cf("curl", dropletPath).Wait(DEFAULT_TIMEOUT)
			if strings.Contains(string(result.Out.Contents()), "FAILED") {
				Fail("staging failed")
			}
			if strings.Contains(string(result.Out.Contents()), "cache not found") {
				Fail("cache was not found")
			}
			return result
		}, CF_PUSH_TIMEOUT).Should(Say("custom buildpack contents - here's a cache"))

		Expect(secondDropletGuid).NotTo(Equal(firstDropletGuid))
	})
})

func createBuildpack() string {
	tmpPath, err := ioutil.TempDir("", "buildpack-cats")
	Expect(err).ToNot(HaveOccurred())

	buildpackArchivePath := path.Join(tmpPath, "buildpack.zip")

	archive_helpers.CreateZipArchive(buildpackArchivePath, []archive_helpers.ArchiveFile{
		{
			Name: "bin/compile",
			Body: `#!/usr/bin/env bash

echo "STAGED WITH CUSTOM BUILDPACK"

mkdir -p $1 $2
if [ -f "$2/cached-file" ]; then
cp $2/cached-file $1/content
else
echo "cache not found" > $1/content
fi

content=$(cat $1/content)
echo "web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done" > $1/Procfile

echo "here's a cache" > $2/cached-file
`,
		},
		{
			Name: "bin/detect",
			Body: `#!/bin/bash
echo no
exit 1
`,
		},
		{
			Name: "bin/release",
			Body: `#!/usr/bin/env bash

cat <<EOF
---
config_vars:
  PATH: bin:/usr/local/bin:/usr/bin:/bin
  FROM_BUILD_PACK: "yes"
default_process_types:
  web: while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "custom buildpack contents - $content"; } | nc -l \$PORT; done
EOF
`,
		},
	})

	return buildpackArchivePath
}
<|endoftext|>


<commit_before>package mailjet

import (
	"fmt"
	"github.com/mailjet/mailjet-apiv3-go/resources"
	"math/rand"
	"net/http"
	"os"
	"testing"
	"time"
)

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func randSeq(n int) string {
	rand.Seed(time.Now().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func TestNewMailjetClient(t *testing.T) {
	ak := os.Getenv("MJ_APIKEY_PUBLIC")
	sk := os.Getenv("MJ_APIKEY_PRIVATE")
	m := NewMailjetClient(ak, sk)

	if ak != m.ApiKeyPublic() {
		t.Fatal("Wrong public key:", m.ApiKeyPublic())
	}

	if sk != m.ApiKeyPrivate() {
		t.Fatal("Wrong secret key:", m.ApiKeyPrivate())
	}

	if http.DefaultClient != m.Client() {
		t.Fatal("HTTP client not default!")
	}
	client := new(http.Client)
	m.SetClient(client)
	if client != m.Client() {
		t.Fatal("HTTP client not equal!")
	}
}

func TestList(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Sender
	count, _, err := m.List("sender", &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one sender expected !")
	}
}

func TestGet(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.User
	resource := "user"
	count, _, err := m.List(resource, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one user expected !")
	}
	if data == nil {
		t.Fatal("Empty result")
	}

	mr := &MailjetRequest{Resource: resource, ID: data[0].ID}
	data = make([]resources.User, 0)
	err = m.Get(mr, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	fmt.Printf("Data: %+v\n", data[0])
}

func TestPost(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Contact
	rstr := randSeq(10)
	fmt.Printf("Create new contact: \"%s@mailjet.com\"\n", rstr)
	fmr := &FullMailjetRequest{
		Info:    &MailjetRequest{Resource: "contact"},
		Payload: &resources.Contact{Name: rstr, Email: rstr + "@mailjet.com"},
	}
	err := m.Post(fmr, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if data == nil {
		t.Fatal("Empty result")
	}
	fmt.Printf("Data: %+v\n", data[0])
}

func TestPut(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Contactslist
	resource := "contactslist"
	count, _, err := m.List(resource, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one contact list expected on test account!")
	}
	if data == nil {
		t.Fatal("Empty result")
	}

	rstr := randSeq(10)
	fmt.Printf("Update name of the contact list: %s -> %s\n", data[0].Name, rstr)
	data[0].Name = randSeq(10)
	fmr := &FullMailjetRequest{
		Info:    &MailjetRequest{Resource: resource, AltID: data[0].Address},
		Payload: data[0],
	}
	err = m.Put(fmr, []string{"Name"})
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}

}

func TestDelete(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Listrecipient
	resource := "listrecipient"
	count, _, err := m.List(resource, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one listrecipient expected !")
	}
	if data == nil {
		t.Fatal("Empty result")
	}

	mr := &MailjetRequest{
		ID:       data[0].ID,
		Resource: resource,
	}
	err = m.Delete(mr)
	if err != nil {
		fmt.Println(err)
	}
}

func TestSendMail(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	param := &MailjetSendMail{
		FromEmail: "gbadi@student.42.fr",
		FromName:  "Guillaume",
		Recipients: []MailjetRecipient{
			MailjetRecipient{
				Email: "gbadi@mailjet.com",
			},
		},
		Subject:  "Send API testing",
		TextPart: "SendMail is working !",
	}
	res, err := m.SendMail(param)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	fmt.Printf("Data: %+v\n", res)
}
<commit_msg>delete test on contact<commit_after>package mailjet

import (
	"fmt"
	"github.com/mailjet/mailjet-apiv3-go/resources"
	"math/rand"
	"net/http"
	"os"
	"testing"
	"time"
)

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func randSeq(n int) string {
	rand.Seed(time.Now().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func TestNewMailjetClient(t *testing.T) {
	ak := os.Getenv("MJ_APIKEY_PUBLIC")
	sk := os.Getenv("MJ_APIKEY_PRIVATE")
	m := NewMailjetClient(ak, sk)

	if ak != m.ApiKeyPublic() {
		t.Fatal("Wrong public key:", m.ApiKeyPublic())
	}

	if sk != m.ApiKeyPrivate() {
		t.Fatal("Wrong secret key:", m.ApiKeyPrivate())
	}

	if http.DefaultClient != m.Client() {
		t.Fatal("HTTP client not default!")
	}
	client := new(http.Client)
	m.SetClient(client)
	if client != m.Client() {
		t.Fatal("HTTP client not equal!")
	}
}

func TestList(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Sender
	count, _, err := m.List("sender", &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one sender expected !")
	}
}

func TestGet(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.User
	resource := "user"
	count, _, err := m.List(resource, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one user expected !")
	}
	if data == nil {
		t.Fatal("Empty result")
	}

	mr := &MailjetRequest{Resource: resource, ID: data[0].ID}
	data = make([]resources.User, 0)
	err = m.Get(mr, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	fmt.Printf("Data: %+v\n", data[0])
}

func TestPost(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Contact
	rstr := randSeq(10)
	fmt.Printf("Create new contact: \"%s@mailjet.com\"\n", rstr)
	fmr := &FullMailjetRequest{
		Info:    &MailjetRequest{Resource: "contact"},
		Payload: &resources.Contact{Name: rstr, Email: rstr + "@mailjet.com"},
	}
	err := m.Post(fmr, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if data == nil {
		t.Fatal("Empty result")
	}
	fmt.Printf("Data: %+v\n", data[0])
}

func TestPut(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Contactslist
	resource := "contactslist"
	count, _, err := m.List(resource, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one contact list expected on test account!")
	}
	if data == nil {
		t.Fatal("Empty result")
	}

	rstr := randSeq(10)
	fmt.Printf("Update name of the contact list: %s -> %s\n", data[0].Name, rstr)
	data[0].Name = randSeq(10)
	fmr := &FullMailjetRequest{
		Info:    &MailjetRequest{Resource: resource, AltID: data[0].Address},
		Payload: data[0],
	}
	err = m.Put(fmr, []string{"Name"})
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}

}

func TestDelete(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	var data []resources.Contact
	resource := "contact"
	count, _, err := m.List(resource, &data)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	if count < 1 {
		t.Fatal("At least one contact expected !")
	}
	if data == nil {
		t.Fatal("Empty result")
	}

	mr := &MailjetRequest{
		ID:       data[0].ID,
		Resource: resource,
	}
	err = m.Delete(mr)
	if err != nil {
		fmt.Println(err)
	}
}

func TestSendMail(t *testing.T) {
	m := NewMailjetClient(os.Getenv("MJ_APIKEY_PUBLIC"), os.Getenv("MJ_APIKEY_PRIVATE"))

	DebugLevel = LevelDebugFull

	param := &MailjetSendMail{
		FromEmail: "gbadi@student.42.fr",
		FromName:  "Guillaume",
		Recipients: []MailjetRecipient{
			MailjetRecipient{
				Email: "gbadi@mailjet.com",
			},
		},
		Subject:  "Send API testing",
		TextPart: "SendMail is working !",
	}
	res, err := m.SendMail(param)
	if err != nil {
		t.Fatal("Unexpected error:", err)
	}
	fmt.Printf("Data: %+v\n", res)
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

type Controller struct {
	storage *perfDB
}

func newController(storage *perfDB) *Controller {
	return &Controller{storage}
}

func (c *Controller) listDatabases(context *gin.Context) {
	databases, err := c.storage.listDatabases()
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	context.JSON(http.StatusOK, databases)
}

func (c *Controller) listMetrics(context *gin.Context) {
	dbname := context.Param("db")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	metrics := c.storage.listMetrics(dbname)
	context.JSON(http.StatusOK, metrics)
}

func (c *Controller) getRawValues(context *gin.Context) {
	dbname := context.Param("db")
	metric := context.Param("metric")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	if err := c.storage.checkMetricExists(dbname, metric); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	values, err := c.storage.getRawValues(dbname, metric)
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	context.JSON(http.StatusOK, values)
}

func (c *Controller) getSummary(context *gin.Context) {
	dbname := context.Param("db")
	metric := context.Param("metric")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	if err := c.storage.checkMetricExists(dbname, metric); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	values, err := c.storage.getSummary(dbname, metric)
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	context.JSON(http.StatusOK, values)
}

func (c *Controller) addSamples(context *gin.Context) {
	var timestamp int64
	if customTimestamp := context.Query("ts"); customTimestamp != "" {
		timestamp = parseTimestamp(customTimestamp)
	} else {
		timestamp = time.Now().UnixNano() / 1e6
	}

	dbname := context.Param("db")

	var samples map[string]interface{}
	if err := context.BindJSON(&samples); err != nil {
		context.AbortWithError(http.StatusBadRequest, err)
		return
	}

	for metric, value := range samples {
		sample := Sample{timestamp, value.(float64)}
		if err := c.storage.addSample(dbname, metric, sample); err != nil {
			context.AbortWithError(http.StatusInternalServerError, err)
			return
		}
	}

	context.JSON(http.StatusOK, map[string]string{"status": "ok"})
}

func (c *Controller) getHeatMapSVG(context *gin.Context) {
	dbname := context.Param("db")
	metric := context.Param("metric")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	if err := c.storage.checkMetricExists(dbname, metric); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	hm, err := c.storage.getHeatMap(dbname, metric)
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	var title string
	if label := context.Query("label"); label != "" {
		title = label
	} else {
		title = metric
	}

	context.Writer.Header().Set("Content-Type", "image/svg+xml")
	generateSVG(context.Writer, hm, title)
}
<commit_msg>Ignore invalid values<commit_after>package main

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

type Controller struct {
	storage *perfDB
}

func newController(storage *perfDB) *Controller {
	return &Controller{storage}
}

func (c *Controller) listDatabases(context *gin.Context) {
	databases, err := c.storage.listDatabases()
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	context.JSON(http.StatusOK, databases)
}

func (c *Controller) listMetrics(context *gin.Context) {
	dbname := context.Param("db")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	metrics := c.storage.listMetrics(dbname)
	context.JSON(http.StatusOK, metrics)
}

func (c *Controller) getRawValues(context *gin.Context) {
	dbname := context.Param("db")
	metric := context.Param("metric")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	if err := c.storage.checkMetricExists(dbname, metric); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	values, err := c.storage.getRawValues(dbname, metric)
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	context.JSON(http.StatusOK, values)
}

func (c *Controller) getSummary(context *gin.Context) {
	dbname := context.Param("db")
	metric := context.Param("metric")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	if err := c.storage.checkMetricExists(dbname, metric); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	values, err := c.storage.getSummary(dbname, metric)
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	context.JSON(http.StatusOK, values)
}

func (c *Controller) addSamples(context *gin.Context) {
	var timestamp int64
	if customTimestamp := context.Query("ts"); customTimestamp != "" {
		timestamp = parseTimestamp(customTimestamp)
	} else {
		timestamp = time.Now().UnixNano() / 1e6
	}

	dbname := context.Param("db")

	var samples map[string]interface{}
	if err := context.BindJSON(&samples); err != nil {
		context.AbortWithError(http.StatusBadRequest, err)
		return
	}

	for metric, rawValue := range samples {
		value, ok := rawValue.(float64)
		if !ok {
			continue
		}
		sample := Sample{timestamp, value}
		if err := c.storage.addSample(dbname, metric, sample); err != nil {
			context.AbortWithError(http.StatusInternalServerError, err)
			return
		}
	}

	context.JSON(http.StatusOK, map[string]string{"status": "ok"})
}

func (c *Controller) getHeatMapSVG(context *gin.Context) {
	dbname := context.Param("db")
	metric := context.Param("metric")

	if err := c.storage.checkDbExists(dbname); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	if err := c.storage.checkMetricExists(dbname, metric); err != nil {
		context.AbortWithError(http.StatusNotFound, err)
		return
	}

	hm, err := c.storage.getHeatMap(dbname, metric)
	if err != nil {
		context.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	var title string
	if label := context.Query("label"); label != "" {
		title = label
	} else {
		title = metric
	}

	context.Writer.Header().Set("Content-Type", "image/svg+xml")
	generateSVG(context.Writer, hm, title)
}
<|endoftext|>


<commit_before>package plugins

import (
    "errors"
    "fmt"
    i "github.com/darkhelmet/goggles/influxdb"
    "syscall"
)

func init() {
    Register("DiskUsage", NewDiskUsage)
}

// Checks disk usage using df
type DiskUsage struct {
    // The path to examine
    Paths []string
}

func (du *DiskUsage) Run(points chan i.P) error {
    for _, path := range du.Paths {
        var stat syscall.Statfs_t
        if err := syscall.Statfs(path, &stat); err != nil {
            return err
        }

        bsize := uint64(stat.Bsize)
        available := bsize * stat.Bavail / 1024 / 1024
        total := bsize * stat.Blocks / 1024 / 1024
        used := total - available
        percent := float64(used) / float64(total) * 100

        points <- i.P{"name": "DiskUsage", "path": path, "used": used, "available": available, "percent": percent, "total": total}
    }
    return nil
}

// Constructor for DiskUsage plugin
func NewDiskUsage(p Params) (Plugin, error) {
    du := &DiskUsage{}

    err := p.Decode(du)
    if err != nil {
        return nil, fmt.Errorf("failed decoding params: %s", err)
    }

    if len(du.Paths) == 0 {
        return nil, errors.New("DiskUsage requires at least one path to check, Paths is empty")
    }

    return du, nil
}
<commit_msg>lines yo<commit_after>package plugins

import (
    "errors"
    "fmt"
    i "github.com/darkhelmet/goggles/influxdb"
    "syscall"
)

func init() {
    Register("DiskUsage", NewDiskUsage)
}

// Checks disk usage
type DiskUsage struct {
    // The path to examine
    Paths []string
}

func (du *DiskUsage) Run(points chan i.P) error {
    for _, path := range du.Paths {
        var stat syscall.Statfs_t
        if err := syscall.Statfs(path, &stat); err != nil {
            return err
        }

        bsize := uint64(stat.Bsize)
        available := bsize * stat.Bavail / 1024 / 1024
        total := bsize * stat.Blocks / 1024 / 1024
        used := total - available
        percent := float64(used) / float64(total) * 100

        points <- i.P{
            "name":      "DiskUsage",
            "path":      path,
            "used":      used,
            "available": available,
            "percent":   percent,
            "total":     total,
        }
    }
    return nil
}

// Constructor for DiskUsage plugin
func NewDiskUsage(p Params) (Plugin, error) {
    du := &DiskUsage{}

    err := p.Decode(du)
    if err != nil {
        return nil, fmt.Errorf("failed decoding params: %s", err)
    }

    if len(du.Paths) == 0 {
        return nil, errors.New("DiskUsage requires at least one path to check, Paths is empty")
    }

    return du, nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/budgets"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsBudgetsBudget() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"account_id": {
				Type:         schema.TypeString,
				Optional:     true,
				ForceNew:     true,
				ValidateFunc: validateAwsAccountId,
			},
			"name": {
				Type:          schema.TypeString,
				Computed:      true,
				Optional:      true,
				ConflictsWith: []string{"name_prefix"},
			},
			"name_prefix": {
				Type:     schema.TypeString,
				Computed: true,
				Optional: true,
				ForceNew: true,
			},
			"budget_type": {
				Type:     schema.TypeString,
				Required: true,
			},
			"limit_amount": {
				Type:     schema.TypeString,
				Required: true,
			},
			"limit_unit": {
				Type:     schema.TypeString,
				Required: true,
			},
			"cost_types": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"include_credit": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_other_subscription": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_recurring": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_refund": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_subscription": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_support": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_tax": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_upfront": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"use_blended": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
					},
				},
			},
			"time_period_start": {
				Type:     schema.TypeString,
				Required: true,
			},
			"time_period_end": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "2087-06-15_00:00",
			},
			"time_unit": {
				Type:     schema.TypeString,
				Required: true,
			},
			"cost_filters": {
				Type:     schema.TypeMap,
				Optional: true,
				Computed: true,
			},
		},
		Create: resourceAwsBudgetsBudgetCreate,
		Read:   resourceAwsBudgetsBudgetRead,
		Update: resourceAwsBudgetsBudgetUpdate,
		Delete: resourceAwsBudgetsBudgetDelete,
	}
}

func resourceAwsBudgetsBudgetCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*AWSClient).budgetconn
	var accountID string
	if v, ok := d.GetOk("account_id"); ok {
		accountID = v.(string)
	} else {
		accountID = meta.(*AWSClient).accountid
	}

	budget, err := expandBudgetsBudgetUnmarshal(d)
	if err != nil {
		return fmt.Errorf("failed creating budget: %v", err)
	}

	_, err = client.CreateBudget(&budgets.CreateBudgetInput{
		AccountId: aws.String(accountID),
		Budget:    budget,
	})
	if err != nil {
		return fmt.Errorf("create budget failed: %v", err)
	}

	d.SetId(fmt.Sprintf("%s:%s", accountID, *budget.BudgetName))
	return resourceAwsBudgetsBudgetUpdate(d, meta)
}

func resourceAwsBudgetsBudgetRead(d *schema.ResourceData, meta interface{}) error {
	accountID, budgetName, err := decodeBudgetsBudgetID(d.Id())
	if err != nil {
		return err
	}

	client := meta.(*AWSClient).budgetconn
	describeBudgetOutput, err := client.DescribeBudget(&budgets.DescribeBudgetInput{
		BudgetName: aws.String(budgetName),
		AccountId:  aws.String(accountID),
	})
	if isAWSErr(err, budgets.ErrCodeNotFoundException, "") {
		log.Printf("[WARN] Budget %s not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	if err != nil {
		return fmt.Errorf("describe budget failed: %v", err)
	}

	flattenedBudget, err := expandBudgetsBudgetFlatten(describeBudgetOutput.Budget)
	if err != nil {
		return fmt.Errorf("failed flattening budget output: %v", err)
	}

	if err := d.Set("name", flattenedBudget.name); err != nil {
		return err
	}

	for k, v := range map[string]interface{}{
		"account_id":        accountID,
		"budget_type":       flattenedBudget.budgetType,
		"time_unit":         flattenedBudget.timeUnit,
		"cost_filters":      convertCostFiltersToStringMap(flattenedBudget.costFilters),
		"limit_amount":      flattenedBudget.limitAmount,
		"limit_unit":        flattenedBudget.limitUnit,
		"cost_types":        []interface{}{flattenedBudget.costTypes},
		"time_period_start": flattenedBudget.timePeriodStart.Format("2006-01-02_15:04"),
		"time_period_end":   flattenedBudget.timePeriodEnd.Format("2006-01-02_15:04"),
	} {
		if _, ok := d.GetOk(k); ok {
			if err := d.Set(k, v); err != nil {
				return err
			}
		}
	}
	return nil
}

func resourceAwsBudgetsBudgetUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*AWSClient).budgetconn
	var accountID string
	if v, ok := d.GetOk("account_id"); ok {
		accountID = v.(string)
	} else {
		accountID = meta.(*AWSClient).accountid
	}

	budget, err := expandBudgetsBudgetUnmarshal(d)
	if err != nil {
		return fmt.Errorf("could not create budget: %v", err)
	}

	_, err = client.UpdateBudget(&budgets.UpdateBudgetInput{
		AccountId: aws.String(accountID),
		NewBudget: budget,
	})
	if err != nil {
		return fmt.Errorf("update budget failed: %v", err)
	}

	return resourceAwsBudgetsBudgetRead(d, meta)
}

func resourceAwsBudgetsBudgetDelete(d *schema.ResourceData, meta interface{}) error {
	accountID, budgetName, err := decodeBudgetsBudgetID(d.Id())
	if err != nil {
		return err
	}

	client := meta.(*AWSClient).budgetconn
	_, err = client.DescribeBudget(&budgets.DescribeBudgetInput{
		BudgetName: aws.String(budgetName),
		AccountId:  aws.String(accountID),
	})
	if isAWSErr(err, budgets.ErrCodeNotFoundException, "") {
		log.Printf("[INFO] budget %s could not be found. skipping delete.", d.Id())
		return nil
	}

	_, err = client.DeleteBudget(&budgets.DeleteBudgetInput{
		BudgetName: aws.String(budgetName),
		AccountId:  aws.String(accountID),
	})
	if err != nil {
		return fmt.Errorf("delete budget failed: %v", err)
	}

	return nil
}

type flattenedBudgetsBudget struct {
	name            *string
	budgetType      *string
	timeUnit        *string
	costFilters     map[string][]*string
	limitAmount     *string
	limitUnit       *string
	costTypes       map[string]bool
	timePeriodStart *time.Time
	timePeriodEnd   *time.Time
}

func expandBudgetsBudgetFlatten(budget *budgets.Budget) (*flattenedBudgetsBudget, error) {
	if budget == nil {
		return nil, fmt.Errorf("empty budget returned from budget output: %v", budget)
	}

	budgetLimit := budget.BudgetLimit
	if budgetLimit == nil {
		return nil, fmt.Errorf("empty limit in budget: %v", budget)
	}

	budgetCostTypes := budget.CostTypes
	if budgetCostTypes == nil {
		return nil, fmt.Errorf("empty CostTypes in budget: %v", budget)
	}

	costTypesMap := map[string]bool{
		"include_credit":             *budgetCostTypes.IncludeCredit,
		"include_other_subscription": *budgetCostTypes.IncludeOtherSubscription,
		"include_recurring":          *budgetCostTypes.IncludeRecurring,
		"include_refund":             *budgetCostTypes.IncludeRefund,
		"include_subscription":       *budgetCostTypes.IncludeSubscription,
		"include_support":            *budgetCostTypes.IncludeSupport,
		"include_tax":                *budgetCostTypes.IncludeTax,
		"include_upfront":            *budgetCostTypes.IncludeUpfront,
		"use_blended":                *budgetCostTypes.UseBlended,
	}
	budgetTimePeriod := budget.TimePeriod
	if budgetTimePeriod == nil {
		return nil, fmt.Errorf("empty TimePeriod in budget: %v", budget)
	}

	budgetTimePeriodStart := budgetTimePeriod.Start
	if budgetTimePeriodStart == nil {
		return nil, fmt.Errorf("empty TimePeriodStart in budget: %v", budget)
	}

	budgetTimePeriodEnd := budgetTimePeriod.End
	if budgetTimePeriodEnd == nil {
		return nil, fmt.Errorf("empty TimePeriodEnd in budget: %v", budget)
	}

	return &flattenedBudgetsBudget{
		name:            budget.BudgetName,
		budgetType:      budget.BudgetType,
		timeUnit:        budget.TimeUnit,
		costFilters:     budget.CostFilters,
		limitAmount:     budgetLimit.Amount,
		limitUnit:       budgetLimit.Unit,
		costTypes:       costTypesMap,
		timePeriodStart: budgetTimePeriodStart,
		timePeriodEnd:   budgetTimePeriodEnd,
	}, nil
}

func convertCostFiltersToStringMap(costFilters map[string][]*string) map[string]string {
	convertedCostFilters := make(map[string]string)
	for k, v := range costFilters {
		filterValues := make([]string, 0)
		for _, singleFilterValue := range v {
			filterValues = append(filterValues, *singleFilterValue)
		}

		convertedCostFilters[k] = strings.Join(filterValues, ",")
	}

	return convertedCostFilters
}

func expandBudgetsBudgetUnmarshal(d *schema.ResourceData) (*budgets.Budget, error) {
	var budgetName string
	if _, id, err := decodeBudgetsBudgetID(d.Id()); err == nil && id != "" {
		budgetName = id

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

	} else if v, ok := d.GetOk("name_prefix"); ok {
		budgetName = resource.PrefixedUniqueId(v.(string))

	} else {
		budgetName = resource.UniqueId()
	}

	budgetType := d.Get("budget_type").(string)
	budgetLimitAmount := d.Get("limit_amount").(string)
	budgetLimitUnit := d.Get("limit_unit").(string)
	costTypes := expandBudgetsCostTypesUnmarshal(d.Get("cost_types").([]interface{}))
	budgetTimeUnit := d.Get("time_unit").(string)
	budgetCostFilters := make(map[string][]*string)
	for k, v := range d.Get("cost_filters").(map[string]interface{}) {
		filterValue := v.(string)
		budgetCostFilters[k] = append(budgetCostFilters[k], aws.String(filterValue))
	}

	budgetTimePeriodStart, err := time.Parse("2006-01-02_15:04", d.Get("time_period_start").(string))
	if err != nil {
		return nil, fmt.Errorf("failure parsing time: %v", err)
	}

	budgetTimePeriodEnd, err := time.Parse("2006-01-02_15:04", d.Get("time_period_end").(string))
	if err != nil {
		return nil, fmt.Errorf("failure parsing time: %v", err)
	}

	budget := &budgets.Budget{
		BudgetName: aws.String(budgetName),
		BudgetType: aws.String(budgetType),
		BudgetLimit: &budgets.Spend{
			Amount: aws.String(budgetLimitAmount),
			Unit:   aws.String(budgetLimitUnit),
		},
		CostTypes: costTypes,
		TimePeriod: &budgets.TimePeriod{
			End:   &budgetTimePeriodEnd,
			Start: &budgetTimePeriodStart,
		},
		TimeUnit:    aws.String(budgetTimeUnit),
		CostFilters: budgetCostFilters,
	}
	return budget, nil
}

func decodeBudgetsBudgetID(id string) (string, string, error) {
	parts := strings.Split(id, ":")
	if len(parts) != 2 {
		return "", "", fmt.Errorf("Unexpected format of ID (%q), expected AccountID:BudgetName", id)
	}
	return parts[0], parts[1], nil
}

func expandBudgetsCostTypesUnmarshal(budgetCostTypes []interface{}) *budgets.CostTypes {
	costTypes := &budgets.CostTypes{
		IncludeCredit:            aws.Bool(true),
		IncludeOtherSubscription: aws.Bool(true),
		IncludeRecurring:         aws.Bool(true),
		IncludeRefund:            aws.Bool(true),
		IncludeSubscription:      aws.Bool(true),
		IncludeSupport:           aws.Bool(true),
		IncludeTax:               aws.Bool(true),
		IncludeUpfront:           aws.Bool(true),
		UseBlended:               aws.Bool(false),
	}
	if len(budgetCostTypes) == 1 {
		costTypesMap := budgetCostTypes[0].(map[string]interface{})
		for k, v := range map[string]*bool{
			"include_credit":             costTypes.IncludeCredit,
			"include_other_subscription": costTypes.IncludeOtherSubscription,
			"include_recurring":          costTypes.IncludeRecurring,
			"include_refund":             costTypes.IncludeRefund,
			"include_subscription":       costTypes.IncludeSubscription,
			"include_support":            costTypes.IncludeSupport,
			"include_tax":                costTypes.IncludeTax,
			"include_upfront":            costTypes.IncludeUpfront,
			"use_blended":                costTypes.UseBlended,
		} {
			if val, ok := costTypesMap[k]; ok {
				*v = val.(bool)
			}
		}
	}

	return costTypes
}
<commit_msg>call read after create budgets budget<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/budgets"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsBudgetsBudget() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"account_id": {
				Type:         schema.TypeString,
				Optional:     true,
				ForceNew:     true,
				ValidateFunc: validateAwsAccountId,
			},
			"name": {
				Type:          schema.TypeString,
				Computed:      true,
				Optional:      true,
				ConflictsWith: []string{"name_prefix"},
			},
			"name_prefix": {
				Type:     schema.TypeString,
				Computed: true,
				Optional: true,
				ForceNew: true,
			},
			"budget_type": {
				Type:     schema.TypeString,
				Required: true,
			},
			"limit_amount": {
				Type:     schema.TypeString,
				Required: true,
			},
			"limit_unit": {
				Type:     schema.TypeString,
				Required: true,
			},
			"cost_types": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"include_credit": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_other_subscription": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_recurring": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_refund": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_subscription": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_support": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_tax": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"include_upfront": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  true,
						},
						"use_blended": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
					},
				},
			},
			"time_period_start": {
				Type:     schema.TypeString,
				Required: true,
			},
			"time_period_end": {
				Type:     schema.TypeString,
				Optional: true,
				Default:  "2087-06-15_00:00",
			},
			"time_unit": {
				Type:     schema.TypeString,
				Required: true,
			},
			"cost_filters": {
				Type:     schema.TypeMap,
				Optional: true,
				Computed: true,
			},
		},
		Create: resourceAwsBudgetsBudgetCreate,
		Read:   resourceAwsBudgetsBudgetRead,
		Update: resourceAwsBudgetsBudgetUpdate,
		Delete: resourceAwsBudgetsBudgetDelete,
	}
}

func resourceAwsBudgetsBudgetCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*AWSClient).budgetconn
	var accountID string
	if v, ok := d.GetOk("account_id"); ok {
		accountID = v.(string)
	} else {
		accountID = meta.(*AWSClient).accountid
	}

	budget, err := expandBudgetsBudgetUnmarshal(d)
	if err != nil {
		return fmt.Errorf("failed creating budget: %v", err)
	}

	_, err = client.CreateBudget(&budgets.CreateBudgetInput{
		AccountId: aws.String(accountID),
		Budget:    budget,
	})
	if err != nil {
		return fmt.Errorf("create budget failed: %v", err)
	}

	d.SetId(fmt.Sprintf("%s:%s", accountID, *budget.BudgetName))
	return resourceAwsBudgetsBudgetRead(d, meta)
}

func resourceAwsBudgetsBudgetRead(d *schema.ResourceData, meta interface{}) error {
	accountID, budgetName, err := decodeBudgetsBudgetID(d.Id())
	if err != nil {
		return err
	}

	client := meta.(*AWSClient).budgetconn
	describeBudgetOutput, err := client.DescribeBudget(&budgets.DescribeBudgetInput{
		BudgetName: aws.String(budgetName),
		AccountId:  aws.String(accountID),
	})
	if isAWSErr(err, budgets.ErrCodeNotFoundException, "") {
		log.Printf("[WARN] Budget %s not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	if err != nil {
		return fmt.Errorf("describe budget failed: %v", err)
	}

	flattenedBudget, err := expandBudgetsBudgetFlatten(describeBudgetOutput.Budget)
	if err != nil {
		return fmt.Errorf("failed flattening budget output: %v", err)
	}

	if err := d.Set("name", flattenedBudget.name); err != nil {
		return err
	}

	for k, v := range map[string]interface{}{
		"account_id":        accountID,
		"budget_type":       flattenedBudget.budgetType,
		"time_unit":         flattenedBudget.timeUnit,
		"cost_filters":      convertCostFiltersToStringMap(flattenedBudget.costFilters),
		"limit_amount":      flattenedBudget.limitAmount,
		"limit_unit":        flattenedBudget.limitUnit,
		"cost_types":        []interface{}{flattenedBudget.costTypes},
		"time_period_start": flattenedBudget.timePeriodStart.Format("2006-01-02_15:04"),
		"time_period_end":   flattenedBudget.timePeriodEnd.Format("2006-01-02_15:04"),
	} {
		if _, ok := d.GetOk(k); ok {
			if err := d.Set(k, v); err != nil {
				return err
			}
		}
	}
	return nil
}

func resourceAwsBudgetsBudgetUpdate(d *schema.ResourceData, meta interface{}) error {
	accountID, _, err := decodeBudgetsBudgetID(d.Id())
	if err != nil {
		return err
	}

	client := meta.(*AWSClient).budgetconn
	budget, err := expandBudgetsBudgetUnmarshal(d)
	if err != nil {
		return fmt.Errorf("could not create budget: %v", err)
	}

	_, err = client.UpdateBudget(&budgets.UpdateBudgetInput{
		AccountId: aws.String(accountID),
		NewBudget: budget,
	})
	if err != nil {
		return fmt.Errorf("update budget failed: %v", err)
	}

	return resourceAwsBudgetsBudgetRead(d, meta)
}

func resourceAwsBudgetsBudgetDelete(d *schema.ResourceData, meta interface{}) error {
	accountID, budgetName, err := decodeBudgetsBudgetID(d.Id())
	if err != nil {
		return err
	}

	client := meta.(*AWSClient).budgetconn
	_, err = client.DescribeBudget(&budgets.DescribeBudgetInput{
		BudgetName: aws.String(budgetName),
		AccountId:  aws.String(accountID),
	})
	if isAWSErr(err, budgets.ErrCodeNotFoundException, "") {
		log.Printf("[INFO] budget %s could not be found. skipping delete.", d.Id())
		return nil
	}

	_, err = client.DeleteBudget(&budgets.DeleteBudgetInput{
		BudgetName: aws.String(budgetName),
		AccountId:  aws.String(accountID),
	})
	if err != nil {
		return fmt.Errorf("delete budget failed: %v", err)
	}

	return nil
}

type flattenedBudgetsBudget struct {
	name            *string
	budgetType      *string
	timeUnit        *string
	costFilters     map[string][]*string
	limitAmount     *string
	limitUnit       *string
	costTypes       map[string]bool
	timePeriodStart *time.Time
	timePeriodEnd   *time.Time
}

func expandBudgetsBudgetFlatten(budget *budgets.Budget) (*flattenedBudgetsBudget, error) {
	if budget == nil {
		return nil, fmt.Errorf("empty budget returned from budget output: %v", budget)
	}

	budgetLimit := budget.BudgetLimit
	if budgetLimit == nil {
		return nil, fmt.Errorf("empty limit in budget: %v", budget)
	}

	budgetCostTypes := budget.CostTypes
	if budgetCostTypes == nil {
		return nil, fmt.Errorf("empty CostTypes in budget: %v", budget)
	}

	costTypesMap := map[string]bool{
		"include_credit":             *budgetCostTypes.IncludeCredit,
		"include_other_subscription": *budgetCostTypes.IncludeOtherSubscription,
		"include_recurring":          *budgetCostTypes.IncludeRecurring,
		"include_refund":             *budgetCostTypes.IncludeRefund,
		"include_subscription":       *budgetCostTypes.IncludeSubscription,
		"include_support":            *budgetCostTypes.IncludeSupport,
		"include_tax":                *budgetCostTypes.IncludeTax,
		"include_upfront":            *budgetCostTypes.IncludeUpfront,
		"use_blended":                *budgetCostTypes.UseBlended,
	}
	budgetTimePeriod := budget.TimePeriod
	if budgetTimePeriod == nil {
		return nil, fmt.Errorf("empty TimePeriod in budget: %v", budget)
	}

	budgetTimePeriodStart := budgetTimePeriod.Start
	if budgetTimePeriodStart == nil {
		return nil, fmt.Errorf("empty TimePeriodStart in budget: %v", budget)
	}

	budgetTimePeriodEnd := budgetTimePeriod.End
	if budgetTimePeriodEnd == nil {
		return nil, fmt.Errorf("empty TimePeriodEnd in budget: %v", budget)
	}

	return &flattenedBudgetsBudget{
		name:            budget.BudgetName,
		budgetType:      budget.BudgetType,
		timeUnit:        budget.TimeUnit,
		costFilters:     budget.CostFilters,
		limitAmount:     budgetLimit.Amount,
		limitUnit:       budgetLimit.Unit,
		costTypes:       costTypesMap,
		timePeriodStart: budgetTimePeriodStart,
		timePeriodEnd:   budgetTimePeriodEnd,
	}, nil
}

func convertCostFiltersToStringMap(costFilters map[string][]*string) map[string]string {
	convertedCostFilters := make(map[string]string)
	for k, v := range costFilters {
		filterValues := make([]string, 0)
		for _, singleFilterValue := range v {
			filterValues = append(filterValues, *singleFilterValue)
		}

		convertedCostFilters[k] = strings.Join(filterValues, ",")
	}

	return convertedCostFilters
}

func expandBudgetsBudgetUnmarshal(d *schema.ResourceData) (*budgets.Budget, error) {
	var budgetName string
	if _, id, err := decodeBudgetsBudgetID(d.Id()); err == nil && id != "" {
		budgetName = id

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

	} else if v, ok := d.GetOk("name_prefix"); ok {
		budgetName = resource.PrefixedUniqueId(v.(string))

	} else {
		budgetName = resource.UniqueId()
	}

	budgetType := d.Get("budget_type").(string)
	budgetLimitAmount := d.Get("limit_amount").(string)
	budgetLimitUnit := d.Get("limit_unit").(string)
	costTypes := expandBudgetsCostTypesUnmarshal(d.Get("cost_types").([]interface{}))
	budgetTimeUnit := d.Get("time_unit").(string)
	budgetCostFilters := make(map[string][]*string)
	for k, v := range d.Get("cost_filters").(map[string]interface{}) {
		filterValue := v.(string)
		budgetCostFilters[k] = append(budgetCostFilters[k], aws.String(filterValue))
	}

	budgetTimePeriodStart, err := time.Parse("2006-01-02_15:04", d.Get("time_period_start").(string))
	if err != nil {
		return nil, fmt.Errorf("failure parsing time: %v", err)
	}

	budgetTimePeriodEnd, err := time.Parse("2006-01-02_15:04", d.Get("time_period_end").(string))
	if err != nil {
		return nil, fmt.Errorf("failure parsing time: %v", err)
	}

	budget := &budgets.Budget{
		BudgetName: aws.String(budgetName),
		BudgetType: aws.String(budgetType),
		BudgetLimit: &budgets.Spend{
			Amount: aws.String(budgetLimitAmount),
			Unit:   aws.String(budgetLimitUnit),
		},
		CostTypes: costTypes,
		TimePeriod: &budgets.TimePeriod{
			End:   &budgetTimePeriodEnd,
			Start: &budgetTimePeriodStart,
		},
		TimeUnit:    aws.String(budgetTimeUnit),
		CostFilters: budgetCostFilters,
	}
	return budget, nil
}

func decodeBudgetsBudgetID(id string) (string, string, error) {
	parts := strings.Split(id, ":")
	if len(parts) != 2 {
		return "", "", fmt.Errorf("Unexpected format of ID (%q), expected AccountID:BudgetName", id)
	}
	return parts[0], parts[1], nil
}

func expandBudgetsCostTypesUnmarshal(budgetCostTypes []interface{}) *budgets.CostTypes {
	costTypes := &budgets.CostTypes{
		IncludeCredit:            aws.Bool(true),
		IncludeOtherSubscription: aws.Bool(true),
		IncludeRecurring:         aws.Bool(true),
		IncludeRefund:            aws.Bool(true),
		IncludeSubscription:      aws.Bool(true),
		IncludeSupport:           aws.Bool(true),
		IncludeTax:               aws.Bool(true),
		IncludeUpfront:           aws.Bool(true),
		UseBlended:               aws.Bool(false),
	}
	if len(budgetCostTypes) == 1 {
		costTypesMap := budgetCostTypes[0].(map[string]interface{})
		for k, v := range map[string]*bool{
			"include_credit":             costTypes.IncludeCredit,
			"include_other_subscription": costTypes.IncludeOtherSubscription,
			"include_recurring":          costTypes.IncludeRecurring,
			"include_refund":             costTypes.IncludeRefund,
			"include_subscription":       costTypes.IncludeSubscription,
			"include_support":            costTypes.IncludeSupport,
			"include_tax":                costTypes.IncludeTax,
			"include_upfront":            costTypes.IncludeUpfront,
			"use_blended":                costTypes.UseBlended,
		} {
			if val, ok := costTypesMap[k]; ok {
				*v = val.(bool)
			}
		}
	}

	return costTypes
}
<|endoftext|>


<commit_before>package zip

import (
	. "jvmgo/any"
	"jvmgo/jvm/rtda"
	rtc "jvmgo/jvm/rtda/class"
	"jvmgo/util"
)

const (
	JZENTRY_NAME    = 0
	JZENTRY_EXTRA   = 1
	JZENTRY_COMMENT = 2
)

func init() {
	_zf(initIDs, "initIDs", "()V")
	_zf(getEntryBytes, "getEntryBytes", "(JI)[B")
	_zf(getEntryFlag, "getEntryFlag", "(J)I")
	_zf(getNextEntry, "getNextEntry", "(JI)J")
	_zf(getTotal, "getTotal", "(J)I")
	_zf(open, "open", "(Ljava/lang/String;IJZ)J")
	_zf(startsWithLOC, "startsWithLOC", "(J)Z")
}

func _zf(method Any, name, desc string) {
	rtc.RegisterNativeMethod("java/util/zip/ZipFile", name, desc, method)
}

// private static native void initIDs();
// ()V
func initIDs(frame *rtda.Frame) {
	// todo
}

// private static native long open(String name, int mode, long lastModified,
//                                 boolean usemmap) throws IOException;
// (Ljava/lang/String;IJZ)J
func open(frame *rtda.Frame) {
	vars := frame.LocalVars()
	nameObj := vars.GetRef(0)

	name := rtda.GoString(nameObj)
	jzfile, err := openZip(name)
	if err != nil {
		// todo
		panic("IOException")
	}

	stack := frame.OperandStack()
	stack.PushLong(jzfile)
}

// private static native boolean startsWithLOC(long jzfile);
// (J)Z
func startsWithLOC(frame *rtda.Frame) {
	// todo
	stack := frame.OperandStack()
	stack.PushBoolean(true)
}

// private static native int getTotal(long jzfile);
// (J)I
func getTotal(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzfile := vars.GetLong(0)

	total := getEntryCount(jzfile)

	stack := frame.OperandStack()
	stack.PushInt(total)
}

// private static native long getNextEntry(long jzfile, int i);
// (JI)J
func getNextEntry(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzfile := vars.GetLong(0)
	i := vars.GetInt(2)

	nextEntry := getJzentry(jzfile, i)

	stack := frame.OperandStack()
	stack.PushLong(nextEntry)
}

// private static native int getEntryFlag(long jzentry);
// (J)I
func getEntryFlag(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzentry := vars.GetLong(0)

	entry := getEntry(jzentry)
	flag := int32(entry.Flags)

	stack := frame.OperandStack()
	stack.PushInt(flag)
}

// private static native byte[] getEntryBytes(long jzentry, int type);
// (JI)[B
func getEntryBytes(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzentry := vars.GetLong(0)
	_type := vars.GetInt(2)

	goBytes := _getEntryBytes(jzentry, _type)
	jBytes := util.CastUint8sToInt8s(goBytes)
	byteArr := rtc.NewByteArray(jBytes, frame.ClassLoader())

	stack := frame.OperandStack()
	stack.PushRef(byteArr)
}

func _getEntryBytes(jzentry int64, _type int32) []byte {
	entry := getEntry(jzentry)
	switch _type {
	case JZENTRY_NAME:
		return []byte(entry.Name)
	case JZENTRY_EXTRA:
		return entry.Extra
	case JZENTRY_COMMENT:
		return []byte(entry.Comment)
	}
	util.Panicf("BAD type: %v", _type)
	return nil
}
<commit_msg>native method: ZipFile.getEntryTime()<commit_after>package zip

import (
	. "jvmgo/any"
	"jvmgo/jvm/rtda"
	rtc "jvmgo/jvm/rtda/class"
	"jvmgo/util"
)

const (
	JZENTRY_NAME    = 0
	JZENTRY_EXTRA   = 1
	JZENTRY_COMMENT = 2
)

func init() {
	_zf(initIDs, "initIDs", "()V")
	_zf(getEntryBytes, "getEntryBytes", "(JI)[B")
	_zf(getEntryFlag, "getEntryFlag", "(J)I")
	_zf(getEntryTime, "getEntryTime", "(J)J")
	_zf(getNextEntry, "getNextEntry", "(JI)J")
	_zf(getTotal, "getTotal", "(J)I")
	_zf(open, "open", "(Ljava/lang/String;IJZ)J")
	_zf(startsWithLOC, "startsWithLOC", "(J)Z")
}

func _zf(method Any, name, desc string) {
	rtc.RegisterNativeMethod("java/util/zip/ZipFile", name, desc, method)
}

// private static native void initIDs();
// ()V
func initIDs(frame *rtda.Frame) {
	// todo
}

// private static native long open(String name, int mode, long lastModified,
//                                 boolean usemmap) throws IOException;
// (Ljava/lang/String;IJZ)J
func open(frame *rtda.Frame) {
	vars := frame.LocalVars()
	nameObj := vars.GetRef(0)

	name := rtda.GoString(nameObj)
	jzfile, err := openZip(name)
	if err != nil {
		// todo
		panic("IOException")
	}

	stack := frame.OperandStack()
	stack.PushLong(jzfile)
}

// private static native boolean startsWithLOC(long jzfile);
// (J)Z
func startsWithLOC(frame *rtda.Frame) {
	// todo
	stack := frame.OperandStack()
	stack.PushBoolean(true)
}

// private static native int getTotal(long jzfile);
// (J)I
func getTotal(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzfile := vars.GetLong(0)

	total := getEntryCount(jzfile)

	stack := frame.OperandStack()
	stack.PushInt(total)
}

// private static native long getNextEntry(long jzfile, int i);
// (JI)J
func getNextEntry(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzfile := vars.GetLong(0)
	i := vars.GetInt(2)

	jzentry := getJzentry(jzfile, i)

	stack := frame.OperandStack()
	stack.PushLong(jzentry)
}

// private static native int getEntryFlag(long jzentry);
// (J)I
func getEntryFlag(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzentry := vars.GetLong(0)

	entry := getEntry(jzentry)
	flag := int32(entry.Flags)

	stack := frame.OperandStack()
	stack.PushInt(flag)
}

// private static native byte[] getEntryBytes(long jzentry, int type);
// (JI)[B
func getEntryBytes(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzentry := vars.GetLong(0)
	_type := vars.GetInt(2)

	goBytes := _getEntryBytes(jzentry, _type)
	jBytes := util.CastUint8sToInt8s(goBytes)
	byteArr := rtc.NewByteArray(jBytes, frame.ClassLoader())

	stack := frame.OperandStack()
	stack.PushRef(byteArr)
}

func _getEntryBytes(jzentry int64, _type int32) []byte {
	entry := getEntry(jzentry)
	switch _type {
	case JZENTRY_NAME:
		return []byte(entry.Name)
	case JZENTRY_EXTRA:
		return entry.Extra
	case JZENTRY_COMMENT:
		return []byte(entry.Comment)
	}
	util.Panicf("BAD type: %v", _type)
	return nil
}

// private static native long getEntryTime(long jzentry);
// (J)J
func getEntryTime(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jzentry := vars.GetLong(0)

	entry := getEntry(jzentry)
	modDate := entry.ModifiedDate
	modTime := entry.ModifiedTime
	time := int64(modDate)<<16 | int64(modTime)

	stack := frame.OperandStack()
	stack.PushLong(time)
}
<|endoftext|>