<commit_before>package app

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/timeredbull/tsuru/api/auth"
	"github.com/timeredbull/tsuru/db"
	"github.com/timeredbull/tsuru/errors"
	"github.com/timeredbull/tsuru/repository"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"net/http"
	"regexp"
	"strings"
)

func sendProjectChangeToGitosis(kind int, team *auth.Team, app *App) {
	ch := repository.Change{
		Kind: kind,
		Args: map[string]string{"group": team.Name, "project": app.Name},
	}
	repository.Ag.Process(ch)
}

func getAppOrError(name string, u *auth.User) (App, error) {
	app := App{Name: name}
	err := app.Get()
	if err != nil {
		return app, &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	if !app.CheckUserAccess(u) {
		return app, &errors.Http{Code: http.StatusForbidden, Message: "User does not have access to this app"}
	}
	return app, nil
}

func CloneRepositoryHandler(w http.ResponseWriter, r *http.Request) error {
	var output string
	app := App{Name: r.URL.Query().Get(":name")}
	err := app.Get()
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	output, err = repository.CloneOrPull(app.Name, app.Units[0].Machine) // should iterate over the machines
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: output}
	}
	c, err := app.conf()
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	err = app.preRestart(c)
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	err = app.updateHooks()
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	err = app.posRestart(c)
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	out := filterOutput([]byte(output), nil)
	n, err := w.Write(out)
	if err != nil {
		return err
	}
	if n != len(out) {
		return &errors.Http{Code: http.StatusInternalServerError, Message: "Failed to write output."}
	}
	return nil
}

func AppDelete(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	app, err := getAppOrError(r.URL.Query().Get(":name"), u)
	if err != nil {
		return err
	}
	app.Destroy()
	for _, t := range app.GetTeams() {
		sendProjectChangeToGitosis(repository.RemoveProject, &t, &app)
	}
	fmt.Fprint(w, "success")
	return nil
}

func getTeamNames(u *auth.User) (names []string, err error) {
	var teams []auth.Team
	err = db.Session.Teams().Find(bson.M{"users.email": u.Email}).All(&teams)
	if err != nil {
		return
	}
	names = make([]string, len(teams))
	for i, team := range teams {
		names[i] = team.Name
	}
	return
}

func AppList(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	teams, err := getTeamNames(u)
	if err != nil {
		return err
	}
	var apps []App
	err = db.Session.Apps().Find(bson.M{"teams": teams}).All(&apps)
	if err != nil {
		return err
	}
	if len(apps) == 0 {
		w.WriteHeader(http.StatusNoContent)
		return nil
	}
	b, err := json.Marshal(apps)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(b).String())
	return nil
}

func AppInfo(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	app, err := getAppOrError(r.URL.Query().Get(":name"), u)
	if err != nil {
		return err
	}
	b, err := json.Marshal(app)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(b).String())
	return nil
}

func createApp(app *App, u *auth.User) ([]byte, error) {
	var teams []auth.Team
	err := db.Session.Teams().Find(bson.M{"users.email": u.Email}).All(&teams)
	if err != nil {
		return nil, err
	}
	if len(teams) < 1 {
		msg := "In order to create an app, you should be member of at least one team"
		return nil, &errors.Http{Code: http.StatusForbidden, Message: msg}
	}
	app.setTeams(teams)
	err = app.Create()
	if err != nil {
		return nil, err
	}
	for _, t := range teams {
		sendProjectChangeToGitosis(repository.AddProject, &t, app)
	}
	msg := map[string]string{
		"status":         "success",
		"repository_url": repository.GetUrl(app.Name),
	}
	return json.Marshal(msg)
}

func CreateAppHandler(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	var app App
	defer r.Body.Close()
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, &app)
	if err != nil {
		return err
	}
	jsonMsg, err := createApp(&app, u)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(jsonMsg).String())
	return nil
}

func grantAccessToTeam(appName, teamName string, u *auth.User) error {
	t := new(auth.Team)
	app := &App{Name: appName}
	err := app.Get()
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	if !app.CheckUserAccess(u) {
		return &errors.Http{Code: http.StatusUnauthorized, Message: "User unauthorized"}
	}
	err = db.Session.Teams().Find(bson.M{"name": teamName}).One(t)
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "Team not found"}
	}
	err = app.GrantAccess(t)
	if err != nil {
		return &errors.Http{Code: http.StatusConflict, Message: err.Error()}
	}
	err = db.Session.Apps().Update(bson.M{"name": app.Name}, app)
	if err != nil {
		return err
	}
	sendProjectChangeToGitosis(repository.AddProject, t, app)
	return nil
}

func GrantAccessToTeamHandler(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	appName := r.URL.Query().Get(":app")
	teamName := r.URL.Query().Get(":team")
	return grantAccessToTeam(appName, teamName, u)
}

func revokeAccessFromTeam(appName, teamName string, u *auth.User) error {
	t := new(auth.Team)
	app := &App{Name: appName}
	err := app.Get()
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	if !app.CheckUserAccess(u) {
		return &errors.Http{Code: http.StatusUnauthorized, Message: "User unauthorized"}
	}
	err = db.Session.Teams().Find(bson.M{"name": teamName}).One(t)
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "Team not found"}
	}
	if len(app.Teams) == 1 {
		msg := "You can not revoke the access from this team, because it is the unique team with access to the app, and an app can not be orphaned"
		return &errors.Http{Code: http.StatusForbidden, Message: msg}
	}
	err = app.RevokeAccess(t)
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: err.Error()}
	}
	err = db.Session.Apps().Update(bson.M{"name": app.Name}, app)
	if err != nil {
		return err
	}
	sendProjectChangeToGitosis(repository.RemoveProject, t, app)
	return nil
}

func RevokeAccessFromTeamHandler(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	appName := r.URL.Query().Get(":app")
	teamName := r.URL.Query().Get(":team")
	return revokeAccessFromTeam(appName, teamName, u)
}

func RunCommand(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	msg := "You must provide the command to run"
	if r.Body == nil {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	c, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	if len(c) < 1 {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	unit := app.unit()
	cmd := fmt.Sprintf("[ -d /home/application/current ] && cd /home/application/current; %s", c)
	app.Log(fmt.Sprintf("running '%s'", c))
	out, err := unit.Command(cmd)
	if err != nil {
		return err
	}
	out = filterOutput(out, nil)
	app.Log(string(out))
	n, err := w.Write(out)
	if err != nil {
		return err
	}
	if n != len(out) {
		return &errors.Http{Code: http.StatusInternalServerError, Message: "Unexpected error writing the output"}
	}
	return nil
}

func GetEnv(w http.ResponseWriter, r *http.Request, u *auth.User) (err error) {
	var variable []byte
	if r.Body != nil {
		variable, err = ioutil.ReadAll(r.Body)
		if err != nil {
			return
		}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	var write = func(v EnvVar) error {
		_, err := fmt.Fprintf(w, "%s\n", &v)
		return err
	}
	if variables := strings.Fields(string(variable)); len(variables) > 0 {
		for _, variable := range variables {
			if v, ok := app.Env[variable]; ok {
				err = write(v)
				if err != nil {
					return
				}
			}
		}
	} else {
		for _, v := range app.Env {
			err = write(v)
			if err != nil {
				return
			}
		}
	}
	return nil
}

func SetEnv(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	msg := "You must provide the environment variables"
	if r.Body == nil {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	if len(body) == 0 {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	regex, err := regexp.Compile(`([A-Z_]+=[^=]+)(\s|$)`)
	if err != nil {
		return err
	}
	e := map[string]string{}
	variables := regex.FindAllStringSubmatch(string(body), -1)
	for _, v := range variables {
		parts := strings.Split(v[1], "=")
		app.SetEnv(EnvVar{Name: parts[0], Value: parts[1], Public: true})
		e[parts[0]] = parts[1]
	}
	if err = db.Session.Apps().Update(bson.M{"name": app.Name}, app); err != nil {
		return err
	}
	mess := Message{
		app: &app,
	}
	env <- mess
	return nil
}

func UnsetEnv(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	msg := "You must provide the environment variables"
	if r.Body == nil {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	if len(body) == 0 {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	e := map[string]string{}
	variables := strings.Fields(string(body))
	for _, variable := range variables {
		delete(app.Env, variable)
		app.Log(fmt.Sprintf("unsetting env %s", variable))
		e[variable] = ""
	}
	if err = db.Session.Apps().Update(bson.M{"name": app.Name}, app); err != nil {
		return err
	}
	mess := Message{
		app: &app,
	}
	env <- mess
	return nil
}

func AppLog(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	b, err := json.Marshal(app.Logs)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(b).String())
	return nil
}
<commit_msg>api/app: extracted method that actually sets the environment to the app<commit_after>package app

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/timeredbull/tsuru/api/auth"
	"github.com/timeredbull/tsuru/db"
	"github.com/timeredbull/tsuru/errors"
	"github.com/timeredbull/tsuru/repository"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"net/http"
	"regexp"
	"strings"
)

func sendProjectChangeToGitosis(kind int, team *auth.Team, app *App) {
	ch := repository.Change{
		Kind: kind,
		Args: map[string]string{"group": team.Name, "project": app.Name},
	}
	repository.Ag.Process(ch)
}

func getAppOrError(name string, u *auth.User) (App, error) {
	app := App{Name: name}
	err := app.Get()
	if err != nil {
		return app, &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	if !app.CheckUserAccess(u) {
		return app, &errors.Http{Code: http.StatusForbidden, Message: "User does not have access to this app"}
	}
	return app, nil
}

func CloneRepositoryHandler(w http.ResponseWriter, r *http.Request) error {
	var output string
	app := App{Name: r.URL.Query().Get(":name")}
	err := app.Get()
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	output, err = repository.CloneOrPull(app.Name, app.Units[0].Machine) // should iterate over the machines
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: output}
	}
	c, err := app.conf()
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	err = app.preRestart(c)
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	err = app.updateHooks()
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	err = app.posRestart(c)
	if err != nil {
		return &errors.Http{Code: http.StatusInternalServerError, Message: err.Error()}
	}
	out := filterOutput([]byte(output), nil)
	n, err := w.Write(out)
	if err != nil {
		return err
	}
	if n != len(out) {
		return &errors.Http{Code: http.StatusInternalServerError, Message: "Failed to write output."}
	}
	return nil
}

func AppDelete(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	app, err := getAppOrError(r.URL.Query().Get(":name"), u)
	if err != nil {
		return err
	}
	app.Destroy()
	for _, t := range app.GetTeams() {
		sendProjectChangeToGitosis(repository.RemoveProject, &t, &app)
	}
	fmt.Fprint(w, "success")
	return nil
}

func getTeamNames(u *auth.User) (names []string, err error) {
	var teams []auth.Team
	err = db.Session.Teams().Find(bson.M{"users.email": u.Email}).All(&teams)
	if err != nil {
		return
	}
	names = make([]string, len(teams))
	for i, team := range teams {
		names[i] = team.Name
	}
	return
}

func AppList(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	teams, err := getTeamNames(u)
	if err != nil {
		return err
	}
	var apps []App
	err = db.Session.Apps().Find(bson.M{"teams": teams}).All(&apps)
	if err != nil {
		return err
	}
	if len(apps) == 0 {
		w.WriteHeader(http.StatusNoContent)
		return nil
	}
	b, err := json.Marshal(apps)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(b).String())
	return nil
}

func AppInfo(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	app, err := getAppOrError(r.URL.Query().Get(":name"), u)
	if err != nil {
		return err
	}
	b, err := json.Marshal(app)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(b).String())
	return nil
}

func createApp(app *App, u *auth.User) ([]byte, error) {
	var teams []auth.Team
	err := db.Session.Teams().Find(bson.M{"users.email": u.Email}).All(&teams)
	if err != nil {
		return nil, err
	}
	if len(teams) < 1 {
		msg := "In order to create an app, you should be member of at least one team"
		return nil, &errors.Http{Code: http.StatusForbidden, Message: msg}
	}
	app.setTeams(teams)
	err = app.Create()
	if err != nil {
		return nil, err
	}
	for _, t := range teams {
		sendProjectChangeToGitosis(repository.AddProject, &t, app)
	}
	msg := map[string]string{
		"status":         "success",
		"repository_url": repository.GetUrl(app.Name),
	}
	return json.Marshal(msg)
}

func CreateAppHandler(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	var app App
	defer r.Body.Close()
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, &app)
	if err != nil {
		return err
	}
	jsonMsg, err := createApp(&app, u)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(jsonMsg).String())
	return nil
}

