<commit_before>// +build !go1.9

// Code generated by cdpgen. DO NOT EDIT.

package page

import (
	"github.com/mafredri/cdp/protocol"
	"github.com/mafredri/cdp/protocol/network"
)

// CreateIsolatedWorldArgs represents the arguments for CreateIsolatedWorld in the Page domain.
type CreateIsolatedWorldArgs struct {
	FrameID             protocol.PageFrameID `json:"frameId"`                       // Id of the frame in which the isolated world should be created.
	WorldName           *string              `json:"worldName,omitempty"`           // An optional name which is reported in the Execution Context.
	GrantUniveralAccess *bool                `json:"grantUniveralAccess,omitempty"` // Whether or not universal access should be granted to the isolated world. This is a powerful option, use with caution.
}

// NewCreateIsolatedWorldArgs initializes CreateIsolatedWorldArgs with the required arguments.
func NewCreateIsolatedWorldArgs(frameID protocol.PageFrameID) *CreateIsolatedWorldArgs {
	args := new(CreateIsolatedWorldArgs)
	args.FrameID = frameID
	return args
}

// SetWorldName sets the WorldName optional argument. An optional name
// which is reported in the Execution Context.
func (a *CreateIsolatedWorldArgs) SetWorldName(worldName string) *CreateIsolatedWorldArgs {
	a.WorldName = &worldName
	return a
}

// SetGrantUniveralAccess sets the GrantUniveralAccess optional argument.
// Whether or not universal access should be granted to the isolated
// world. This is a powerful option, use with caution.
func (a *CreateIsolatedWorldArgs) SetGrantUniveralAccess(grantUniveralAccess bool) *CreateIsolatedWorldArgs {
	a.GrantUniveralAccess = &grantUniveralAccess
	return a
}

// GetResourceContentArgs represents the arguments for GetResourceContent in the Page domain.
type GetResourceContentArgs struct {
	FrameID protocol.PageFrameID `json:"frameId"` // Frame id to get resource for.
	URL     string               `json:"url"`     // URL of the resource to get content for.
}

// NewGetResourceContentArgs initializes GetResourceContentArgs with the required arguments.
func NewGetResourceContentArgs(frameID protocol.PageFrameID, url string) *GetResourceContentArgs {
	args := new(GetResourceContentArgs)
	args.FrameID = frameID
	args.URL = url
	return args
}

// NavigateArgs represents the arguments for Navigate in the Page domain.
type NavigateArgs struct {
	URL            string                `json:"url"`                      // URL to navigate the page to.
	Referrer       *string               `json:"referrer,omitempty"`       // Referrer URL.
	TransitionType TransitionType        `json:"transitionType,omitempty"` // Intended transition type.
	FrameID        *protocol.PageFrameID `json:"frameId,omitempty"`        // Frame id to navigate, if not specified navigates the top frame.
}

// NewNavigateArgs initializes NavigateArgs with the required arguments.
func NewNavigateArgs(url string) *NavigateArgs {
	args := new(NavigateArgs)
	args.URL = url
	return args
}

// SetReferrer sets the Referrer optional argument. Referrer URL.
func (a *NavigateArgs) SetReferrer(referrer string) *NavigateArgs {
	a.Referrer = &referrer
	return a
}

// SetTransitionType sets the TransitionType optional argument.
// Intended transition type.
func (a *NavigateArgs) SetTransitionType(transitionType TransitionType) *NavigateArgs {
	a.TransitionType = transitionType
	return a
}

// SetFrameID sets the FrameID optional argument. Frame id to
// navigate, if not specified navigates the top frame.
func (a *NavigateArgs) SetFrameID(frameID FrameID) *NavigateArgs {
	a.FrameID = &frameID
	return a
}

// NavigateReply represents the return values for Navigate in the Page domain.
type NavigateReply struct {
	FrameID   protocol.PageFrameID `json:"frameId"`             // Frame id that has navigated (or failed to navigate)
	LoaderID  *network.LoaderID    `json:"loaderId,omitempty"`  // Loader identifier.
	ErrorText *string              `json:"errorText,omitempty"` // User friendly error message, present if and only if navigation has failed.
}

// SearchInResourceArgs represents the arguments for SearchInResource in the Page domain.
type SearchInResourceArgs struct {
	FrameID       protocol.PageFrameID `json:"frameId"`                 // Frame id for resource to search in.
	URL           string               `json:"url"`                     // URL of the resource to search in.
	Query         string               `json:"query"`                   // String to search for.
	CaseSensitive *bool                `json:"caseSensitive,omitempty"` // If true, search is case sensitive.
	IsRegex       *bool                `json:"isRegex,omitempty"`       // If true, treats string parameter as regex.
}

// NewSearchInResourceArgs initializes SearchInResourceArgs with the required arguments.
func NewSearchInResourceArgs(frameID protocol.PageFrameID, url string, query string) *SearchInResourceArgs {
	args := new(SearchInResourceArgs)
	args.FrameID = frameID
	args.URL = url
	args.Query = query
	return args
}

// SetCaseSensitive sets the CaseSensitive optional argument. If true,
// search is case sensitive.
func (a *SearchInResourceArgs) SetCaseSensitive(caseSensitive bool) *SearchInResourceArgs {
	a.CaseSensitive = &caseSensitive
	return a
}

// SetIsRegex sets the IsRegex optional argument. If true, treats
// string parameter as regex.
func (a *SearchInResourceArgs) SetIsRegex(isRegex bool) *SearchInResourceArgs {
	a.IsRegex = &isRegex
	return a
}

// SetDocumentContentArgs represents the arguments for SetDocumentContent in the Page domain.
type SetDocumentContentArgs struct {
	FrameID protocol.PageFrameID `json:"frameId"` // Frame id to set HTML for.
	HTML    string               `json:"html"`    // HTML content to set.
}

// NewSetDocumentContentArgs initializes SetDocumentContentArgs with the required arguments.
func NewSetDocumentContentArgs(frameID protocol.PageFrameID, html string) *SetDocumentContentArgs {
	args := new(SetDocumentContentArgs)
	args.FrameID = frameID
	args.HTML = html
	return args
}
<commit_msg>protocol: Add missing package for page frame ID<commit_after>// +build !go1.9

// Code generated by cdpgen. DO NOT EDIT.

package page

import (
	"github.com/mafredri/cdp/protocol"
	"github.com/mafredri/cdp/protocol/network"
)

// CreateIsolatedWorldArgs represents the arguments for CreateIsolatedWorld in the Page domain.
type CreateIsolatedWorldArgs struct {
	FrameID             protocol.PageFrameID `json:"frameId"`                       // Id of the frame in which the isolated world should be created.
	WorldName           *string              `json:"worldName,omitempty"`           // An optional name which is reported in the Execution Context.
	GrantUniveralAccess *bool                `json:"grantUniveralAccess,omitempty"` // Whether or not universal access should be granted to the isolated world. This is a powerful option, use with caution.
}

// NewCreateIsolatedWorldArgs initializes CreateIsolatedWorldArgs with the required arguments.
func NewCreateIsolatedWorldArgs(frameID protocol.PageFrameID) *CreateIsolatedWorldArgs {
	args := new(CreateIsolatedWorldArgs)
	args.FrameID = frameID
	return args
}

// SetWorldName sets the WorldName optional argument. An optional name
// which is reported in the Execution Context.
func (a *CreateIsolatedWorldArgs) SetWorldName(worldName string) *CreateIsolatedWorldArgs {
	a.WorldName = &worldName
	return a
}

// SetGrantUniveralAccess sets the GrantUniveralAccess optional argument.
// Whether or not universal access should be granted to the isolated
// world. This is a powerful option, use with caution.
func (a *CreateIsolatedWorldArgs) SetGrantUniveralAccess(grantUniveralAccess bool) *CreateIsolatedWorldArgs {
	a.GrantUniveralAccess = &grantUniveralAccess
	return a
}

// GetResourceContentArgs represents the arguments for GetResourceContent in the Page domain.
type GetResourceContentArgs struct {
	FrameID protocol.PageFrameID `json:"frameId"` // Frame id to get resource for.
	URL     string               `json:"url"`     // URL of the resource to get content for.
}

// NewGetResourceContentArgs initializes GetResourceContentArgs with the required arguments.
func NewGetResourceContentArgs(frameID protocol.PageFrameID, url string) *GetResourceContentArgs {
	args := new(GetResourceContentArgs)
	args.FrameID = frameID
	args.URL = url
	return args
}

// NavigateArgs represents the arguments for Navigate in the Page domain.
type NavigateArgs struct {
	URL            string                `json:"url"`                      // URL to navigate the page to.
	Referrer       *string               `json:"referrer,omitempty"`       // Referrer URL.
	TransitionType TransitionType        `json:"transitionType,omitempty"` // Intended transition type.
	FrameID        *protocol.PageFrameID `json:"frameId,omitempty"`        // Frame id to navigate, if not specified navigates the top frame.
}

// NewNavigateArgs initializes NavigateArgs with the required arguments.
func NewNavigateArgs(url string) *NavigateArgs {
	args := new(NavigateArgs)
	args.URL = url
	return args
}

// SetReferrer sets the Referrer optional argument. Referrer URL.
func (a *NavigateArgs) SetReferrer(referrer string) *NavigateArgs {
	a.Referrer = &referrer
	return a
}

// SetTransitionType sets the TransitionType optional argument.
// Intended transition type.
func (a *NavigateArgs) SetTransitionType(transitionType TransitionType) *NavigateArgs {
	a.TransitionType = transitionType
	return a
}

// SetFrameID sets the FrameID optional argument. Frame id to
// navigate, if not specified navigates the top frame.
func (a *NavigateArgs) SetFrameID(frameID protocol.PageFrameID) *NavigateArgs {
	a.FrameID = &frameID
	return a
}

// NavigateReply represents the return values for Navigate in the Page domain.
type NavigateReply struct {
	FrameID   protocol.PageFrameID `json:"frameId"`             // Frame id that has navigated (or failed to navigate)
	LoaderID  *network.LoaderID    `json:"loaderId,omitempty"`  // Loader identifier.
	ErrorText *string              `json:"errorText,omitempty"` // User friendly error message, present if and only if navigation has failed.
}

// SearchInResourceArgs represents the arguments for SearchInResource in the Page domain.
type SearchInResourceArgs struct {
	FrameID       protocol.PageFrameID `json:"frameId"`                 // Frame id for resource to search in.
	URL           string               `json:"url"`                     // URL of the resource to search in.
	Query         string               `json:"query"`                   // String to search for.
	CaseSensitive *bool                `json:"caseSensitive,omitempty"` // If true, search is case sensitive.
	IsRegex       *bool                `json:"isRegex,omitempty"`       // If true, treats string parameter as regex.
}

