<commit_before>package impl

import (
	"io"
	"reflect"
	"strings"
	"testing"
)

func TestNew(t *testing.T) {
	tests := []struct {
		in  int
		out *MarkovChain
		ok  bool
	}{
		{
			in: 2,
			out: &MarkovChain{
				order: 2,
			},
			ok: true,
		},
		{
			in: 47,
			out: &MarkovChain{
				order: 47,
			},
			ok: true,
		},
		{
			in: 1,
			out: &MarkovChain{
				order: 1,
			},
			ok: true,
		},
		{}, // The all-zero case is the test for order = 0.
		{
			in: -1,
		},
	}

	for _, tc := range tests {
		out, err := New(tc.in)
		if err == nil && !tc.ok {
			t.Errorf("New(%d) = %+v, want err", tc.in, out)
			continue
		}
		if err != nil && tc.ok {
			t.Errorf("New(%d) = %s, want %+v", tc.in, err, tc.out)
			continue
		}
		if !reflect.DeepEqual(out, tc.out) && tc.ok {
			t.Errorf("New(d) = %+v, want %+v", tc.in, out, tc.out)
		}
	}
}

func TestTrain(t *testing.T) {
	type input struct {
		r     string // For convenience of pretty test outputs.
		order int
	}
	tests := []struct {
		in  input
		out *MarkovChain
		ok  bool
	}{
		// Test vacuous case of no input data.
		{
			in: input{
				order: 2,
			},
			out: &MarkovChain{
				order: 2,
			},
			ok: true,
		},
		// Simple order = 1 case.
		{
			in: input{
				r:     "I see a tree built into the sidewalk.",
				order: 1,
			},
			out: &MarkovChain{
				order: 1,
				lessons: []lesson{
					lesson{
						back: []string{""},
						next: "I",
					},
					lesson{
						back: []string{"I"},
						next: "see",
					},
					lesson{
						back: []string{"see"},
						next: "a",
					},
					lesson{
						back: []string{"a"},
						next: "tree",
					},
					lesson{
						back: []string{"tree"},
						next: "built",
					},
					lesson{
						back: []string{"built"},
						next: "into",
					},
					lesson{
						back: []string{"into"},
						next: "the",
					},
					lesson{
						back: []string{"the"},
						next: "sidewalk.",
					},
				},
			},
			ok: true,
		},
		// Simple order = 2 case.
		{
			in: input{
				r:     "The tree has two posts supporting it.",
				order: 2,
			},
			out: &MarkovChain{
				order: 2,
				lessons: []lesson{
					lesson{
						back: []string{"", ""},
						next: "The",
					},
					lesson{
						back: []string{"", "The"},
						next: "tree",
					},
					lesson{
						back: []string{"The", "tree"},
						next: "has",
					},
					lesson{
						back: []string{"tree", "has"},
						next: "two",
					},
					lesson{
						back: []string{"has", "two"},
						next: "posts",
					},
					lesson{
						back: []string{"two", "posts"},
						next: "supporting",
					},
					lesson{
						back: []string{"posts", "supporting"},
						next: "it.",
					},
				},
			},
			ok: true,
		},
		// Simple order = 3 case.
		{
			in: input{
				r:     "There's a coat on one post.",
				order: 3,
			},
			out: &MarkovChain{
				order: 3,
				lessons: []lesson{
					{
						back: []string{"", "", ""},
						next: "There's",
					},
					{
						back: []string{"", "", "There's"},
						next: "a",
					},
					{
						back: []string{"", "There's", "a"},
						next: "coat",
					},
					{
						back: []string{"There's", "a", "coat"},
						next: "on",
					},
					{
						back: []string{"a", "coat", "on"},
						next: "one",
					},
					{
						back: []string{"coat", "on", "one"},
						next: "post.",
					},
				},
			},
			ok: true,
		},
	}

	for _, tc := range tests {
		// Set up.
		m, err := New(tc.in.order)
		if err != nil {
			t.Errorf("New(%d) got err, want nil (New is not SUT)", tc.in.order)
			continue
		}

		r := strings.NewReader(tc.in.r)

		err = m.Train(r)

		if err == nil && !tc.ok {
			t.Errorf("New(%d).Train(%s) = %+v, want err", tc.in.order, tc.in.r, m)
			continue
		}
		if err != nil && tc.ok {
			t.Errorf("New(%d).Train(%s) = %s, want %+v", tc.in.order, tc.in.r, err, tc.out)
			continue
		}
		if !reflect.DeepEqual(m, tc.out) && tc.ok {
			t.Errorf("New(%d).Train(%s) = %+v, want %+v", tc.in.order, tc.in.r, m, tc.out)
		}
	}

	// Test case with nil reader. Cannot be captured in above test loop.
	order := 2
	m, err := New(order)
	if err != nil {
		t.Errorf("New(%d) got err, want nil (New is not SUT)", 2)
		return
	}

	var r io.Reader
	if err := m.Train(r); err == nil {
		t.Errorf("New(%d).Train(nil reader) = %+v, want err", order, m)
	}
}
<commit_msg>Fix failing tests.<commit_after>package impl

import (
	"io"
	"reflect"
	"strings"
	"testing"
)

func TestNew(t *testing.T) {
	tests := []struct {
		in  int
		out *MarkovChain
		ok  bool
	}{
		{
			in: 2,
			out: &MarkovChain{
				Order: 2,
			},
			ok: true,
		},
		{
			in: 47,
			out: &MarkovChain{
				Order: 47,
			},
			ok: true,
		},
		{
			in: 1,
			out: &MarkovChain{
				Order: 1,
			},
			ok: true,
		},
		{}, // The all-zero case is the test for order = 0.
		{
			in: -1,
		},
	}

	for _, tc := range tests {
		out, err := New(tc.in)
		if err == nil && !tc.ok {
			t.Errorf("New(%d) = %+v, want err", tc.in, out)
			continue
		}
		if err != nil && tc.ok {
			t.Errorf("New(%d) = %s, want %+v", tc.in, err, tc.out)
			continue
		}
		if !reflect.DeepEqual(out, tc.out) && tc.ok {
			t.Errorf("New(d) = %+v, want %+v", tc.in, out, tc.out)
		}
	}
}

func TestTrain(t *testing.T) {
	type input struct {
		r     string // For convenience of pretty test outputs.
		order int
	}
	tests := []struct {
		in  input
		out *MarkovChain
		ok  bool
	}{
		// Test vacuous case of no input data.
		{
			in: input{
				order: 2,
			},
			out: &MarkovChain{
				Order: 2,
			},
			ok: true,
		},
		// Simple order = 1 case.
		{
			in: input{
				r:     "I see a tree built into the sidewalk.",
				order: 1,
			},
			out: &MarkovChain{
				Order: 1,
				Lessons: []lesson{
					lesson{
						Back: []string{""},
						Next: "I",
					},
					lesson{
						Back: []string{"I"},
						Next: "see",
					},
					lesson{
						Back: []string{"see"},
						Next: "a",
					},
					lesson{
						Back: []string{"a"},
						Next: "tree",
					},
					lesson{
						Back: []string{"tree"},
						Next: "built",
					},
					lesson{
						Back: []string{"built"},
						Next: "into",
					},
					lesson{
						Back: []string{"into"},
						Next: "the",
					},
					lesson{
						Back: []string{"the"},
						Next: "sidewalk.",
					},
				},
			},
			ok: true,
		},
		// Simple order = 2 case.
		{
			in: input{
				r:     "The tree has two posts supporting it.",
				order: 2,
			},
			out: &MarkovChain{
				Order: 2,
				Lessons: []lesson{
					lesson{
						Back: []string{"", ""},
						Next: "The",
					},
					lesson{
						Back: []string{"", "The"},
						Next: "tree",
					},
					lesson{
						Back: []string{"The", "tree"},
						Next: "has",
					},
					lesson{
						Back: []string{"tree", "has"},
						Next: "two",
					},
					lesson{
						Back: []string{"has", "two"},
						Next: "posts",
					},
					lesson{
						Back: []string{"two", "posts"},
						Next: "supporting",
					},
					lesson{
						Back: []string{"posts", "supporting"},
						Next: "it.",
					},
				},
			},
			ok: true,
		},
		// Simple order = 3 case.
		{
			in: input{
				r:     "There's a coat on one post.",
				order: 3,
			},
			out: &MarkovChain{
				Order: 3,
				Lessons: []lesson{
					{
						Back: []string{"", "", ""},
						Next: "There's",
					},
					{
						Back: []string{"", "", "There's"},
						Next: "a",
					},
					{
						Back: []string{"", "There's", "a"},
						Next: "coat",
					},
					{
						Back: []string{"There's", "a", "coat"},
						Next: "on",
					},
					{
						Back: []string{"a", "coat", "on"},
						Next: "one",
					},
					{
						Back: []string{"coat", "on", "one"},
						Next: "post.",
					},
				},
			},
			ok: true,
		},
	}

	for _, tc := range tests {
		// Set up.
		m, err := New(tc.in.order)
		if err != nil {
			t.Errorf("New(%d) got err, want nil (New is not SUT)", tc.in.order)
			continue
		}

		r := strings.NewReader(tc.in.r)

		err = m.Train(r)

		if err == nil && !tc.ok {
			t.Errorf("New(%d).Train(%s) = %+v, want err", tc.in.order, tc.in.r, m)
			continue
		}
		if err != nil && tc.ok {
			t.Errorf("New(%d).Train(%s) = %s, want %+v", tc.in.order, tc.in.r, err, tc.out)
			continue
		}
		if !reflect.DeepEqual(m, tc.out) && tc.ok {
			t.Errorf("New(%d).Train(%s) = %+v, want %+v", tc.in.order, tc.in.r, m, tc.out)
		}
	}

	// Test case with nil reader. Cannot be captured in above test loop.
	order := 2
	m, err := New(order)
	if err != nil {
		t.Errorf("New(%d) got err, want nil (New is not SUT)", 2)
		return
	}

	var r io.Reader
	if err := m.Train(r); err == nil {
		t.Errorf("New(%d).Train(nil reader) = %+v, want err", order, m)
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"github.com/github/git-lfs/config"
	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/spf13/cobra"
)

func envCommand(cmd *cobra.Command, args []string) {
	config.ShowConfigWarnings = true
	endpoint := cfg.Endpoint("download")

	gitV, err := git.Config.Version()
	if err != nil {
		gitV = "Error getting git version: " + err.Error()
	}

	Print(config.VersionDesc)
	Print(gitV)
	Print("")

	if len(endpoint.Url) > 0 {
		Print("Endpoint=%s (auth=%s)", endpoint.Url, cfg.EndpointAccess(endpoint))
		if len(endpoint.SshUserAndHost) > 0 {
			Print("  SSH=%s:%s", endpoint.SshUserAndHost, endpoint.SshPath)
		}
	}

	for _, remote := range cfg.Remotes() {
		remoteEndpoint := cfg.RemoteEndpoint(remote, "download")
		Print("Endpoint (%s)=%s (auth=%s)", remote, remoteEndpoint.Url, cfg.EndpointAccess(remoteEndpoint))
		if len(remoteEndpoint.SshUserAndHost) > 0 {
			Print("  SSH=%s:%s", remoteEndpoint.SshUserAndHost, remoteEndpoint.SshPath)
		}
	}

	for _, env := range lfs.Environ(cfg, TransferManifest()) {
		Print(env)
	}

	for _, key := range []string{"filter.lfs.smudge", "filter.lfs.clean"} {
		value, _ := cfg.Git.Get(key)
		Print("git config %s = %q", key, value)
	}
}

func init() {
	RegisterCommand("env", envCommand, func(cmd *cobra.Command) bool {
		return true
	})
}
<commit_msg>env is simple enough it doesn't need a callback<commit_after>package commands

import (
	"github.com/github/git-lfs/config"
	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/spf13/cobra"
)

func envCommand(cmd *cobra.Command, args []string) {
	config.ShowConfigWarnings = true
	endpoint := cfg.Endpoint("download")

	gitV, err := git.Config.Version()
	if err != nil {
		gitV = "Error getting git version: " + err.Error()
	}

	Print(config.VersionDesc)
	Print(gitV)
	Print("")

	if len(endpoint.Url) > 0 {
		Print("Endpoint=%s (auth=%s)", endpoint.Url, cfg.EndpointAccess(endpoint))
		if len(endpoint.SshUserAndHost) > 0 {
			Print("  SSH=%s:%s", endpoint.SshUserAndHost, endpoint.SshPath)
		}
	}

	for _, remote := range cfg.Remotes() {
		remoteEndpoint := cfg.RemoteEndpoint(remote, "download")
		Print("Endpoint (%s)=%s (auth=%s)", remote, remoteEndpoint.Url, cfg.EndpointAccess(remoteEndpoint))
		if len(remoteEndpoint.SshUserAndHost) > 0 {
			Print("  SSH=%s:%s", remoteEndpoint.SshUserAndHost, remoteEndpoint.SshPath)
		}
	}

	for _, env := range lfs.Environ(cfg, TransferManifest()) {
		Print(env)
	}

	for _, key := range []string{"filter.lfs.smudge", "filter.lfs.clean"} {
		value, _ := cfg.Git.Get(key)
		Print("git config %s = %q", key, value)
	}
}

func init() {
	RegisterCommand("env", envCommand, nil)
}
<|endoftext|>


<commit_before>package http

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	cmds "github.com/jbenet/go-ipfs/commands"
	u "github.com/jbenet/go-ipfs/util"
)