func grantAccessToTeam(appName, teamName string, u *auth.User) error {
	t := new(auth.Team)
	app := &App{Name: appName}
	err := app.Get()
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	if !app.CheckUserAccess(u) {
		return &errors.Http{Code: http.StatusUnauthorized, Message: "User unauthorized"}
	}
	err = db.Session.Teams().Find(bson.M{"name": teamName}).One(t)
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "Team not found"}
	}
	err = app.GrantAccess(t)
	if err != nil {
		return &errors.Http{Code: http.StatusConflict, Message: err.Error()}
	}
	err = db.Session.Apps().Update(bson.M{"name": app.Name}, app)
	if err != nil {
		return err
	}
	sendProjectChangeToGitosis(repository.AddProject, t, app)
	return nil
}

func GrantAccessToTeamHandler(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	appName := r.URL.Query().Get(":app")
	teamName := r.URL.Query().Get(":team")
	return grantAccessToTeam(appName, teamName, u)
}

func revokeAccessFromTeam(appName, teamName string, u *auth.User) error {
	t := new(auth.Team)
	app := &App{Name: appName}
	err := app.Get()
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "App not found"}
	}
	if !app.CheckUserAccess(u) {
		return &errors.Http{Code: http.StatusUnauthorized, Message: "User unauthorized"}
	}
	err = db.Session.Teams().Find(bson.M{"name": teamName}).One(t)
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: "Team not found"}
	}
	if len(app.Teams) == 1 {
		msg := "You can not revoke the access from this team, because it is the unique team with access to the app, and an app can not be orphaned"
		return &errors.Http{Code: http.StatusForbidden, Message: msg}
	}
	err = app.RevokeAccess(t)
	if err != nil {
		return &errors.Http{Code: http.StatusNotFound, Message: err.Error()}
	}
	err = db.Session.Apps().Update(bson.M{"name": app.Name}, app)
	if err != nil {
		return err
	}
	sendProjectChangeToGitosis(repository.RemoveProject, t, app)
	return nil
}

func RevokeAccessFromTeamHandler(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	appName := r.URL.Query().Get(":app")
	teamName := r.URL.Query().Get(":team")
	return revokeAccessFromTeam(appName, teamName, u)
}

func RunCommand(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	msg := "You must provide the command to run"
	if r.Body == nil {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	c, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	if len(c) < 1 {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	unit := app.unit()
	cmd := fmt.Sprintf("[ -d /home/application/current ] && cd /home/application/current; %s", c)
	app.Log(fmt.Sprintf("running '%s'", c))
	out, err := unit.Command(cmd)
	if err != nil {
		return err
	}
	out = filterOutput(out, nil)
	app.Log(string(out))
	n, err := w.Write(out)
	if err != nil {
		return err
	}
	if n != len(out) {
		return &errors.Http{Code: http.StatusInternalServerError, Message: "Unexpected error writing the output"}
	}
	return nil
}

func GetEnv(w http.ResponseWriter, r *http.Request, u *auth.User) (err error) {
	var variable []byte
	if r.Body != nil {
		variable, err = ioutil.ReadAll(r.Body)
		if err != nil {
			return
		}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	var write = func(v EnvVar) error {
		_, err := fmt.Fprintf(w, "%s\n", &v)
		return err
	}
	if variables := strings.Fields(string(variable)); len(variables) > 0 {
		for _, variable := range variables {
			if v, ok := app.Env[variable]; ok {
				err = write(v)
				if err != nil {
					return
				}
			}
		}
	} else {
		for _, v := range app.Env {
			err = write(v)
			if err != nil {
				return
			}
		}
	}
	return nil
}

func SetEnvsToApp(app *App, envs []EnvVar) error {
	for _, env := range envs {
		app.SetEnv(env)
	}
	if err := db.Session.Apps().Update(bson.M{"name": app.Name}, app); err != nil {
		return err
	}
	mess := Message{
		app: app,
	}
	env <- mess
	return nil
}

func SetEnv(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	msg := "You must provide the environment variables"
	if r.Body == nil {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	if len(body) == 0 {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	regex, err := regexp.Compile(`([A-Z_]+=[^=]+)(\s|$)`)
	if err != nil {
		return err
	}
	variables := regex.FindAllStringSubmatch(string(body), -1)
	envs := make([]EnvVar, len(variables))
	for i, v := range variables {
		parts := strings.Split(v[1], "=")
		envs[i] = EnvVar{Name: parts[0], Value: parts[1], Public: true}
	}
	return SetEnvsToApp(&app, envs)
}

func UnsetEnv(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	msg := "You must provide the environment variables"
	if r.Body == nil {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	if len(body) == 0 {
		return &errors.Http{Code: http.StatusBadRequest, Message: msg}
	}
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	e := map[string]string{}
	variables := strings.Fields(string(body))
	for _, variable := range variables {
		delete(app.Env, variable)
		app.Log(fmt.Sprintf("unsetting env %s", variable))
		e[variable] = ""
	}
	if err = db.Session.Apps().Update(bson.M{"name": app.Name}, app); err != nil {
		return err
	}
	mess := Message{
		app: &app,
	}
	env <- mess
	return nil
}

func AppLog(w http.ResponseWriter, r *http.Request, u *auth.User) error {
	appName := r.URL.Query().Get(":name")
	app, err := getAppOrError(appName, u)
	if err != nil {
		return err
	}
	b, err := json.Marshal(app.Logs)
	if err != nil {
		return err
	}
	fmt.Fprint(w, bytes.NewBuffer(b).String())
	return nil
}
<|endoftext|>


<commit_before>package api_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"regexp"
	"strings"
	"testing"

	"github.com/minodisk/qiitactl/api"
	"github.com/minodisk/qiitactl/testutil"
)

var (
	server     *httptest.Server
	rUserAgent = regexp.MustCompile(`qiitactl/\d+\.\d+\.\d+`)
)

func TestMain(m *testing.M) {
	mux := http.NewServeMux()

	mux.HandleFunc("/api/v2/echo", func(w http.ResponseWriter, r *http.Request) {
		auth := r.Header.Get("Authorization")
		if auth != "Bearer XXXXXXXXXXXX" {
			b, _ := json.Marshal(api.ResponseError{
				Type:    "unauthorized",
				Message: "Unauthorized",
			})
			w.WriteHeader(401)
			w.Write(b)
			return
		}

		ua := r.Header.Get("User-Agent")
		if !rUserAgent.MatchString(ua) {
			b, _ := json.Marshal(api.ResponseError{
				Type:    "bad_request",
				Message: "Bad Request",
			})
			w.WriteHeader(400)
			w.Write(b)
			return
		}

		defer r.Body.Close()
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			testutil.ResponseError(w, 500, err)
			return
		}

		if len(b) == 0 {
			fmt.Fprintf(w, "%s %s is accepted", r.Method, r.URL)
			return
		}

		contentType := r.Header.Get("Content-Type")
		if contentType != "application/json" {
			testutil.ResponseError(w, 400, api.ResponseError{
				Type:    "bad_request",
				Message: "Bad Request",
			})
			return
		}

		var v interface{}
		err = json.Unmarshal(b, &v)
		if err != nil {
			testutil.ResponseError(w, 500, err)
			return
		}
		b, err = json.Marshal(v)
		if err != nil {
			testutil.ResponseError(w, 500, err)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	})

	mux.HandleFunc("/api/v2/errors/response", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(500)
		b, _ := json.Marshal(api.ResponseError{"internal_server_error", "Internal Server Error"})
		w.Write(b)
	})

	mux.HandleFunc("/api/v2/errors/status", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(500)
	})

	server = httptest.NewServer(mux)
	defer server.Close()

	code := m.Run()

	// clean up
	testutil.CleanUp()

	os.Exit(code)
}

func TestBuildURL(t *testing.T) {
	func() {
		actual := api.BuildURL("", "/echo")
		if actual != "https://qiita.com/api/v2/echo" {
			t.Errorf("wrong url: %s", actual)
		}
	}()

	func() {
		actual := api.BuildURL("increments", "/echo")
		if actual != "https://increments.qiita.com/api/v2/echo" {
			t.Errorf("wrong url: %s", actual)
		}
	}()
}

func TestClientProcess(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Options("", "/echo", nil)
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "OPTIONS", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientProcessWithEmptyToken(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err := client.Options("", "/echo", nil)
	_, ok := err.(api.EmptyTokenError)
	if !ok {
		t.Fatal("empty token error should occur")
	}
}

func TestClientProcessWithWrongToken(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "YYYYYYYYYYYY")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err = client.Options("", "/echo", nil)
	_, ok := err.(api.WrongTokenError)
	if !ok {
		t.Fatal("wrong token error should occur")
	}
}

func TestClientProcessWithResponseError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err = client.Options("", "/errors/response", nil)
	_, ok := err.(api.ResponseError)
	if !ok {
		t.Fatal("response error should occur")
	}
}

func TestClientProcessWithStatusError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err = client.Options("", "/errors/status", nil)
	_, ok := err.(api.StatusError)
	if !ok {
		t.Fatal("status error should occur")
	}
}

func TestClientPost(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})
	client.DebugMode(true)

	body, _, err := client.Post("", "/echo", "data")
	if err != nil {
		t.Fatal(err)
	}

	var b string
	err = json.Unmarshal(body, &b)
	if err != nil {
		t.Fatal(err)
	}
	if b != "data" {
		t.Errorf("wrong body: %s", b)
	}
}