// NewSearchInResourceArgs initializes SearchInResourceArgs with the required arguments.
func NewSearchInResourceArgs(frameID protocol.PageFrameID, url string, query string) *SearchInResourceArgs {
	args := new(SearchInResourceArgs)
	args.FrameID = frameID
	args.URL = url
	args.Query = query
	return args
}

// SetCaseSensitive sets the CaseSensitive optional argument. If true,
// search is case sensitive.
func (a *SearchInResourceArgs) SetCaseSensitive(caseSensitive bool) *SearchInResourceArgs {
	a.CaseSensitive = &caseSensitive
	return a
}

// SetIsRegex sets the IsRegex optional argument. If true, treats
// string parameter as regex.
func (a *SearchInResourceArgs) SetIsRegex(isRegex bool) *SearchInResourceArgs {
	a.IsRegex = &isRegex
	return a
}

// SetDocumentContentArgs represents the arguments for SetDocumentContent in the Page domain.
type SetDocumentContentArgs struct {
	FrameID protocol.PageFrameID `json:"frameId"` // Frame id to set HTML for.
	HTML    string               `json:"html"`    // HTML content to set.
}

// NewSetDocumentContentArgs initializes SetDocumentContentArgs with the required arguments.
func NewSetDocumentContentArgs(frameID protocol.PageFrameID, html string) *SetDocumentContentArgs {
	args := new(SetDocumentContentArgs)
	args.FrameID = frameID
	args.HTML = html
	return args
}
<|endoftext|>


<commit_before>package store

import (
	"encoding/json"
	"fmt"
	"path"
	"time"
)

// global store
var s *Store

// CONSTANTS
const (
	ERROR = -1 + iota
	SET
	DELETE
	GET
)

var PERMANENT = time.Unix(0, 0)

type Store struct {
	// use the build-in hash map as the key-value store structure
	Nodes map[string]Node `json:"nodes"`

	// the string channel to send messages to the outside world
	// now we use it to send changes to the hub of the web service
	messager *chan string
}

type Node struct {
	Value string `json:"value"`

	// if the node is a permanent one the ExprieTime will be Unix(0,0)
	// Otherwise after the expireTime, the node will be deleted
	ExpireTime time.Time `json:"expireTime"`

	// a channel to update the expireTime of the node
	update chan time.Time `json:"-"`
}

type Response struct {
	Action   int    `json:"action"`
	Key      string `json:"key"`
	OldValue string `json:"oldValue"`
	NewValue string `json:"newValue"`

	// if the key existed before the action, this field should be true
	// if the key did not exist before the action, this field should be false
	Exist bool `json:"exist"`

	Expiration time.Time `json:"expiration"`

	Index uint64 `json:"index"`
}

func init() {
	s = createStore()
	s.messager = nil
}

// make a new stroe
func createStore() *Store {
	s := new(Store)
	s.Nodes = make(map[string]Node)
	return s
}

// return a pointer to the store
func GetStore() *Store {
	return s
}

// set the messager of the store
func (s *Store) SetMessager(messager *chan string) {
	s.messager = messager
}

// set the key to value, return the old value if the key exists
func Set(key string, value string, expireTime time.Time, index uint64) ([]byte, error) {

	key = path.Clean(key)

	var isExpire bool = false

	isExpire = !expireTime.Equal(PERMANENT)

	// when the slow follower receive the set command
	// the key may be expired, we should not add the node
	// also if the node exist, we need to delete the node
	if isExpire && expireTime.Sub(time.Now()) < 0 {
		return Delete(key, index)
	}

	// get the node
	node, ok := s.Nodes[key]

	if ok {
		// if node is not permanent before
		// update its expireTime
		if !node.ExpireTime.Equal(PERMANENT) {

			node.update <- expireTime

		} else {
			// if we want the permanent node to have expire time
			// we need to create a chan and create a go routine
			if isExpire {
				node.update = make(chan time.Time)
				go expire(key, node.update, expireTime)
			}
		}

		// update the information of the node
		s.Nodes[key] = Node{value, expireTime, node.update}

		resp := Response{SET, key, node.Value, value, true, expireTime, index}

		msg, err := json.Marshal(resp)

		notify(resp)

		// send to the messager
		if s.messager != nil && err == nil {

			*s.messager <- string(msg)
		}

		return msg, err

		// add new node
	} else {

		update := make(chan time.Time)

		s.Nodes[key] = Node{value, expireTime, update}

		if isExpire {
			go expire(key, update, expireTime)
		}

		resp := Response{SET, key, "", value, false, expireTime, index}

		msg, err := json.Marshal(resp)

		// nofity the watcher
		notify(resp)

		// notify the web interface
		if s.messager != nil && err == nil {

			*s.messager <- string(msg)
		}

		return msg, err
	}
}

// should be used as a go routine to delete the key when it expires
func expire(key string, update chan time.Time, expireTime time.Time) {
	duration := expireTime.Sub(time.Now())

	for {
		select {
		// timeout delete the node
		case <-time.After(duration):
			node, ok := s.Nodes[key]
			if !ok {
				return
			} else {

				delete(s.Nodes, key)

				resp := Response{DELETE, key, node.Value, "", true, node.ExpireTime, 0}

				msg, err := json.Marshal(resp)

				notify(resp)

				// notify the messager
				if s.messager != nil && err == nil {

					*s.messager <- string(msg)
				}

				return

			}

		case updateTime := <-update:
			//update duration
			// if the node become a permanent one, the go routine is
			// not needed
			if updateTime.Equal(PERMANENT) {
				fmt.Println("permanent")
				return
			}
			// update duration
			duration = updateTime.Sub(time.Now())
		}
	}
}

// get the value of the key
func Get(key string) Response {
	key = path.Clean(key)

	node, ok := s.Nodes[key]

	if ok {
		return Response{GET, key, node.Value, node.Value, true, node.ExpireTime, 0}
	} else {
		return Response{GET, key, "", "", false, time.Unix(0, 0), 0}
	}
}

// delete the key
func Delete(key string, index uint64) ([]byte, error) {
	key = path.Clean(key)

	node, ok := s.Nodes[key]

	if ok {

		if node.ExpireTime.Equal(PERMANENT) {

			delete(s.Nodes, key)

		} else {

			// kill the expire go routine
			node.update <- PERMANENT
			delete(s.Nodes, key)

		}

		resp := Response{DELETE, key, node.Value, "", true, node.ExpireTime, index}

		msg, err := json.Marshal(resp)

		notify(resp)

		// notify the messager
		if s.messager != nil && err == nil {

			*s.messager <- string(msg)
		}

		return msg, err

	} else {

		return json.Marshal(Response{DELETE, key, "", "", false, time.Unix(0, 0), index})
	}
}

// save the current state of the storage system
func (s *Store) Save() ([]byte, error) {
	b, err := json.Marshal(s)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return b, nil
}

// recovery the state of the stroage system from a previous state
func (s *Store) Recovery(state []byte) error {
	err := json.Unmarshal(state, s)

	// clean the expired nodes
	clean()

	return err
}

// clean all expired keys
func clean() {
	for key, node := range s.Nodes {

		if node.ExpireTime.Equal(PERMANENT) {
			continue
		} else {

			if node.ExpireTime.Sub(time.Now()) >= time.Second {
				node.update = make(chan time.Time)
				go expire(key, node.update, node.ExpireTime)

			} else {
				// we should delete this node
				delete(s.Nodes, key)
			}
		}

	}
}
<commit_msg>keep index in the store<commit_after>package store

import (
	"encoding/json"
	"fmt"
	"path"
	"time"
)

// global store
var s *Store

// CONSTANTS
const (
	ERROR = -1 + iota
	SET
	DELETE
	GET
)

var PERMANENT = time.Unix(0, 0)

type Store struct {
	// use the build-in hash map as the key-value store structure
	Nodes map[string]Node `json:"nodes"`

	// the string channel to send messages to the outside world
	// now we use it to send changes to the hub of the web service
	messager *chan string

	// current Index
	index uint64
}

type Node struct {
	Value string `json:"value"`

	// if the node is a permanent one the ExprieTime will be Unix(0,0)
	// Otherwise after the expireTime, the node will be deleted
	ExpireTime time.Time `json:"expireTime"`

	// a channel to update the expireTime of the node
	update chan time.Time `json:"-"`
}

type Response struct {
	Action   int    `json:"action"`
	Key      string `json:"key"`
	OldValue string `json:"oldValue"`
	NewValue string `json:"newValue"`

	// if the key existed before the action, this field should be true
	// if the key did not exist before the action, this field should be false
	Exist bool `json:"exist"`

	Expiration time.Time `json:"expiration"`

	Index uint64 `json:"index"`
}

func init() {
	s = createStore()
	s.messager = nil
}

// make a new stroe
func createStore() *Store {
	s := new(Store)
	s.Nodes = make(map[string]Node)
	return s
}

// return a pointer to the store
func GetStore() *Store {
	return s
}

// set the messager of the store
func (s *Store) SetMessager(messager *chan string) {
	s.messager = messager
}

// set the key to value, return the old value if the key exists
func Set(key string, value string, expireTime time.Time, index uint64) ([]byte, error) {

	//update index
	s.index = index

	key = path.Clean(key)

	var isExpire bool = false

	isExpire = !expireTime.Equal(PERMANENT)

	// when the slow follower receive the set command
	// the key may be expired, we should not add the node
	// also if the node exist, we need to delete the node
	if isExpire && expireTime.Sub(time.Now()) < 0 {
		return Delete(key, index)
	}

	// get the node
	node, ok := s.Nodes[key]

	if ok {
		// if node is not permanent before
		// update its expireTime
		if !node.ExpireTime.Equal(PERMANENT) {

			node.update <- expireTime

		} else {
			// if we want the permanent node to have expire time
			// we need to create a chan and create a go routine
			if isExpire {
				node.update = make(chan time.Time)
				go expire(key, node.update, expireTime)
			}
		}

		// update the information of the node
		s.Nodes[key] = Node{value, expireTime, node.update}

		resp := Response{SET, key, node.Value, value, true, expireTime, index}

		msg, err := json.Marshal(resp)

		notify(resp)

		// send to the messager
		if s.messager != nil && err == nil {

			*s.messager <- string(msg)
		}

		return msg, err

		// add new node
	} else {

		update := make(chan time.Time)

		s.Nodes[key] = Node{value, expireTime, update}

		if isExpire {
			go expire(key, update, expireTime)
		}

		resp := Response{SET, key, "", value, false, expireTime, index}

		msg, err := json.Marshal(resp)

		// nofity the watcher
		notify(resp)

		// notify the web interface
		if s.messager != nil && err == nil {

			*s.messager <- string(msg)
		}

		return msg, err
	}
}