const (
	ApiUrlFormat = "http://%s%s/%s?%s"
	ApiPath      = "/api/v0" // TODO: make configurable
)

// Client is the commands HTTP client interface.
type Client interface {
	Send(req cmds.Request) (cmds.Response, error)
}

type client struct {
	serverAddress string
}

func NewClient(address string) Client {
	return &client{address}
}

func (c *client) Send(req cmds.Request) (cmds.Response, error) {
	userEncoding, _ := req.Option(cmds.EncShort).String()
	req.SetOption(cmds.EncShort, cmds.JSON)

	query, inputStream, err := getQuery(req)
	if err != nil {
		return nil, err
	}

	path := strings.Join(req.Path(), "/")
	url := fmt.Sprintf(ApiUrlFormat, c.serverAddress, ApiPath, path, query)

	httpRes, err := http.Post(url, "application/octet-stream", inputStream)
	if err != nil {
		return nil, err
	}

	res, err := getResponse(httpRes, req)
	if err != nil {
		return nil, err
	}

	if len(userEncoding) > 0 {
		req.SetOption(cmds.EncShort, userEncoding)
	}

	return res, nil
}

func getQuery(req cmds.Request) (string, io.Reader, error) {
	// TODO: handle multiple files with multipart
	var inputStream io.Reader

	query := url.Values{}
	for k, v := range req.Options() {
		str := fmt.Sprintf("%v", v)
		query.Set(k, str)
	}

	args := req.Arguments()
	argDefs := req.Command().Arguments
	var argDef cmds.Argument

	for i, arg := range args {
		if i < len(argDefs) {
			argDef = argDefs[i]
		}

		if argDef.Type == cmds.ArgString {
			str, ok := arg.(string)
			if !ok {
				return "", nil, u.ErrCast()
			}
			query.Add("arg", str)

		} else {
			// TODO: multipart
			if inputStream != nil {
				return "", nil, fmt.Errorf("Currently, only one file stream is possible per request")
			}
			var ok bool
			inputStream, ok = arg.(io.Reader)
			if !ok {
				return "", nil, u.ErrCast()
			}
		}
	}

	return query.Encode(), inputStream, nil
}

// getResponse decodes a http.Response to create a cmds.Response
func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error) {
	var err error
	res := cmds.NewResponse(req)

	contentType := httpRes.Header["Content-Type"][0]
	contentType = strings.Split(contentType, ";")[0]

	if len(httpRes.Header.Get(streamHeader)) > 0 {
		res.SetOutput(httpRes.Body)
		return res, nil
	}

	dec := json.NewDecoder(httpRes.Body)

	if httpRes.StatusCode >= http.StatusBadRequest {
		e := cmds.Error{}

		if httpRes.StatusCode == http.StatusNotFound {
			// handle 404s
			e.Message = "Command not found."
			e.Code = cmds.ErrClient

		} else if contentType == "text/plain" {
			// handle non-marshalled errors
			buf := bytes.NewBuffer(nil)
			io.Copy(buf, httpRes.Body)
			e.Message = string(buf.Bytes())
			e.Code = cmds.ErrNormal

		} else {
			// handle marshalled errors
			err = dec.Decode(&e)
			if err != nil {
				return nil, err
			}
		}

		res.SetError(e, e.Code)

	} else {
		v := req.Command().Type
		err = dec.Decode(&v)
		if err != nil {
			return nil, err
		}

		res.SetOutput(v)
	}

	return res, nil
}
<commit_msg>explain(commands/http)<commit_after>package http

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	cmds "github.com/jbenet/go-ipfs/commands"
	u "github.com/jbenet/go-ipfs/util"
)

const (
	ApiUrlFormat = "http://%s%s/%s?%s"
	ApiPath      = "/api/v0" // TODO: make configurable
)

// Client is the commands HTTP client interface.
type Client interface {
	Send(req cmds.Request) (cmds.Response, error)
}

type client struct {
	serverAddress string
}

func NewClient(address string) Client {
	return &client{address}
}

func (c *client) Send(req cmds.Request) (cmds.Response, error) {

	// save user-provided encoding
	previousUserProvidedEncoding, found, err := req.Option(cmds.EncShort).String()
	if err != nil {
		return nil, err
	}

	// override with json to send to server
	req.SetOption(cmds.EncShort, cmds.JSON)

	query, inputStream, err := getQuery(req)
	if err != nil {
		return nil, err
	}

	path := strings.Join(req.Path(), "/")
	url := fmt.Sprintf(ApiUrlFormat, c.serverAddress, ApiPath, path, query)

	// TODO extract string const?
	httpRes, err := http.Post(url, "application/octet-stream", inputStream)
	if err != nil {
		return nil, err
	}

	// using the overridden JSON encoding in request
	res, err := getResponse(httpRes, req)
	if err != nil {
		return nil, err
	}

	if found && len(previousUserProvidedEncoding) > 0 {
		// reset to user provided encoding after sending request
		// NB: if user has provided an encoding but it is the empty string,
		// still leave it as JSON.
		req.SetOption(cmds.EncShort, previousUserProvidedEncoding)
	}

	return res, nil
}

func getQuery(req cmds.Request) (string, io.Reader, error) {
	// TODO: handle multiple files with multipart
	var inputStream io.Reader

	query := url.Values{}
	for k, v := range req.Options() {
		str := fmt.Sprintf("%v", v)
		query.Set(k, str)
	}

	args := req.Arguments()
	argDefs := req.Command().Arguments
	var argDef cmds.Argument

	for i, arg := range args {
		if i < len(argDefs) {
			argDef = argDefs[i]
		}

		if argDef.Type == cmds.ArgString {
			str, ok := arg.(string)
			if !ok {
				return "", nil, u.ErrCast()
			}
			query.Add("arg", str)

		} else {
			// TODO: multipart
			if inputStream != nil {
				return "", nil, fmt.Errorf("Currently, only one file stream is possible per request")
			}
			var ok bool
			inputStream, ok = arg.(io.Reader)
			if !ok {
				return "", nil, u.ErrCast()
			}
		}
	}

	return query.Encode(), inputStream, nil
}

// getResponse decodes a http.Response to create a cmds.Response
func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error) {
	var err error
	res := cmds.NewResponse(req)

	contentType := httpRes.Header["Content-Type"][0]
	contentType = strings.Split(contentType, ";")[0]

	if len(httpRes.Header.Get(streamHeader)) > 0 {
		res.SetOutput(httpRes.Body)
		return res, nil
	}

	dec := json.NewDecoder(httpRes.Body)

	if httpRes.StatusCode >= http.StatusBadRequest {
		e := cmds.Error{}

		if httpRes.StatusCode == http.StatusNotFound {
			// handle 404s
			e.Message = "Command not found."
			e.Code = cmds.ErrClient

		} else if contentType == "text/plain" {
			// handle non-marshalled errors
			buf := bytes.NewBuffer(nil)
			io.Copy(buf, httpRes.Body)
			e.Message = string(buf.Bytes())
			e.Code = cmds.ErrNormal

		} else {
			// handle marshalled errors
			err = dec.Decode(&e)
			if err != nil {
				return nil, err
			}
		}

		res.SetError(e, e.Code)

	} else {
		v := req.Command().Type
		err = dec.Decode(&v)
		if err != nil {
			return nil, err
		}

		res.SetOutput(v)
	}

	return res, nil
}
<|endoftext|>


<commit_before>/*
Package sabercat implements net/http.FileSystem to serve
contents directly from MongoDB's GridFS.

To serve all files from a database containing a GridFS
called `fs` via http:

	session, err := mgo.Dial("mongodb://localhost/database")
	if err != nil {
		log.Fatalf("Could not connect to mongodb: %s", err)
	}
	db := session.DB("") // Use DB name from the URL
	http.Handle("/", http.FileServer(&sabercat.GridDir{
		PathPrefix: "",
		GridFS:     db.GridFS("fs"),
	}
*/
package sabercat

import (
	"labix.org/v2/mgo"
	"net/http"
	"path/filepath"
)

type GridDir struct {
	PathPrefix string
	GridFS     *mgo.GridFS
}

func (gd *GridDir) Open(name string) (http.File, error) {
	filename := filepath.Join(gd.PathPrefix, name)
	f, err := gd.GridFS.Open(filename)
	return &gridFile{f}, err
}
<commit_msg>Fix documentation<commit_after>/*
Package sabercat implements net/http.FileSystem to serve
contents directly from MongoDB's GridFS.

To serve all files from a database containing a GridFS
called `fs` via http:

	session, err := mgo.Dial("mongodb://localhost/database")
	if err != nil {
		log.Fatalf("Could not connect to mongodb: %s", err)
	}
	db := session.DB("") // Use DB name from the URL
	http.Handle("/", http.FileServer(&sabercat.GridDir{
		PathPrefix: "",
		GridFS:     db.GridFS("fs"),
	}

Directory listing has not been implemented.
*/
package sabercat

import (
	"labix.org/v2/mgo"
	"net/http"
	"path/filepath"
)

type GridDir struct {
	PathPrefix string
	GridFS     *mgo.GridFS
}

func (gd *GridDir) Open(name string) (http.File, error) {
	filename := filepath.Join(gd.PathPrefix, name)
	f, err := gd.GridFS.Open(filename)
	return &gridFile{f}, err
}
<|endoftext|>


<commit_before>package dispatcher_client

import (
	"net"

	"github.com/xiaonanln/vacuum/common"
	. "github.com/xiaonanln/vacuum/proto"
	"github.com/xiaonanln/vacuum/vlog"
)

type DispatcherRespHandler interface {
	HandleDispatcherResp_CreateString(name string, stringID string, args []interface{})
	HandleDispatcherResp_LoadString(name string, stringID string)
	HandleDispatcherResp_DeclareService(stringID string, serviceName string)
	HandleDispatcherResp_SendStringMessage(stringID string, msg common.StringMessage)
	HandleDispatcherResp_CloseString(stringID string)
	HandleDispatcherResp_DelString(stringID string)
	HandleDispatcherResp_OnMigrateString(name string, stringID string, data map[string]interface{})
	HandleDispatcherResp_StartMigrateString(stringID string)
}

type DispatcherClient struct {
	MessageConnection
}

var (
	dispatcherRespHandler DispatcherRespHandler
)

func newDispatcherClient(conn net.Conn) *DispatcherClient {
	return &DispatcherClient{
		MessageConnection: NewMessageConnection(conn),
	}
}

func (dc *DispatcherClient) RegisterVacuumServer(serverID int) error {
	req := RegisterVacuumServerReq{
		ServerID: serverID,
	}
	return dc.SendMsg(REGISTER_VACUUM_SERVER_REQ, &req)
}

func (dc *DispatcherClient) SendStringMessage(stringID string, msg interface{}) error {
	req := StringMessageRelay{
		Msg: msg,
	}
	return dc.SendRelayMsg(stringID, STRING_MESSAGE_RELAY, &req)
}

func (dc *DispatcherClient) SendCreateStringReq(name string, stringID string, args []interface{}) error {
	req := CreateStringReq{
		Name:     name,
		StringID: stringID,
		Args:     args,
	}
	return dc.SendMsg(CREATE_STRING_REQ, &req)
}

func (dc *DispatcherClient) SendLoadStringReq(name string, stringID string) error {
	req := LoadStringReq{
		Name:     name,
		StringID: stringID,
	}
	return dc.SendMsg(LOAD_STRING_REQ, &req)
}

func (dc *DispatcherClient) SendCreateStringLocallyReq(name string, stringID string) error {
	req := CreateStringLocallyReq{
		Name:     name,
		StringID: stringID,
	}
	return dc.SendMsg(CREATE_STRING_LOCALLY_REQ, &req)
}

func (dc *DispatcherClient) SendDeclareServiceReq(stringID string, serviceName string) error {
	req := DeclareServiceReq{
		StringID:    stringID,
		ServiceName: serviceName,
	}
	return dc.SendMsg(DECLARE_SERVICE_REQ, &req)
}

func (dc *DispatcherClient) SendStringDelReq(stringID string) error {
	req := StringDelReq{
		StringID: stringID,
	}
	return dc.SendMsg(STRING_DEL_REQ, &req)
}

func (dc *DispatcherClient) SendStartMigrateStringReq(stringID string) error {
	req := StartMigrateStringReq{
		StringID: stringID,
	}
	return dc.SendMsg(START_MIGRATE_STRING_REQ, &req)
}