func TestClientGet(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Get("", "/echo", &url.Values{})
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "GET", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientGetWithDebugMode(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})
	client.DebugMode(true)

	body, _, err := client.Get("", "/echo", &url.Values{})
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "GET", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientPatch(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Patch("", "/echo", nil)
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "PATCH", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientDelete(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Delete("", "/echo", nil)
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "DELETE", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestEmptyTokenError(t *testing.T) {
	err := api.EmptyTokenError{}
	if !strings.HasPrefix(err.Error(), "empty token:") {
		t.Errorf("wrong Error: %s", err.Error())
	}
}

func TestWrongTokenError(t *testing.T) {
	err := api.WrongTokenError{}
	if !strings.HasPrefix(err.Error(), "wrong token:") {
		t.Errorf("wrong Error: %s", err.Error())
	}
}

func TestResponseError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := api.ResponseError{
		Type:    "not_found",
		Message: "Not found",
	}
	if err.Error() != "Not found" {
		t.Errorf("wrong Error: %s", err.Error())
	}
}

func TestStatusError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := api.StatusError{
		Code:    404,
		Message: "404 Not Found",
	}
	if err.Error() != "404 Not Found" {
		t.Errorf("wrong Error: %s", err.Error())
	}
}
<commit_msg>Add test for NewClient<commit_after>package api_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"regexp"
	"strings"
	"testing"

	"github.com/minodisk/qiitactl/api"
	"github.com/minodisk/qiitactl/testutil"
)

var (
	server     *httptest.Server
	rUserAgent = regexp.MustCompile(`qiitactl/\d+\.\d+\.\d+`)
)

func TestMain(m *testing.M) {
	mux := http.NewServeMux()

	mux.HandleFunc("/api/v2/echo", func(w http.ResponseWriter, r *http.Request) {
		auth := r.Header.Get("Authorization")
		if auth != "Bearer XXXXXXXXXXXX" {
			b, _ := json.Marshal(api.ResponseError{
				Type:    "unauthorized",
				Message: "Unauthorized",
			})
			w.WriteHeader(401)
			w.Write(b)
			return
		}

		ua := r.Header.Get("User-Agent")
		if !rUserAgent.MatchString(ua) {
			b, _ := json.Marshal(api.ResponseError{
				Type:    "bad_request",
				Message: "Bad Request",
			})
			w.WriteHeader(400)
			w.Write(b)
			return
		}

		defer r.Body.Close()
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			testutil.ResponseError(w, 500, err)
			return
		}

		if len(b) == 0 {
			fmt.Fprintf(w, "%s %s is accepted", r.Method, r.URL)
			return
		}

		contentType := r.Header.Get("Content-Type")
		if contentType != "application/json" {
			testutil.ResponseError(w, 400, api.ResponseError{
				Type:    "bad_request",
				Message: "Bad Request",
			})
			return
		}

		var v interface{}
		err = json.Unmarshal(b, &v)
		if err != nil {
			testutil.ResponseError(w, 500, err)
			return
		}
		b, err = json.Marshal(v)
		if err != nil {
			testutil.ResponseError(w, 500, err)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	})

	mux.HandleFunc("/api/v2/errors/response", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(500)
		b, _ := json.Marshal(api.ResponseError{"internal_server_error", "Internal Server Error"})
		w.Write(b)
	})

	mux.HandleFunc("/api/v2/errors/status", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(500)
	})

	server = httptest.NewServer(mux)
	defer server.Close()

	code := m.Run()

	// clean up
	testutil.CleanUp()

	os.Exit(code)
}

func TestBuildURL(t *testing.T) {
	func() {
		actual := api.BuildURL("", "/echo")
		if actual != "https://qiita.com/api/v2/echo" {
			t.Errorf("wrong url: %s", actual)
		}
	}()

	func() {
		actual := api.BuildURL("increments", "/echo")
		if actual != "https://increments.qiita.com/api/v2/echo" {
			t.Errorf("wrong url: %s", actual)
		}
	}()
}

func TestNewClient(t *testing.T) {
	c := api.NewClient(nil)
	if c.BuildURL == nil {
		t.Error("BuildURL should be filled with default function")
	}
}

func TestClientProcess(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Options("", "/echo", nil)
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "OPTIONS", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientProcessWithEmptyToken(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err := client.Options("", "/echo", nil)
	_, ok := err.(api.EmptyTokenError)
	if !ok {
		t.Fatal("empty token error should occur")
	}
}

func TestClientProcessWithWrongToken(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "YYYYYYYYYYYY")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err = client.Options("", "/echo", nil)
	_, ok := err.(api.WrongTokenError)
	if !ok {
		t.Fatal("wrong token error should occur")
	}
}

func TestClientProcessWithResponseError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err = client.Options("", "/errors/response", nil)
	_, ok := err.(api.ResponseError)
	if !ok {
		t.Fatal("response error should occur")
	}
}

func TestClientProcessWithStatusError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	_, _, err = client.Options("", "/errors/status", nil)
	_, ok := err.(api.StatusError)
	if !ok {
		t.Fatal("status error should occur")
	}
}

func TestClientPost(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})
	client.DebugMode(true)

	body, _, err := client.Post("", "/echo", "data")
	if err != nil {
		t.Fatal(err)
	}

	var b string
	err = json.Unmarshal(body, &b)
	if err != nil {
		t.Fatal(err)
	}
	if b != "data" {
		t.Errorf("wrong body: %s", b)
	}
}

func TestClientGet(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Get("", "/echo", &url.Values{})
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "GET", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientGetWithDebugMode(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})
	client.DebugMode(true)

	body, _, err := client.Get("", "/echo", &url.Values{})
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "GET", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientPatch(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Patch("", "/echo", nil)
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "PATCH", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestClientDelete(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := os.Setenv("QIITA_ACCESS_TOKEN", "XXXXXXXXXXXX")
	if err != nil {
		log.Fatal(err)
	}
	client := api.NewClient(func(subDomain, path string) (url string) {
		url = fmt.Sprintf("%s%s%s", server.URL, "/api/v2", path)
		return
	})

	body, _, err := client.Delete("", "/echo", nil)
	if err != nil {
		t.Fatal(err)
	}

	if string(body) != fmt.Sprintf("%s /api/v2%s is accepted", "DELETE", "/echo") {
		t.Errorf("wrong body: %s", body)
	}
}

func TestEmptyTokenError(t *testing.T) {
	err := api.EmptyTokenError{}
	if !strings.HasPrefix(err.Error(), "empty token:") {
		t.Errorf("wrong Error: %s", err.Error())
	}
}

func TestWrongTokenError(t *testing.T) {
	err := api.WrongTokenError{}
	if !strings.HasPrefix(err.Error(), "wrong token:") {
		t.Errorf("wrong Error: %s", err.Error())
	}
}

func TestResponseError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := api.ResponseError{
		Type:    "not_found",
		Message: "Not found",
	}
	if err.Error() != "Not found" {
		t.Errorf("wrong Error: %s", err.Error())
	}
}

func TestStatusError(t *testing.T) {
	testutil.CleanUp()
	defer testutil.CleanUp()

	err := api.StatusError{
		Code:    404,
		Message: "404 Not Found",
	}
	if err.Error() != "404 Not Found" {
		t.Errorf("wrong Error: %s", err.Error())
	}
}
<|endoftext|>


<commit_before>package schedules

import (
	"encoding/json"
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
)

// Section Collections

func HandleSectionIndex(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	var sections []Section
	err := database.Find(&sections).Error
	if err != nil {
		log.Critical(err.Error())
		rw.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(rw, "Error Retrieving Sections\n")
		return
	}
	json.NewEncoder(rw).Encode(sections)
}

func HandleSectionCreate(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Create")
}

// Section Singular

func HandleSectionShow(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Show")
}

func HandleSectionEdit(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Edit")
}

func HandleSectionDelete(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Delete")
}
<commit_msg>Adds simple Get functions to query database for Sections<commit_after>package schedules

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
)

// Section Collections