// should be used as a go routine to delete the key when it expires
func expire(key string, update chan time.Time, expireTime time.Time) {
	duration := expireTime.Sub(time.Now())

	for {
		select {
		// timeout delete the node
		case <-time.After(duration):
			node, ok := s.Nodes[key]
			if !ok {
				return
			} else {

				delete(s.Nodes, key)

				resp := Response{DELETE, key, node.Value, "", true, node.ExpireTime, s.index}

				msg, err := json.Marshal(resp)

				notify(resp)

				// notify the messager
				if s.messager != nil && err == nil {

					*s.messager <- string(msg)
				}

				return

			}

		case updateTime := <-update:
			//update duration
			// if the node become a permanent one, the go routine is
			// not needed
			if updateTime.Equal(PERMANENT) {
				fmt.Println("permanent")
				return
			}
			// update duration
			duration = updateTime.Sub(time.Now())
		}
	}
}

// get the value of the key
func Get(key string) Response {
	key = path.Clean(key)

	node, ok := s.Nodes[key]

	if ok {
		return Response{GET, key, node.Value, node.Value, true, node.ExpireTime, s.index}
	} else {
		return Response{GET, key, "", "", false, time.Unix(0, 0), s.index}
	}
}

// delete the key
func Delete(key string, index uint64) ([]byte, error) {
	//update index
	s.index = index

	key = path.Clean(key)

	node, ok := s.Nodes[key]

	if ok {

		if node.ExpireTime.Equal(PERMANENT) {

			delete(s.Nodes, key)

		} else {

			// kill the expire go routine
			node.update <- PERMANENT
			delete(s.Nodes, key)

		}

		resp := Response{DELETE, key, node.Value, "", true, node.ExpireTime, index}

		msg, err := json.Marshal(resp)

		notify(resp)

		// notify the messager
		if s.messager != nil && err == nil {

			*s.messager <- string(msg)
		}

		return msg, err

	} else {

		return json.Marshal(Response{DELETE, key, "", "", false, time.Unix(0, 0), index})
	}
}

// save the current state of the storage system
func (s *Store) Save() ([]byte, error) {
	b, err := json.Marshal(s)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return b, nil
}

// recovery the state of the stroage system from a previous state
func (s *Store) Recovery(state []byte) error {
	err := json.Unmarshal(state, s)

	// clean the expired nodes
	clean()

	return err
}

// clean all expired keys
func clean() {
	for key, node := range s.Nodes {

		if node.ExpireTime.Equal(PERMANENT) {
			continue
		} else {

			if node.ExpireTime.Sub(time.Now()) >= time.Second {
				node.update = make(chan time.Time)
				go expire(key, node.update, node.ExpireTime)

			} else {
				// we should delete this node
				delete(s.Nodes, key)
			}
		}

	}
}
<|endoftext|>


<commit_before>package helm

import (
	"fmt"

	"testing"
)

func TestParseImage(t *testing.T) {
	imp := NewHelmImplementer("192.168.99.100:30083")

	releases, err := imp.ListReleases()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	fmt.Println(releases.Count)

	for _, release := range releases.Releases {
		ref, err := parseImage(release.Chart, release.Config)
		if err != nil {
			t.Errorf("failed to parse image, error: %s", err)
		}

		fmt.Println(ref.Remote())
	}
}

func TestUpdateRelease(t *testing.T) {
	imp := NewHelmImplementer("192.168.99.100:30083")

	releases, err := imp.ListReleases()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	for _, release := range releases.Releases {

		ref, err := parseImage(release.Chart, release.Config)
		if err != nil {
			t.Errorf("failed to parse image, error: %s", err)
		}

		fmt.Println(ref.Remote())

		err = updateHelmRelease(imp, release.Name, release.Chart, "image.tag=0.0.11")

		if err != nil {
			t.Errorf("failed to update release, error: %s", err)
		}
	}
}
<commit_msg>tests<commit_after>package helm

import (
	"fmt"

	"github.com/ghodss/yaml"
	"github.com/rusenask/keel/types"

	"k8s.io/helm/pkg/chartutil"

	"testing"
)

// helper function to generate keel configuration
func testingConfigYaml(cfg *KeelChartConfig) (vals chartutil.Values, err error) {
	root := &Root{Keel: *cfg}
	bts, err := yaml.Marshal(root)
	if err != nil {
		return nil, err
	}

	return chartutil.ReadValues(bts)
}

func TestParseImage(t *testing.T) {
	imp := NewHelmImplementer("192.168.99.100:30083")

	releases, err := imp.ListReleases()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	fmt.Println(releases.Count)

	for _, release := range releases.Releases {
		ref, err := parseImage(release.Chart, release.Config)
		if err != nil {
			t.Errorf("failed to parse image, error: %s", err)
		}

		fmt.Println(ref.Remote())
	}
}

func TestGetChartPolicy(t *testing.T) {
	imp := NewHelmImplementer("192.168.99.100:30083")

	releases, err := imp.ListReleases()
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	policyFound := false

	for _, release := range releases.Releases {

		vals, err := values(release.Chart, release.Config)
		if err != nil {
			t.Fatalf("failed to get values: %s", err)
		}

		// policy, err := getChartPolicy(vals)
		// if err != nil {
		// 	t.Errorf("failed to parse image, error: %s", err)
		// }
		cfg, err := getKeelConfig(vals)
		if err != nil {
			t.Errorf("failed to get image paths: %s", err)
		}

		fmt.Println(cfg)

		if cfg.Policy == types.PolicyTypeAll {
			policyFound = true
		}
	}

	if !policyFound {
		t.Errorf("policy not found")
	}
}

func TestGetTriggerFromConfig(t *testing.T) {
	vals, err := testingConfigYaml(&KeelChartConfig{Trigger: "poll"})
	if err != nil {
		t.Fatalf("Failed to load testdata: %s", err)
	}

	cfg, err := getKeelConfig(vals)
	if err != nil {
		t.Errorf("failed to get image paths: %s", err)
	}

	if cfg.Trigger != "poll" {
		t.Errorf("invalid trigger: %s", cfg.Trigger)
	}
}

func TestGetPolicyFromConfig(t *testing.T) {
	vals, err := testingConfigYaml(&KeelChartConfig{Policy: types.PolicyTypeAll})
	if err != nil {
		t.Fatalf("Failed to load testdata: %s", err)
	}

	cfg, err := getKeelConfig(vals)
	if err != nil {
		t.Errorf("failed to get image paths: %s", err)
	}

	if cfg.Policy != types.PolicyTypeAll {
		t.Errorf("invalid policy: %s", cfg.Policy)
	}
}

// func TestUpdateRelease(t *testing.T) {
// 	imp := NewHelmImplementer("192.168.99.100:30083")

// 	releases, err := imp.ListReleases()
// 	if err != nil {
// 		t.Fatalf("unexpected error: %s", err)
// 	}

// 	for _, release := range releases.Releases {

// 		ref, err := parseImage(release.Chart, release.Config)
// 		if err != nil {
// 			t.Errorf("failed to parse image, error: %s", err)
// 		}

// 		fmt.Println(ref.Remote())

// 		err = updateHelmRelease(imp, release.Name, release.Chart, "image.tag=0.0.11")

// 		if err != nil {
// 			t.Errorf("failed to update release, error: %s", err)
// 		}
// 	}
// }
<|endoftext|>


<commit_before>// Package fitbit implements the OAuth protocol for authenticating users through Fitbit.
// This package can be used as a reference implementation of an OAuth provider for Goth.
package fitbit

import (
	"encoding/json"
	"io"
	"net/http"

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

const (
	authURL         string = "https://www.fitbit.com/oauth2/authorize"
	tokenURL        string = "https://api.fitbit.com/oauth2/token"
	endpointProfile string = "https://api.fitbit.com/1/user/-/profile.json" // '-' for logged in user
)

const (
	// ScopeActivity includes activity data and exercise log related features, such as steps, distance, calories burned, and active minutes
	ScopeActivity = "activity"
	// ScopeHeartRate includes the continuous heart rate data and related analysis
	ScopeHeartRate = "heartrate"
	// ScopeLocation includes the GPS and other location data
	ScopeLocation = "location"
	// ScopeNutrition includes calorie consumption and nutrition related features, such as food/water logging, goals, and plans
	ScopeNutrition = "nutrition"
	// ScopeProfile is the basic user information
	ScopeProfile = "profile"
	// ScopeSettings includes user account and device settings, such as alarms
	ScopeSettings = "settings"
	// ScopeSleep includes sleep logs and related sleep analysis
	ScopeSleep = "sleep"
	// ScopeSocial includes friend-related features, such as friend list, invitations, and leaderboard
	ScopeSocial = "social"
	// ScopeWeight includes weight and related information, such as body mass index, body fat percentage, and goals
	ScopeWeight = "weight"
)

// New creates a new Fitbit provider, and sets up important connection details.
// You should always call `fitbit.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:   clientKey,
		Secret:      secret,
		CallbackURL: callbackURL,
	}
	p.config = newConfig(p, scopes)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Fitbit.
type Provider struct {
	ClientKey   string
	Secret      string
	CallbackURL string
	config      *oauth2.Config
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return "fitbit"
}

// Debug is a no-op for the fitbit package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks Fitbit for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	url := p.config.AuthCodeURL(state)
	session := &Session{
		AuthURL: url,
	}
	return session, nil
}

// FetchUser will go to Fitbit and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	s := session.(*Session)
	user := goth.User{
		AccessToken:  s.AccessToken,
		Provider:     p.Name(),
		RefreshToken: s.RefreshToken,
		ExpiresAt:    s.ExpiresAt,
	}

	req, err := http.NewRequest("GET", endpointProfile, nil)
	if err != nil {
		return user, err
	}
	req.Header.Set("Authorization", "Bearer "+s.AccessToken)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		if resp != nil {
			resp.Body.Close()
		}
		return user, err
	}
	defer resp.Body.Close()
	//err = userFromReader(io.TeeReader(resp.Body, os.Stdout), &user)
	err = userFromReader(resp.Body, &user)
	return user, err
}

func userFromReader(reader io.Reader, user *goth.User) error {
	u := struct {
		User struct {
			Age         string `json:"age"`
			Avatar      string `json:"avatar"`
			Country     string `json:"country"`
			FullName    string `json:"fullName"`
			DisplayName string `json:"displayName"`
		} `json:"user"`
	}{}

	err := json.NewDecoder(reader).Decode(&u)
	if err != nil {
		return err
	}

	user.Location = u.User.Country
	user.Name = u.User.FullName
	user.NickName = u.User.DisplayName
	user.AvatarURL = u.User.Avatar

	return err
}

func newConfig(provider *Provider, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     provider.ClientKey,
		ClientSecret: provider.Secret,
		RedirectURL:  provider.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{
			"email",
		},
	}

	defaultScopes := map[string]struct{}{
		"email": {},
	}

	for _, scope := range scopes {
		if _, exists := defaultScopes[scope]; !exists {
			c.Scopes = append(c.Scopes, scope)
		}
	}

	return c
}