func (dc *DispatcherClient) SendMigrateStringReq(name string, stringID string, serverID int, data map[string]interface{}) error {
	req := MigrateStringReq{
		Name:     name,
		StringID: stringID,
		ServerID: serverID,
		Data:     data,
	}

	return dc.SendMsg(MIGRATE_STRING_REQ, &req)
}

func (dc *DispatcherClient) RelayCloseString(stringID string) error {
	req := CloseStringRelay{}
	return dc.SendRelayMsg(stringID, CLOSE_STRING_RELAY, &req)
}

//
//func (mc MessageConnection) SendRawRelayMsg(targetID string, msgTypeAndPayload []byte) error {
//	var pkgSize uint32 = SIZE_FIELD_SIZE + STRING_ID_SIZE + len(msgTypeAndPayload)
//	var pkgSizeBuf [SIZE_FIELD_SIZE]byte
//	NETWORK_ENDIAN.PutUint32(pkgSizeBuf, pkgSize)
//
//}

func (dc *DispatcherClient) HandleMsg(msg *Message, pktSize uint32, msgtype MsgType_t) error {
	vlog.Debugf("<<< HandleMsg: size %v, msgtype %v", pktSize, msgtype)
	payload := msg[PREPAYLOAD_SIZE:pktSize]
	if msgtype == START_MIGRATE_STRING_RESP {
		return dc.handleStartMigrateStringResp(payload)
	} else if msgtype == MIGRATE_STRING_RESP {
		// migrate string to this server
		return dc.handleMigrateStringResp(payload)
	} else if msgtype == CREATE_STRING_RESP {
		// create real string instance
		return dc.handleCreateStringResp(payload)
	} else if msgtype == DECLARE_SERVICE_RESP {
		// declare service
		return dc.handleDeclareServiceResp(payload)
	} else if msgtype == STRING_DEL_RESP {
		return dc.handleStringDelResp(payload)
	} else if msgtype == LOAD_STRING_RESP {
		return dc.handleLoadStringResp(payload)
	} else {
		vlog.Panicf("serveDispatcherClient: invalid msg type: %v", msgtype)
		return nil
	}
}

func (dc *DispatcherClient) HandleRelayMsg(msg *Message, pktSize uint32, targetID string) error {
	var msgType MsgType_t = MsgType_t(NETWORK_ENDIAN.Uint16(msg[SIZE_FIELD_SIZE+STRING_ID_SIZE : SIZE_FIELD_SIZE+STRING_ID_SIZE+TYPE_FIELD_SIZE]))

	vlog.Debugf("<<< HandleRelayMsg: size %v, msgtype %v", pktSize, msgType)

	payload := msg[RELAY_PREPAYLOAD_SIZE:pktSize]
	if msgType == STRING_MESSAGE_RELAY {
		return dc.handleSendStringRelay(targetID, payload)
	} else if msgType == CLOSE_STRING_RELAY {
		return dc.handleCloseStringRelay(targetID)
	} else {
		vlog.Panicf("invalid msg type: %v", msgType)
		return nil
	}
}

func (dc *DispatcherClient) handleSendStringRelay(targetID string, payload []byte) error {
	var pkt StringMessageRelay
	err := MSG_PACKER.UnpackMsg(payload, &pkt)
	if err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_SendStringMessage(targetID, pkt.Msg)
	return nil
}

func (dc *DispatcherClient) handleCloseStringRelay(targetID string) error {
	dispatcherRespHandler.HandleDispatcherResp_CloseString(targetID)
	return nil
}

func (dc *DispatcherClient) handleCreateStringResp(payload []byte) error {
	var resp CreateStringResp
	err := MSG_PACKER.UnpackMsg(payload, &resp)
	if err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_CreateString(resp.Name, resp.StringID, resp.Args)
	return nil
}

func (dc *DispatcherClient) handleDeclareServiceResp(payload []byte) error {
	var resp DeclareServiceResp
	err := MSG_PACKER.UnpackMsg(payload, &resp)
	if err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_DeclareService(resp.StringID, resp.ServiceName)
	return nil
}

func (dc *DispatcherClient) handleStringDelResp(payload []byte) error {
	var resp StringDelResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_DelString(resp.StringID)
	return nil
}

func (dc *DispatcherClient) handleLoadStringResp(payload []byte) error {
	var resp LoadStringResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_LoadString(resp.Name, resp.StringID)
	return nil
}

func (dc *DispatcherClient) handleStartMigrateStringResp(payload []byte) error {
	// Received start-migrate from dispatcher, now we start the real migrate progress
	var resp StartMigrateStringResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_StartMigrateString(resp.StringID)
	return nil
}

func (dc *DispatcherClient) handleMigrateStringResp(payload []byte) error {
	var resp MigrateStringResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_OnMigrateString(resp.Name, resp.StringID, resp.Data)
	return nil
}
<commit_msg>migrating<commit_after>package dispatcher_client

import (
	"net"

	"github.com/xiaonanln/vacuum/common"
	. "github.com/xiaonanln/vacuum/proto"
	"github.com/xiaonanln/vacuum/vlog"
)

type DispatcherRespHandler interface {
	HandleDispatcherResp_CreateString(name string, stringID string, args []interface{})
	HandleDispatcherResp_LoadString(name string, stringID string)
	HandleDispatcherResp_DeclareService(stringID string, serviceName string)
	HandleDispatcherResp_SendStringMessage(stringID string, msg common.StringMessage)
	HandleDispatcherResp_CloseString(stringID string)
	HandleDispatcherResp_DelString(stringID string)
	HandleDispatcherResp_OnMigrateString(name string, stringID string, data map[string]interface{})
	HandleDispatcherResp_StartMigrateString(stringID string)
}

type DispatcherClient struct {
	MessageConnection
}

var (
	dispatcherRespHandler DispatcherRespHandler
)

func newDispatcherClient(conn net.Conn) *DispatcherClient {
	return &DispatcherClient{
		MessageConnection: NewMessageConnection(conn),
	}
}

func (dc *DispatcherClient) RegisterVacuumServer(serverID int) error {
	req := RegisterVacuumServerReq{
		ServerID: serverID,
	}
	return dc.SendMsg(REGISTER_VACUUM_SERVER_REQ, &req)
}

func (dc *DispatcherClient) SendStringMessage(stringID string, msg interface{}) error {
	req := StringMessageRelay{
		Msg: msg,
	}
	return dc.SendRelayMsg(stringID, STRING_MESSAGE_RELAY, &req)
}

func (dc *DispatcherClient) SendCreateStringReq(name string, stringID string, args []interface{}) error {
	req := CreateStringReq{
		Name:     name,
		StringID: stringID,
		Args:     args,
	}
	return dc.SendMsg(CREATE_STRING_REQ, &req)
}

func (dc *DispatcherClient) SendLoadStringReq(name string, stringID string) error {
	req := LoadStringReq{
		Name:     name,
		StringID: stringID,
	}
	return dc.SendMsg(LOAD_STRING_REQ, &req)
}

func (dc *DispatcherClient) SendCreateStringLocallyReq(name string, stringID string) error {
	req := CreateStringLocallyReq{
		Name:     name,
		StringID: stringID,
	}
	return dc.SendMsg(CREATE_STRING_LOCALLY_REQ, &req)
}

func (dc *DispatcherClient) SendDeclareServiceReq(stringID string, serviceName string) error {
	req := DeclareServiceReq{
		StringID:    stringID,
		ServiceName: serviceName,
	}
	return dc.SendMsg(DECLARE_SERVICE_REQ, &req)
}

func (dc *DispatcherClient) SendStringDelReq(stringID string) error {
	req := StringDelReq{
		StringID: stringID,
	}
	return dc.SendMsg(STRING_DEL_REQ, &req)
}

func (dc *DispatcherClient) SendStartMigrateStringReq(stringID string) error {
	req := StartMigrateStringReq{
		StringID: stringID,
	}
	return dc.SendMsg(START_MIGRATE_STRING_REQ, &req)
}

func (dc *DispatcherClient) SendMigrateStringReq(name string, stringID string, serverID int, data map[string]interface{}) error {
	req := MigrateStringReq{
		Name:     name,
		StringID: stringID,
		ServerID: serverID,
		Data:     data,
	}

	return dc.SendMsg(MIGRATE_STRING_REQ, &req)
}

func (dc *DispatcherClient) RelayCloseString(stringID string) error {
	req := CloseStringRelay{}
	return dc.SendRelayMsg(stringID, CLOSE_STRING_RELAY, &req)
}

//
//func (mc MessageConnection) SendRawRelayMsg(targetID string, msgTypeAndPayload []byte) error {
//	var pkgSize uint32 = SIZE_FIELD_SIZE + STRING_ID_SIZE + len(msgTypeAndPayload)
//	var pkgSizeBuf [SIZE_FIELD_SIZE]byte
//	NETWORK_ENDIAN.PutUint32(pkgSizeBuf, pkgSize)
//
//}

func (dc *DispatcherClient) HandleMsg(msg *Message, pktSize uint32, msgtype MsgType_t) error {
	vlog.Debugf("<<< HandleMsg: size %v, msgtype %v", pktSize, msgtype)
	payload := msg[PREPAYLOAD_SIZE:pktSize]
	if msgtype == START_MIGRATE_STRING_RESP {
		return dc.handleStartMigrateStringResp(payload)
	} else if msgtype == MIGRATE_STRING_RESP {
		// migrate string to this server
		return dc.handleMigrateStringResp(payload)
	} else if msgtype == CREATE_STRING_RESP {
		// create real string instance
		return dc.handleCreateStringResp(payload)
	} else if msgtype == DECLARE_SERVICE_RESP {
		// declare service
		return dc.handleDeclareServiceResp(payload)
	} else if msgtype == STRING_DEL_RESP {
		return dc.handleStringDelResp(payload)
	} else if msgtype == LOAD_STRING_RESP {
		return dc.handleLoadStringResp(payload)
	} else {
		vlog.Panicf("serveDispatcherClient: invalid msg type: %v", msgtype)
		return nil
	}
}

func (dc *DispatcherClient) HandleRelayMsg(msg *Message, pktSize uint32, targetID string) error {
	var msgType MsgType_t = MsgType_t(NETWORK_ENDIAN.Uint16(msg[SIZE_FIELD_SIZE+STRING_ID_SIZE : SIZE_FIELD_SIZE+STRING_ID_SIZE+TYPE_FIELD_SIZE]))

	vlog.Debugf("<<< HandleRelayMsg: size %v, msgtype %v", pktSize, msgType)
	defer vlog.Debugf("<<< HandleRelayMsg END")

	payload := msg[RELAY_PREPAYLOAD_SIZE:pktSize]
	if msgType == STRING_MESSAGE_RELAY {
		return dc.handleSendStringRelay(targetID, payload)
	} else if msgType == CLOSE_STRING_RELAY {
		return dc.handleCloseStringRelay(targetID)
	} else {
		vlog.Panicf("invalid msg type: %v", msgType)
		return nil
	}
}

func (dc *DispatcherClient) handleSendStringRelay(targetID string, payload []byte) error {
	var pkt StringMessageRelay
	err := MSG_PACKER.UnpackMsg(payload, &pkt)
	if err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_SendStringMessage(targetID, pkt.Msg)
	return nil
}

func (dc *DispatcherClient) handleCloseStringRelay(targetID string) error {
	dispatcherRespHandler.HandleDispatcherResp_CloseString(targetID)
	return nil
}

func (dc *DispatcherClient) handleCreateStringResp(payload []byte) error {
	var resp CreateStringResp
	err := MSG_PACKER.UnpackMsg(payload, &resp)
	if err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_CreateString(resp.Name, resp.StringID, resp.Args)
	return nil
}

func (dc *DispatcherClient) handleDeclareServiceResp(payload []byte) error {
	var resp DeclareServiceResp
	err := MSG_PACKER.UnpackMsg(payload, &resp)
	if err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_DeclareService(resp.StringID, resp.ServiceName)
	return nil
}

func (dc *DispatcherClient) handleStringDelResp(payload []byte) error {
	var resp StringDelResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_DelString(resp.StringID)
	return nil
}

func (dc *DispatcherClient) handleLoadStringResp(payload []byte) error {
	var resp LoadStringResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_LoadString(resp.Name, resp.StringID)
	return nil
}

func (dc *DispatcherClient) handleStartMigrateStringResp(payload []byte) error {
	// Received start-migrate from dispatcher, now we start the real migrate progress
	var resp StartMigrateStringResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_StartMigrateString(resp.StringID)
	return nil
}