// Queries the database for a particular section in a given semester.
func GetSectionByCRN(crn int, semester string) (Section, error) {
	if database == nil {
		return Section{}, errors.New("Database not yet initialized")
	}
	var response []Section
	database.Where(&Section{CRN: crn, Semester: semester}).Find(&response)
	if len(response) > 1 {
		return Section{}, errors.New("Multiple matches found")
	}
	switch length := len(response); {
	case length > 1:
		return Section{}, errors.New(fmt.Sprintf("Multiple matches found with crn: %d", crn))
	case length == 0:
		return Section{}, errors.New(fmt.Sprintf("Section %d does not exist", crn))
	}
	return response[0], nil
}

// Queries the database for a list of sections in a given semester.
func GetSectionsByCRN(crns []int, semester string) ([]Section, error) {
	var sections []Section
	for _, crn := range crns {
		newSection, err := GetSectionByCRN(crn, semester)
		if err != nil {
			return []Section{}, err
		}
		sections = append(sections, newSection)
	}
	return sections, nil
}

func HandleSectionIndex(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	var sections []Section
	err := database.Find(&sections).Error
	if err != nil {
		log.Critical(err.Error())
		rw.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(rw, "Error Retrieving Sections\n")
		return
	}
	json.NewEncoder(rw).Encode(sections)
}

func HandleSectionCreate(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Create")
}

// Section Singular

func HandleSectionShow(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Show")
}

func HandleSectionEdit(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Edit")
}