//RefreshToken get new access token based on the refresh token
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	token := &oauth2.Token{RefreshToken: refreshToken}
	ts := p.config.TokenSource(oauth2.NoContext, token)
	newToken, err := ts.Token()
	if err != nil {
		return nil, err
	}
	return newToken, err
}

//RefreshTokenAvailable refresh token is not provided by fitbit
func (p *Provider) RefreshTokenAvailable() bool {
	return true
}
<commit_msg>removed email as scope as it's invalid, replaced with profile.<commit_after>// Package fitbit implements the OAuth protocol for authenticating users through Fitbit.
// This package can be used as a reference implementation of an OAuth provider for Goth.
package fitbit

import (
	"encoding/json"
	"io"
	"net/http"

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

const (
	authURL         string = "https://www.fitbit.com/oauth2/authorize"
	tokenURL        string = "https://api.fitbit.com/oauth2/token"
	endpointProfile string = "https://api.fitbit.com/1/user/-/profile.json" // '-' for logged in user
)

const (
	// ScopeActivity includes activity data and exercise log related features, such as steps, distance, calories burned, and active minutes
	ScopeActivity = "activity"
	// ScopeHeartRate includes the continuous heart rate data and related analysis
	ScopeHeartRate = "heartrate"
	// ScopeLocation includes the GPS and other location data
	ScopeLocation = "location"
	// ScopeNutrition includes calorie consumption and nutrition related features, such as food/water logging, goals, and plans
	ScopeNutrition = "nutrition"
	// ScopeProfile is the basic user information
	ScopeProfile = "profile"
	// ScopeSettings includes user account and device settings, such as alarms
	ScopeSettings = "settings"
	// ScopeSleep includes sleep logs and related sleep analysis
	ScopeSleep = "sleep"
	// ScopeSocial includes friend-related features, such as friend list, invitations, and leaderboard
	ScopeSocial = "social"
	// ScopeWeight includes weight and related information, such as body mass index, body fat percentage, and goals
	ScopeWeight = "weight"
)

// New creates a new Fitbit provider, and sets up important connection details.
// You should always call `fitbit.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:   clientKey,
		Secret:      secret,
		CallbackURL: callbackURL,
	}
	p.config = newConfig(p, scopes)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Fitbit.
type Provider struct {
	ClientKey   string
	Secret      string
	CallbackURL string
	config      *oauth2.Config
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return "fitbit"
}

// Debug is a no-op for the fitbit package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks Fitbit for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	url := p.config.AuthCodeURL(state)
	session := &Session{
		AuthURL: url,
	}
	return session, nil
}

// FetchUser will go to Fitbit and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	s := session.(*Session)
	user := goth.User{
		AccessToken:  s.AccessToken,
		Provider:     p.Name(),
		RefreshToken: s.RefreshToken,
		ExpiresAt:    s.ExpiresAt,
	}

	req, err := http.NewRequest("GET", endpointProfile, nil)
	if err != nil {
		return user, err
	}
	req.Header.Set("Authorization", "Bearer "+s.AccessToken)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		if resp != nil {
			resp.Body.Close()
		}
		return user, err
	}
	defer resp.Body.Close()
	//err = userFromReader(io.TeeReader(resp.Body, os.Stdout), &user)
	err = userFromReader(resp.Body, &user)
	return user, err
}

func userFromReader(reader io.Reader, user *goth.User) error {
	u := struct {
		User struct {
			Age         string `json:"age"`
			Avatar      string `json:"avatar"`
			Country     string `json:"country"`
			FullName    string `json:"fullName"`
			DisplayName string `json:"displayName"`
		} `json:"user"`
	}{}

	err := json.NewDecoder(reader).Decode(&u)
	if err != nil {
		return err
	}

	user.Location = u.User.Country
	user.Name = u.User.FullName
	user.NickName = u.User.DisplayName
	user.AvatarURL = u.User.Avatar

	return err
}

func newConfig(provider *Provider, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     provider.ClientKey,
		ClientSecret: provider.Secret,
		RedirectURL:  provider.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{
			ScopeProfile,
		},
	}

	defaultScopes := map[string]struct{}{
		ScopeProfile: {},
	}

	for _, scope := range scopes {
		if _, exists := defaultScopes[scope]; !exists {
			c.Scopes = append(c.Scopes, scope)
		}
	}

	return c
}

//RefreshToken get new access token based on the refresh token
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	token := &oauth2.Token{RefreshToken: refreshToken}
	ts := p.config.TokenSource(oauth2.NoContext, token)
	newToken, err := ts.Token()
	if err != nil {
		return nil, err
	}
	return newToken, err
}

//RefreshTokenAvailable refresh token is not provided by fitbit
func (p *Provider) RefreshTokenAvailable() bool {
	return true
}
<|endoftext|>


<commit_before>package providers

import (
	"io/ioutil"
	"os"
	"testing"

	log "github.com/Sirupsen/logrus"
	"github.com/camptocamp/conplicity/lib"
	"github.com/docker/engine-api/types"
)

func TestGetProvider(t *testing.T) {
	var dir, expected, got string
	var p Provider

	// Test PostgreSQL detection
	expected = "PostgreSQL"
	dir, _ = ioutil.TempDir("", "test_get_provider_postgresql")
	defer os.RemoveAll(dir)
	ioutil.WriteFile(dir+"/PG_VERSION", []byte{}, 0644)

	p = GetProvider(&conplicity.Conplicity{}, &types.Volume{
		Mountpoint: dir,
	})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}

	// Test MySQL detection
	expected = "MySQL"
	dir, _ = ioutil.TempDir("", "test_get_provider_mysql")
	defer os.RemoveAll(dir)
	os.Mkdir(dir+"/mysql", 0755)

	p = GetProvider(&conplicity.Conplicity{}, &types.Volume{
		Mountpoint: dir,
	})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}

	// Test OpenLDAP detection
	expected = "OpenLDAP"
	dir, _ = ioutil.TempDir("", "test_get_provider_openldap")
	defer os.RemoveAll(dir)
	ioutil.WriteFile(dir+"/DB_CONFIG", []byte{}, 0644)

	p = GetProvider(&conplicity.Conplicity{}, &types.Volume{
		Mountpoint: dir,
	})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}

	// Test Default detection
	expected = "Default"
	dir, _ = ioutil.TempDir("", "test_get_provider_default")
	defer os.RemoveAll(dir)

	p = GetProvider(&conplicity.Conplicity{}, &types.Volume{
		Mountpoint: dir,
	})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}
}

func TestPrepareBackup(t *testing.T) {
	// Use Default provider
	dir, _ := ioutil.TempDir("", "test_backup_volume")
	defer os.RemoveAll(dir)

	p := &DefaultProvider{
		BaseProvider: &BaseProvider{
			handler: &conplicity.Conplicity{},
			vol: &types.Volume{
				Name:       dir,
				Driver:     "local",
				Mountpoint: "/mnt",
			},
		},
	}

	// Fill Config manually
	p.handler.Config = &conplicity.Config{} // Init Config
	p.handler.Config.Duplicity.Image = "camptocamp/duplicity:latest"
	p.handler.Config.Docker.Endpoint = "unix:///var/run/docker.sock"
	p.handler.Hostname, _ = os.Hostname()
	p.handler.SetupDocker()

	log.SetLevel(log.DebugLevel)

	err := PrepareBackup(p)

	if err != nil {
		t.Fatalf("Expected no error, got error: %v", err)
	}
}

func TestBackupVolume(t *testing.T) {
	t.Skip("Skipping as it hangs forever on Travis CI")

	// Use Base provider
	dir, _ := ioutil.TempDir("", "test_backup_volume")
	defer os.RemoveAll(dir)

	p := &BaseProvider{
		handler: &conplicity.Conplicity{},
	}

	// Fill Config manually
	p.handler.Config = &conplicity.Config{} // Init Config
	p.handler.Config.Duplicity.FullIfOlderThan = "314D"
	p.handler.Config.Duplicity.RemoveOlderThan = "1Y"
	p.handler.Config.Duplicity.TargetURL = "file:///tmp/backup"
	p.handler.Config.Duplicity.Image = "camptocamp/duplicity:latest"
	p.handler.Config.Docker.Endpoint = "unix:///var/run/docker.sock"
	p.handler.Hostname, _ = os.Hostname()
	p.handler.SetupDocker()

	log.SetLevel(log.DebugLevel)

	err := p.BackupVolume(&types.Volume{
		Name:       dir,
		Driver:     "local",
		Mountpoint: "/mnt",
	})

	if err != nil {
		t.Fatalf("Expected no error, got error: %v", err)
	}
}

func TestBaseGetHandler(t *testing.T) {
	expected := ""

	p := &BaseProvider{
		handler: &conplicity.Conplicity{},
	}
	got := p.GetHandler().Hostname
	if expected != got {
		t.Fatalf("Expected %s, got %s", expected, got)
	}
}

func TestBaseGetVolume(t *testing.T) {
	got := (&BaseProvider{}).GetVolume()
	if got != nil {
		t.Fatalf("Expected to get nil, got %s", got)
	}
}

func TestBaseGetBackupDir(t *testing.T) {
	got := (&BaseProvider{}).GetBackupDir()
	if got != "" {
		t.Fatalf("Expected to get nil, got %s", got)
	}
}
<commit_msg>Fix providers tests<commit_after>package providers

import (
	"io/ioutil"
	"os"
	"testing"

	log "github.com/Sirupsen/logrus"
	"github.com/camptocamp/conplicity/config"
	"github.com/camptocamp/conplicity/lib"
	"github.com/camptocamp/conplicity/volume"
	"github.com/docker/engine-api/types"
)

func TestGetProvider(t *testing.T) {
	var dir, expected, got string
	var p Provider

	// Test PostgreSQL detection
	expected = "PostgreSQL"
	dir, _ = ioutil.TempDir("", "test_get_provider_postgresql")
	defer os.RemoveAll(dir)
	ioutil.WriteFile(dir+"/PG_VERSION", []byte{}, 0644)

	p = GetProvider(&conplicity.Conplicity{}, &volume.Volume{
		Volume: &types.Volume{
			Mountpoint: dir,
		}})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}

	// Test MySQL detection
	expected = "MySQL"
	dir, _ = ioutil.TempDir("", "test_get_provider_mysql")
	defer os.RemoveAll(dir)
	os.Mkdir(dir+"/mysql", 0755)

	p = GetProvider(&conplicity.Conplicity{}, &volume.Volume{
		Volume: &types.Volume{
			Mountpoint: dir,
		}})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}

	// Test OpenLDAP detection
	expected = "OpenLDAP"
	dir, _ = ioutil.TempDir("", "test_get_provider_openldap")
	defer os.RemoveAll(dir)
	ioutil.WriteFile(dir+"/DB_CONFIG", []byte{}, 0644)

	p = GetProvider(&conplicity.Conplicity{}, &volume.Volume{
		Volume: &types.Volume{
			Mountpoint: dir,
		}})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}

	// Test Default detection
	expected = "Default"
	dir, _ = ioutil.TempDir("", "test_get_provider_default")
	defer os.RemoveAll(dir)

	p = GetProvider(&conplicity.Conplicity{}, &volume.Volume{
		Volume: &types.Volume{
			Mountpoint: dir,
		}})
	got = p.GetName()
	if got != expected {
		t.Fatalf("Expected provider %s, got %s", expected, got)
	}
}