func (dc *DispatcherClient) handleMigrateStringResp(payload []byte) error {
	var resp MigrateStringResp
	if err := MSG_PACKER.UnpackMsg(payload, &resp); err != nil {
		return err
	}

	dispatcherRespHandler.HandleDispatcherResp_OnMigrateString(resp.Name, resp.StringID, resp.Data)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "image"
    "image/color"
    "image/png"
    "os"
    "sort"

    "github.com/zagrodzki/goscope/dummy"
    "github.com/zagrodzki/goscope/scope"
)

type Plot struct {
    *image.RGBA
}

func (plot Plot) Fill(col color.RGBA) {
    bounds := plot.Bounds()
    for i := bounds.Min.X; i < bounds.Max.X; i++ {
        for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
            plot.Set(i, j, col)
        }
    }
}

func Min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

func Max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func Abs(a int) int {
    if a < 0 {
        return -a
    }
    return a
}

func SamplesToPoints(s []scope.Sample, start, end image.Point) []image.Point {
    if len(s) == 0 {
        return nil
    }
    minY := s[0]
    maxY := s[0]
    for _, y := range s {
        if minY > y {
            minY = y
        }
        if maxY < y {
            maxY = y
        }
    }
    rangeX := float64(len(s)-1)
    rangeY := float64(maxY - minY)
    var points []image.Point
    sums := make(map[int]int)
    sizes := make(map[int]int)
    for i, y := range s {
        mapX := int(float64(start.X) + (float64(i) / rangeX) * float64(end.X - start.X))
        mapY := int(float64(end.Y) - ((float64(y) - float64(minY)) / rangeY) * float64(end.Y - start.Y))
        sums[mapX] += mapY
        sizes[mapX] += 1
    }
    var keys []int
    for k := range sums {
        keys = append(keys, k)
    }
    for _, i := range keys {
        points = append(points, image.Point{i, int(float64(sums[i])/float64(sizes[i]))})
    }

    return points
}

func (plot Plot) DrawLine(p1, p2 image.Point, col color.RGBA) {
    if p1.X == p2.X {
        for i := Min(p1.Y, p2.Y); i <= Max(p1.Y, p2.Y); i++ {
            plot.Set(p1.X, i, col)
        }
        return
    }
    a := float64(p1.Y - p2.Y) / float64(p1.X - p2.X)
    b := float64(p1.Y) - float64(p1.X) * a

    if Abs(p1.X - p2.X) >= Abs(p1.Y - p2.Y) {
        for i := Min(p1.X, p2.X); i <= Max(p1.X, p2.X); i++ {
            plot.Set(i, int(a * float64(i) + b), col)
        }
    } else {
        for i := Min(p1.Y, p2.Y); i <= Max(p1.Y, p2.Y); i++ {
            plot.Set(int((float64(i) - b) / a), i, col)
        }
    }
}

type XSorter []image.Point

func (a XSorter) Len() int           { return len(a) }
func (a XSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a XSorter) Less(i, j int) bool { return a[i].X < a[j].X }

func (plot Plot) DrawSamples(start, end image.Point, s []scope.Sample, col color.RGBA) {
    points := SamplesToPoints(s, start, end)
    sort.Sort(XSorter(points))
    for i := 1; i < len(points); i++ {
        plot.DrawLine(points[i-1], points[i], col)
    }
}

func (plot Plot) DrawAll(samples map[scope.ChanID][]scope.Sample, col color.RGBA) {
    b := plot.Bounds()
    x1 := b.Min.X + 10
    x2 := b.Max.X - 10
    y1 := b.Min.Y + 10
    y2 := b.Min.Y + 10 + int((b.Max.Y - b.Min.Y - 10 * (len(samples) + 1)) / len(samples))
    step := y2 - b.Min.Y
    for _, v := range samples {
        plot.DrawSamples(image.Point{x1, y1}, image.Point{x2, y2}, v, col)
        y1 = y1 + step
        y2 = y2 + step
    }
}

func main() {
    dum, _ := dummy.Open("")
    data, stop, _ := dum.StartSampling()

    samples := (<-data).Samples
    fmt.Println(samples)
    stop()

    plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}
    colWhite := color.RGBA{255, 255, 255, 255}
    colRed := color.RGBA{255, 0, 0, 255}
    plot.Fill(colWhite)
    plot.DrawAll(samples, colRed)

    f, err := os.Create("draw.png")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    png.Encode(f, plot)
}
<commit_msg>AggrPoint introduced<commit_after>package main

import (
    "fmt"
    "image"
    "image/color"
    "image/png"
    "os"
    "sort"

    "github.com/zagrodzki/goscope/dummy"
    "github.com/zagrodzki/goscope/scope"
)

type Plot struct {
    *image.RGBA
}

func (plot Plot) Fill(col color.RGBA) {
    bounds := plot.Bounds()
    for i := bounds.Min.X; i < bounds.Max.X; i++ {
        for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
            plot.Set(i, j, col)
        }
    }
}

func Min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

func Max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func Abs(a int) int {
    if a < 0 {
        return -a
    }
    return a
}

type AggrPoint struct {
    x int
    sumY int
    sizeY int
}

func (p AggrPoint) add(x, y int) AggrPoint {
    p.x = x
    p.sumY += y
    p.sizeY++
    return p
}

func (p AggrPoint) toPoint() image.Point {
    return image.Point{p.x, p.sumY / p.sizeY}
}

func SamplesToPoints(s []scope.Sample, start, end image.Point) []image.Point {
    if len(s) == 0 {
        return nil
    }
    minY := s[0]
    maxY := s[0]
    for _, y := range s {
        if minY > y {
            minY = y
        }
        if maxY < y {
            maxY = y
        }
    }

    rangeX := float64(len(s)-1)
    rangeY := float64(maxY - minY)
    aggrPoints := make(map[int]AggrPoint)
    for i, y := range s {
        mapX := int(float64(start.X) + float64(i) / rangeX * float64(end.X - start.X))
        mapY := int(float64(end.Y) - float64(y - minY) / rangeY * float64(end.Y - start.Y))
        aggrPoints[mapX] = aggrPoints[mapX].add(mapX, mapY)
    }
    fmt.Println(aggrPoints)
    var points []image.Point
    for _, p := range aggrPoints {
        points = append(points, p.toPoint())
    }

    return points
}

func (plot Plot) DrawLine(p1, p2 image.Point, col color.RGBA) {
    if p1.X == p2.X {
        for i := Min(p1.Y, p2.Y); i <= Max(p1.Y, p2.Y); i++ {
            plot.Set(p1.X, i, col)
        }
        return
    }
    a := float64(p1.Y - p2.Y) / float64(p1.X - p2.X)
    b := float64(p1.Y) - float64(p1.X) * a

    if Abs(p1.X - p2.X) >= Abs(p1.Y - p2.Y) {
        for i := Min(p1.X, p2.X); i <= Max(p1.X, p2.X); i++ {
            plot.Set(i, int(a * float64(i) + b), col)
        }
    } else {
        for i := Min(p1.Y, p2.Y); i <= Max(p1.Y, p2.Y); i++ {
            plot.Set(int((float64(i) - b) / a), i, col)
        }
    }
}

type XSorter []image.Point

func (a XSorter) Len() int           { return len(a) }
func (a XSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a XSorter) Less(i, j int) bool { return a[i].X < a[j].X }

func (plot Plot) DrawSamples(start, end image.Point, s []scope.Sample, col color.RGBA) {
    points := SamplesToPoints(s, start, end)
    sort.Sort(XSorter(points))
    for i := 1; i < len(points); i++ {
        plot.DrawLine(points[i-1], points[i], col)
    }
}

func (plot Plot) DrawAll(samples map[scope.ChanID][]scope.Sample, col color.RGBA) {
    b := plot.Bounds()
    x1 := b.Min.X + 10
    x2 := b.Max.X - 10
    y1 := b.Min.Y + 10
    y2 := b.Min.Y + 10 + int((b.Max.Y - b.Min.Y - 10 * (len(samples) + 1)) / len(samples))
    step := y2 - b.Min.Y
    for _, v := range samples {
        plot.DrawSamples(image.Point{x1, y1}, image.Point{x2, y2}, v, col)
        y1 = y1 + step
        y2 = y2 + step
    }
}

func main() {
    dum, _ := dummy.Open("")
    data, stop, _ := dum.StartSampling()

    samples := (<-data).Samples
    fmt.Println(samples)
    stop()

    plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}
    colWhite := color.RGBA{255, 255, 255, 255}
    colRed := color.RGBA{255, 0, 0, 255}
    plot.Fill(colWhite)
    plot.DrawAll(samples, colRed)

    f, err := os.Create("draw.png")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    png.Encode(f, plot)
}
<|endoftext|>


<commit_before>package cors

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/volatile/core"
)

const (
	headerAllowCredentials = "Access-Control-Allow-Credentials"
	headerAllowHeaders     = "Access-Control-Allow-Headers"
	headerAllowMethods     = "Access-Control-Allow-Methods"
	headerAllowOrigin      = "Access-Control-Allow-Origin"
	headerExposeHeaders    = "Access-Control-Expose-Headers"
	headerMaxAge           = "Access-Control-Max-Age"

	headerRequestHeaders = "Access-Control-Request-Headers"
	headerRequestMethod  = "Access-Control-Request-Method"
)

// Options represents access control options.
type Options struct {
	// AllowedHeaders indicates, in the case of a preflight request, which headers can be used during the actual request.
	AllowedHeaders []string
	// AllowedMethods indicates, in the case of a preflight request, which methods can be used during the actual request.
	AllowedMethods []string
	// AllowedOrigins indicates which origins can make a request.
	AllowedOrigins []string
	// CredentialsAllowed indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates.
	CredentialsAllowed bool
	// ExposedHeaders whitelists headers that browsers are allowed to access.
	ExposedHeaders []string
	// MaxAge indicates how long the results of a preflight request can be cached.
	MaxAge time.Duration
}

type formattedOptions struct {
	AllowedHeaders     string
	AllowedMethods     string
	AllowedOrigins     string
	CredentialsAllowed string
	ExposedHeaders     string
	MaxAge             string
}

// Use tells the core to use this handler with the provided options.
func Use(options *Options) {
	fmtOpt := formatCORS(options)
	core.Use(func(c *core.Context) {
		setCORS(c, fmtOpt, func() {
			c.Next()
		})
	})
}

// LocalUse allows to set CORS locally, for a single handler.
// Remember you can't set headers after Write or WriteHeader has been called.
func LocalUse(c *core.Context, options *Options, handler func()) {
	setCORS(c, formatCORS(options), handler)
}

func formatCORS(opt *Options) *formattedOptions {
	if opt == nil {
		opt = new(Options)
	}

	fmtOpt := &formattedOptions{
		AllowedHeaders:     strings.Join(opt.AllowedHeaders, ", "),
		AllowedMethods:     strings.Join(opt.AllowedMethods, ", "),
		CredentialsAllowed: strconv.FormatBool(opt.CredentialsAllowed),
		ExposedHeaders:     strings.Join(opt.ExposedHeaders, ", "),
		MaxAge:             fmt.Sprintf("%.f", opt.MaxAge.Seconds()),
	}

	// If no allowed origins set, all origins are allowed.
	if opt.AllowedOrigins == nil {
		fmtOpt.AllowedOrigins = "*"
	} else {
		fmtOpt.AllowedOrigins = strings.Join(opt.AllowedOrigins, ", ")
	}

	return fmtOpt
}

// setCORS set the response headers and continue if it's not a preflight request.
func setCORS(c *core.Context, fmtOpt *formattedOptions, handler func()) {
	c.ResponseWriter.Header().Set(headerAllowOrigin, fmtOpt.AllowedOrigins)

	if fmtOpt.CredentialsAllowed == "true" {
		c.ResponseWriter.Header().Set(headerAllowCredentials, fmtOpt.CredentialsAllowed)
	}

	if fmtOpt.ExposedHeaders != "" {
		c.ResponseWriter.Header().Set(headerExposeHeaders, fmtOpt.ExposedHeaders)
	}

	if fmtOpt.MaxAge != "0" {
		c.ResponseWriter.Header().Set(headerMaxAge, fmtOpt.MaxAge)
	}

	// OPTIONS is used for preflight requests.
	// For that, only the CORS handler must respond, so the handlers chain is broken.
	if c.Request.Method == "OPTIONS" {
		// If no allowed headers are set, accept all from the real request.
		if fmtOpt.AllowedHeaders == "" {
			c.ResponseWriter.Header().Set(headerAllowHeaders, c.Request.Header.Get(headerRequestHeaders))
		} else {
			c.ResponseWriter.Header().Set(headerAllowHeaders, fmtOpt.AllowedHeaders)
		}

		// If no allowed methods are set, accept the method of the real request.
		if fmtOpt.AllowedMethods == "" {
			c.ResponseWriter.Header().Set(headerAllowMethods, c.Request.Header.Get(headerRequestMethod))
		} else {
			c.ResponseWriter.Header().Set(headerAllowMethods, fmtOpt.AllowedMethods)
		}

		c.ResponseWriter.WriteHeader(http.StatusOK)
	} else {
		handler()
	}
}
<commit_msg>Set Vary Origin if allowed origins specified<commit_after>package cors

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/volatile/core"
)