func HandleSectionDelete(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	fmt.Fprintln(rw, "Section Delete")
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package privdata

import (
	"time"

	"github.com/hyperledger/fabric/core/common/privdata"
	"github.com/hyperledger/fabric/gossip/api"
	gossipCommon "github.com/hyperledger/fabric/gossip/common"
	"github.com/hyperledger/fabric/gossip/discovery"
	"github.com/hyperledger/fabric/gossip/filter"
	gossip2 "github.com/hyperledger/fabric/gossip/gossip"
	"github.com/hyperledger/fabric/gossip/util"
	"github.com/hyperledger/fabric/protos/common"
	proto "github.com/hyperledger/fabric/protos/gossip"
	"github.com/hyperledger/fabric/protos/ledger/rwset"
	"github.com/spf13/viper"
)

// gossipAdapter an adapter for API's required from gossip module
type gossipAdapter interface {
	// SendByCriteria sends a given message to all peers that match the given SendCriteria
	SendByCriteria(message *proto.SignedGossipMessage, criteria gossip2.SendCriteria) error

	// PeerFilter receives a SubChannelSelectionCriteria and returns a RoutingFilter that selects
	// only peer identities that match the given criteria, and that they published their channel participation
	PeerFilter(channel gossipCommon.ChainID, messagePredicate api.SubChannelSelectionCriteria) (filter.RoutingFilter, error)
}

// PvtDataDistributor interface to defines API of distributing private data
type PvtDataDistributor interface {
	// Distribute broadcast reliably private data read write set based on policies
	Distribute(txID string, privData *rwset.TxPvtReadWriteSet, ps privdata.PolicyStore, pp privdata.PolicyParser) error
}

// distributorImpl the implementation of the private data distributor interface
type distributorImpl struct {
	chainID  string
	minAck   int
	maxPeers int
	gossipAdapter
}

// NewDistributor a constructor for private data distributor capable to send
// private read write sets for underlined collection
func NewDistributor(chainID string, gossip gossipAdapter) PvtDataDistributor {
	return &distributorImpl{
		chainID:       chainID,
		gossipAdapter: gossip,
		minAck:        viper.GetInt("peer.gossip.pvtData.minAck"),
		maxPeers:      viper.GetInt("peer.gossip.pvtData.maxPeers"),
	}
}

// Distribute broadcast reliably private data read write set based on policies
func (d *distributorImpl) Distribute(txID string, privData *rwset.TxPvtReadWriteSet, ps privdata.PolicyStore, pp privdata.PolicyParser) error {
	for _, pvtRwset := range privData.NsPvtRwset {
		namespace := pvtRwset.Namespace
		for _, collection := range pvtRwset.CollectionPvtRwset {
			collectionName := collection.CollectionName
			policyFilter := pp.Parse(ps.CollectionPolicy(rwset.CollectionCriteria{
				Namespace:  namespace,
				Collection: collectionName,
				TxId:       txID,
				Channel:    d.chainID,
			}))

			routingFilter, err := d.gossipAdapter.PeerFilter(gossipCommon.ChainID(d.chainID), func(signature api.PeerSignature) bool {
				return policyFilter(common.SignedData{
					Data:      signature.Message,
					Signature: signature.Signature,
					Identity:  []byte(signature.PeerIdentity),
				})
			})

			if err != nil {
				logger.Error("Failed to retrieve peer routing filter, due to", err, "collection name", collectionName)
				return err
			}

			msg := &proto.GossipMessage{
				Channel: []byte(d.chainID),
				Nonce:   util.RandomUInt64(),
				Tag:     proto.GossipMessage_CHAN_ONLY,
				Content: &proto.GossipMessage_PrivateData{
					PrivateData: &proto.PrivateDataMessage{
						Payload: &proto.PrivatePayload{
							Namespace:      namespace,
							CollectionName: collectionName,
							TxId:           txID,
							PrivateRwset:   collection.Rwset,
						},
					},
				},
			}

			pvtDataMsg, err := msg.NoopSign()
			if err != nil {
				return err
			}

			err = d.gossipAdapter.SendByCriteria(pvtDataMsg, gossip2.SendCriteria{
				Timeout:  time.Second,
				Channel:  gossipCommon.ChainID(d.chainID),
				MaxPeers: d.maxPeers,
				MinAck:   d.minAck,
				IsEligible: func(member discovery.NetworkMember) bool {
					return routingFilter(member)
				},
			})

			if err != nil {
				logger.Warning("Could not send private data for channel", d.chainID,
					"collection name", collectionName, "due to", err)

				return err
			}
		}
	}
	return nil
}
<commit_msg>[FAB-5084] Push private data upon endorsement -typoFix<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package privdata

import (
	"time"

	"github.com/hyperledger/fabric/core/common/privdata"
	"github.com/hyperledger/fabric/gossip/api"
	gossipCommon "github.com/hyperledger/fabric/gossip/common"
	"github.com/hyperledger/fabric/gossip/discovery"
	"github.com/hyperledger/fabric/gossip/filter"
	gossip2 "github.com/hyperledger/fabric/gossip/gossip"
	"github.com/hyperledger/fabric/gossip/util"
	"github.com/hyperledger/fabric/protos/common"
	proto "github.com/hyperledger/fabric/protos/gossip"
	"github.com/hyperledger/fabric/protos/ledger/rwset"
	"github.com/spf13/viper"
)

// gossipAdapter an adapter for API's required from gossip module
type gossipAdapter interface {
	// SendByCriteria sends a given message to all peers that match the given SendCriteria
	SendByCriteria(message *proto.SignedGossipMessage, criteria gossip2.SendCriteria) error

	// PeerFilter receives a SubChannelSelectionCriteria and returns a RoutingFilter that selects
	// only peer identities that match the given criteria, and that they published their channel participation
	PeerFilter(channel gossipCommon.ChainID, messagePredicate api.SubChannelSelectionCriteria) (filter.RoutingFilter, error)
}

// PvtDataDistributor interface to defines API of distributing private data
type PvtDataDistributor interface {
	// Distribute broadcast reliably private data read write set based on policies
	Distribute(txID string, privData *rwset.TxPvtReadWriteSet, ps privdata.PolicyStore, pp privdata.PolicyParser) error
}

// distributorImpl the implementation of the private data distributor interface
type distributorImpl struct {
	chainID  string
	minAck   int
	maxPeers int
	gossipAdapter
}

// NewDistributor a constructor for private data distributor capable to send
// private read write sets for underlying collection
func NewDistributor(chainID string, gossip gossipAdapter) PvtDataDistributor {
	return &distributorImpl{
		chainID:       chainID,
		gossipAdapter: gossip,
		minAck:        viper.GetInt("peer.gossip.pvtData.minAck"),
		maxPeers:      viper.GetInt("peer.gossip.pvtData.maxPeers"),
	}
}

// Distribute broadcast reliably private data read write set based on policies
func (d *distributorImpl) Distribute(txID string, privData *rwset.TxPvtReadWriteSet, ps privdata.PolicyStore, pp privdata.PolicyParser) error {
	for _, pvtRwset := range privData.NsPvtRwset {
		namespace := pvtRwset.Namespace
		for _, collection := range pvtRwset.CollectionPvtRwset {
			collectionName := collection.CollectionName
			policyFilter := pp.Parse(ps.CollectionPolicy(rwset.CollectionCriteria{
				Namespace:  namespace,
				Collection: collectionName,
				TxId:       txID,
				Channel:    d.chainID,
			}))

			routingFilter, err := d.gossipAdapter.PeerFilter(gossipCommon.ChainID(d.chainID), func(signature api.PeerSignature) bool {
				return policyFilter(common.SignedData{
					Data:      signature.Message,
					Signature: signature.Signature,
					Identity:  []byte(signature.PeerIdentity),
				})
			})

			if err != nil {
				logger.Error("Failed to retrieve peer routing filter, due to", err, "collection name", collectionName)
				return err
			}

			msg := &proto.GossipMessage{
				Channel: []byte(d.chainID),
				Nonce:   util.RandomUInt64(),
				Tag:     proto.GossipMessage_CHAN_ONLY,
				Content: &proto.GossipMessage_PrivateData{
					PrivateData: &proto.PrivateDataMessage{
						Payload: &proto.PrivatePayload{
							Namespace:      namespace,
							CollectionName: collectionName,
							TxId:           txID,
							PrivateRwset:   collection.Rwset,
						},
					},
				},
			}

			pvtDataMsg, err := msg.NoopSign()
			if err != nil {
				return err
			}

			err = d.gossipAdapter.SendByCriteria(pvtDataMsg, gossip2.SendCriteria{
				Timeout:  time.Second,
				Channel:  gossipCommon.ChainID(d.chainID),
				MaxPeers: d.maxPeers,
				MinAck:   d.minAck,
				IsEligible: func(member discovery.NetworkMember) bool {
					return routingFilter(member)
				},
			})

			if err != nil {
				logger.Warning("Could not send private data for channel", d.chainID,
					"collection name", collectionName, "due to", err)

				return err
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package aiven

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strings"
)

type (
	// Service represents the Service model on Aiven.
	Service struct {
		CloudName  string         `json:"cloud_name"`
		CreateTime string         `json:"create_time"`
		UpdateTime string         `json:"update_time"`
		GroupList  []string       `json:"group_list"`
		NodeCount  int            `json:"node_count"`
		Plan       string         `json:"plan"`
		Name       string         `json:"service_name"`
		Type       string         `json:"service_type"`
		URI        string         `json:"service_uri"`
		State      string         `json:"state"`
		Metadata   interface{}    `json:"metadata"`
		Users      []*ServiceUser `json:"users"`
		UserConfig interface{}    `json:"user_config"`
	}

	// ServicesHandler is the client that interacts with the Service API
	// endpoints on Aiven.
	ServicesHandler struct {
		client *Client
	}

	// CreateServiceRequest are the parameters to create a Service.
	CreateServiceRequest struct {
		Cloud       string                 `json:"cloud,omitempty"`
		GroupName   string                 `json:"group_name,omitempty"`
		Plan        string                 `json:"plan,omitempty"`
		ServiceName string                 `json:"service_name"`
		ServiceType string                 `json:"service_type"`
		UserConfig  map[string]interface{} `json:"user_config,omitempty"`
	}

	// UpdateServiceRequest are the parameters to update a Service.
	UpdateServiceRequest struct {
		Cloud     string `json:"cloud,omitempty"`
		GroupName string `json:"group_name,omitempty"`
		Plan      string `json:"plan,omitempty"`
		Powered   bool   `json:"powered"` // TODO: figure out if we can overwrite the default?
	}

	// ServiceResponse represents the response from Aiven after interacting with
	// the Service API.
	ServiceResponse struct {
		APIResponse
		Service *Service `json:"service"`
	}

	// ServiceListResponse represents the response from Aiven for listing
	// services.
	ServiceListResponse struct {
		APIResponse
		Services []*Service `json:"services"`
	}
)

// Hostname parses the hostname out of the Service URI.
func (s *Service) Hostname() (string, error) {
	hn, _, err := getHostPort(s.URI)
	return hn, err
}

// Port parses the port out of the service URI.
func (s *Service) Port() (string, error) {
	_, port, err := getHostPort(s.URI)
	return port, err
}

func getHostPort(uri string) (string, string, error) {
	hostURL, err := url.Parse(uri)
	if err != nil {
		return "", "", err
	}

	if hostURL.Host == "" {
		return hostURL.Scheme, hostURL.Opaque, nil
	}

	sp := strings.Split(hostURL.Host, ":")
	if len(sp) != 2 {
		return "", "", ErrInvalidHost
	}

	return sp[0], sp[1], nil
}

// Create creates the given Service on Aiven.
func (h *ServicesHandler) Create(project string, req CreateServiceRequest) (*Service, error) {
	rsp, err := h.client.doPostRequest(fmt.Sprintf("/project/%s/service", project), req)
	if err != nil {
		return nil, err
	}

	return parseServiceResponse(rsp)
}

// Get gets a specific service from Aiven.
func (h *ServicesHandler) Get(project, service string) (*Service, error) {
	rsp, err := h.client.doGetRequest(fmt.Sprintf("/project/%s/service/%s", project, service), nil)
	if err != nil {
		return nil, err
	}

	return parseServiceResponse(rsp)
}

// Update will update the given service with the given parameters.
func (h *ServicesHandler) Update(project, service string, req UpdateServiceRequest) (*Service, error) {
	rsp, err := h.client.doPutRequest(fmt.Sprintf("/project/%s/service/%s", project, service), req)
	if err != nil {
		return nil, err
	}

	return parseServiceResponse(rsp)
}

// Delete will delete the given service from Aiven.
func (h *ServicesHandler) Delete(project, service string) error {
	bts, err := h.client.doDeleteRequest(fmt.Sprintf("/project/%s/service/%s", project, service), nil)
	if err != nil {
		return err
	}

	return handleDeleteResponse(bts)
}

// List will fetch all services for a given project.
func (h *ServicesHandler) List(project string) ([]*Service, error) {
	rsp, err := h.client.doGetRequest(fmt.Sprintf("/project/%s/service", project), nil)
	if err != nil {
		return nil, err
	}

	var response *ServiceListResponse
	if err := json.Unmarshal(rsp, &response); err != nil {
		return nil, err
	}

	if len(response.Errors) != 0 {
		return nil, errors.New(response.Message)
	}

	return response.Services, nil
}

func parseServiceResponse(rsp []byte) (*Service, error) {
	var response *ServiceResponse
	if err := json.Unmarshal(rsp, &response); err != nil {
		return nil, err
	}

	if len(response.Errors) != 0 {
		return nil, errors.New(response.Message)
	}

	return response.Service, nil
}
<commit_msg>Adds user_config to service update<commit_after>package aiven

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strings"
)

type (
	// Service represents the Service model on Aiven.
	Service struct {
		CloudName  string         `json:"cloud_name"`
		CreateTime string         `json:"create_time"`
		UpdateTime string         `json:"update_time"`
		GroupList  []string       `json:"group_list"`
		NodeCount  int            `json:"node_count"`
		Plan       string         `json:"plan"`
		Name       string         `json:"service_name"`
		Type       string         `json:"service_type"`
		URI        string         `json:"service_uri"`
		State      string         `json:"state"`
		Metadata   interface{}    `json:"metadata"`
		Users      []*ServiceUser `json:"users"`
		UserConfig interface{}    `json:"user_config"`
	}

	// ServicesHandler is the client that interacts with the Service API
	// endpoints on Aiven.
	ServicesHandler struct {
		client *Client
	}

	// CreateServiceRequest are the parameters to create a Service.
	CreateServiceRequest struct {
		Cloud       string                 `json:"cloud,omitempty"`
		GroupName   string                 `json:"group_name,omitempty"`
		Plan        string                 `json:"plan,omitempty"`
		ServiceName string                 `json:"service_name"`
		ServiceType string                 `json:"service_type"`
		UserConfig  map[string]interface{} `json:"user_config,omitempty"`
	}

	// UpdateServiceRequest are the parameters to update a Service.
	UpdateServiceRequest struct {
		Cloud      string                 `json:"cloud,omitempty"`
		GroupName  string                 `json:"group_name,omitempty"`
		Plan       string                 `json:"plan,omitempty"`
		Powered    bool                   `json:"powered"` // TODO: figure out if we can overwrite the default?
		UserConfig map[string]interface{} `json:"user_config,omitempty"`
	}

	// ServiceResponse represents the response from Aiven after interacting with
	// the Service API.
	ServiceResponse struct {
		APIResponse
		Service *Service `json:"service"`
	}

	// ServiceListResponse represents the response from Aiven for listing
	// services.
	ServiceListResponse struct {
		APIResponse
		Services []*Service `json:"services"`
	}
)

// Hostname parses the hostname out of the Service URI.
func (s *Service) Hostname() (string, error) {
	hn, _, err := getHostPort(s.URI)
	return hn, err
}

// Port parses the port out of the service URI.
func (s *Service) Port() (string, error) {
	_, port, err := getHostPort(s.URI)
	return port, err
}

func getHostPort(uri string) (string, string, error) {
	hostURL, err := url.Parse(uri)
	if err != nil {
		return "", "", err
	}

	if hostURL.Host == "" {
		return hostURL.Scheme, hostURL.Opaque, nil
	}

	sp := strings.Split(hostURL.Host, ":")
	if len(sp) != 2 {
		return "", "", ErrInvalidHost
	}

	return sp[0], sp[1], nil
}

// Create creates the given Service on Aiven.
func (h *ServicesHandler) Create(project string, req CreateServiceRequest) (*Service, error) {
	rsp, err := h.client.doPostRequest(fmt.Sprintf("/project/%s/service", project), req)
	if err != nil {
		return nil, err
	}

	return parseServiceResponse(rsp)
}

// Get gets a specific service from Aiven.
func (h *ServicesHandler) Get(project, service string) (*Service, error) {
	rsp, err := h.client.doGetRequest(fmt.Sprintf("/project/%s/service/%s", project, service), nil)
	if err != nil {
		return nil, err
	}

	return parseServiceResponse(rsp)
}

// Update will update the given service with the given parameters.
func (h *ServicesHandler) Update(project, service string, req UpdateServiceRequest) (*Service, error) {
	rsp, err := h.client.doPutRequest(fmt.Sprintf("/project/%s/service/%s", project, service), req)
	if err != nil {
		return nil, err
	}

	return parseServiceResponse(rsp)
}

// Delete will delete the given service from Aiven.
func (h *ServicesHandler) Delete(project, service string) error {
	bts, err := h.client.doDeleteRequest(fmt.Sprintf("/project/%s/service/%s", project, service), nil)
	if err != nil {
		return err
	}

	return handleDeleteResponse(bts)
}

// List will fetch all services for a given project.
func (h *ServicesHandler) List(project string) ([]*Service, error) {
	rsp, err := h.client.doGetRequest(fmt.Sprintf("/project/%s/service", project), nil)
	if err != nil {
		return nil, err
	}

	var response *ServiceListResponse
	if err := json.Unmarshal(rsp, &response); err != nil {
		return nil, err
	}

	if len(response.Errors) != 0 {
		return nil, errors.New(response.Message)
	}

	return response.Services, nil
}

func parseServiceResponse(rsp []byte) (*Service, error) {
	var response *ServiceResponse
	if err := json.Unmarshal(rsp, &response); err != nil {
		return nil, err
	}

	if len(response.Errors) != 0 {
		return nil, errors.New(response.Message)
	}

	return response.Service, nil
}
<|endoftext|>


<commit_before>// +build !windows

package main

//runService dummy for non windows systems
func runService() chan bool {
	return make(chan bool)
}
<commit_msg>handle os.interrupt and stop server #137<commit_after>// +build !windows

package main

import (
	"os"
	"os/signal"
)

//runService wait for os interrupt
func runService() chan bool {
	waitChan := make(chan bool)

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for range c {
			waitChan <- true
			return
		}
	}()
	return waitChan
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/gorilla/mux"
	uuid "github.com/satori/go.uuid"
)

var jobMutex sync.Mutex
var jobs = make(map[string]*Job)

type SlicerService struct {
	EndPoint   string `yaml:"endPoint"`
	Executable string `yaml:"executable"`
}

type Service struct {
	EndPoint          string            `yaml:"endPoint" json:"end_point"`
	CommandLine       []string          `yaml:"commandLine" json:"command_line"`
	Description       string            `json:"description"`
	Defaults          map[string]string `json:"defaults" yaml:"defaults"`
	CreateEmptyOutput bool              `json:"create_empty_output" yaml:"create_empty_output"`
	Arguments         []string          `json:"arguments"`
	Parameters        []string          `json:"parameters"`
	InputFiles        []string          `json:"input_files"`
	OutputFiles       []string          `json:"output_files"`
	InputZip          []string          `json:"input_directories"`
	OutputZip         []string          `json:"output_directories"`
}

// Parse our argements
func NewService() *Service {
	var service Service
	service.Defaults = make(map[string]string)
	service.Arguments = make([]string, 0)
	service.Parameters = make([]string, 0)
	service.InputFiles = make([]string, 0)
	service.OutputFiles = make([]string, 0)
	return &service
}

func (service *Service) setup() *Service {
	if service.Defaults == nil {
		service.Defaults = make(map[string]string)
	}
	if service.Arguments == nil {
		service.Arguments = make([]string, 0)
	}
	if service.Parameters == nil {
		service.Parameters = make([]string, 0)
	}
	if service.InputFiles == nil {
		service.InputFiles = make([]string, 0)
	}
	if service.OutputFiles == nil {
		service.OutputFiles = make([]string, 0)
	}
	if service.InputZip == nil {
		service.InputZip = make([]string, 0)
	}
	if service.OutputZip == nil {
		service.OutputZip = make([]string, 0)
	}
	for _, arg := range service.CommandLine {
		// Do we start with an #?
		key := arg[1:]
		prefix := arg[0]
		isArg := false
		if prefix == '#' {
			isArg = true
			service.Parameters = append(service.Arguments, key)
		} else if prefix == '<' {
			isArg = true
			service.InputFiles = append(service.InputFiles, key)
		} else if prefix == '>' {
			isArg = true
			service.OutputFiles = append(service.OutputFiles, key)
		} else if prefix == '^' {
			isArg = true
			service.InputZip = append(service.InputZip, key)
		} else if prefix == '~' {
			isArg = true
			service.OutputZip = append(service.OutputZip, key)
		}
		if isArg {
			service.Arguments = append(service.Arguments, key)
		}
	}
	return service
}

// Return all services as JSON
func GetServices(w http.ResponseWriter, request *http.Request) {
	json.NewEncoder(w).Encode(config)
}

// Particular info about a service as JSON
func GetService(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	service := config.ServiceMap[vars["id"]]
	json.NewEncoder(w).Encode(service)
}

// Start up the service
func StartService(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	service := config.ServiceMap[vars["id"]]
	if service == nil {
		http.Error(w, "service not found", http.StatusNotFound)
		return
	}
	log.Printf("Found service %v on endpoint %v", vars["id"], service.EndPoint)
	// Pull out our arguments
	err := request.ParseMultipartForm(10 * 1024 * 1024)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	job := Job{
		UUID:        uuid.NewV4().String(),
		Service:     service,
		CommandLine: service.CommandLine,
		FileMap:     make(map[string]string),
		ZipMap:      make(map[string]string),
		EndPoint:    service.EndPoint,
		Host:        advertisedHost,
		Port:        advertisedPort,
		Address:     make([]string, 0),
	}

	// do we have an email address?
	if request.MultipartForm.Value["mail"] != nil {
		job.Address = request.MultipartForm.Value["mail"]
	}

	// Make a working directory
	job.WorkingDirectory = filepath.Join(config.Directory, service.EndPoint, job.UUID)
	err = os.MkdirAll(job.WorkingDirectory, 0755)
	if err != nil {
		log.Printf("Error making working directory: %v", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = job.ParseCommandLine(request)
	if err != nil {
		log.Printf("Error parsing command line: %v", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	job.Start()
	json.NewEncoder(w).Encode(&job)
	jobs[job.UUID] = &job
}

func GetJob(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	job := jobs[vars["id"]]
	json.NewEncoder(w).Encode(job)
}

func WaitForJob(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	job := jobs[vars["id"]]
	job.Wait()
	json.NewEncoder(w).Encode(job)
}

func GetJobFile(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	key := vars["id"]
	job := jobs[key]
	if job == nil {
		http.Error(w, fmt.Sprintf("job %v does not exist", key), http.StatusInternalServerError)
		return
	}
	file, ok := job.FileMap[vars["filename"]]
	if ok {
		fileToSend := filepath.Join(job.WorkingDirectory, file)
		log.Printf("Request for %s, sending %s", vars["filename"], fileToSend)
		w.Header().Set("Content-Disposition", "attachment;filename="+filepath.Base(file))
		http.ServeFile(w, request, fileToSend)
		return
	}
	file, ok = job.ZipMap[vars["filename"]]
	if ok {
		outputDirectory := filepath.Join(job.WorkingDirectory, file)
		zipFilename := filepath.Base(vars["filename"])
		if !strings.HasSuffix(zipFilename, ".zip") {
			zipFilename += ".zip"
		}
		log.Printf("Requested %v: sending directory %v as a zip file", vars["filename"], outputDirectory)
		w.Header().Set("Content-Disposition", "attachment; filename=\""+zipFilename+"\"")
		gz := zip.NewWriter(w)
		defer gz.Close()

		filepath.Walk(outputDirectory, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			// Don't create an entry for the root of the directory
			if path == outputDirectory {
				return err
			}

			header, err := zip.FileInfoHeader(info)
			if err != nil {
				return err
			}

			// Take off the path, and a leading "/" to make the output relative
			header.Name = strings.TrimPrefix(path, outputDirectory)
			header.Name = strings.TrimPrefix(header.Name, "/")

			// log.Printf("Adding %v from %v", header.Name, path)

			if info.IsDir() {
				header.Name += "/"
			} else {
				header.Method = zip.Deflate
			}

			writer, err := gz.CreateHeader(header)
			if err != nil {
				return err
			}

			if info.IsDir() {
				return nil
			}

			file, err := os.Open(path)
			if err != nil {
				return err
			}
			defer file.Close()
			_, err = io.Copy(writer, file)
			return err
		})
		return
	}
}

func GetJobZip(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	key := vars["id"]
	job := jobs[key]
	if job == nil {
		http.Error(w, fmt.Sprintf("job %v does not exist", key), http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Disposition", "attachment;filename="+job.EndPoint+"-"+job.UUID+".zip")
	gz := zip.NewWriter(w)
	defer gz.Close()

	filepath.Walk(job.WorkingDirectory, getDirectoryStreamer(job, gz))
}

func getDirectoryStreamer(job *Job, gz *zip.Writer) func(path string, info os.FileInfo, err error) error {
	return func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		log.Printf("Walking %v", path)
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		header.Name = filepath.Join(job.UUID, strings.TrimPrefix(path, job.WorkingDirectory))

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := gz.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	}
}

func GetHealth(w http.ResponseWriter, request *http.Request) {
	numberOfJobs := len(jobs)
	if numberOfJobs <= config.WarnLevel {
		w.WriteHeader(200)
	} else if numberOfJobs <= config.CriticalLevel {
		w.WriteHeader(429)
	} else {
		w.WriteHeader(500)
	}
	json.NewEncoder(w).Encode(jobs)
}
<commit_msg>Ensure services are only setup once<commit_after>package main

import (
	"archive/zip"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/gorilla/mux"
	uuid "github.com/satori/go.uuid"
)

var jobMutex sync.Mutex
var jobs = make(map[string]*Job)

type SlicerService struct {
	EndPoint   string `yaml:"endPoint"`
	Executable string `yaml:"executable"`
}

type Service struct {
	EndPoint          string            `yaml:"endPoint" json:"end_point"`
	CommandLine       []string          `yaml:"commandLine" json:"command_line"`
	Description       string            `json:"description"`
	Defaults          map[string]string `json:"defaults" yaml:"defaults"`
	CreateEmptyOutput bool              `json:"create_empty_output" yaml:"create_empty_output"`
	Arguments         []string          `json:"arguments"`
	Parameters        []string          `json:"parameters"`
	InputFiles        []string          `json:"input_files"`
	OutputFiles       []string          `json:"output_files"`
	InputZip          []string          `json:"input_directories"`
	OutputZip         []string          `json:"output_directories"`
	isSetup           bool
}

// Parse our argements
func NewService() *Service {
	var service Service
	service.Defaults = make(map[string]string)
	service.Arguments = make([]string, 0)
	service.Parameters = make([]string, 0)
	service.InputFiles = make([]string, 0)
	service.OutputFiles = make([]string, 0)
	return &service
}

func (service *Service) setup() *Service {
	if service.isSetup {
		return service
	}
	if service.Defaults == nil {
		service.Defaults = make(map[string]string)
	}
	if service.Arguments == nil {
		service.Arguments = make([]string, 0)
	}
	if service.Parameters == nil {
		service.Parameters = make([]string, 0)
	}
	if service.InputFiles == nil {
		service.InputFiles = make([]string, 0)
	}
	if service.OutputFiles == nil {
		service.OutputFiles = make([]string, 0)
	}
	if service.InputZip == nil {
		service.InputZip = make([]string, 0)
	}
	if service.OutputZip == nil {
		service.OutputZip = make([]string, 0)
	}
	for _, arg := range service.CommandLine {
		// Do we start with an # or other prefix?  If so, add to proper
		// structure and argument list
		key := arg[1:]
		prefix := arg[0]
		isArg := false

		if prefix == '#' {
			isArg = true
			service.Parameters = append(service.Arguments, key)
		} else if prefix == '<' {
			isArg = true
			service.InputFiles = append(service.InputFiles, key)
		} else if prefix == '>' {
			isArg = true
			service.OutputFiles = append(service.OutputFiles, key)
		} else if prefix == '^' {
			isArg = true
			service.InputZip = append(service.InputZip, key)
		} else if prefix == '~' {
			isArg = true
			service.OutputZip = append(service.OutputZip, key)
		}
		if isArg {
			service.Arguments = append(service.Arguments, key)
		}
	}
	service.isSetup = true
	return service
}

// Return all services as JSON
func GetServices(w http.ResponseWriter, request *http.Request) {
	json.NewEncoder(w).Encode(config)
}

// Particular info about a service as JSON
func GetService(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	service := config.ServiceMap[vars["id"]]
	json.NewEncoder(w).Encode(service)
}

// Start up the service
func StartService(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	service := config.ServiceMap[vars["id"]]
	if service == nil {
		http.Error(w, "service not found", http.StatusNotFound)
		return
	}
	log.Printf("Found service %v on endpoint %v", vars["id"], service.EndPoint)
	// Pull out our arguments
	err := request.ParseMultipartForm(10 * 1024 * 1024)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	job := Job{
		UUID:        uuid.NewV4().String(),
		Service:     service,
		CommandLine: service.CommandLine,
		FileMap:     make(map[string]string),
		ZipMap:      make(map[string]string),
		EndPoint:    service.EndPoint,
		Host:        advertisedHost,
		Port:        advertisedPort,
		Address:     make([]string, 0),
	}

	// do we have an email address?
	if request.MultipartForm.Value["mail"] != nil {
		job.Address = request.MultipartForm.Value["mail"]
	}

	// Make a working directory
	job.WorkingDirectory = filepath.Join(config.Directory, service.EndPoint, job.UUID)
	err = os.MkdirAll(job.WorkingDirectory, 0755)
	if err != nil {
		log.Printf("Error making working directory: %v", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = job.ParseCommandLine(request)
	if err != nil {
		log.Printf("Error parsing command line: %v", err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	job.Start()
	json.NewEncoder(w).Encode(&job)
	jobs[job.UUID] = &job
}

func GetJob(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	job := jobs[vars["id"]]
	json.NewEncoder(w).Encode(job)
}

func WaitForJob(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	job := jobs[vars["id"]]
	job.Wait()
	json.NewEncoder(w).Encode(job)
}

func GetJobFile(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	key := vars["id"]
	job := jobs[key]
	if job == nil {
		http.Error(w, fmt.Sprintf("job %v does not exist", key), http.StatusInternalServerError)
		return
	}
	file, ok := job.FileMap[vars["filename"]]
	if ok {
		fileToSend := filepath.Join(job.WorkingDirectory, file)
		log.Printf("Request for %s, sending %s", vars["filename"], fileToSend)
		w.Header().Set("Content-Disposition", "attachment;filename="+filepath.Base(file))
		http.ServeFile(w, request, fileToSend)
		return
	}
	file, ok = job.ZipMap[vars["filename"]]
	if ok {
		outputDirectory := filepath.Join(job.WorkingDirectory, file)
		zipFilename := filepath.Base(vars["filename"])
		if !strings.HasSuffix(zipFilename, ".zip") {
			zipFilename += ".zip"
		}
		log.Printf("Requested %v: sending directory %v as a zip file", vars["filename"], outputDirectory)
		w.Header().Set("Content-Disposition", "attachment; filename=\""+zipFilename+"\"")
		gz := zip.NewWriter(w)
		defer gz.Close()

		filepath.Walk(outputDirectory, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			// Don't create an entry for the root of the directory
			if path == outputDirectory {
				return err
			}

			header, err := zip.FileInfoHeader(info)
			if err != nil {
				return err
			}

			// Take off the path, and a leading "/" to make the output relative
			header.Name = strings.TrimPrefix(path, outputDirectory)
			header.Name = strings.TrimPrefix(header.Name, "/")

			// log.Printf("Adding %v from %v", header.Name, path)

			if info.IsDir() {
				header.Name += "/"
			} else {
				header.Method = zip.Deflate
			}

			writer, err := gz.CreateHeader(header)
			if err != nil {
				return err
			}

			if info.IsDir() {
				return nil
			}

			file, err := os.Open(path)
			if err != nil {
				return err
			}
			defer file.Close()
			_, err = io.Copy(writer, file)
			return err
		})
		return
	}
}

func GetJobZip(w http.ResponseWriter, request *http.Request) {
	vars := mux.Vars(request)
	key := vars["id"]
	job := jobs[key]
	if job == nil {
		http.Error(w, fmt.Sprintf("job %v does not exist", key), http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Disposition", "attachment;filename="+job.EndPoint+"-"+job.UUID+".zip")
	gz := zip.NewWriter(w)
	defer gz.Close()

	filepath.Walk(job.WorkingDirectory, getDirectoryStreamer(job, gz))
}

func getDirectoryStreamer(job *Job, gz *zip.Writer) func(path string, info os.FileInfo, err error) error {
	return func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		log.Printf("Walking %v", path)
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		header.Name = filepath.Join(job.UUID, strings.TrimPrefix(path, job.WorkingDirectory))

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := gz.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	}
}

func GetHealth(w http.ResponseWriter, request *http.Request) {
	numberOfJobs := len(jobs)
	if numberOfJobs <= config.WarnLevel {
		w.WriteHeader(200)
	} else if numberOfJobs <= config.CriticalLevel {
		w.WriteHeader(429)
	} else {
		w.WriteHeader(500)
	}
	json.NewEncoder(w).Encode(jobs)
}
<|endoftext|>


<commit_before>package api

import (
	"sort"
	"time"
)

// Evaluations is used to query the evaluation endpoints.
type Evaluations struct {
	client *Client
}

// Evaluations returns a new handle on the evaluations.
func (c *Client) Evaluations() *Evaluations {
	return &Evaluations{client: c}
}

// List is used to dump all of the evaluations.
func (e *Evaluations) List(q *QueryOptions) ([]*Evaluation, *QueryMeta, error) {
	var resp []*Evaluation
	qm, err := e.client.query("/v1/evaluations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(EvalIndexSort(resp))
	return resp, qm, nil
}

func (e *Evaluations) PrefixList(prefix string) ([]*Evaluation, *QueryMeta, error) {
	return e.List(&QueryOptions{Prefix: prefix})
}

// Info is used to query a single evaluation by its ID.
func (e *Evaluations) Info(evalID string, q *QueryOptions) (*Evaluation, *QueryMeta, error) {
	var resp Evaluation
	qm, err := e.client.query("/v1/evaluation/"+evalID, &resp, q)
	if err != nil {
		return nil, nil, err
	}
	return &resp, qm, nil
}

// Allocations is used to retrieve a set of allocations given
// an evaluation ID.
func (e *Evaluations) Allocations(evalID string, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
	var resp []*AllocationListStub
	qm, err := e.client.query("/v1/evaluation/"+evalID+"/allocations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(AllocIndexSort(resp))
	return resp, qm, nil
}

// Evaluation is used to serialize an evaluation.
type Evaluation struct {
	ID                string
	Priority          int
	Type              string
	TriggeredBy       string
	JobID             string
	JobModifyIndex    uint64
	NodeID            string
	NodeModifyIndex   uint64
	Status            string
	StatusDescription string
	Wait              time.Duration
	NextEval          string
	PreviousEval      string
	BlockedEval       string
	FailedTGAllocs    map[string]*AllocationMetric
	CreateIndex       uint64
	ModifyIndex       uint64
}

// EvalIndexSort is a wrapper to sort evaluations by CreateIndex.
// We reverse the test so that we get the highest index first.
type EvalIndexSort []*Evaluation

func (e EvalIndexSort) Len() int {
	return len(e)
}

func (e EvalIndexSort) Less(i, j int) bool {
	return e[i].CreateIndex > e[j].CreateIndex
}

func (e EvalIndexSort) Swap(i, j int) {
	e[i], e[j] = e[j], e[i]
}
<commit_msg>Add QueuedAllocations to api.Evaluation<commit_after>package api

import (
	"sort"
	"time"
)

// Evaluations is used to query the evaluation endpoints.
type Evaluations struct {
	client *Client
}

// Evaluations returns a new handle on the evaluations.
func (c *Client) Evaluations() *Evaluations {
	return &Evaluations{client: c}
}

// List is used to dump all of the evaluations.
func (e *Evaluations) List(q *QueryOptions) ([]*Evaluation, *QueryMeta, error) {
	var resp []*Evaluation
	qm, err := e.client.query("/v1/evaluations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(EvalIndexSort(resp))
	return resp, qm, nil
}

func (e *Evaluations) PrefixList(prefix string) ([]*Evaluation, *QueryMeta, error) {
	return e.List(&QueryOptions{Prefix: prefix})
}

// Info is used to query a single evaluation by its ID.
func (e *Evaluations) Info(evalID string, q *QueryOptions) (*Evaluation, *QueryMeta, error) {
	var resp Evaluation
	qm, err := e.client.query("/v1/evaluation/"+evalID, &resp, q)
	if err != nil {
		return nil, nil, err
	}
	return &resp, qm, nil
}

// Allocations is used to retrieve a set of allocations given
// an evaluation ID.
func (e *Evaluations) Allocations(evalID string, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
	var resp []*AllocationListStub
	qm, err := e.client.query("/v1/evaluation/"+evalID+"/allocations", &resp, q)
	if err != nil {
		return nil, nil, err
	}
	sort.Sort(AllocIndexSort(resp))
	return resp, qm, nil
}

// Evaluation is used to serialize an evaluation.
type Evaluation struct {
	ID                string
	Priority          int
	Type              string
	TriggeredBy       string
	JobID             string
	JobModifyIndex    uint64
	NodeID            string
	NodeModifyIndex   uint64
	Status            string
	StatusDescription string
	Wait              time.Duration
	NextEval          string
	PreviousEval      string
	BlockedEval       string
	FailedTGAllocs    map[string]*AllocationMetric
	QueuedAllocations map[string]int
	CreateIndex       uint64
	ModifyIndex       uint64
}

// EvalIndexSort is a wrapper to sort evaluations by CreateIndex.
// We reverse the test so that we get the highest index first.
type EvalIndexSort []*Evaluation

func (e EvalIndexSort) Len() int {
	return len(e)
}

func (e EvalIndexSort) Less(i, j int) bool {
	return e[i].CreateIndex > e[j].CreateIndex
}

func (e EvalIndexSort) Swap(i, j int) {
	e[i], e[j] = e[j], e[i]
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package syscall

import "unsafe"

func Getpagesize() int	{ return 4096 }

func TimespecToNsec(ts Timespec) int64	{ return int64(ts.Sec)*1e9 + int64(ts.Nsec) }

func NsecToTimespec(nsec int64) (ts Timespec) {
	ts.Sec = int32(nsec / 1e9);
	ts.Nsec = int32(nsec % 1e9);
	return;
}

func TimevalToNsec(tv Timeval) int64	{ return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }

func NsecToTimeval(nsec int64) (tv Timeval) {
	nsec += 999;	// round up to microsecond
	tv.Sec = int32(nsec / 1e9);
	tv.Usec = int32(nsec % 1e9 / 1e3);
	return;
}

// 64-bit file system and 32-bit uid calls
// (386 default is 32-bit file system and 16-bit uid).
//sys	Chown(path string, uid int, gid int) (errno int) = SYS_CHOWN32
//sys	Fchown(fd int, uid int, gid int) (errno int) = SYS_FCHOWN32
//sys	Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
//sys	Fstatfs(fd int, buf *Statfs_t) (errno int) = SYS_FSTATFS64
//sys	Getegid() (egid int) = SYS_GETEGID32
//sys	Geteuid() (euid int) = SYS_GETEUID32
//sys	Getgid() (gid int) = SYS_GETGID32
//sys	Getuid() (uid int) = SYS_GETUID32
//sys	Ioperm(from int, num int, on int) (errno int)
//sys	Iopl(level int) (errno int)
//sys	Lchown(path string, uid int, gid int) (errno int) = SYS_LCHOWN32
//sys	Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
//sys	Setfsgid(gid int) (errno int) = SYS_SETFSGID32
//sys	Setfsuid(uid int) (errno int) = SYS_SETFSUID32
//sys	Setgid(gid int) (errno int) = SYS_SETGID32
//sys	Setregid(rgid int, egid int) (errno int) = SYS_SETREGID32
//sys	Setresgid(rgid int, egid int, sgid int) (errno int) = SYS_SETRESGID32
//sys	Setresuid(ruid int, euid int, suid int) (errno int) = SYS_SETRESUID32
//sys	Setreuid(ruid int, euid int) (errno int) = SYS_SETREUID32
//sys	Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
//sys	Statfs(path string, buf *Statfs_t) (errno int) = SYS_STATFS64
//sys	SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
//sys	getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
//sys	setgroups(n int, list *_Gid_t) (errno int) = SYS_SETGROUPS32
//sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) = SYS__NEWSELECT

// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)

// On x86 Linux, all the socket calls go through an extra indirection,
// I think because the 5-register system call interface can't handle
// the 6-argument calls like sendto and recvfrom.  Instead the
// arguments to the underlying system call are the number below
// and a pointer to an array of uintptr.  We hide the pointer in the
// socketcall assembly to avoid allocation on every system call.

const (
	// see linux/net.h
	_SOCKET		= 1;
	_BIND		= 2;
	_CONNECT	= 3;
	_LISTEN		= 4;
	_ACCEPT		= 5;
	_GETSOCKNAME	= 6;
	_GETPEERNAME	= 7;
	_SOCKETPAIR	= 8;
	_SEND		= 9;
	_RECV		= 10;
	_SENDTO		= 11;
	_RECVFROM	= 12;
	_SHUTDOWN	= 13;
	_SETSOCKOPT	= 14;
	_GETSOCKOPT	= 15;
	_SENDMSG	= 16;
	_RECVMSG	= 17;
)

func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)

func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
	fd, errno = socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0);
	return;
}

func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
	_, errno = socketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0);
	return;
}

func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
	_, errno = socketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0);
	return;
}

func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
	_, errno = socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0);
	return;
}

func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
	_, errno = socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0);
	return;
}

func socket(domain int, typ int, proto int) (fd int, errno int) {
	fd, errno = socketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0);
	return;
}

func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
	_, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0);
	return;
}