func TestPrepareBackup(t *testing.T) {
	// Use Default provider
	dir, _ := ioutil.TempDir("", "test_backup_volume")
	defer os.RemoveAll(dir)

	p := &DefaultProvider{
		BaseProvider: &BaseProvider{
			handler: &conplicity.Conplicity{},
			vol: &volume.Volume{
				Volume: &types.Volume{
					Name:       dir,
					Driver:     "local",
					Mountpoint: "/mnt",
				},
			},
		},
	}

	// Fill Config manually
	p.handler.Config = &config.Config{} // Init Config
	p.handler.Config.Duplicity.Image = "camptocamp/duplicity:latest"
	p.handler.Config.Docker.Endpoint = "unix:///var/run/docker.sock"
	p.handler.Hostname, _ = os.Hostname()
	p.handler.SetupDocker()

	log.SetLevel(log.DebugLevel)

	err := PrepareBackup(p)

	if err != nil {
		t.Fatalf("Expected no error, got error: %v", err)
	}
}

func TestBaseGetHandler(t *testing.T) {
	expected := ""

	p := &BaseProvider{
		handler: &conplicity.Conplicity{},
	}
	got := p.GetHandler().Hostname
	if expected != got {
		t.Fatalf("Expected %s, got %s", expected, got)
	}
}

func TestBaseGetVolume(t *testing.T) {
	got := (&BaseProvider{}).GetVolume()
	if got != nil {
		t.Fatalf("Expected to get nil, got %s", got)
	}
}

func TestBaseGetBackupDir(t *testing.T) {
	got := (&BaseProvider{}).GetBackupDir()
	if got != "" {
		t.Fatalf("Expected to get nil, got %s", got)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/dpapathanasiou/go-recaptcha"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

type ParsedResponse struct {
	Success bool     `json:"success"`
	Links   []string `json:"links"`
}

type EmailUser struct {
	Username    string
	Password    string
	EmailServer string
	Port        int
}

type SmtpTemplateData struct {
	From    string
	To      string
	Subject string
	Body    string
}

type Configuration struct {
	Smtp                EmailUser
	RecaptchaPrivateKey string
}

type ReCaptcha struct {
	Response  string
	Challenge string
}

type SendEmailData struct {
	YourEmail string
	YourName  string
	Feedback  string
	Captcha   ReCaptcha
}

var conf Configuration

func sendMail(emailUser EmailUser, auth smtp.Auth, from string, to string, subject string, body string) error {
	const emailTemplate = `From: {{.From}}
To: {{.To}}
Subject: {{.Subject}}

{{.Body}}

Sincerely,

{{.From}}
`
	var err error
	var doc bytes.Buffer
	context := &SmtpTemplateData{from, to, subject, body}
	t := template.New("emailTemplate")
	t, err = t.Parse(emailTemplate)
	if err != nil {
		log.Print("error trying to parse mail template ", err)
	}
	err = t.Execute(&doc, context)
	if err != nil {
		log.Print("error trying to execute mail template ", err)
	}
	err = smtp.SendMail(emailUser.EmailServer+":"+strconv.Itoa(emailUser.Port),
		auth,
		emailUser.Username,
		[]string{"nathanleclaire@gmail.com"},
		doc.Bytes())
	if err != nil {
		log.Print("ERROR: attempting to send a mail ", err)
	}

	return nil
}

func readConfigurationFile(filepath string) Configuration {
	var conf Configuration
	rawConfigurationJson, err := ioutil.ReadFile(filepath)
	if err != nil {
		log.Print("error reading smtp config file ", err)
	}
	err = json.Unmarshal(rawConfigurationJson, &conf)
	if err != nil {
		log.Print("error unmarshalling config ", err)
	}
	return conf
}

func connectToSmtpServer(emailUser EmailUser) smtp.Auth {
	auth := smtp.PlainAuth("", emailUser.Username, emailUser.Password, emailUser.EmailServer)
	return auth
}

func getFailedSlurpResponse() []byte {
	failResponse := &ParsedResponse{false, nil}
	failResponseJSON, err := json.Marshal(failResponse)
	if err != nil {
		log.Print("something went really weird in attempt to marshal a fail json ", err)
		failResponseJSON, _ = json.Marshal(nil)
	}
	return failResponseJSON
}

func slurpHandler(w http.ResponseWriter, r *http.Request) {
	urlToScrape := strings.ToLower(r.URL.Query().Get("urlToScrape"))

	var doc *goquery.Document
	var e error
	var parsedResponseJSON []byte

	links := []string{}

	if doc, e = goquery.NewDocument(urlToScrape); e == nil {
		if crossDomainRegex, err := regexp.Compile(`^http`); err != nil {
			log.Printf("issue compiling regular expression to validate cross domain URLs")
		}
		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			if href, exists := s.Attr("href"); exists == true {
				if crossDomainRegex.Match([]byte(href)) {
					links = append(links, href)
				} else {
					if href != "" {
						links = append(links, urlToScrape+href)
					} else {
						// TODO: set error on blank link in client side code,
						// also change over to including content of link text
						// to show in table
						links = append(links, '')
					}
				}
			} else {
				log.Print("href does not exist for: ", s)
			}
		})
		parsedResponse := &ParsedResponse{true, links}
		if parsedResponseJSON, err = json.Marshal(parsedResponse); err != nil {
			parsedResponseJSON = getFailedSlurpResponse()
		}
	} else {
		log.Print("error querying for document: ", urlToScrape, "err : ", e)
		parsedResponseJSON = getFailedSlurpResponse()
	}

	w.Write(parsedResponseJSON)

}

func checkHandler(w http.ResponseWriter, r *http.Request) {
	urlToCheck := r.URL.Query().Get("urlToCheck")
	externalServerResponse, err := http.Get(urlToCheck)
	if err != nil {
		log.Print("error getting in checkHandler ", urlToCheck)
	}

	response := map[string]interface{}{
		"status":     externalServerResponse.Status,
		"statusCode": externalServerResponse.StatusCode,
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		log.Print("error Marshalling check response json: ", err)
	}
	w.Write(responseJSON)
}

func emailHandlerClosure(auth smtp.Auth, recaptchaPrivateKey string, emailUser EmailUser) http.HandlerFunc {
	// Use a closure so we can pass auth to the handler
	return (func(w http.ResponseWriter, r *http.Request) {

		var jsonResponse []byte
		var err error
		response := map[string]interface{}{
			"success": true,
		}
		dec := json.NewDecoder(r.Body)
		contactData := SendEmailData{}
		err = dec.Decode(&contactData)
		if err != nil {
			log.Print(err)
			response["success"] = false
		}

		// call the recaptcha server
		recaptcha.Init(recaptchaPrivateKey)
		captchaIsValid := recaptcha.Confirm(r.RemoteAddr, contactData.Captcha.Challenge, contactData.Captcha.Response)

		if captchaIsValid {
			go sendMail(emailUser,
				auth,
				contactData.YourName+fmt.Sprintf(" <%s>", contactData.YourEmail),
				"Nathan LeClaire <nathan.leclaire@gmail.com>",
				"CFBL Feedback from "+contactData.YourName,
				contactData.Feedback)
		} else {
			response["success"] = false
		}
		jsonResponse, err = json.Marshal(response)
		if err != nil {
			log.Print("marshalling r ", err)
		}
		w.Write(jsonResponse)
	})
}

func main() {
	conf = readConfigurationFile("../conf/conf.json")
	auth := connectToSmtpServer(conf.Smtp)
	http.HandleFunc("/slurp", slurpHandler)
	http.HandleFunc("/check", checkHandler)
	http.HandleFunc("/email", emailHandlerClosure(auth, conf.RecaptchaPrivateKey, conf.Smtp))
	http.Handle("/", http.FileServer(http.Dir("..")))
	http.Handle("/css/", http.FileServer(http.Dir("..")))
	http.Handle("/img/", http.FileServer(http.Dir("..")))
	http.Handle("/lib/", http.FileServer(http.Dir("..")))
	http.Handle("/partials/", http.FileServer(http.Dir("..")))
	http.Handle("/js/", http.FileServer(http.Dir("..")))
	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>Update main.go<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/dpapathanasiou/go-recaptcha"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

type ParsedResponse struct {
	Success bool     `json:"success"`
	Links   []string `json:"links"`
}

type EmailUser struct {
	Username    string
	Password    string
	EmailServer string
	Port        int
}

type SmtpTemplateData struct {
	From    string
	To      string
	Subject string
	Body    string
}

type Configuration struct {
	Smtp                EmailUser
	RecaptchaPrivateKey string
}

type ReCaptcha struct {
	Response  string
	Challenge string
}

type SendEmailData struct {
	YourEmail string
	YourName  string
	Feedback  string
	Captcha   ReCaptcha
}

var conf Configuration

func sendMail(emailUser EmailUser, auth smtp.Auth, from string, to string, subject string, body string) error {
	const emailTemplate = `From: {{.From}}
To: {{.To}}
Subject: {{.Subject}}

{{.Body}}

Sincerely,

{{.From}}
`
	var err error
	var doc bytes.Buffer
	context := &SmtpTemplateData{from, to, subject, body}
	t := template.New("emailTemplate")
	t, err = t.Parse(emailTemplate)
	if err != nil {
		log.Print("error trying to parse mail template ", err)
	}
	err = t.Execute(&doc, context)
	if err != nil {
		log.Print("error trying to execute mail template ", err)
	}
	err = smtp.SendMail(emailUser.EmailServer+":"+strconv.Itoa(emailUser.Port),
		auth,
		emailUser.Username,
		[]string{"nathanleclaire@gmail.com"},
		doc.Bytes())
	if err != nil {
		log.Print("ERROR: attempting to send a mail ", err)
	}

	return nil
}

func readConfigurationFile(filepath string) Configuration {
	var conf Configuration
	rawConfigurationJson, err := ioutil.ReadFile(filepath)
	if err != nil {
		log.Print("error reading smtp config file ", err)
	}
	err = json.Unmarshal(rawConfigurationJson, &conf)
	if err != nil {
		log.Print("error unmarshalling config ", err)
	}
	return conf
}

func connectToSmtpServer(emailUser EmailUser) smtp.Auth {
	auth := smtp.PlainAuth("", emailUser.Username, emailUser.Password, emailUser.EmailServer)
	return auth
}

func getFailedSlurpResponse() []byte {
	failResponse := &ParsedResponse{false, nil}
	failResponseJSON, err := json.Marshal(failResponse)
	if err != nil {
		log.Print("something went really weird in attempt to marshal a fail json ", err)
		failResponseJSON, _ = json.Marshal(nil)
	}
	return failResponseJSON
}

func slurpHandler(w http.ResponseWriter, r *http.Request) {
	urlToScrape := strings.ToLower(r.URL.Query().Get("urlToScrape"))

	var doc *goquery.Document
	var e error
	var parsedResponseJSON []byte

	links := []string{}

	if doc, e = goquery.NewDocument(urlToScrape); e == nil {
		if crossDomainRegex, err := regexp.Compile(`^http`); err != nil {
			log.Printf("issue compiling regular expression to validate cross domain URLs")
		}
		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			if href, exists := s.Attr("href"); exists == true {
				if crossDomainRegex.Match([]byte(href)) {
					links = append(links, href)
				} else {
					if href != "" {
						links = append(links, urlToScrape+href)
					} else {
						// TODO: set error on blank link in client side code,
						// also change over to including content of link text
						// to show in table
						links = append(links, "")
					}
				}
			} else {
				log.Print("href does not exist for: ", s)
			}
		})
		parsedResponse := &ParsedResponse{true, links}
		if parsedResponseJSON, err = json.Marshal(parsedResponse); err != nil {
			parsedResponseJSON = getFailedSlurpResponse()
		}
	} else {
		log.Print("error querying for document: ", urlToScrape, "err : ", e)
		parsedResponseJSON = getFailedSlurpResponse()
	}

	w.Write(parsedResponseJSON)

}