const (
	headerAllowCredentials = "Access-Control-Allow-Credentials"
	headerAllowHeaders     = "Access-Control-Allow-Headers"
	headerAllowMethods     = "Access-Control-Allow-Methods"
	headerAllowOrigin      = "Access-Control-Allow-Origin"
	headerExposeHeaders    = "Access-Control-Expose-Headers"
	headerMaxAge           = "Access-Control-Max-Age"

	headerRequestHeaders = "Access-Control-Request-Headers"
	headerRequestMethod  = "Access-Control-Request-Method"
)

// Options represents access control options.
type Options struct {
	// AllowedHeaders indicates, in the case of a preflight request, which headers can be used during the actual request.
	AllowedHeaders []string
	// AllowedMethods indicates, in the case of a preflight request, which methods can be used during the actual request.
	AllowedMethods []string
	// AllowedOrigins indicates which origins can make a request.
	AllowedOrigins []string
	// CredentialsAllowed indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates.
	CredentialsAllowed bool
	// ExposedHeaders whitelists headers that browsers are allowed to access.
	ExposedHeaders []string
	// MaxAge indicates how long the results of a preflight request can be cached.
	MaxAge time.Duration
}

type formattedOptions struct {
	AllowedHeaders     string
	AllowedMethods     string
	AllowedOrigins     string
	CredentialsAllowed string
	ExposedHeaders     string
	MaxAge             string
}

// Use tells the core to use this handler with the provided options.
func Use(options *Options) {
	fmtOpt := formatCORS(options)
	core.Use(func(c *core.Context) {
		setCORS(c, fmtOpt, func() {
			c.Next()
		})
	})
}

// LocalUse allows to set CORS locally, for a single handler.
// Remember you can't set headers after Write or WriteHeader has been called.
func LocalUse(c *core.Context, options *Options, handler func()) {
	setCORS(c, formatCORS(options), handler)
}

func formatCORS(opt *Options) *formattedOptions {
	if opt == nil {
		opt = new(Options)
	}

	fmtOpt := &formattedOptions{
		AllowedHeaders:     strings.Join(opt.AllowedHeaders, ", "),
		AllowedMethods:     strings.Join(opt.AllowedMethods, ", "),
		CredentialsAllowed: strconv.FormatBool(opt.CredentialsAllowed),
		ExposedHeaders:     strings.Join(opt.ExposedHeaders, ", "),
		MaxAge:             fmt.Sprintf("%.f", opt.MaxAge.Seconds()),
	}

	// If no allowed origins set, all origins are allowed.
	if opt.AllowedOrigins == nil {
		fmtOpt.AllowedOrigins = "*"
	} else {
		fmtOpt.AllowedOrigins = strings.Join(opt.AllowedOrigins, ", ")
	}

	return fmtOpt
}

// setCORS set the response headers and continue if it's not a preflight request.
func setCORS(c *core.Context, fmtOpt *formattedOptions, handler func()) {
	c.ResponseWriter.Header().Set(headerAllowOrigin, fmtOpt.AllowedOrigins)
	if fmtOpt.AllowedOrigins != "*" {
		c.ResponseWriter.Header().Set("Vary", "Origin")
	}

	if fmtOpt.CredentialsAllowed == "true" {
		c.ResponseWriter.Header().Set(headerAllowCredentials, fmtOpt.CredentialsAllowed)
	}

	if fmtOpt.ExposedHeaders != "" {
		c.ResponseWriter.Header().Set(headerExposeHeaders, fmtOpt.ExposedHeaders)
	}

	if fmtOpt.MaxAge != "0" {
		c.ResponseWriter.Header().Set(headerMaxAge, fmtOpt.MaxAge)
	}

	// OPTIONS is used for preflight requests.
	// For that, only the CORS handler must respond, so the handlers chain is broken.
	if c.Request.Method == "OPTIONS" {
		// If no allowed headers are set, accept all from the real request.
		if fmtOpt.AllowedHeaders == "" {
			c.ResponseWriter.Header().Set(headerAllowHeaders, c.Request.Header.Get(headerRequestHeaders))
		} else {
			c.ResponseWriter.Header().Set(headerAllowHeaders, fmtOpt.AllowedHeaders)
		}

		// If no allowed methods are set, accept the method of the real request.
		if fmtOpt.AllowedMethods == "" {
			c.ResponseWriter.Header().Set(headerAllowMethods, c.Request.Header.Get(headerRequestMethod))
		} else {
			c.ResponseWriter.Header().Set(headerAllowMethods, fmtOpt.AllowedMethods)
		}

		c.ResponseWriter.WriteHeader(http.StatusOK)
	} else {
		handler()
	}
}
<|endoftext|>


<commit_before>package tardeploy

import (
	"fmt"
	"os"

	"path"

	"time"

	"strings"

	"github.com/pkg/errors"
	"github.com/prometheus/log"
)

// to handle gzip: compress/gzip
// to handle  tar: archive/tar

func (configuration *Configuration) SetupApplication(tarball string) error {
	log.Println(fmt.Sprintf("Setup for %s", tarball))

	var (
		application string
		err         error
	)

	if application, err = makeApplication(tarball); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not determine application name for %s", tarball))
	}

	timestamp := time.Now().Format("20060102150405")
	log.Debugf("Using timestamp %s", timestamp)
	versionPath := path.Join(configuration.Directories.ApplicationDirectory, application, timestamp)

	if err := configuration.ensureDirectories(application, versionPath); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not handle directories %s", application))
	}

	if err := configuration.ensureFiles(path.Join(configuration.Directories.TarballDirectory, tarball), versionPath); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not handle files %s", tarball))
	}

	if err := configuration.recreateWebSymbolicLink(application, versionPath); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not handle symbolic link for %s", application))
	}

	// remove directories that are not part of configured backup delay

	return nil
}

func (configuration *Configuration) RemoveApplication(tarball string) error {
	log.Println(fmt.Sprintf("Remove for %s", tarball))

	var (
		application string
		err         error
	)

	if application, err = makeApplication(tarball); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not determine application name for %s", tarball))
	}

	if err := configuration.removeWebSymbolicLink(application); err != nil {
		return err
	}

	return os.RemoveAll(path.Join(configuration.Directories.ApplicationDirectory, application))
}

// helper

func makeApplication(tarball string) (string, error) {
	if !strings.HasSuffix(tarball, ".tgz") && !strings.HasSuffix(tarball, ".tar.gz") {
		return "", errors.New("Only tar.gz or tgz allowed")
	}

	if strings.HasSuffix(tarball, ".tar.gz") {
		if len(tarball) == 7 {
			return "", errors.New("Expected at least one character as application name")
		}
		return tarball[0 : len(tarball)-7], nil
	}

	if len(tarball) == 4 {
		return "", errors.New("Expected at least one character as application name")
	}

	return tarball[0 : len(tarball)-4], nil
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}
<commit_msg>Call trigger methods<commit_after>package tardeploy

import (
	"fmt"
	"os"

	"path"

	"time"

	"strings"

	"github.com/pkg/errors"
	"github.com/prometheus/log"
)

// to handle gzip: compress/gzip
// to handle  tar: archive/tar

func (configuration *Configuration) SetupApplication(tarball string) error {
	log.Println(fmt.Sprintf("Setup for %s", tarball))

	var (
		application string
		err         error
	)

	if application, err = makeApplication(tarball); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not determine application name for %s", tarball))
	}

	if err := configuration.beforeRunTrigger(application); err != nil {
		return errors.Wrap(err, "Could not run trigger")
	}
	defer func() {
		if err := configuration.beforeRunTrigger(application); err != nil {
			log.Warnf("Could not run after trigger: %s", err.Error())
		}
	}()

	timestamp := time.Now().Format("20060102150405")
	log.Debugf("Using timestamp %s", timestamp)
	versionPath := path.Join(configuration.Directories.ApplicationDirectory, application, timestamp)

	if err := configuration.ensureDirectories(application, versionPath); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not handle directories %s", application))
	}

	if err := configuration.ensureFiles(path.Join(configuration.Directories.TarballDirectory, tarball), versionPath); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not handle files %s", tarball))
	}

	if err := configuration.recreateWebSymbolicLink(application, versionPath); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not handle symbolic link for %s", application))
	}

	// remove directories that are not part of configured backup delay

	return nil
}

func (configuration *Configuration) RemoveApplication(tarball string) error {
	log.Println(fmt.Sprintf("Remove for %s", tarball))

	var (
		application string
		err         error
	)

	if application, err = makeApplication(tarball); err != nil {
		return errors.Wrap(err, fmt.Sprintf("Could not determine application name for %s", tarball))
	}

	if err := configuration.removeWebSymbolicLink(application); err != nil {
		return err
	}

	return os.RemoveAll(path.Join(configuration.Directories.ApplicationDirectory, application))
}

// helper

func makeApplication(tarball string) (string, error) {
	if !strings.HasSuffix(tarball, ".tgz") && !strings.HasSuffix(tarball, ".tar.gz") {
		return "", errors.New("Only tar.gz or tgz allowed")
	}

	if strings.HasSuffix(tarball, ".tar.gz") {
		if len(tarball) == 7 {
			return "", errors.New("Expected at least one character as application name")
		}
		return tarball[0 : len(tarball)-7], nil
	}

	if len(tarball) == 4 {
		return "", errors.New("Expected at least one character as application name")
	}

	return tarball[0 : len(tarball)-4], nil
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}
<|endoftext|>


<commit_before>package chromedp

import (
	"context"
	"encoding/json"
	"sync"
	"sync/atomic"
	"time"

	"github.com/mailru/easyjson"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/dom"
	"github.com/chromedp/cdproto/inspector"
	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/cdproto/target"
)

// Target manages a Chrome DevTools Protocol target.
type Target struct {
	browser   *Browser
	sessionID target.SessionID

	waitQueue  chan func(cur *cdp.Frame) bool
	eventQueue chan *cdproto.Message

	// below are the old TargetHandler fields.

	// frames is the set of encountered frames.
	frames map[cdp.FrameID]*cdp.Frame

	// cur is the current top level frame. TODO: delete mutex
	curMu sync.RWMutex
	cur   *cdp.Frame

	// logging funcs
	logf, errf func(string, ...interface{})
}

func (t *Target) run(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		case msg := <-t.eventQueue:
			//fmt.Printf("%d %s: %s\n", msg.ID, msg.Method, msg.Params)
			if err := t.processEvent(ctx, msg); err != nil {
				t.errf("could not process event: %v", err)
				continue
			}
		default:
			// prevent busy spinning. TODO: do better
			time.Sleep(5 * time.Millisecond)
			n := len(t.waitQueue)
			if n == 0 {
				continue
			}

			t.curMu.RLock()
			cur := t.cur
			t.curMu.RUnlock()
			if cur == nil {
				continue
			}

			for i := 0; i < n; i++ {
				fn := <-t.waitQueue
				if !fn(cur) {
					// try again later.
					t.waitQueue <- fn
				}
			}
		}
	}
}

func (t *Target) Execute(ctx context.Context, method string, params json.Marshaler, res json.Unmarshaler) error {
	paramsMsg := emptyObj
	if params != nil {
		var err error
		if paramsMsg, err = json.Marshal(params); err != nil {
			return err
		}
	}
	innerID := atomic.AddInt64(&t.browser.next, 1)
	msg := &cdproto.Message{
		ID:     innerID,
		Method: cdproto.MethodType(method),
		Params: paramsMsg,
	}
	msgJSON, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	sendParams := target.SendMessageToTarget(string(msgJSON)).
		WithSessionID(t.sessionID)
	sendParamsJSON, _ := json.Marshal(sendParams)

	// We want to grab the response from the inner message.
	ch := make(chan *cdproto.Message, 1)
	t.browser.cmdQueue <- cmdJob{
		msg:  &cdproto.Message{ID: innerID},
		resp: ch,
	}

	// The response from the outer message is uninteresting; pass a nil
	// resp channel.
	outerID := atomic.AddInt64(&t.browser.next, 1)
	t.browser.cmdQueue <- cmdJob{
		msg: &cdproto.Message{
			ID:     outerID,
			Method: target.CommandSendMessageToTarget,
			Params: sendParamsJSON,
		},
	}

	select {
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return json.Unmarshal(msg.Result, res)
		}
	case <-ctx.Done():
		return ctx.Err()
	}
	return nil
}

// below are the old TargetHandler methods.