func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
	var base uintptr;
	if len(p) > 0 {
		base = uintptr(unsafe.Pointer(&p[0]))
	}
	n, errno = socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)));
	return;
}

func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
	var base uintptr;
	if len(p) > 0 {
		base = uintptr(unsafe.Pointer(&p[0]))
	}
	_, errno = socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen));
	return;
}

func Listen(s int, n int) (errno int) {
	_, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0);
	return;
}

func (r *PtraceRegs) PC() uint64	{ return uint64(uint32(r.Eip)) }

func (r *PtraceRegs) SetPC(pc uint64)	{ r.Eip = int32(pc) }
<commit_msg>Add Shutdown to 32-bit GNU/Linux build.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package syscall

import "unsafe"

func Getpagesize() int	{ return 4096 }

func TimespecToNsec(ts Timespec) int64	{ return int64(ts.Sec)*1e9 + int64(ts.Nsec) }

func NsecToTimespec(nsec int64) (ts Timespec) {
	ts.Sec = int32(nsec / 1e9);
	ts.Nsec = int32(nsec % 1e9);
	return;
}

func TimevalToNsec(tv Timeval) int64	{ return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }

func NsecToTimeval(nsec int64) (tv Timeval) {
	nsec += 999;	// round up to microsecond
	tv.Sec = int32(nsec / 1e9);
	tv.Usec = int32(nsec % 1e9 / 1e3);
	return;
}