func checkHandler(w http.ResponseWriter, r *http.Request) {
	urlToCheck := r.URL.Query().Get("urlToCheck")
	externalServerResponse, err := http.Get(urlToCheck)
	if err != nil {
		log.Print("error getting in checkHandler ", urlToCheck)
	}

	response := map[string]interface{}{
		"status":     externalServerResponse.Status,
		"statusCode": externalServerResponse.StatusCode,
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		log.Print("error Marshalling check response json: ", err)
	}
	w.Write(responseJSON)
}

func emailHandlerClosure(auth smtp.Auth, recaptchaPrivateKey string, emailUser EmailUser) http.HandlerFunc {
	// Use a closure so we can pass auth to the handler
	return (func(w http.ResponseWriter, r *http.Request) {

		var jsonResponse []byte
		var err error
		response := map[string]interface{}{
			"success": true,
		}
		dec := json.NewDecoder(r.Body)
		contactData := SendEmailData{}
		err = dec.Decode(&contactData)
		if err != nil {
			log.Print(err)
			response["success"] = false
		}

		// call the recaptcha server
		recaptcha.Init(recaptchaPrivateKey)
		captchaIsValid := recaptcha.Confirm(r.RemoteAddr, contactData.Captcha.Challenge, contactData.Captcha.Response)

		if captchaIsValid {
			go sendMail(emailUser,
				auth,
				contactData.YourName+fmt.Sprintf(" <%s>", contactData.YourEmail),
				"Nathan LeClaire <nathan.leclaire@gmail.com>",
				"CFBL Feedback from "+contactData.YourName,
				contactData.Feedback)
		} else {
			response["success"] = false
		}
		jsonResponse, err = json.Marshal(response)
		if err != nil {
			log.Print("marshalling r ", err)
		}
		w.Write(jsonResponse)
	})
}

func main() {
	conf = readConfigurationFile("../conf/conf.json")
	auth := connectToSmtpServer(conf.Smtp)
	http.HandleFunc("/slurp", slurpHandler)
	http.HandleFunc("/check", checkHandler)
	http.HandleFunc("/email", emailHandlerClosure(auth, conf.RecaptchaPrivateKey, conf.Smtp))
	http.Handle("/", http.FileServer(http.Dir("..")))
	http.Handle("/css/", http.FileServer(http.Dir("..")))
	http.Handle("/img/", http.FileServer(http.Dir("..")))
	http.Handle("/lib/", http.FileServer(http.Dir("..")))
	http.Handle("/partials/", http.FileServer(http.Dir("..")))
	http.Handle("/js/", http.FileServer(http.Dir("..")))
	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>


<commit_before>/*
	This file is part of go-ethereum

	go-ethereum 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.

	go-ethereum 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 go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/*

For each request type, define the following:

1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder()
2. json.Decoder() calls "UnmarshalJSON" defined on each "Args" struct
3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to JSON

*/
package rpc

import (
	"encoding/json"
	"math/big"
	"strings"

	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/xeth"
)

type EthereumApi struct {
	pipe *xeth.JSXEth
}

func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	if args.BlockNumber > 0 {
		*reply = p.pipe.BlockByNumber(args.BlockNumber)
	} else {
		*reply = p.pipe.BlockByHash(args.Hash)
	}
	return nil
}

func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body)
	*reply = result
	return nil
}

func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error {
	err := args.requirementsContract()
	if err != nil {
		return err
	}

	result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body)
	*reply = result
	return nil
}

func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
	err := args.requirementsPushTx()
	if err != nil {
		return err
	}
	result, _ := p.pipe.PushTx(args.Tx)
	*reply = result
	return nil
}

func (p *EthereumApi) GetKey(args interface{}, reply *interface{}) error {
	*reply = p.pipe.Key()
	return nil
}

func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address))

	var hx string
	if strings.Index(args.Key, "0x") == 0 {
		hx = string([]byte(args.Key)[2:])
	} else {
		// Convert the incoming string (which is a bigint) into hex
		i, _ := new(big.Int).SetString(args.Key, 10)
		hx = ethutil.Bytes2Hex(i.Bytes())
	}
	jsonlogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx)
	value := state.Storage(ethutil.Hex2Bytes(hx))
	*reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}
	return nil
}

func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
	*reply = p.pipe.PeerCount()
	return nil
}

func (p *EthereumApi) GetIsListening(reply *interface{}) error {
	*reply = p.pipe.IsListening()
	return nil
}

func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
	*reply = p.pipe.CoinBase()
	return nil
}

func (p *EthereumApi) GetIsMining(reply *interface{}) error {
	*reply = p.pipe.IsMining()
	return nil
}

func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.pipe.TxCountAt(args.Address)
	return nil
}

func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address))
	*reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address}
	return nil
}

func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.pipe.CodeAt(args.Address)
	return nil
}

type GetBlockArgs struct {
	BlockNumber int32
	Hash        string
}

func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) {
	argint, argstr := int32(0), ""
	if err = json.Unmarshal(b, &argint); err == nil {
		obj.BlockNumber = argint
		return
	}
	if err = json.Unmarshal(b, &argstr); err == nil {
		obj.Hash = argstr
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (obj *GetBlockArgs) requirements() error {
	if obj.BlockNumber == 0 && obj.Hash == "" {
		return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument")
	}
	return nil
}

type NewTxArgs struct {
	Sec       string `json:"sec"`
	Recipient string `json:"recipient"`
	Value     string `json:"value"`
	Gas       string `json:"gas"`
	GasPrice  string `json:"gasprice"`
	Init      string `json:"init"`
	Body      string `json:"body"`
}

// type TxResponse struct {
// 	Hash string
// }

func (a *NewTxArgs) requirements() error {
	if a.Recipient == "" {
		return NewErrorResponse("Transact requires a 'recipient' address as argument")
	}
	if a.Value == "" {
		return NewErrorResponse("Transact requires a 'value' as argument")
	}
	if a.Gas == "" {
		return NewErrorResponse("Transact requires a 'gas' value as argument")
	}
	if a.GasPrice == "" {
		return NewErrorResponse("Transact requires a 'gasprice' value as argument")
	}
	return nil
}

func (a *NewTxArgs) requirementsContract() error {
	if a.Value == "" {
		return NewErrorResponse("Create requires a 'value' as argument")
	}
	if a.Gas == "" {
		return NewErrorResponse("Create requires a 'gas' value as argument")
	}
	if a.GasPrice == "" {
		return NewErrorResponse("Create requires a 'gasprice' value as argument")
	}
	if a.Body == "" {
		return NewErrorResponse("Create requires a 'body' value as argument")
	}
	return nil
}

type PushTxArgs struct {
	Tx string `json:"tx"`
}

func (a *PushTxArgs) requirementsPushTx() error {
	if a.Tx == "" {
		return NewErrorResponse("PushTx requires a 'tx' as argument")
	}
	return nil
}

type GetStorageArgs struct {
	Address string
	Key     string
}

func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (a *GetStorageArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
	}
	if a.Key == "" {
		return NewErrorResponse("GetStorageAt requires an 'key' value as argument")
	}
	return nil
}

type GetStorageAtRes struct {
	Key     string `json:"key"`
	Value   string `json:"value"`
	Address string `json:"address"`
}

type GetTxCountArgs struct {
	Address string `json:"address"`
}

// type GetTxCountRes struct {
// 	Nonce int `json:"nonce"`
// }

func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse("Could not determine JSON parameters")
}

func (a *GetTxCountArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetTxCountAt requires an 'address' value as argument")
	}
	return nil
}

// type GetPeerCountRes struct {
// 	PeerCount int `json:"peerCount"`
// }

// type GetListeningRes struct {
// 	IsListening bool `json:"isListening"`
// }

// type GetCoinbaseRes struct {
// 	Coinbase string `json:"coinbase"`
// }

// type GetMiningRes struct {
// 	IsMining bool `json:"isMining"`
// }

type GetBalanceArgs struct {
	Address string
}

func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, &arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse("Could not determine JSON parameters")
}

func (a *GetBalanceArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetBalanceAt requires an 'address' value as argument")
	}
	return nil
}

type BalanceRes struct {
	Balance string `json:"balance"`
	Address string `json:"address"`
}

type GetCodeAtArgs struct {
	Address string
}

func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, &arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (a *GetCodeAtArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetCodeAt requires an 'address' value as argument")
	}
	return nil
}
<commit_msg>Stub missing UnmarshalJSON methods<commit_after>/*
	This file is part of go-ethereum

	go-ethereum 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.

	go-ethereum 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 go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/*

For each request type, define the following:

1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder()
2. json.Decoder() calls "UnmarshalJSON" defined on each "Args" struct
3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to JSON

*/
package rpc

import (
	"encoding/json"
	"math/big"
	"strings"

	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/xeth"
)

type EthereumApi struct {
	pipe *xeth.JSXEth
}

func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	if args.BlockNumber > 0 {
		*reply = p.pipe.BlockByNumber(args.BlockNumber)
	} else {
		*reply = p.pipe.BlockByHash(args.Hash)
	}
	return nil
}

func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body)
	*reply = result
	return nil
}