// processEvent processes an incoming event.
func (t *Target) processEvent(ctxt context.Context, msg *cdproto.Message) error {
	if msg == nil {
		return ErrChannelClosed
	}
	switch msg.Method {
	case "Page.frameClearedScheduledNavigation",
		"Page.frameScheduledNavigation":
		// These events are now deprecated, and UnmarshalMessage panics
		// when they are received from Chrome. For now, to avoid panics
		// and compile errors, and to fix chromedp v0 when installed via
		// 'go get -u', skip the events here.
		return nil
	}

	// unmarshal
	ev, err := cdproto.UnmarshalMessage(msg)
	if err != nil {
		return err
	}

	switch ev.(type) {
	case *inspector.EventDetached:
		return nil
	case *dom.EventDocumentUpdated:
		t.documentUpdated(ctxt)
		return nil
	}

	switch msg.Method.Domain() {
	case "Page":
		t.pageEvent(ctxt, ev)
	case "DOM":
		t.domEvent(ctxt, ev)
	}
	return nil
}

// documentUpdated handles the document updated event, retrieving the document
// root for the root frame.
func (t *Target) documentUpdated(ctxt context.Context) {
	t.curMu.RLock()
	f := t.cur
	t.curMu.RUnlock()
	f.Lock()
	defer f.Unlock()

	// invalidate nodes
	if f.Root != nil {
		close(f.Root.Invalidated)
	}

	f.Nodes = make(map[cdp.NodeID]*cdp.Node)
	var err error
	f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, t)
	if err == context.Canceled {
		return // TODO: perhaps not necessary, but useful to keep the tests less noisy
	}
	if err != nil {
		t.errf("could not retrieve document root for %s: %v", f.ID, err)
		return
	}
	f.Root.Invalidated = make(chan struct{})
	walk(f.Nodes, f.Root)
}

// emptyObj is an empty JSON object message.
var emptyObj = easyjson.RawMessage([]byte(`{}`))

// pageEvent handles incoming page events.
func (t *Target) pageEvent(ctxt context.Context, ev interface{}) {
	var id cdp.FrameID
	var op frameOp

	switch e := ev.(type) {
	case *page.EventFrameNavigated:
		t.frames[e.Frame.ID] = e.Frame
		t.curMu.Lock()
		t.cur = e.Frame
		t.curMu.Unlock()
		return

	case *page.EventFrameAttached:
		id, op = e.FrameID, frameAttached(e.ParentFrameID)

	case *page.EventFrameDetached:
		id, op = e.FrameID, frameDetached

	case *page.EventFrameStartedLoading:
		// TODO: this happens before EventFrameNavigated, so the frame
		// isn't in t.frames yet.
		//id, op = e.FrameID, frameStartedLoading
		return

	case *page.EventFrameStoppedLoading:
		id, op = e.FrameID, frameStoppedLoading

		// ignored events
	case *page.EventFrameRequestedNavigation:
		return
	case *page.EventDomContentEventFired:
		return
	case *page.EventLoadEventFired:
		return
	case *page.EventFrameResized:
		return
	case *page.EventLifecycleEvent:
		return

	default:
		t.errf("unhandled page event %T", ev)
		return
	}

	f := t.frames[id]

	f.Lock()
	defer f.Unlock()

	op(f)
}

// domEvent handles incoming DOM events.
func (t *Target) domEvent(ctxt context.Context, ev interface{}) {
	t.curMu.RLock()
	f := t.cur
	t.curMu.RUnlock()

	var id cdp.NodeID
	var op nodeOp

	switch e := ev.(type) {
	case *dom.EventSetChildNodes:
		id, op = e.ParentID, setChildNodes(f.Nodes, e.Nodes)

	case *dom.EventAttributeModified:
		id, op = e.NodeID, attributeModified(e.Name, e.Value)

	case *dom.EventAttributeRemoved:
		id, op = e.NodeID, attributeRemoved(e.Name)

	case *dom.EventInlineStyleInvalidated:
		if len(e.NodeIds) == 0 {
			return
		}

		id, op = e.NodeIds[0], inlineStyleInvalidated(e.NodeIds[1:])

	case *dom.EventCharacterDataModified:
		id, op = e.NodeID, characterDataModified(e.CharacterData)

	case *dom.EventChildNodeCountUpdated:
		id, op = e.NodeID, childNodeCountUpdated(e.ChildNodeCount)

	case *dom.EventChildNodeInserted:
		id, op = e.ParentNodeID, childNodeInserted(f.Nodes, e.PreviousNodeID, e.Node)

	case *dom.EventChildNodeRemoved:
		id, op = e.ParentNodeID, childNodeRemoved(f.Nodes, e.NodeID)

	case *dom.EventShadowRootPushed:
		id, op = e.HostID, shadowRootPushed(f.Nodes, e.Root)

	case *dom.EventShadowRootPopped:
		id, op = e.HostID, shadowRootPopped(f.Nodes, e.RootID)

	case *dom.EventPseudoElementAdded:
		id, op = e.ParentID, pseudoElementAdded(f.Nodes, e.PseudoElement)

	case *dom.EventPseudoElementRemoved:
		id, op = e.ParentID, pseudoElementRemoved(f.Nodes, e.PseudoElementID)

	case *dom.EventDistributedNodesUpdated:
		id, op = e.InsertionPointID, distributedNodesUpdated(e.DistributedNodes)

	default:
		t.errf("unhandled node event %T", ev)
		return
	}

	n, ok := f.Nodes[id]
	if !ok {
		// Node ID has been invalidated. Nothing to do.
		return
	}

	f.Lock()
	defer f.Unlock()

	op(n)
}

type TargetOption func(*Target)
<commit_msg>remove top level frame mutex from Target<commit_after>package chromedp

import (
	"context"
	"encoding/json"
	"sync/atomic"
	"time"

	"github.com/mailru/easyjson"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/dom"
	"github.com/chromedp/cdproto/inspector"
	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/cdproto/target"
)

// Target manages a Chrome DevTools Protocol target.
type Target struct {
	browser   *Browser
	sessionID target.SessionID

	waitQueue  chan func(cur *cdp.Frame) bool
	eventQueue chan *cdproto.Message

	// below are the old TargetHandler fields.

	// frames is the set of encountered frames.
	frames map[cdp.FrameID]*cdp.Frame

	// cur is the current top level frame.
	cur *cdp.Frame

	// logging funcs
	logf, errf func(string, ...interface{})
}

func (t *Target) run(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		case msg := <-t.eventQueue:
			if err := t.processEvent(ctx, msg); err != nil {
				t.errf("could not process event: %v", err)
				continue
			}
		default:
			// prevent busy spinning. TODO: do better
			time.Sleep(5 * time.Millisecond)
			n := len(t.waitQueue)
			if n == 0 {
				continue
			}
			if t.cur == nil {
				continue
			}

			for i := 0; i < n; i++ {
				fn := <-t.waitQueue
				if !fn(t.cur) {
					// try again later.
					t.waitQueue <- fn
				}
			}
		}
	}
}

func (t *Target) Execute(ctx context.Context, method string, params json.Marshaler, res json.Unmarshaler) error {
	paramsMsg := emptyObj
	if params != nil {
		var err error
		if paramsMsg, err = json.Marshal(params); err != nil {
			return err
		}
	}
	innerID := atomic.AddInt64(&t.browser.next, 1)
	msg := &cdproto.Message{
		ID:     innerID,
		Method: cdproto.MethodType(method),
		Params: paramsMsg,
	}
	msgJSON, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	sendParams := target.SendMessageToTarget(string(msgJSON)).
		WithSessionID(t.sessionID)
	sendParamsJSON, _ := json.Marshal(sendParams)

	// We want to grab the response from the inner message.
	ch := make(chan *cdproto.Message, 1)
	t.browser.cmdQueue <- cmdJob{
		msg:  &cdproto.Message{ID: innerID},
		resp: ch,
	}

	// The response from the outer message is uninteresting; pass a nil
	// resp channel.
	outerID := atomic.AddInt64(&t.browser.next, 1)
	t.browser.cmdQueue <- cmdJob{
		msg: &cdproto.Message{
			ID:     outerID,
			Method: target.CommandSendMessageToTarget,
			Params: sendParamsJSON,
		},
	}

	select {
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return json.Unmarshal(msg.Result, res)
		}
	case <-ctx.Done():
		return ctx.Err()
	}
	return nil
}

// below are the old TargetHandler methods.

// processEvent processes an incoming event.
func (t *Target) processEvent(ctxt context.Context, msg *cdproto.Message) error {
	if msg == nil {
		return ErrChannelClosed
	}
	switch msg.Method {
	case "Page.frameClearedScheduledNavigation",
		"Page.frameScheduledNavigation":
		// These events are now deprecated, and UnmarshalMessage panics
		// when they are received from Chrome. For now, to avoid panics
		// and compile errors, and to fix chromedp v0 when installed via
		// 'go get -u', skip the events here.
		return nil
	}

	// unmarshal
	ev, err := cdproto.UnmarshalMessage(msg)
	if err != nil {
		return err
	}

	switch ev.(type) {
	case *inspector.EventDetached:
		return nil
	case *dom.EventDocumentUpdated:
		t.documentUpdated(ctxt)
		return nil
	}

	switch msg.Method.Domain() {
	case "Page":
		t.pageEvent(ctxt, ev)
	case "DOM":
		t.domEvent(ctxt, ev)
	}
	return nil
}

// documentUpdated handles the document updated event, retrieving the document
// root for the root frame.
func (t *Target) documentUpdated(ctxt context.Context) {
	f := t.cur
	f.Lock()
	defer f.Unlock()

	// invalidate nodes
	if f.Root != nil {
		close(f.Root.Invalidated)
	}

	f.Nodes = make(map[cdp.NodeID]*cdp.Node)
	var err error
	f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, t)
	if err == context.Canceled {
		return // TODO: perhaps not necessary, but useful to keep the tests less noisy
	}
	if err != nil {
		t.errf("could not retrieve document root for %s: %v", f.ID, err)
		return
	}
	f.Root.Invalidated = make(chan struct{})
	walk(f.Nodes, f.Root)
}

// emptyObj is an empty JSON object message.
var emptyObj = easyjson.RawMessage([]byte(`{}`))

// pageEvent handles incoming page events.
func (t *Target) pageEvent(ctxt context.Context, ev interface{}) {
	var id cdp.FrameID
	var op frameOp

	switch e := ev.(type) {
	case *page.EventFrameNavigated:
		t.frames[e.Frame.ID] = e.Frame
		t.cur = e.Frame
		return

	case *page.EventFrameAttached:
		id, op = e.FrameID, frameAttached(e.ParentFrameID)

	case *page.EventFrameDetached:
		id, op = e.FrameID, frameDetached

	case *page.EventFrameStartedLoading:
		// TODO: this happens before EventFrameNavigated, so the frame
		// isn't in t.frames yet.
		//id, op = e.FrameID, frameStartedLoading
		return

	case *page.EventFrameStoppedLoading:
		id, op = e.FrameID, frameStoppedLoading

		// ignored events
	case *page.EventFrameRequestedNavigation:
		return
	case *page.EventDomContentEventFired:
		return
	case *page.EventLoadEventFired:
		return
	case *page.EventFrameResized:
		return
	case *page.EventLifecycleEvent:
		return

	default:
		t.errf("unhandled page event %T", ev)
		return
	}

	f := t.frames[id]

	f.Lock()
	defer f.Unlock()

	op(f)
}

// domEvent handles incoming DOM events.
func (t *Target) domEvent(ctxt context.Context, ev interface{}) {
	f := t.cur

	var id cdp.NodeID
	var op nodeOp

	switch e := ev.(type) {
	case *dom.EventSetChildNodes:
		id, op = e.ParentID, setChildNodes(f.Nodes, e.Nodes)

	case *dom.EventAttributeModified:
		id, op = e.NodeID, attributeModified(e.Name, e.Value)

	case *dom.EventAttributeRemoved:
		id, op = e.NodeID, attributeRemoved(e.Name)

	case *dom.EventInlineStyleInvalidated:
		if len(e.NodeIds) == 0 {
			return
		}

		id, op = e.NodeIds[0], inlineStyleInvalidated(e.NodeIds[1:])

	case *dom.EventCharacterDataModified:
		id, op = e.NodeID, characterDataModified(e.CharacterData)

	case *dom.EventChildNodeCountUpdated:
		id, op = e.NodeID, childNodeCountUpdated(e.ChildNodeCount)

	case *dom.EventChildNodeInserted:
		id, op = e.ParentNodeID, childNodeInserted(f.Nodes, e.PreviousNodeID, e.Node)

	case *dom.EventChildNodeRemoved:
		id, op = e.ParentNodeID, childNodeRemoved(f.Nodes, e.NodeID)

	case *dom.EventShadowRootPushed:
		id, op = e.HostID, shadowRootPushed(f.Nodes, e.Root)

	case *dom.EventShadowRootPopped:
		id, op = e.HostID, shadowRootPopped(f.Nodes, e.RootID)

	case *dom.EventPseudoElementAdded:
		id, op = e.ParentID, pseudoElementAdded(f.Nodes, e.PseudoElement)

	case *dom.EventPseudoElementRemoved:
		id, op = e.ParentID, pseudoElementRemoved(f.Nodes, e.PseudoElementID)

	case *dom.EventDistributedNodesUpdated:
		id, op = e.InsertionPointID, distributedNodesUpdated(e.DistributedNodes)

	default:
		t.errf("unhandled node event %T", ev)
		return
	}

	n, ok := f.Nodes[id]
	if !ok {
		// Node ID has been invalidated. Nothing to do.
		return
	}

	f.Lock()
	defer f.Unlock()

	op(n)
}