// 64-bit file system and 32-bit uid calls
// (386 default is 32-bit file system and 16-bit uid).
//sys	Chown(path string, uid int, gid int) (errno int) = SYS_CHOWN32
//sys	Fchown(fd int, uid int, gid int) (errno int) = SYS_FCHOWN32
//sys	Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
//sys	Fstatfs(fd int, buf *Statfs_t) (errno int) = SYS_FSTATFS64
//sys	Getegid() (egid int) = SYS_GETEGID32
//sys	Geteuid() (euid int) = SYS_GETEUID32
//sys	Getgid() (gid int) = SYS_GETGID32
//sys	Getuid() (uid int) = SYS_GETUID32
//sys	Ioperm(from int, num int, on int) (errno int)
//sys	Iopl(level int) (errno int)
//sys	Lchown(path string, uid int, gid int) (errno int) = SYS_LCHOWN32
//sys	Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
//sys	Setfsgid(gid int) (errno int) = SYS_SETFSGID32
//sys	Setfsuid(uid int) (errno int) = SYS_SETFSUID32
//sys	Setgid(gid int) (errno int) = SYS_SETGID32
//sys	Setregid(rgid int, egid int) (errno int) = SYS_SETREGID32
//sys	Setresgid(rgid int, egid int, sgid int) (errno int) = SYS_SETRESGID32
//sys	Setresuid(ruid int, euid int, suid int) (errno int) = SYS_SETRESUID32
//sys	Setreuid(ruid int, euid int) (errno int) = SYS_SETREUID32
//sys	Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
//sys	Statfs(path string, buf *Statfs_t) (errno int) = SYS_STATFS64
//sys	SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
//sys	getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
//sys	setgroups(n int, list *_Gid_t) (errno int) = SYS_SETGROUPS32
//sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) = SYS__NEWSELECT

// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)

// On x86 Linux, all the socket calls go through an extra indirection,
// I think because the 5-register system call interface can't handle
// the 6-argument calls like sendto and recvfrom.  Instead the
// arguments to the underlying system call are the number below
// and a pointer to an array of uintptr.  We hide the pointer in the
// socketcall assembly to avoid allocation on every system call.

const (
	// see linux/net.h
	_SOCKET		= 1;
	_BIND		= 2;
	_CONNECT	= 3;
	_LISTEN		= 4;
	_ACCEPT		= 5;
	_GETSOCKNAME	= 6;
	_GETPEERNAME	= 7;
	_SOCKETPAIR	= 8;
	_SEND		= 9;
	_RECV		= 10;
	_SENDTO		= 11;
	_RECVFROM	= 12;
	_SHUTDOWN	= 13;
	_SETSOCKOPT	= 14;
	_GETSOCKOPT	= 15;
	_SENDMSG	= 16;
	_RECVMSG	= 17;
)

func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)

func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
	fd, errno = socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0);
	return;
}

func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
	_, errno = socketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0);
	return;
}

func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
	_, errno = socketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0);
	return;
}

func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
	_, errno = socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0);
	return;
}

func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
	_, errno = socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0);
	return;
}

func socket(domain int, typ int, proto int) (fd int, errno int) {
	fd, errno = socketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0);
	return;
}

func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
	_, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0);
	return;
}

func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
	var base uintptr;
	if len(p) > 0 {
		base = uintptr(unsafe.Pointer(&p[0]))
	}
	n, errno = socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)));
	return;
}

func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
	var base uintptr;
	if len(p) > 0 {
		base = uintptr(unsafe.Pointer(&p[0]))
	}
	_, errno = socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen));
	return;
}

func Listen(s int, n int) (errno int) {
	_, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0);
	return;
}

func Shutdown(s, how int) (errno int) {
	_, errno = socketcall(_SHUTDOWN, uintptr(s), uintptr(how), 0, 0, 0, 0);
	return;
}

func (r *PtraceRegs) PC() uint64	{ return uint64(uint32(r.Eip)) }

func (r *PtraceRegs) SetPC(pc uint64)	{ r.Eip = int32(pc) }
<|endoftext|>