func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error {
	err := args.requirementsContract()
	if err != nil {
		return err
	}

	result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body)
	*reply = result
	return nil
}

func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
	err := args.requirementsPushTx()
	if err != nil {
		return err
	}
	result, _ := p.pipe.PushTx(args.Tx)
	*reply = result
	return nil
}

func (p *EthereumApi) GetKey(args interface{}, reply *interface{}) error {
	*reply = p.pipe.Key()
	return nil
}

func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address))

	var hx string
	if strings.Index(args.Key, "0x") == 0 {
		hx = string([]byte(args.Key)[2:])
	} else {
		// Convert the incoming string (which is a bigint) into hex
		i, _ := new(big.Int).SetString(args.Key, 10)
		hx = ethutil.Bytes2Hex(i.Bytes())
	}
	jsonlogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx)
	value := state.Storage(ethutil.Hex2Bytes(hx))
	*reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}
	return nil
}

func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
	*reply = p.pipe.PeerCount()
	return nil
}

func (p *EthereumApi) GetIsListening(reply *interface{}) error {
	*reply = p.pipe.IsListening()
	return nil
}

func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
	*reply = p.pipe.CoinBase()
	return nil
}

func (p *EthereumApi) GetIsMining(reply *interface{}) error {
	*reply = p.pipe.IsMining()
	return nil
}

func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.pipe.TxCountAt(args.Address)
	return nil
}

func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address))
	*reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address}
	return nil
}

func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.pipe.CodeAt(args.Address)
	return nil
}

type GetBlockArgs struct {
	BlockNumber int32
	Hash        string
}

func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) {
	argint, argstr := int32(0), ""
	if err = json.Unmarshal(b, &argint); err == nil {
		obj.BlockNumber = argint
		return
	}
	if err = json.Unmarshal(b, &argstr); err == nil {
		obj.Hash = argstr
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (obj *GetBlockArgs) requirements() error {
	if obj.BlockNumber == 0 && obj.Hash == "" {
		return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument")
	}
	return nil
}

type NewTxArgs struct {
	Sec       string `json:"sec"`
	Recipient string `json:"recipient"`
	Value     string `json:"value"`
	Gas       string `json:"gas"`
	GasPrice  string `json:"gasprice"`
	Init      string `json:"init"`
	Body      string `json:"body"`
}

// type TxResponse struct {
// 	Hash string
// }

func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
	if err = json.Unmarshal(b, obj); err == nil {
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (a *NewTxArgs) requirements() error {
	if a.Recipient == "" {
		return NewErrorResponse("Transact requires a 'recipient' address as argument")
	}
	if a.Value == "" {
		return NewErrorResponse("Transact requires a 'value' as argument")
	}
	if a.Gas == "" {
		return NewErrorResponse("Transact requires a 'gas' value as argument")
	}
	if a.GasPrice == "" {
		return NewErrorResponse("Transact requires a 'gasprice' value as argument")
	}
	return nil
}

func (a *NewTxArgs) requirementsContract() error {
	if a.Value == "" {
		return NewErrorResponse("Create requires a 'value' as argument")
	}
	if a.Gas == "" {
		return NewErrorResponse("Create requires a 'gas' value as argument")
	}
	if a.GasPrice == "" {
		return NewErrorResponse("Create requires a 'gasprice' value as argument")
	}
	if a.Body == "" {
		return NewErrorResponse("Create requires a 'body' value as argument")
	}
	return nil
}

type PushTxArgs struct {
	Tx string `json:"tx"`
}

func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, arg0); err == nil {
		obj.Tx = arg0
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (a *PushTxArgs) requirementsPushTx() error {
	if a.Tx == "" {
		return NewErrorResponse("PushTx requires a 'tx' as argument")
	}
	return nil
}

type GetStorageArgs struct {
	Address string
	Key     string
}

func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (a *GetStorageArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
	}
	if a.Key == "" {
		return NewErrorResponse("GetStorageAt requires an 'key' value as argument")
	}
	return nil
}

type GetStorageAtRes struct {
	Key     string `json:"key"`
	Value   string `json:"value"`
	Address string `json:"address"`
}

type GetTxCountArgs struct {
	Address string `json:"address"`
}

// type GetTxCountRes struct {
// 	Nonce int `json:"nonce"`
// }

func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse("Could not determine JSON parameters")
}

func (a *GetTxCountArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetTxCountAt requires an 'address' value as argument")
	}
	return nil
}

// type GetPeerCountRes struct {
// 	PeerCount int `json:"peerCount"`
// }

// type GetListeningRes struct {
// 	IsListening bool `json:"isListening"`
// }

// type GetCoinbaseRes struct {
// 	Coinbase string `json:"coinbase"`
// }

// type GetMiningRes struct {
// 	IsMining bool `json:"isMining"`
// }

type GetBalanceArgs struct {
	Address string
}

func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, &arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse("Could not determine JSON parameters")
}

func (a *GetBalanceArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetBalanceAt requires an 'address' value as argument")
	}
	return nil
}

type BalanceRes struct {
	Balance string `json:"balance"`
	Address string `json:"address"`
}

type GetCodeAtArgs struct {
	Address string
}

func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) {
	arg0 := ""
	if err = json.Unmarshal(b, &arg0); err == nil {
		obj.Address = arg0
		return
	}
	return NewErrorResponse(ErrorDecodeArgs)
}