type TargetOption func(*Target)
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Julien Vehent jvehent@mozilla.com [:ulfr]

package database /* import "mig.ninja/mig/database" */

import (
	"database/sql"
	"fmt"
	"time"

	_ "github.com/lib/pq"
	"mig.ninja/mig"
)

// ActiveInvestigators returns a slice of investigators keys marked as active
func (db *DB) ActiveInvestigatorsKeys() (keys [][]byte, err error) {
	rows, err := db.c.Query("SELECT publickey FROM investigators WHERE status='active'")
	if rows != nil {
		defer rows.Close()
	}
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while listing active investigators keys: '%v'", err)
		return
	}
	if err == sql.ErrNoRows { // having an empty DB is not an issue
		return
	}
	for rows.Next() {
		var key []byte
		err = rows.Scan(&key)
		if err != nil {
			err = fmt.Errorf("Error while retrieving investigator key: '%v'", err)
			return
		}
		keys = append(keys, key)
	}
	if err := rows.Err(); err != nil {
		err = fmt.Errorf("Failed to complete active investigators query: '%v'", err)
	}
	return
}

// InvestigatorByID searches the database for an investigator with a given ID
func (db *DB) InvestigatorByID(iid float64) (inv mig.Investigator, err error) {
	err = db.c.QueryRow("SELECT id, name, pgpfingerprint, publickey, status, createdat, lastmodified FROM investigators WHERE id=$1",
		iid).Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.PublicKey, &inv.Status, &inv.CreatedAt, &inv.LastModified)
	if err != nil {
		err = fmt.Errorf("Error while retrieving investigator: '%v'", err)
		return
	}
	if err == sql.ErrNoRows {
		return
	}
	return
}

// InvestigatorByFingerprint searches the database for an investigator that
// has a given fingerprint
func (db *DB) InvestigatorByFingerprint(fp string) (inv mig.Investigator, err error) {
	err = db.c.QueryRow(`SELECT investigators.id, investigators.name, investigators.pgpfingerprint,
		investigators.publickey, investigators.status, investigators.createdat, investigators.lastmodified,
		investigators.isadmin FROM investigators WHERE LOWER(pgpfingerprint)=LOWER($1)`,
		fp).Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.PublicKey, &inv.Status,
		&inv.CreatedAt, &inv.LastModified, &inv.IsAdmin)
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while finding investigator: '%v'", err)
		return
	}
	if err == sql.ErrNoRows {
		err = fmt.Errorf("InvestigatorByFingerprint: no investigator found for fingerprint '%s'", fp)
		return
	}
	return
}

//InvestigatorByActionID returns the list of investigators that signed a given action
func (db *DB) InvestigatorByActionID(aid float64) (invs []mig.Investigator, err error) {
	rows, err := db.c.Query(`SELECT investigators.id, investigators.name, investigators.pgpfingerprint,
		investigators.status, investigators.createdat, investigators.lastmodified
		FROM investigators, signatures
		WHERE signatures.actionid=$1
		AND signatures.investigatorid=investigators.id`, aid)
	if rows != nil {
		defer rows.Close()
	}
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while finding investigator: '%v'", err)
		return
	}
	for rows.Next() {
		var inv mig.Investigator
		err = rows.Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.Status, &inv.CreatedAt, &inv.LastModified)
		if err != nil {
			err = fmt.Errorf("Failed to retrieve investigator data: '%v'", err)
			return
		}
		invs = append(invs, inv)
	}
	if err := rows.Err(); err != nil {
		err = fmt.Errorf("Failed to complete database query: '%v'", err)
	}
	return
}

// InsertInvestigator creates a new investigator in the database and returns its ID,
// or an error if the insertion failed, or if the investigator already exists
func (db *DB) InsertInvestigator(inv mig.Investigator) (iid float64, err error) {
	_, err = db.c.Exec(`INSERT INTO investigators
		(name, pgpfingerprint, publickey, status, createdat, lastmodified)
		VALUES ($1, $2, $3, 'active', $4, $5)`,
		inv.Name, inv.PGPFingerprint, inv.PublicKey, time.Now().UTC(), time.Now().UTC())
	if err != nil {
		if err.Error() == `pq: duplicate key value violates unique constraint "investigators_pgpfingerprint_idx"` {
			return iid, fmt.Errorf("Investigator's PGP Fingerprint already exists in database")
		}
		return iid, fmt.Errorf("Failed to create investigator: '%v'", err)
	}
	inv, err = db.InvestigatorByFingerprint(inv.PGPFingerprint)
	if err != nil {
		return 0, fmt.Errorf("Failed to retrieve investigator ID: '%v'", err)
	}
	iid = inv.ID
	return
}

// InsertSchedulerInvestigator creates a new migscheduler investigator in the database
// and returns its ID, or an error if the insertion failed, or if the investigator already exists
func (db *DB) InsertSchedulerInvestigator(inv mig.Investigator) (iid float64, err error) {
	_, err = db.c.Exec(`INSERT INTO investigators
		(name, pgpfingerprint, publickey, privatekey, status, createdat, lastmodified)
		VALUES ($1, $2, $3, $4, 'active', $5, $6)`,
		inv.Name, inv.PGPFingerprint, inv.PublicKey, inv.PrivateKey, time.Now().UTC(), time.Now().UTC())
	if err != nil {
		if err.Error() == `pq: duplicate key value violates unique constraint "investigators_pgpfingerprint_idx"` {
			return iid, fmt.Errorf("Investigator's PGP Fingerprint already exists in database")
		}
		return iid, fmt.Errorf("Failed to create investigator: '%v'", err)
	}
	inv, err = db.InvestigatorByFingerprint(inv.PGPFingerprint)
	if err != nil {
		return 0, fmt.Errorf("Failed to retrieve investigator ID: '%v'", err)
	}
	iid = inv.ID
	return
}

// UpdateInvestigatorStatus updates the status of an investigator
func (db *DB) UpdateInvestigatorStatus(inv mig.Investigator) (err error) {
	if inv.Status != mig.StatusActiveInvestigator && inv.Status != mig.StatusDisabledInvestigator {
		return fmt.Errorf("Invalid investigator status '%s'", inv.Status)
	}
	_, err = db.c.Exec(`UPDATE investigators SET (status) = ($1) WHERE id=$2`,
		inv.Status, inv.ID)
	if err != nil {
		return fmt.Errorf("Failed to update investigator: '%v'", err)
	}
	return
}

// GetSchedulerPrivKey returns the first active private key found for user migscheduler
func (db *DB) GetSchedulerPrivKey() (key []byte, err error) {
	err = db.c.QueryRow(`SELECT privatekey FROM investigators
		WHERE name ='migscheduler' AND status='active'
		ORDER BY id ASC LIMIT 1`).Scan(&key)
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while retrieving scheduler private key: '%v'", err)
		return
	}
	if err == sql.ErrNoRows { // having an empty DB is not an issue
		err = fmt.Errorf("no private key found for migscheduler")
		return
	}
	return
}

// GetSchedulerInvestigator returns the first active scheduler investigator
func (db *DB) GetSchedulerInvestigator() (inv mig.Investigator, err error) {
	err = db.c.QueryRow(`SELECT id, name, pgpfingerprint, publickey, status, createdat, lastmodified
		FROM investigators WHERE name ='migscheduler' AND status='active' ORDER BY id ASC LIMIT 1`,
	).Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.PublicKey, &inv.Status, &inv.CreatedAt, &inv.LastModified)
	if err != nil {
		err = fmt.Errorf("Error while retrieving scheduler investigator: '%v'", err)
		return
	}
	if err == sql.ErrNoRows {
		return
	}
	return
}
<commit_msg>[minor] populate IsAdmin for various other investigator queries<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Julien Vehent jvehent@mozilla.com [:ulfr]

package database /* import "mig.ninja/mig/database" */

import (
	"database/sql"
	"fmt"
	"time"

	_ "github.com/lib/pq"
	"mig.ninja/mig"
)

// ActiveInvestigators returns a slice of investigators keys marked as active
func (db *DB) ActiveInvestigatorsKeys() (keys [][]byte, err error) {
	rows, err := db.c.Query("SELECT publickey FROM investigators WHERE status='active'")
	if rows != nil {
		defer rows.Close()
	}
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while listing active investigators keys: '%v'", err)
		return
	}
	if err == sql.ErrNoRows { // having an empty DB is not an issue
		return
	}
	for rows.Next() {
		var key []byte
		err = rows.Scan(&key)
		if err != nil {
			err = fmt.Errorf("Error while retrieving investigator key: '%v'", err)
			return
		}
		keys = append(keys, key)
	}
	if err := rows.Err(); err != nil {
		err = fmt.Errorf("Failed to complete active investigators query: '%v'", err)
	}
	return
}

// InvestigatorByID searches the database for an investigator with a given ID
func (db *DB) InvestigatorByID(iid float64) (inv mig.Investigator, err error) {
	err = db.c.QueryRow(`SELECT id, name, pgpfingerprint, publickey, status,
		createdat, lastmodified, isadmin FROM investigators WHERE id=$1`,
		iid).Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.PublicKey,
		&inv.Status, &inv.CreatedAt, &inv.LastModified, &inv.IsAdmin)
	if err != nil {
		err = fmt.Errorf("Error while retrieving investigator: '%v'", err)
		return
	}
	if err == sql.ErrNoRows {
		return
	}
	return
}

// InvestigatorByFingerprint searches the database for an investigator that
// has a given fingerprint
func (db *DB) InvestigatorByFingerprint(fp string) (inv mig.Investigator, err error) {
	err = db.c.QueryRow(`SELECT investigators.id, investigators.name, investigators.pgpfingerprint,
		investigators.publickey, investigators.status, investigators.createdat,
		investigators.lastmodified, investigators.isadmin
		FROM investigators WHERE LOWER(pgpfingerprint)=LOWER($1)`,
		fp).Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.PublicKey, &inv.Status,
		&inv.CreatedAt, &inv.LastModified, &inv.IsAdmin)
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while finding investigator: '%v'", err)
		return
	}
	if err == sql.ErrNoRows {
		err = fmt.Errorf("InvestigatorByFingerprint: no investigator found for fingerprint '%s'", fp)
		return
	}
	return
}

//InvestigatorByActionID returns the list of investigators that signed a given action
func (db *DB) InvestigatorByActionID(aid float64) (invs []mig.Investigator, err error) {
	rows, err := db.c.Query(`SELECT investigators.id, investigators.name, investigators.pgpfingerprint,
		investigators.status, investigators.createdat, investigators.lastmodified,
		investigators.isadmin
		FROM investigators, signatures
		WHERE signatures.actionid=$1
		AND signatures.investigatorid=investigators.id`, aid)
	if rows != nil {
		defer rows.Close()
	}
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while finding investigator: '%v'", err)
		return
	}
	for rows.Next() {
		var inv mig.Investigator
		err = rows.Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.Status, &inv.CreatedAt, &inv.LastModified, &inv.IsAdmin)
		if err != nil {
			err = fmt.Errorf("Failed to retrieve investigator data: '%v'", err)
			return
		}
		invs = append(invs, inv)
	}
	if err := rows.Err(); err != nil {
		err = fmt.Errorf("Failed to complete database query: '%v'", err)
	}
	return
}

// InsertInvestigator creates a new investigator in the database and returns its ID,
// or an error if the insertion failed, or if the investigator already exists
func (db *DB) InsertInvestigator(inv mig.Investigator) (iid float64, err error) {
	_, err = db.c.Exec(`INSERT INTO investigators
		(name, pgpfingerprint, publickey, status, createdat, lastmodified)
		VALUES ($1, $2, $3, 'active', $4, $5)`,
		inv.Name, inv.PGPFingerprint, inv.PublicKey, time.Now().UTC(), time.Now().UTC())
	if err != nil {
		if err.Error() == `pq: duplicate key value violates unique constraint "investigators_pgpfingerprint_idx"` {
			return iid, fmt.Errorf("Investigator's PGP Fingerprint already exists in database")
		}
		return iid, fmt.Errorf("Failed to create investigator: '%v'", err)
	}
	inv, err = db.InvestigatorByFingerprint(inv.PGPFingerprint)
	if err != nil {
		return 0, fmt.Errorf("Failed to retrieve investigator ID: '%v'", err)
	}
	iid = inv.ID
	return
}

// InsertSchedulerInvestigator creates a new migscheduler investigator in the database
// and returns its ID, or an error if the insertion failed, or if the investigator already exists
func (db *DB) InsertSchedulerInvestigator(inv mig.Investigator) (iid float64, err error) {
	_, err = db.c.Exec(`INSERT INTO investigators
		(name, pgpfingerprint, publickey, privatekey, status, createdat, lastmodified)
		VALUES ($1, $2, $3, $4, 'active', $5, $6)`,
		inv.Name, inv.PGPFingerprint, inv.PublicKey, inv.PrivateKey, time.Now().UTC(), time.Now().UTC())
	if err != nil {
		if err.Error() == `pq: duplicate key value violates unique constraint "investigators_pgpfingerprint_idx"` {
			return iid, fmt.Errorf("Investigator's PGP Fingerprint already exists in database")
		}
		return iid, fmt.Errorf("Failed to create investigator: '%v'", err)
	}
	inv, err = db.InvestigatorByFingerprint(inv.PGPFingerprint)
	if err != nil {
		return 0, fmt.Errorf("Failed to retrieve investigator ID: '%v'", err)
	}
	iid = inv.ID
	return
}

// UpdateInvestigatorStatus updates the status of an investigator
func (db *DB) UpdateInvestigatorStatus(inv mig.Investigator) (err error) {
	if inv.Status != mig.StatusActiveInvestigator && inv.Status != mig.StatusDisabledInvestigator {
		return fmt.Errorf("Invalid investigator status '%s'", inv.Status)
	}
	_, err = db.c.Exec(`UPDATE investigators SET (status) = ($1) WHERE id=$2`,
		inv.Status, inv.ID)
	if err != nil {
		return fmt.Errorf("Failed to update investigator: '%v'", err)
	}
	return
}

// GetSchedulerPrivKey returns the first active private key found for user migscheduler
func (db *DB) GetSchedulerPrivKey() (key []byte, err error) {
	err = db.c.QueryRow(`SELECT privatekey FROM investigators
		WHERE name ='migscheduler' AND status='active'
		ORDER BY id ASC LIMIT 1`).Scan(&key)
	if err != nil && err != sql.ErrNoRows {
		err = fmt.Errorf("Error while retrieving scheduler private key: '%v'", err)
		return
	}
	if err == sql.ErrNoRows { // having an empty DB is not an issue
		err = fmt.Errorf("no private key found for migscheduler")
		return
	}
	return
}

// GetSchedulerInvestigator returns the first active scheduler investigator
func (db *DB) GetSchedulerInvestigator() (inv mig.Investigator, err error) {
	err = db.c.QueryRow(`SELECT id, name, pgpfingerprint, publickey, status, createdat, lastmodified
		FROM investigators WHERE name ='migscheduler' AND status='active' ORDER BY id ASC LIMIT 1`,
	).Scan(&inv.ID, &inv.Name, &inv.PGPFingerprint, &inv.PublicKey, &inv.Status, &inv.CreatedAt, &inv.LastModified)
	if err != nil {
		err = fmt.Errorf("Error while retrieving scheduler investigator: '%v'", err)
		return
	}
	if err == sql.ErrNoRows {
		return
	}
	return
}
<|endoftext|>


<commit_before><commit_msg>            cmd/go: build: print import errors when invoked on files<commit_after><|endoftext|>


<commit_before>package summary

import (
	"strings"
)

// taken from golang.org/x/text/collate/sort_test.go, implements collate's Lister interface
type stringList []string

func (s stringList) Append(str string) stringList {
	return append(s, str)
}

func (s stringList) Len() int {
	return len(s)
}

func (s stringList) Swap(i, j int) {
	s[j], s[i] = s[i], s[j]
}

func (s stringList) Bytes(i int) []byte {
	return []byte(s[i])
}

func (s stringList) Join(sep string) string {
	return strings.Join(s, sep)
}

func (s stringList) JoinBytes(sep string) []byte {
	return []byte(s.Join(sep))
}
<commit_msg>documentation<commit_after>package summary

import (
	"strings"
)

// A list of strings that might be swapped, accessed by index, and joined alltogether.
// Taken from golang.org/x/text/collate/sort_test.go, implements collate's Lister interface
type stringList []string

func (s stringList) Append(str string) stringList {
	return append(s, str)
}

func (s stringList) Len() int {
	return len(s)
}

func (s stringList) Swap(i, j int) {
	s[j], s[i] = s[i], s[j]
}

func (s stringList) Bytes(i int) []byte {
	return []byte(s[i])
}

// Joins all the strings in this stringList, separating each by the given separator.
func (s stringList) Join(sep string) string {
	return strings.Join(s, sep)
}

// Returns the result of Join(sep) as []byte.
func (s stringList) JoinBytes(sep string) []byte {
	return []byte(s.Join(sep))
}
<|endoftext|>


<commit_before>/*
 *  FillPDF - Fill PDF forms
 *  Copyright DesertBit
 *  Author: Roland Singer
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package fillpdf

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
)

// Form represents the PDF form.
// This is a key value map.
type Form map[string]interface{}

// Fill a PDF form with the specified form values and create a final filled PDF file.
// One variadic boolean specifies, whenever to overwrite the destination file if it exists.
func Fill(form Form, formPDFFile, destPDFFile string, overwrite ...bool) (err error) {
	// Get the absolute paths.
	formPDFFile, err = filepath.Abs(formPDFFile)
	if err != nil {
		return fmt.Errorf("failed to create the absolute path: %v", err)
	}
	destPDFFile, err = filepath.Abs(destPDFFile)
	if err != nil {
		return fmt.Errorf("failed to create the absolute path: %v", err)
	}

	// Check if the form file exists.
	e, err := exists(formPDFFile)
	if err != nil {
		return fmt.Errorf("failed to check if form PDF file exists: %v", err)
	} else if !e {
		return fmt.Errorf("form PDF file does not exists: '%s'", formPDFFile)
	}

	// Check if the pdftk utility exists.
	_, err = exec.LookPath("pdftk")
	if err != nil {
		return fmt.Errorf("pdftk utility is not installed!")
	}

	// Create a temporary directory.
	tmpDir, err := ioutil.TempDir("", "fillpdf-")
	if err != nil {
		return fmt.Errorf("failed to create temporary directory: %v", err)
	}

	// Remove the temporary directory on defer again.
	defer func() {
		errD := os.RemoveAll(tmpDir)
		// Log the error only.
		if errD != nil {
			log.Printf("fillpdf: failed to remove temporary directory '%s' again: %v", tmpDir, errD)
		}
	}()

	// Create the temporary output file path.
	outputFile := filepath.Clean(tmpDir + "/output.pdf")

	// Create the fdf data file.
	fdfFile := filepath.Clean(tmpDir + "/data.fdf")
	err = createFdfFile(form, fdfFile)
	if err != nil {
		return fmt.Errorf("failed to create fdf form data file: %v", err)
	}

	// Create the pdftk command line arguments.
	args := []string{
		formPDFFile,
		"fill_form", fdfFile,
		"output", outputFile,
		"flatten",
	}

	// Run the pdftk utility.
	err = runCommandInPath(tmpDir, "pdftk", args...)
	if err != nil {
		return fmt.Errorf("pdftk error: %v", err)
	}

	// Check if the destination file exists.
	e, err = exists(destPDFFile)
	if err != nil {
		return fmt.Errorf("failed to check if destination PDF file exists: %v", err)
	} else if e {
		if len(overwrite) == 0 || !overwrite[0] {
			return fmt.Errorf("destination PDF file already exists: '%s'", destPDFFile)
		}

		err = os.Remove(destPDFFile)
		if err != nil {
			return fmt.Errorf("failed to remove destination PDF file: %v", err)
		}
	}

	// On success, copy the output file to the final destination.
	err = copyFile(outputFile, destPDFFile)
	if err != nil {
		return fmt.Errorf("failed to copy created output PDF to final destination: %v", err)
	}

	return nil
}

func createFdfFile(form Form, path string) error {
	// Create the file.
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()

	// Create a new writer.
	w := bufio.NewWriter(file)

	// Write the fdf header.
	fmt.Fprintln(w, fdfHeader)

	// Write the form data.
	for key, value := range form {
		fmt.Fprintf(w, "<< /T (%s) /V (%v)>>\n", key, value)
	}

	// Write the fdf footer.
	fmt.Fprintln(w, fdfFooter)

	// Flush everything.
	return w.Flush()
}

const fdfHeader = `%FDF-1.2
%,,oe"
1 0 obj
<<
/FDF << /Fields [`

const fdfFooter = `]
>>
>>
endobj
trailer
<<
/Root 1 0 R
>>
%%EOF`
<commit_msg>added options (#8)<commit_after>/*
 *  FillPDF - Fill PDF forms
 *  Copyright DesertBit
 *  Author: Roland Singer
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package fillpdf

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
)

// Form represents the PDF form.
// This is a key value map.
type Form map[string]interface{}

// Options represents the options to alter the PDF filling process
type Options struct {
	// Overwrite will overwrite any pre existing filled PDF
	Overwrite bool
	// Flatten will flatten the document making the form fields no longer editable
	Flatten bool
}

// Initialize default options to use if the user did not specify them.
var opts = Options{
	Overwrite: true,
	Flatten:   true,
}

// Fill a PDF form with the specified form values and create a final filled PDF file.
// The options parameter alters few aspects of the generation.
func Fill(form Form, formPDFFile, destPDFFile string, options ...Options) (err error) {
	// Get the absolute paths.
	formPDFFile, err = filepath.Abs(formPDFFile)
	if err != nil {
		return fmt.Errorf("failed to create the absolute path: %v", err)
	}
	destPDFFile, err = filepath.Abs(destPDFFile)
	if err != nil {
		return fmt.Errorf("failed to create the absolute path: %v", err)
	}

	// Check if the form file exists.
	e, err := exists(formPDFFile)
	if err != nil {
		return fmt.Errorf("failed to check if form PDF file exists: %v", err)
	} else if !e {
		return fmt.Errorf("form PDF file does not exists: '%s'", formPDFFile)
	}

	// Check if the pdftk utility exists.
	_, err = exec.LookPath("pdftk")
	if err != nil {
		return fmt.Errorf("pdftk utility is not installed!")
	}

	// Create a temporary directory.
	tmpDir, err := ioutil.TempDir("", "fillpdf-")
	if err != nil {
		return fmt.Errorf("failed to create temporary directory: %v", err)
	}

	// Remove the temporary directory on defer again.
	defer func() {
		errD := os.RemoveAll(tmpDir)
		// Log the error only.
		if errD != nil {
			log.Printf("fillpdf: failed to remove temporary directory '%s' again: %v", tmpDir, errD)
		}
	}()

	// Create the temporary output file path.
	outputFile := filepath.Clean(tmpDir + "/output.pdf")

	// Create the fdf data file.
	fdfFile := filepath.Clean(tmpDir + "/data.fdf")
	err = createFdfFile(form, fdfFile)
	if err != nil {
		return fmt.Errorf("failed to create fdf form data file: %v", err)
	}

	// Create the pdftk command line arguments.
	args := []string{
		formPDFFile,
		"fill_form", fdfFile,
		"output", outputFile,
	}

	// If the user provided the options we overwrite the defaults with the given struct.
	if len(options) > 0 {
		opts = options[0]
	}

	// If the user specified to flatten the output PDF we append the related parameter.
	if opts.Flatten {
		args = append(args, "flatten")
	}

	// Run the pdftk utility.
	err = runCommandInPath(tmpDir, "pdftk", args...)
	if err != nil {
		return fmt.Errorf("pdftk error: %v", err)
	}

	// Check if the destination file exists.
	e, err = exists(destPDFFile)
	if err != nil {
		return fmt.Errorf("failed to check if destination PDF file exists: %v", err)
	} else if e {
		if !opts.Overwrite {
			return fmt.Errorf("destination PDF file already exists: '%s'", destPDFFile)
		}

		err = os.Remove(destPDFFile)
		if err != nil {
			return fmt.Errorf("failed to remove destination PDF file: %v", err)
		}
	}

	// On success, copy the output file to the final destination.
	err = copyFile(outputFile, destPDFFile)
	if err != nil {
		return fmt.Errorf("failed to copy created output PDF to final destination: %v", err)
	}

	return nil
}

func createFdfFile(form Form, path string) error {
	// Create the file.
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()

	// Create a new writer.
	w := bufio.NewWriter(file)

	// Write the fdf header.
	fmt.Fprintln(w, fdfHeader)

	// Write the form data.
	for key, value := range form {
		fmt.Fprintf(w, "<< /T (%s) /V (%v)>>\n", key, value)
	}

	// Write the fdf footer.
	fmt.Fprintln(w, fdfFooter)

	// Flush everything.
	return w.Flush()
}

const fdfHeader = `%FDF-1.2
%,,oe"
1 0 obj
<<
/FDF << /Fields [`

const fdfFooter = `]
>>
>>
endobj
trailer
<<
/Root 1 0 R
>>
%%EOF`
<|endoftext|>