func (a *GetCodeAtArgs) requirements() error {
	if a.Address == "" {
		return NewErrorResponse("GetCodeAt requires an 'address' value as argument")
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpctest

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"github.com/decred/dcrd/wire"

	rpc "github.com/decred/dcrrpcclient"
	"github.com/decred/dcrutil"
)

// nodeConfig contains all the args, and data required to launch a dcrd process
// and connect the rpc client to it.
type nodeConfig struct {
	rpcUser    string
	rpcPass    string
	listen     string
	rpcListen  string
	rpcConnect string
	dataDir    string
	logDir     string
	profile    string
	debugLevel string
	extra      []string
	prefix     string

	exe          string
	endpoint     string
	certFile     string
	keyFile      string
	certificates []byte
}

// newConfig returns a nodeConfig with default values.
func newConfig(prefix, certFile, keyFile string, extra []string) (*nodeConfig, error) {
	// TODO: use defaultP2pPort and defaultRPCPort instead of literals
	a := &nodeConfig{
		listen:    "127.0.0.1:18555",
		rpcListen: "127.0.0.1:19556",
		rpcUser:   "user",
		rpcPass:   "pass",
		extra:     extra,
		prefix:    prefix,

		exe:      "dcrd",
		endpoint: "ws",
		certFile: certFile,
		keyFile:  keyFile,
	}
	if err := a.setDefaults(); err != nil {
		return nil, err
	}
	return a, nil
}

// setDefaults sets the default values of the config. It also creates the
// temporary data, and log directories which must be cleaned up with a call to
// cleanup().
func (n *nodeConfig) setDefaults() error {
	datadir, err := ioutil.TempDir(n.prefix, "data")
	if err != nil {
		return err
	}
	n.dataDir = datadir
	logdir, err := ioutil.TempDir(n.prefix, "logs")
	if err != nil {
		return err
	}
	n.logDir = logdir
	cert, err := ioutil.ReadFile(n.certFile)
	if err != nil {
		return err
	}
	n.certificates = cert
	return nil
}

// arguments returns an array of arguments that be used to launch the
// dcrd process.
func (n *nodeConfig) arguments() []string {
	args := []string{}
	// --simnet
	args = append(args, fmt.Sprintf("--%s", strings.ToLower(wire.SimNet.String())))
	if n.rpcUser != "" {
		// --rpcuser
		args = append(args, fmt.Sprintf("--rpcuser=%s", n.rpcUser))
	}
	if n.rpcPass != "" {
		// --rpcpass
		args = append(args, fmt.Sprintf("--rpcpass=%s", n.rpcPass))
	}
	if n.listen != "" {
		// --listen
		args = append(args, fmt.Sprintf("--listen=%s", n.listen))
	}
	if n.rpcListen != "" {
		// --rpclisten
		args = append(args, fmt.Sprintf("--rpclisten=%s", n.rpcListen))
	}
	if n.rpcConnect != "" {
		// --rpcconnect
		args = append(args, fmt.Sprintf("--rpcconnect=%s", n.rpcConnect))
	}
	// --rpccert
	args = append(args, fmt.Sprintf("--rpccert=%s", n.certFile))
	// --rpckey
	args = append(args, fmt.Sprintf("--rpckey=%s", n.keyFile))
	if n.dataDir != "" {
		// --datadir
		args = append(args, fmt.Sprintf("--datadir=%s", n.dataDir))
	}
	if n.logDir != "" {
		// --logdir
		args = append(args, fmt.Sprintf("--logdir=%s", n.logDir))
	}
	if n.profile != "" {
		// --profile
		args = append(args, fmt.Sprintf("--profile=%s", n.profile))
	}
	if n.debugLevel != "" {
		// --debuglevel
		args = append(args, fmt.Sprintf("--debuglevel=%s", n.debugLevel))
	}
	args = append(args, n.extra...)
	return args
}

// command returns the exec.Cmd which will be used to start the dcrd process.
func (n *nodeConfig) command() *exec.Cmd {
	return exec.Command(n.exe, n.arguments()...)
}

// rpcConnConfig returns the rpc connection config that can be used
// to connect to the dcrd process that is launched via Start().
func (n *nodeConfig) rpcConnConfig() rpc.ConnConfig {
	return rpc.ConnConfig{
		Host:                 n.rpcListen,
		Endpoint:             n.endpoint,
		User:                 n.rpcUser,
		Pass:                 n.rpcPass,
		Certificates:         n.certificates,
		DisableAutoReconnect: true,
	}
}

// String returns the string representation of this nodeConfig.
func (n *nodeConfig) String() string {
	return n.prefix
}

// cleanup removes the tmp data and log directories.
func (n *nodeConfig) cleanup() error {
	dirs := []string{
		n.logDir,
		n.dataDir,
	}
	var err error
	for _, dir := range dirs {
		if err = os.RemoveAll(dir); err != nil {
			log.Printf("Cannot remove dir %s: %v", dir, err)
		}
	}
	return err
}

// node houses the neccessary state required to configure, launch, and manaage
// a dcrd process.
type node struct {
	config *nodeConfig

	cmd     *exec.Cmd
	pidFile string

	dataDir string
}

// newNode creates a new node instance according to the passed config. dataDir
// will be used to hold a file recording the pid of the launched process, and
// as the base for the log and data directories for dcrd.
func newNode(config *nodeConfig, dataDir string) (*node, error) {
	return &node{
		config:  config,
		dataDir: dataDir,
		cmd:     config.command(),
	}, nil
}

// Start creates a new dcrd process, and writes its pid in a file reserved for
// recording the pid of the launched process. This file can ue used to terminate
// the procress in case of a hang, or panic. In the case of a failing test case,
// or panic, it is important that the process be stopped via stop(), otherwise,
// it will persist unless explicitly killed.
func (n *node) Start() error {
	if err := n.cmd.Start(); err != nil {
		return err
	}

	pid, err := os.Create(fmt.Sprintf("%s.pid", n.config))
	if err != nil {
		return err
	}

	n.pidFile = pid.Name()
	if _, err = fmt.Fprintf(pid, "%d\n", n.cmd.Process.Pid); err != nil {
		return err
	}

	if err := pid.Close(); err != nil {
		return err
	}

	return nil
}

// Stop interrupts the running dcrd process process, and waits until it exits
// properly. On windows, interrupt is not supported, so a kill signal is used
// instead
func (n *node) Stop() error {
	if n.cmd == nil || n.cmd.Process == nil {
		// return if not properly initialized
		// or error starting the process
		return nil
	}
	defer n.cmd.Wait()
	if runtime.GOOS == "windows" {
		return n.cmd.Process.Signal(os.Kill)
	}
	return n.cmd.Process.Signal(os.Interrupt)
}

// Cleanup cleanups process and args files. The file housing the pid of the
// created process will be deleted, as well as any directories created by the
// process.
func (n *node) Cleanup() error {
	if n.pidFile != "" {
		if err := os.Remove(n.pidFile); err != nil {
			log.Printf("unable to remove file %s: %v", n.pidFile,
				err)
		}
	}

	return n.config.cleanup()
}

// shutdown terminates the running dcrd process, and cleans up all
// file/directories created by node.
func (n *node) Shutdown() error {
	if err := n.Stop(); err != nil {
		return err
	}
	if err := n.Cleanup(); err != nil {
		return err
	}
	return nil
}

// genCertPair generates a key/cert pair to the paths provided.
func genCertPair(certFile, keyFile, certFileWallet, keyFileWallet string) error {
	org := "rpctest autogenerated cert"
	validUntil := time.Now().Add(10 * 365 * 24 * time.Hour)
	cert, key, err := dcrutil.NewTLSCertPair(org, validUntil, nil)
	if err != nil {
		return err
	}
	// Write cert and key files.
	if err = ioutil.WriteFile(certFile, cert, 0666); err != nil {
		return err
	}
	if err = ioutil.WriteFile(keyFile, key, 0600); err != nil {
		os.Remove(certFile)
		return err
	}
	if err = ioutil.WriteFile(certFileWallet, cert, 0666); err != nil {
		return err
	}
	if err = ioutil.WriteFile(keyFileWallet, key, 0600); err != nil {
		os.Remove(certFile)
		return err
	}
	return nil
}
<commit_msg>Add --txindex to node args. (#333)<commit_after>// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpctest

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"github.com/decred/dcrd/wire"

	rpc "github.com/decred/dcrrpcclient"
	"github.com/decred/dcrutil"
)

// nodeConfig contains all the args, and data required to launch a dcrd process
// and connect the rpc client to it.
type nodeConfig struct {
	rpcUser    string
	rpcPass    string
	listen     string
	rpcListen  string
	rpcConnect string
	dataDir    string
	logDir     string
	profile    string
	debugLevel string
	extra      []string
	prefix     string

	exe          string
	endpoint     string
	certFile     string
	keyFile      string
	certificates []byte
}

// newConfig returns a nodeConfig with default values.
func newConfig(prefix, certFile, keyFile string, extra []string) (*nodeConfig, error) {
	// TODO: use defaultP2pPort and defaultRPCPort instead of literals
	a := &nodeConfig{
		listen:    "127.0.0.1:18555",
		rpcListen: "127.0.0.1:19556",
		rpcUser:   "user",
		rpcPass:   "pass",
		extra:     extra,
		prefix:    prefix,

		exe:      "dcrd",
		endpoint: "ws",
		certFile: certFile,
		keyFile:  keyFile,
	}
	if err := a.setDefaults(); err != nil {
		return nil, err
	}
	return a, nil
}

// setDefaults sets the default values of the config. It also creates the
// temporary data, and log directories which must be cleaned up with a call to
// cleanup().
func (n *nodeConfig) setDefaults() error {
	datadir, err := ioutil.TempDir(n.prefix, "data")
	if err != nil {
		return err
	}
	n.dataDir = datadir
	logdir, err := ioutil.TempDir(n.prefix, "logs")
	if err != nil {
		return err
	}
	n.logDir = logdir
	cert, err := ioutil.ReadFile(n.certFile)
	if err != nil {
		return err
	}
	n.certificates = cert
	return nil
}

// arguments returns an array of arguments that be used to launch the
// dcrd process.
func (n *nodeConfig) arguments() []string {
	args := []string{}
	// --simnet
	args = append(args, fmt.Sprintf("--%s", strings.ToLower(wire.SimNet.String())))
	if n.rpcUser != "" {
		// --rpcuser
		args = append(args, fmt.Sprintf("--rpcuser=%s", n.rpcUser))
	}
	if n.rpcPass != "" {
		// --rpcpass
		args = append(args, fmt.Sprintf("--rpcpass=%s", n.rpcPass))
	}
	if n.listen != "" {
		// --listen
		args = append(args, fmt.Sprintf("--listen=%s", n.listen))
	}
	if n.rpcListen != "" {
		// --rpclisten
		args = append(args, fmt.Sprintf("--rpclisten=%s", n.rpcListen))
	}
	if n.rpcConnect != "" {
		// --rpcconnect
		args = append(args, fmt.Sprintf("--rpcconnect=%s", n.rpcConnect))
	}
	// --rpccert
	args = append(args, fmt.Sprintf("--rpccert=%s", n.certFile))
	// --rpckey
	args = append(args, fmt.Sprintf("--rpckey=%s", n.keyFile))
	if n.dataDir != "" {
		// --datadir
		args = append(args, fmt.Sprintf("--datadir=%s", n.dataDir))
	}
	if n.logDir != "" {
		// --logdir
		args = append(args, fmt.Sprintf("--logdir=%s", n.logDir))
	}
	if n.profile != "" {
		// --profile
		args = append(args, fmt.Sprintf("--profile=%s", n.profile))
	}
	if n.debugLevel != "" {
		// --debuglevel
		args = append(args, fmt.Sprintf("--debuglevel=%s", n.debugLevel))
	}
	args = append(args, "--txindex")
	args = append(args, "--addrindex")
	args = append(args, n.extra...)
	return args
}

// command returns the exec.Cmd which will be used to start the dcrd process.
func (n *nodeConfig) command() *exec.Cmd {
	return exec.Command(n.exe, n.arguments()...)
}

// rpcConnConfig returns the rpc connection config that can be used
// to connect to the dcrd process that is launched via Start().
func (n *nodeConfig) rpcConnConfig() rpc.ConnConfig {
	return rpc.ConnConfig{
		Host:                 n.rpcListen,
		Endpoint:             n.endpoint,
		User:                 n.rpcUser,
		Pass:                 n.rpcPass,
		Certificates:         n.certificates,
		DisableAutoReconnect: true,
	}
}

// String returns the string representation of this nodeConfig.
func (n *nodeConfig) String() string {
	return n.prefix
}

// cleanup removes the tmp data and log directories.
func (n *nodeConfig) cleanup() error {
	dirs := []string{
		n.logDir,
		n.dataDir,
	}
	var err error
	for _, dir := range dirs {
		if err = os.RemoveAll(dir); err != nil {
			log.Printf("Cannot remove dir %s: %v", dir, err)
		}
	}
	return err
}

// node houses the neccessary state required to configure, launch, and manaage
// a dcrd process.
type node struct {
	config *nodeConfig

	cmd     *exec.Cmd
	pidFile string

	dataDir string
}

// newNode creates a new node instance according to the passed config. dataDir
// will be used to hold a file recording the pid of the launched process, and
// as the base for the log and data directories for dcrd.
func newNode(config *nodeConfig, dataDir string) (*node, error) {
	return &node{
		config:  config,
		dataDir: dataDir,
		cmd:     config.command(),
	}, nil
}

// Start creates a new dcrd process, and writes its pid in a file reserved for
// recording the pid of the launched process. This file can ue used to terminate
// the procress in case of a hang, or panic. In the case of a failing test case,
// or panic, it is important that the process be stopped via stop(), otherwise,
// it will persist unless explicitly killed.
func (n *node) Start() error {
	if err := n.cmd.Start(); err != nil {
		return err
	}

	pid, err := os.Create(fmt.Sprintf("%s.pid", n.config))
	if err != nil {
		return err
	}

	n.pidFile = pid.Name()
	if _, err = fmt.Fprintf(pid, "%d\n", n.cmd.Process.Pid); err != nil {
		return err
	}

	if err := pid.Close(); err != nil {
		return err
	}

	return nil
}

// Stop interrupts the running dcrd process process, and waits until it exits
// properly. On windows, interrupt is not supported, so a kill signal is used
// instead
func (n *node) Stop() error {
	if n.cmd == nil || n.cmd.Process == nil {
		// return if not properly initialized
		// or error starting the process
		return nil
	}
	defer n.cmd.Wait()
	if runtime.GOOS == "windows" {
		return n.cmd.Process.Signal(os.Kill)
	}
	return n.cmd.Process.Signal(os.Interrupt)
}

// Cleanup cleanups process and args files. The file housing the pid of the
// created process will be deleted, as well as any directories created by the
// process.
func (n *node) Cleanup() error {
	if n.pidFile != "" {
		if err := os.Remove(n.pidFile); err != nil {
			log.Printf("unable to remove file %s: %v", n.pidFile,
				err)
		}
	}

	return n.config.cleanup()
}

// shutdown terminates the running dcrd process, and cleans up all
// file/directories created by node.
func (n *node) Shutdown() error {
	if err := n.Stop(); err != nil {
		return err
	}
	if err := n.Cleanup(); err != nil {
		return err
	}
	return nil
}

// genCertPair generates a key/cert pair to the paths provided.
func genCertPair(certFile, keyFile, certFileWallet, keyFileWallet string) error {
	org := "rpctest autogenerated cert"
	validUntil := time.Now().Add(10 * 365 * 24 * time.Hour)
	cert, key, err := dcrutil.NewTLSCertPair(org, validUntil, nil)
	if err != nil {
		return err
	}
	// Write cert and key files.
	if err = ioutil.WriteFile(certFile, cert, 0666); err != nil {
		return err
	}
	if err = ioutil.WriteFile(keyFile, key, 0600); err != nil {
		os.Remove(certFile)
		return err
	}
	if err = ioutil.WriteFile(certFileWallet, cert, 0666); err != nil {
		return err
	}
	if err = ioutil.WriteFile(keyFileWallet, key, 0600); err != nil {
		os.Remove(certFile)
		return err
	}
	return nil
}
<|endoftext|>