<commit_before>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tournaments

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strconv"

	"appengine"
	"appengine/taskqueue"

	"github.com/taironas/route"

	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	mdl "github.com/santiaago/gonawin/models"
)

// addAdmin type holds the information needed read the request and log any errors.
type addAdmin struct {
	c    appengine.Context // appengine context
	desc string            // handler description
	r    *http.Request     // the HTTP request
}

// tournament returns a tournament instance.
// It gets the 'tournamentId' from the request and queries the datastore to get
// the tournament.
func (aa addAdmin) tournament() (*mdl.Tournament, error) {

	strTournamentId, err := route.Context.Get(aa.r, "tournamentId")
	if err != nil {
		log.Errorf(aa.c, "%s error getting tournament id, err:%v", aa.desc, err)
		return nil, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var tournamentId int64
	tournamentId, err = strconv.ParseInt(strTournamentId, 0, 64)
	if err != nil {
		log.Errorf(aa.c, "%s error converting tournament id from string to int64, err:%v", aa.desc, err)
		return nil, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var tournament *mdl.Tournament
	if tournament, err = mdl.TournamentById(aa.c, tournamentId); err != nil {
		log.Errorf(aa.c, "%s tournament not found: %v", aa.desc, err)
		return nil, &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}
	return tournament, nil
}

// userId returns a userId.
// It gets the 'userId' from the request and parses it to int64
func (aa addAdmin) userId() (int64, error) {

	strUserId, err := route.Context.Get(aa.r, "userId")
	if err != nil {
		log.Errorf(aa.c, "%s error getting user id, err:%v", aa.desc, err)
		return 0, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	var userId int64
	userId, err = strconv.ParseInt(strUserId, 0, 64)
	if err != nil {
		log.Errorf(aa.c, "%s error converting user id from string to int64, err:%v", aa.desc, err)
		return 0, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}
	return userId, nil
}

// admin returns a admin mdl.User object with respect to the
// userId passed as param.
func (aa addAdmin) admin(userId int64) (*mdl.User, error) {

	newAdmin, err := mdl.UserById(aa.c, userId)
	log.Infof(aa.c, "%s User: %v", aa.desc, newAdmin)
	if err != nil {
		log.Errorf(aa.c, "%s user not found", aa.desc)
		return nil, &helpers.NotFound{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}
	return newAdmin, nil
}

// AddAdmin let you add an admin to a tournament.
//	GET	/j/tournaments/[0-9]+/admin/add/
//
func AddAdmin(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament add admin Handler:"

	aa := addAdmin{c, desc, r}

	var tournament *mdl.Tournament
	var err error

	if tournament, err = aa.tournament(); err != nil {
		return err
	}

	var userId int64
	if userId, err = aa.userId(); err != nil {
		return err
	}

	var newAdmin *mdl.User
	if newAdmin, err = aa.admin(userId); err != nil {
		return err
	}

	// add admin to tournament
	if err = tournament.AddAdmin(c, newAdmin.Id); err != nil {
		log.Errorf(c, "%s error on AddAdmin to tournament: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	// send response
	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name", "AdminIds", "Private"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	msg := fmt.Sprintf("You added %s as admin of tournament %s.", newAdmin.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}

// RemoveAdmin handler lets you remove an admin from a tournament.
//
// Use this handler to remove a user as admin of the current tournament.
//	GET	/j/tournaments/[0-9]+/admin/remove/
//
func RemoveAdmin(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	c := appengine.NewContext(r)
	desc := "Tournament remove admin Handler:"

	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	// get tournament id and user id
	strTournamentId, err1 := route.Context.Get(r, "tournamentId")
	if err1 != nil {
		log.Errorf(c, "%s error getting tournament id, err:%v", desc, err1)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var tournamentId int64
	tournamentId, err1 = strconv.ParseInt(strTournamentId, 0, 64)
	if err1 != nil {
		log.Errorf(c, "%s error converting tournament id from string to int64, err:%v", desc, err1)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	strUserId, err2 := route.Context.Get(r, "userId")
	if err2 != nil {
		log.Errorf(c, "%s error getting user id, err:%v", desc, err2)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	var userId int64
	userId, err2 = strconv.ParseInt(strUserId, 0, 64)
	if err2 != nil {
		log.Errorf(c, "%s error converting user id from string to int64, err:%v", desc, err2)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	var tournament *mdl.Tournament
	if tournament, err1 = mdl.TournamentById(c, tournamentId); err1 != nil {
		log.Errorf(c, "%s tournament not found: %v.", desc, err1)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var oldAdmin *mdl.User
	oldAdmin, err := mdl.UserById(c, userId)
	log.Infof(c, "%s User: %v.", desc, oldAdmin)
	if err != nil {
		log.Errorf(c, "%s user not found.", desc)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	if err = tournament.RemoveAdmin(c, oldAdmin.Id); err != nil {
		log.Errorf(c, "%s error on RemoveAdmin to tournament: %v.", desc, err)
		return &helpers.InternalServerError{Err: err}
	}

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name", "AdminIds", "Private"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	msg := fmt.Sprintf("You removed %s as admin of tournament %s.", oldAdmin.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}
	return templateshlp.RenderJson(w, c, data)

}

// Tournament sync scores handler:
//
// Use this handler to run taks to sync scores of all users in tournament.
//	GET	/j/tournaments/[0-9]+/admin/syncscores/
//
func SyncScores(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	c := appengine.NewContext(r)
	desc := "Tournament sync scores Handler:"
	log.Infof(c, "%v", desc)
	if r.Method == "POST" {
		// get tournament id
		strTournamentId, err := route.Context.Get(r, "tournamentId")
		if err != nil {
			log.Errorf(c, "%s error getting tournament id, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournamentId int64
		tournamentId, err = strconv.ParseInt(strTournamentId, 0, 64)
		if err != nil {
			log.Errorf(c, "%s error converting tournament id from string to int64, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournament *mdl.Tournament
		if tournament, err = mdl.TournamentById(c, tournamentId); err != nil {
			log.Errorf(c, "%s tournament not found: %v", desc, err)
			return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}
		// prepare data to add task to queue.
		b1, errm := json.Marshal(tournament)
		if errm != nil {
			log.Errorf(c, "%s Error marshaling", desc, errm)
		}

		task := taskqueue.NewPOSTTask("/a/sync/scores/", url.Values{
			"tournament": []string{string(b1)},
		})

		if _, err = taskqueue.Add(c, task, "gw-queue"); err != nil {
			log.Errorf(c, "%s unable to add task to taskqueue.", desc)
			return err
		} else {
			log.Infof(c, "%s add task to taskqueue successfully", desc)
		}

		msg := fmt.Sprintf("You send task to synch scores for all users.")
		data := struct {
			MessageInfo string `json:",omitempty"`
		}{
			msg,
		}

		return templateshlp.RenderJson(w, c, data)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}

// Tournament activate phase handler:
//
// Use this handler to activate all the matches of given phase in tournament.
//	GET	/j/tournaments/[0-9]+/admin/activatephase/
//
func ActivatePhase(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	c := appengine.NewContext(r)
	desc := "Tournament activate phase handler:"
	log.Infof(c, "%v", desc)
	if r.Method == "POST" {
		// get tournament id
		strTournamentId, err := route.Context.Get(r, "tournamentId")
		if err != nil {
			log.Errorf(c, "%s error getting tournament id, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournamentId int64
		tournamentId, err = strconv.ParseInt(strTournamentId, 0, 64)
		if err != nil {
			log.Errorf(c, "%s error converting tournament id from string to int64, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournament *mdl.Tournament
		if tournament, err = mdl.TournamentById(c, tournamentId); err != nil {
			log.Errorf(c, "%s tournament not found: %v", desc, err)
			return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		phaseName := r.FormValue("phaseName")

		matches := mdl.GetMatchesByPhase(c, tournament, phaseName)

		for _, match := range matches {
			match.Ready = true
		}

		return mdl.UpdateMatches(c, matches)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}
<commit_msg>rename type addAdmin to requestContext<commit_after>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tournaments

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strconv"

	"appengine"
	"appengine/taskqueue"

	"github.com/taironas/route"

	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	mdl "github.com/santiaago/gonawin/models"
)

// requestContext type holds the information needed read the request and log any errors.
type requestContext struct {
	c    appengine.Context // appengine context
	desc string            // handler description
	r    *http.Request     // the HTTP request
}

// tournament returns a tournament instance.
// It gets the 'tournamentId' from the request and queries the datastore to get
// the tournament.
func (rc requestContext) tournament() (*mdl.Tournament, error) {

	strTournamentId, err := route.Context.Get(rc.r, "tournamentId")
	if err != nil {
		log.Errorf(rc.c, "%s error getting tournament id, err:%v", rc.desc, err)
		return nil, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var tournamentId int64
	tournamentId, err = strconv.ParseInt(strTournamentId, 0, 64)
	if err != nil {
		log.Errorf(rc.c, "%s error converting tournament id from string to int64, err:%v", rc.desc, err)
		return nil, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var tournament *mdl.Tournament
	if tournament, err = mdl.TournamentById(rc.c, tournamentId); err != nil {
		log.Errorf(rc.c, "%s tournament not found: %v", rc.desc, err)
		return nil, &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}
	return tournament, nil
}

// userId returns a userId.
// It gets the 'userId' from the request and parses it to int64
func (rc requestContext) userId() (int64, error) {

	strUserId, err := route.Context.Get(rc.r, "userId")
	if err != nil {
		log.Errorf(rc.c, "%s error getting user id, err:%v", rc.desc, err)
		return 0, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	var userId int64
	userId, err = strconv.ParseInt(strUserId, 0, 64)
	if err != nil {
		log.Errorf(rc.c, "%s error converting user id from string to int64, err:%v", rc.desc, err)
		return 0, &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}
	return userId, nil
}

// admin returns a admin mdl.User object with respect to the
// userId passed as param.
func (rc requestContext) admin(userId int64) (*mdl.User, error) {

	newAdmin, err := mdl.UserById(rc.c, userId)
	log.Infof(rc.c, "%s User: %v", rc.desc, newAdmin)
	if err != nil {
		log.Errorf(rc.c, "%s user not found", rc.desc)
		return nil, &helpers.NotFound{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}
	return newAdmin, nil
}

// AddAdmin let you add an admin to a tournament.
//	GET	/j/tournaments/[0-9]+/admin/add/
//
func AddAdmin(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament add admin Handler:"

	rc := requestContext{c, desc, r}

	var tournament *mdl.Tournament
	var err error

	if tournament, err = rc.tournament(); err != nil {
		return err
	}

	var userId int64
	if userId, err = rc.userId(); err != nil {
		return err
	}

	var newAdmin *mdl.User
	if newAdmin, err = rc.admin(userId); err != nil {
		return err
	}

	// add admin to tournament
	if err = tournament.AddAdmin(c, newAdmin.Id); err != nil {
		log.Errorf(c, "%s error on AddAdmin to tournament: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	// send response
	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name", "AdminIds", "Private"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	msg := fmt.Sprintf("You added %s as admin of tournament %s.", newAdmin.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}

// RemoveAdmin handler lets you remove an admin from a tournament.
//
// Use this handler to remove a user as admin of the current tournament.
//	GET	/j/tournaments/[0-9]+/admin/remove/
//
func RemoveAdmin(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament remove admin Handler:"

	// get tournament id and user id
	strTournamentId, err1 := route.Context.Get(r, "tournamentId")
	if err1 != nil {
		log.Errorf(c, "%s error getting tournament id, err:%v", desc, err1)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var tournamentId int64
	tournamentId, err1 = strconv.ParseInt(strTournamentId, 0, 64)
	if err1 != nil {
		log.Errorf(c, "%s error converting tournament id from string to int64, err:%v", desc, err1)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	var tournament *mdl.Tournament
	if tournament, err1 = mdl.TournamentById(c, tournamentId); err1 != nil {
		log.Errorf(c, "%s tournament not found: %v.", desc, err1)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
	}

	strUserId, err2 := route.Context.Get(r, "userId")
	if err2 != nil {
		log.Errorf(c, "%s error getting user id, err:%v", desc, err2)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	var userId int64
	userId, err2 = strconv.ParseInt(strUserId, 0, 64)
	if err2 != nil {
		log.Errorf(c, "%s error converting user id from string to int64, err:%v", desc, err2)
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	var oldAdmin *mdl.User
	oldAdmin, err := mdl.UserById(c, userId)
	log.Infof(c, "%s User: %v.", desc, oldAdmin)
	if err != nil {
		log.Errorf(c, "%s user not found.", desc)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeUserNotFound)}
	}

	if err = tournament.RemoveAdmin(c, oldAdmin.Id); err != nil {
		log.Errorf(c, "%s error on RemoveAdmin to tournament: %v.", desc, err)
		return &helpers.InternalServerError{Err: err}
	}

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name", "AdminIds", "Private"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	msg := fmt.Sprintf("You removed %s as admin of tournament %s.", oldAdmin.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}
	return templateshlp.RenderJson(w, c, data)

}

// Tournament sync scores handler:
//
// Use this handler to run taks to sync scores of all users in tournament.
//	GET	/j/tournaments/[0-9]+/admin/syncscores/
//
func SyncScores(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	c := appengine.NewContext(r)
	desc := "Tournament sync scores Handler:"
	log.Infof(c, "%v", desc)
	if r.Method == "POST" {
		// get tournament id
		strTournamentId, err := route.Context.Get(r, "tournamentId")
		if err != nil {
			log.Errorf(c, "%s error getting tournament id, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournamentId int64
		tournamentId, err = strconv.ParseInt(strTournamentId, 0, 64)
		if err != nil {
			log.Errorf(c, "%s error converting tournament id from string to int64, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournament *mdl.Tournament
		if tournament, err = mdl.TournamentById(c, tournamentId); err != nil {
			log.Errorf(c, "%s tournament not found: %v", desc, err)
			return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}
		// prepare data to add task to queue.
		b1, errm := json.Marshal(tournament)
		if errm != nil {
			log.Errorf(c, "%s Error marshaling", desc, errm)
		}

		task := taskqueue.NewPOSTTask("/a/sync/scores/", url.Values{
			"tournament": []string{string(b1)},
		})

		if _, err = taskqueue.Add(c, task, "gw-queue"); err != nil {
			log.Errorf(c, "%s unable to add task to taskqueue.", desc)
			return err
		} else {
			log.Infof(c, "%s add task to taskqueue successfully", desc)
		}

		msg := fmt.Sprintf("You send task to synch scores for all users.")
		data := struct {
			MessageInfo string `json:",omitempty"`
		}{
			msg,
		}

		return templateshlp.RenderJson(w, c, data)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}

// Tournament activate phase handler:
//
// Use this handler to activate all the matches of given phase in tournament.
//	GET	/j/tournaments/[0-9]+/admin/activatephase/
//
func ActivatePhase(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	c := appengine.NewContext(r)
	desc := "Tournament activate phase handler:"
	log.Infof(c, "%v", desc)
	if r.Method == "POST" {
		// get tournament id
		strTournamentId, err := route.Context.Get(r, "tournamentId")
		if err != nil {
			log.Errorf(c, "%s error getting tournament id, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournamentId int64
		tournamentId, err = strconv.ParseInt(strTournamentId, 0, 64)
		if err != nil {
			log.Errorf(c, "%s error converting tournament id from string to int64, err:%v", desc, err)
			return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		var tournament *mdl.Tournament
		if tournament, err = mdl.TournamentById(c, tournamentId); err != nil {
			log.Errorf(c, "%s tournament not found: %v", desc, err)
			return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		phaseName := r.FormValue("phaseName")

		matches := mdl.GetMatchesByPhase(c, tournament, phaseName)

		for _, match := range matches {
			match.Ready = true
		}

		return mdl.UpdateMatches(c, matches)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}
<|endoftext|>


<commit_before>package gol

import "fmt"

type mask level

const (
	MASK_ALL     mask = mask(LEVEL_CRITICAL) | mask(LEVEL_ERROR) | mask(LEVEL_WARNING) | mask(LEVEL_INFO) | mask(LEVEL_DEBUG)
	MASK_DEFAULT mask = mask(LEVEL_CRITICAL) | mask(LEVEL_ERROR) | mask(LEVEL_WARNING) | mask(LEVEL_INFO)
)

func maskByName(name string) (mask mask, error error) {
	switch (name) {
	case "all":
		mask = MASK_ALL
		return
	case "default":
		mask = MASK_DEFAULT
		return
	}
	error = fmt.Errorf("unknown mask '%s', try 'all' or 'default'", name)
	return
}
<commit_msg>added another default mask case<commit_after>package gol

import "fmt"

type mask level

const (
	MASK_ALL     mask = mask(LEVEL_CRITICAL) | mask(LEVEL_ERROR) | mask(LEVEL_WARNING) | mask(LEVEL_INFO) | mask(LEVEL_DEBUG)
	MASK_DEFAULT mask = mask(LEVEL_CRITICAL) | mask(LEVEL_ERROR) | mask(LEVEL_WARNING) | mask(LEVEL_INFO)
)

func maskByName(name string) (mask mask, error error) {
	switch (name) {
	case "all":
		mask = MASK_ALL
		return
	case "default", "":
		mask = MASK_DEFAULT
		return
	}
	error = fmt.Errorf("unknown mask '%s', try 'all' or 'default'", name)
	return
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package broker

import (
	"net"

	"github.com/TheThingsNetwork/ttn/core"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/TheThingsNetwork/ttn/utils/stats"
	"github.com/apex/log"
	"github.com/brocaar/lorawan"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

// component implements the core.BrokerServer interface
type component struct {
	Components
	SecretKey    [32]byte
	NetAddrUp    string
	NetAddrDown  string
	MaxDevNonces uint
}

// Components defines a structure to make the instantiation easier to read
type Components struct {
	NetworkController NetworkController
	AppStorage        AppStorage
	Ctx               log.Interface
}

// Options defines a structure to make the instantiation easier to read
type Options struct {
	NetAddrUp   string
	NetAddrDown string
	SecretKey   [32]byte
}

// Interface defines the Broker interface
type Interface interface {
	core.BrokerServer
	core.BrokerManagerServer
	Start() error
}

// New construct a new Broker component
func New(c Components, o Options) Interface {
	return component{
		Components:   c,
		NetAddrUp:    o.NetAddrUp,
		NetAddrDown:  o.NetAddrDown,
		MaxDevNonces: 10,
		SecretKey:    [32]byte{14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 42, 42, 42, 42, 42, 42}, // TODO Use options & ENV var
	}
}

// Start actually runs the component and starts the rpc server
func (b component) Start() error {
	connUp, err := net.Listen("tcp", b.NetAddrUp)
	if err != nil {
		return errors.New(errors.Operational, err)
	}

	connDown, err := net.Listen("tcp", b.NetAddrDown)
	if err != nil {
		return errors.New(errors.Operational, err)
	}

	server := grpc.NewServer()
	core.RegisterBrokerServer(server, b)
	core.RegisterBrokerManagerServer(server, b)

	cherr := make(chan error)

	go func() {
		cherr <- server.Serve(connUp)
	}()

	go func() {
		cherr <- server.Serve(connDown)
	}()

	if err := <-cherr; err != nil {
		return errors.New(errors.Operational, err)
	}
	return nil
}

// HandleJoin implements the core.BrokerServer interface
func (b component) HandleJoin(bctx context.Context, req *core.JoinBrokerReq) (*core.JoinBrokerRes, error) {
	b.Ctx.Debug("Handling join request")

	// Validate incoming data
	if req == nil || len(req.DevEUI) != 8 || len(req.AppEUI) != 8 || len(req.DevNonce) != 2 || len(req.MIC) != 4 || req.Metadata == nil {
		b.Ctx.Debug("Invalid request. Parameters are incorrect.")
		return new(core.JoinBrokerRes), errors.New(errors.Structural, "Invalid parameters")
	}
	ctx := b.Ctx.WithField("AppEUI", req.AppEUI).WithField("DevEUI", req.DevEUI)

	// Check if devNonce already referenced
	appEntry, err := b.AppStorage.read(req.AppEUI)
	if err != nil {
		ctx.WithError(err).Debug("Unable to lookup activation")
		return new(core.JoinBrokerRes), err
	}
	nonces, err := b.NetworkController.readNonces(req.AppEUI, req.DevEUI)
	if err != nil {
		if err.(errors.Failure).Nature != errors.NotFound {
			ctx.WithError(err).Debug("Unable to retrieve associated devNonces")
			return new(core.JoinBrokerRes), err
		}
		nonces = noncesEntry{
			AppEUI: req.AppEUI,
			DevEUI: req.DevEUI,
		}
	}

	var found bool
	for _, n := range nonces.DevNonces {
		if n[0] == req.DevNonce[0] && n[1] == req.DevNonce[1] {
			found = true
			break
		}
	}
	if found {
		ctx.Debug("Unable to proceed join request. DevNonce already used by the past.")
		return new(core.JoinBrokerRes), errors.New(errors.Structural, "DevNonce used by the past")
	}

	// Forward the registration to the handler
	handler, closer, err := appEntry.Dialer.Dial()
	if err != nil {
		ctx.WithError(err).Debug("Unable to dial handler")
		return new(core.JoinBrokerRes), err
	}
	defer closer.Close()
	res, err := handler.HandleJoin(context.Background(), &core.JoinHandlerReq{
		DevEUI:   req.DevEUI,
		AppEUI:   req.AppEUI,
		DevNonce: req.DevNonce,
		MIC:      req.MIC,
		Metadata: req.Metadata,
	})
	if err != nil {
		ctx.WithError(err).Debug("Error while contacting handler")
		return new(core.JoinBrokerRes), errors.New(errors.Operational, err)
	}

	// Handle the response
	if res == nil || res.Payload == nil {
		ctx.Debug("No Join-Accept")
		return new(core.JoinBrokerRes), nil
	}

	if len(res.DevAddr) != 4 || len(res.NwkSKey) != 16 {
		ctx.Debug("Invalid response from handler")
		return new(core.JoinBrokerRes), errors.New(errors.Operational, "Invalid response from handler")
	}

	// Update the DevNonce
	nonces.DevNonces = append(nonces.DevNonces, req.DevNonce)
	if uint(len(nonces.DevNonces)) > b.MaxDevNonces {
		nonces.DevNonces = nonces.DevNonces[1:]
	}
	err = b.NetworkController.upsertNonces(nonces)
	if err != nil {
		ctx.WithError(err).Debug("Unable to update activation entry")
		return new(core.JoinBrokerRes), err
	}

	var nwkSKey [16]byte
	copy(nwkSKey[:], res.NwkSKey)
	err = b.NetworkController.upsert(devEntry{
		Dialer:  appEntry.Dialer,
		DevAddr: res.DevAddr,
		AppEUI:  req.AppEUI,
		DevEUI:  req.DevEUI,
		NwkSKey: nwkSKey,
		FCntUp:  0,
	})
	if err != nil {
		ctx.WithError(err).Debug("Unable to store device")
		return new(core.JoinBrokerRes), err
	}
	return &core.JoinBrokerRes{
		Payload:  res.Payload,
		Metadata: res.Metadata,
	}, nil
}

// HandleData implements the core.BrokerServer interface
func (b component) HandleData(bctx context.Context, req *core.DataBrokerReq) (*core.DataBrokerRes, error) {
	// Get some logs / analytics
	stats.MarkMeter("broker.uplink.in")
	b.Ctx.Debug("Handling uplink packet")

	// Validate incoming data
	uplinkPayload, err := core.NewLoRaWANData(req.Payload, true)
	if err != nil {
		b.Ctx.WithError(err).Debug("Unable to interpret LoRaWAN payload")
		return new(core.DataBrokerRes), errors.New(errors.Structural, err)
	}
	devAddr := req.Payload.MACPayload.FHDR.DevAddr // No nil ref, ensured by NewLoRaWANData()
	ctx := b.Ctx.WithField("DevAddr", devAddr)

	// Check whether we should handle it
	entries, err := b.NetworkController.read(devAddr)
	if err != nil {
		ctx = ctx.WithError(err)
		switch err.(errors.Failure).Nature {
		case errors.NotFound:
			stats.MarkMeter("broker.uplink.handler_lookup.device_not_found")
			ctx.Debug("Uplink device not found")
		default:
			ctx.Warn("Database lookup failed")
		}
		return new(core.DataBrokerRes), err
	}
	stats.UpdateHistogram("broker.uplink.handler_lookup.entries", int64(len(entries)))

	// Several handlers might be associated to the same device, we distinguish them using
	// MIC check. Only one should verify the MIC check
	// The device only stores a 16-bits counter but could reflect a 32-bits one.
	// The counter is used for the MIC computation, thus, we're gonna try both 16-bits and
	// 32-bits counters.
	// We keep track of the real counter in the network controller.
	fhdr := &uplinkPayload.MACPayload.(*lorawan.MACPayload).FHDR // No nil ref, ensured by NewLoRaWANData()
	fcnt16 := fhdr.FCnt                                          // Keep a reference to the original counter

	var mEntry *devEntry
	for _, entry := range entries {
		// retrieve the network session key
		key := lorawan.AES128Key(entry.NwkSKey)

		// Check with 16-bits counters
		fhdr.FCnt = fcnt16
		fcnt32, err := b.NetworkController.wholeCounter(fcnt16, entry.FCntUp)
		if err != nil {
			continue
		}

		ok, err := uplinkPayload.ValidateMIC(key)
		if err != nil {
			continue
		}
		fhdr.FCnt = fcnt32
		if !ok { // Check with 32-bits counter
			ok, err = uplinkPayload.ValidateMIC(key)
		}

		if ok {
			mEntry = &entry
			stats.MarkMeter("broker.uplink.handler_lookup.mic_match")
			ctx.WithField("handler", string(entry.Dialer.MarshalSafely())).Debug("MIC check succeeded")
			break // We stop at the first valid check ...
		}
	}

	if mEntry == nil {
		stats.MarkMeter("broker.uplink.handler_lookup.no_mic_match")
		err := errors.New(errors.NotFound, "MIC check returned no matches")
		ctx.WithError(err).Debug("Unable to handle uplink")
		return new(core.DataBrokerRes), err
	}

	// It does matter here to use the DevEUI from the entry and not from the packet.
	// The packet actually holds a DevAddr and the real DevEUI has been determined thanks
	// to the MIC check + persistence
	mEntry.FCntUp = fhdr.FCnt
	if err := b.NetworkController.upsert(*mEntry); err != nil {
		ctx.WithError(err).Debug("Unable to update Frame Counter")
		return new(core.DataBrokerRes), err
	}

	// Then we forward the packet to the handler and wait for the response
	handler, closer, err := mEntry.Dialer.Dial()
	if err != nil {
		ctx.WithError(err).Debug("Unable to dial handler")
		return new(core.DataBrokerRes), err
	}
	defer closer.Close()
	resp, err := handler.HandleDataUp(context.Background(), &core.DataUpHandlerReq{
		Payload:  req.Payload.MACPayload.FRMPayload,
		DevEUI:   mEntry.DevEUI,
		AppEUI:   mEntry.AppEUI,
		FCnt:     fhdr.FCnt,
		MType:    req.Payload.MHDR.MType,
		Metadata: req.Metadata,
	})

	if err != nil {
		stats.MarkMeter("broker.uplink.bad_handler_response")
		ctx.WithError(err).Debug("Unexpected answer from handler")
		return new(core.DataBrokerRes), errors.New(errors.Operational, err)
	}
	stats.MarkMeter("broker.uplink.ok")

	// No response, we stop here and propagate the "no answer".
	// In case of confirmed data, the handler is in charge of creating the confirmation
	if resp == nil || resp.Payload == nil {
		ctx.Debug("Packet successfully sent. There's no downlink.")
		return new(core.DataBrokerRes), nil
	}

	// If a response was sent, i.e. a downlink data, we need to compute the right MIC
	ctx.Debug("Packet successfully sent. Handling downlink response")
	downlinkPayload, err := core.NewLoRaWANData(resp.Payload, false)
	if err != nil {
		ctx.WithError(err).Debug("Unable to interpret LoRaWAN downlink datagram")
		return new(core.DataBrokerRes), errors.New(errors.Structural, err)
	}
	stats.MarkMeter("broker.downlink.in")
	if err := downlinkPayload.SetMIC(lorawan.AES128Key(mEntry.NwkSKey)); err != nil {
		ctx.WithError(err).Debug("Unable to set MIC")
		return new(core.DataBrokerRes), errors.New(errors.Structural, "Unable to set response MIC")
	}
	resp.Payload.MIC = downlinkPayload.MIC[:]

	// And finally, we acknowledge the answer
	return &core.DataBrokerRes{
		Payload:  resp.Payload,
		Metadata: resp.Metadata,
	}, nil
}
<commit_msg>Improve logging in broker<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package broker

import (
	"net"

	"github.com/TheThingsNetwork/ttn/core"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/TheThingsNetwork/ttn/utils/stats"
	"github.com/apex/log"
	"github.com/brocaar/lorawan"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

// component implements the core.BrokerServer interface
type component struct {
	Components
	SecretKey    [32]byte
	NetAddrUp    string
	NetAddrDown  string
	MaxDevNonces uint
}

// Components defines a structure to make the instantiation easier to read
type Components struct {
	NetworkController NetworkController
	AppStorage        AppStorage
	Ctx               log.Interface
}

// Options defines a structure to make the instantiation easier to read
type Options struct {
	NetAddrUp   string
	NetAddrDown string
	SecretKey   [32]byte
}

// Interface defines the Broker interface
type Interface interface {
	core.BrokerServer
	core.BrokerManagerServer
	Start() error
}

// New construct a new Broker component
func New(c Components, o Options) Interface {
	return component{
		Components:   c,
		NetAddrUp:    o.NetAddrUp,
		NetAddrDown:  o.NetAddrDown,
		MaxDevNonces: 10,
		SecretKey:    [32]byte{14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 42, 42, 42, 42, 42, 42}, // TODO Use options & ENV var
	}
}

// Start actually runs the component and starts the rpc server
func (b component) Start() error {
	connUp, err := net.Listen("tcp", b.NetAddrUp)
	if err != nil {
		return errors.New(errors.Operational, err)
	}

	connDown, err := net.Listen("tcp", b.NetAddrDown)
	if err != nil {
		return errors.New(errors.Operational, err)
	}

	server := grpc.NewServer()
	core.RegisterBrokerServer(server, b)
	core.RegisterBrokerManagerServer(server, b)

	cherr := make(chan error)

	go func() {
		cherr <- server.Serve(connUp)
	}()

	go func() {
		cherr <- server.Serve(connDown)
	}()

	if err := <-cherr; err != nil {
		return errors.New(errors.Operational, err)
	}
	return nil
}

// HandleJoin implements the core.BrokerServer interface
func (b component) HandleJoin(bctx context.Context, req *core.JoinBrokerReq) (*core.JoinBrokerRes, error) {
	b.Ctx.Debug("Handling join request")

	// Validate incoming data
	if req == nil || len(req.DevEUI) != 8 || len(req.AppEUI) != 8 || len(req.DevNonce) != 2 || len(req.MIC) != 4 || req.Metadata == nil {
		b.Ctx.Debug("Invalid request. Parameters are incorrect.")
		return new(core.JoinBrokerRes), errors.New(errors.Structural, "Invalid parameters")
	}
	ctx := b.Ctx.WithField("AppEUI", req.AppEUI).WithField("DevEUI", req.DevEUI)

	// Check if devNonce already referenced
	appEntry, err := b.AppStorage.read(req.AppEUI)
	if err != nil {
		ctx.WithError(err).Debug("Unable to lookup activation")
		return new(core.JoinBrokerRes), err
	}
	nonces, err := b.NetworkController.readNonces(req.AppEUI, req.DevEUI)
	if err != nil {
		if err.(errors.Failure).Nature != errors.NotFound {
			ctx.WithError(err).Debug("Unable to retrieve associated devNonces")
			return new(core.JoinBrokerRes), err
		}
		nonces = noncesEntry{
			AppEUI: req.AppEUI,
			DevEUI: req.DevEUI,
		}
	}

	var found bool
	for _, n := range nonces.DevNonces {
		if n[0] == req.DevNonce[0] && n[1] == req.DevNonce[1] {
			found = true
			break
		}
	}
	if found {
		ctx.Debug("Unable to proceed join request. DevNonce already used by the past.")
		return new(core.JoinBrokerRes), errors.New(errors.Structural, "DevNonce used by the past")
	}

	// Forward the registration to the handler
	handler, closer, err := appEntry.Dialer.Dial()
	if err != nil {
		ctx.WithError(err).Debug("Unable to dial handler")
		return new(core.JoinBrokerRes), err
	}
	defer closer.Close()
	res, err := handler.HandleJoin(context.Background(), &core.JoinHandlerReq{
		DevEUI:   req.DevEUI,
		AppEUI:   req.AppEUI,
		DevNonce: req.DevNonce,
		MIC:      req.MIC,
		Metadata: req.Metadata,
	})
	if err != nil {
		ctx.WithError(err).Debug("Error while contacting handler")
		return new(core.JoinBrokerRes), errors.New(errors.Operational, err)
	}

	// Handle the response
	if res == nil || res.Payload == nil {
		ctx.Debug("No Join-Accept")
		return new(core.JoinBrokerRes), nil
	}

	if len(res.DevAddr) != 4 || len(res.NwkSKey) != 16 {
		ctx.Debug("Invalid response from handler")
		return new(core.JoinBrokerRes), errors.New(errors.Operational, "Invalid response from handler")
	}

	// Update the DevNonce
	nonces.DevNonces = append(nonces.DevNonces, req.DevNonce)
	if uint(len(nonces.DevNonces)) > b.MaxDevNonces {
		nonces.DevNonces = nonces.DevNonces[1:]
	}
	err = b.NetworkController.upsertNonces(nonces)
	if err != nil {
		ctx.WithError(err).Debug("Unable to update activation entry")
		return new(core.JoinBrokerRes), err
	}

	var nwkSKey [16]byte
	copy(nwkSKey[:], res.NwkSKey)
	err = b.NetworkController.upsert(devEntry{
		Dialer:  appEntry.Dialer,
		DevAddr: res.DevAddr,
		AppEUI:  req.AppEUI,
		DevEUI:  req.DevEUI,
		NwkSKey: nwkSKey,
		FCntUp:  0,
	})
	if err != nil {
		ctx.WithError(err).Debug("Unable to store device")
		return new(core.JoinBrokerRes), err
	}
	return &core.JoinBrokerRes{
		Payload:  res.Payload,
		Metadata: res.Metadata,
	}, nil
}

// HandleData implements the core.BrokerServer interface
func (b component) HandleData(bctx context.Context, req *core.DataBrokerReq) (*core.DataBrokerRes, error) {
	// Get some logs / analytics
	stats.MarkMeter("broker.uplink.in")
	b.Ctx.Debug("Handling uplink packet")

	// Validate incoming data
	uplinkPayload, err := core.NewLoRaWANData(req.Payload, true)
	if err != nil {
		b.Ctx.WithError(err).Debug("Unable to interpret LoRaWAN payload")
		return new(core.DataBrokerRes), errors.New(errors.Structural, err)
	}
	devAddr := req.Payload.MACPayload.FHDR.DevAddr // No nil ref, ensured by NewLoRaWANData()
	ctx := b.Ctx.WithField("DevAddr", devAddr)

	// Check whether we should handle it
	entries, err := b.NetworkController.read(devAddr)
	if err != nil {
		ctx = ctx.WithError(err)
		switch err.(errors.Failure).Nature {
		case errors.NotFound:
			stats.MarkMeter("broker.uplink.handler_lookup.device_not_found")
			ctx.Debug("Uplink device not found")
		default:
			ctx.Warn("Database lookup failed")
		}
		return new(core.DataBrokerRes), err
	}
	stats.UpdateHistogram("broker.uplink.handler_lookup.entries", int64(len(entries)))

	// Several handlers might be associated to the same device, we distinguish them using
	// MIC check. Only one should verify the MIC check
	// The device only stores a 16-bits counter but could reflect a 32-bits one.
	// The counter is used for the MIC computation, thus, we're gonna try both 16-bits and
	// 32-bits counters.
	// We keep track of the real counter in the network controller.
	fhdr := &uplinkPayload.MACPayload.(*lorawan.MACPayload).FHDR // No nil ref, ensured by NewLoRaWANData()
	fcnt16 := fhdr.FCnt                                          // Keep a reference to the original counter

	var mEntry *devEntry
	for _, entry := range entries {
		// retrieve the network session key
		key := lorawan.AES128Key(entry.NwkSKey)

		// Check with 16-bits counters
		fhdr.FCnt = fcnt16
		fcnt32, err := b.NetworkController.wholeCounter(fcnt16, entry.FCntUp)
		if err != nil {
			continue
		}

		ok, err := uplinkPayload.ValidateMIC(key)
		if err != nil {
			continue
		}
		fhdr.FCnt = fcnt32
		if !ok { // Check with 32-bits counter
			ok, err = uplinkPayload.ValidateMIC(key)
			if err != nil {
				continue
			}
		}

		if ok {
			mEntry = &entry
			stats.MarkMeter("broker.uplink.handler_lookup.mic_match")
			ctx.WithField("handler", string(entry.Dialer.MarshalSafely())).Debug("MIC check succeeded")
			break // We stop at the first valid check ...
		}
	}

	if mEntry == nil {
		stats.MarkMeter("broker.uplink.handler_lookup.no_mic_match")
		err := errors.New(errors.NotFound, "FCntUp or MIC check did not match")
		ctx.WithError(err).Debug("Unable to handle uplink")
		return new(core.DataBrokerRes), err
	}

	// It does matter here to use the DevEUI from the entry and not from the packet.
	// The packet actually holds a DevAddr and the real DevEUI has been determined thanks
	// to the MIC check + persistence
	mEntry.FCntUp = fhdr.FCnt
	if err := b.NetworkController.upsert(*mEntry); err != nil {
		ctx.WithError(err).Debug("Unable to update Frame Counter")
		return new(core.DataBrokerRes), err
	}

	// Then we forward the packet to the handler and wait for the response
	handler, closer, err := mEntry.Dialer.Dial()
	if err != nil {
		ctx.WithError(err).Debug("Unable to dial handler")
		return new(core.DataBrokerRes), err
	}
	defer closer.Close()
	resp, err := handler.HandleDataUp(context.Background(), &core.DataUpHandlerReq{
		Payload:  req.Payload.MACPayload.FRMPayload,
		DevEUI:   mEntry.DevEUI,
		AppEUI:   mEntry.AppEUI,
		FCnt:     fhdr.FCnt,
		MType:    req.Payload.MHDR.MType,
		Metadata: req.Metadata,
	})

	if err != nil {
		stats.MarkMeter("broker.uplink.bad_handler_response")
		ctx.WithError(err).Debug("Unexpected answer from handler")
		return new(core.DataBrokerRes), errors.New(errors.Operational, err)
	}
	stats.MarkMeter("broker.uplink.ok")

	// No response, we stop here and propagate the "no answer".
	// In case of confirmed data, the handler is in charge of creating the confirmation
	if resp == nil || resp.Payload == nil {
		ctx.Debug("Packet successfully sent. There's no downlink.")
		return new(core.DataBrokerRes), nil
	}

	// If a response was sent, i.e. a downlink data, we need to compute the right MIC
	ctx.Debug("Packet successfully sent. Handling downlink response")
	downlinkPayload, err := core.NewLoRaWANData(resp.Payload, false)
	if err != nil {
		ctx.WithError(err).Debug("Unable to interpret LoRaWAN downlink datagram")
		return new(core.DataBrokerRes), errors.New(errors.Structural, err)
	}
	stats.MarkMeter("broker.downlink.in")
	if err := downlinkPayload.SetMIC(lorawan.AES128Key(mEntry.NwkSKey)); err != nil {
		ctx.WithError(err).Debug("Unable to set MIC")
		return new(core.DataBrokerRes), errors.New(errors.Structural, "Unable to set response MIC")
	}
	resp.Payload.MIC = downlinkPayload.MIC[:]

	// And finally, we acknowledge the answer
	return &core.DataBrokerRes{
		Payload:  resp.Payload,
		Metadata: resp.Metadata,
	}, nil
}
<|endoftext|>


<commit_before>package glmenu

import (
	"github.com/4ydx/gltext"
	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/go-gl/mathgl/mgl32"
	"os"
)

type Point struct {
	X, Y float32
}

var vertexShaderSource string = `
#version 330

uniform mat4 matrix;

in vec4 position;

void main() {
  gl_Position = matrix * position;
}
` + "\x00"

var fragmentShaderSource string = `
#version 330

uniform vec4 background;
out vec4 fragment_color;

void main() {
  fragment_color = background;
}
` + "\x00"

type MouseClick int

const (
	MouseUnclicked MouseClick = iota
	MouseLeft
	MouseRight
	MouseCenter
)

type Menu struct {
	//trigger
	OnShow         func()
	OnEnterRelease func()

	// options
	Visible      bool
	ShowOnKey    glfw.Key
	Height       float32
	Width        float32
	IsAutoCenter bool
	lowerLeft    Point

	backgroundUniform int32
	Background        mgl32.Vec4

	// interactive objects
	Font          *gltext.Font
	Labels        []*Label
	TextBoxes     []*TextBox
	TextScaleRate float32 // increment during a scale operation

	// opengl oriented
	WindowWidth   float32
	WindowHeight  float32
	program       uint32 // shader program
	glMatrix      int32  // ortho matrix
	position      uint32 // index location
	vao           uint32
	vbo           uint32
	ebo           uint32
	vboData       []float32
	vboIndexCount int
	eboData       []int32
	eboIndexCount int
}

func (menu *Menu) AddLabel(label *Label, str string) {
	label.Load(menu, menu.Font)
	label.SetString(str)
	label.Text.SetScale(1)
	label.Text.SetPosition(0, 0)
	label.Text.SetColor(0, 0, 0)
	menu.Labels = append(menu.Labels, label)
}

func (menu *Menu) AddTextBox(textbox *TextBox, str string, width int32, height int32, borderWidth int32) {
	textbox.Load(menu, width, height, borderWidth)
	textbox.SetString(str)
	textbox.Text.SetScale(1)
	textbox.Text.SetPosition(0, 0)
	textbox.Text.SetColor(0, 0, 0)
	menu.TextBoxes = append(menu.TextBoxes, textbox)
}

func (menu *Menu) Show() {
	for i := range menu.Labels {
		menu.Labels[i].Reset()
	}
	menu.Visible = true
	if menu.OnShow != nil {
		menu.OnShow()
	}
}

func (menu *Menu) Hide() {
	for i := range menu.Labels {
		menu.Labels[i].Reset()
	}
	menu.Visible = false
}

func (menu *Menu) Toggle() {
	for i := range menu.Labels {
		menu.Labels[i].Reset()
	}
	menu.Visible = !menu.Visible
}

func (menu *Menu) Load(width float32, height float32, scale int32) (err error) {
	glfloat_size := 4
	glint_size := 4

	menu.Visible = false
	menu.ShowOnKey = glfw.KeyM
	menu.Width = width
	menu.Height = height

	// load font
	fd, err := os.Open("font/luximr.ttf")
	if err != nil {
		return
	}
	defer fd.Close()

	menu.Font, err = gltext.LoadTruetype(fd, scale, 32, 127)
	if err != nil {
		return
	}

	// 2DO: make this time dependent rather than fps dependent
	menu.TextScaleRate = 0.01

	// create shader program and define attributes and uniforms
	menu.program, err = gltext.NewProgram(vertexShaderSource, fragmentShaderSource)
	if err != nil {
		return
	}
	menu.glMatrix = gl.GetUniformLocation(menu.program, gl.Str("matrix\x00"))
	menu.backgroundUniform = gl.GetUniformLocation(menu.program, gl.Str("background\x00"))
	menu.position = uint32(gl.GetAttribLocation(menu.program, gl.Str("position\x00")))

	gl.GenVertexArrays(1, &menu.vao)
	gl.GenBuffers(1, &menu.vbo)
	gl.GenBuffers(1, &menu.ebo)

	// vao
	gl.BindVertexArray(menu.vao)

	// 2DO: Change text depth to get it to render? For now this works.
	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LEQUAL)

	// vbo
	// specify the buffer for which the VertexAttribPointer calls apply
	gl.BindBuffer(gl.ARRAY_BUFFER, menu.vbo)

	gl.EnableVertexAttribArray(menu.position)
	gl.VertexAttribPointer(
		menu.position,
		2,
		gl.FLOAT,
		false,
		0, // no stride... yet
		gl.PtrOffset(0),
	)

	// ebo
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, menu.ebo)

	// i am guessing that order is important here
	gl.BindVertexArray(0)
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)

	// ebo, vbo data
	menu.vboIndexCount = 4 * 2 // four indices (2 points per index)
	menu.eboIndexCount = 6     // 6 triangle indices for a quad
	menu.vboData = make([]float32, menu.vboIndexCount, menu.vboIndexCount)
	menu.eboData = make([]int32, menu.eboIndexCount, menu.eboIndexCount)
	menu.lowerLeft = menu.findCenter()
	menu.makeBufferData()

	// setup context
	gl.BindVertexArray(menu.vao)
	gl.BindBuffer(gl.ARRAY_BUFFER, menu.vbo)
	gl.BufferData(
		gl.ARRAY_BUFFER, glfloat_size*menu.vboIndexCount, gl.Ptr(menu.vboData), gl.DYNAMIC_DRAW)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, menu.ebo)
	gl.BufferData(
		gl.ELEMENT_ARRAY_BUFFER, glint_size*menu.eboIndexCount, gl.Ptr(menu.eboData), gl.DYNAMIC_DRAW)
	gl.BindVertexArray(0)

	// not necesssary, but i just want to better understand using vertex arrays
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
	return nil
}

func (menu *Menu) ResizeWindow(width float32, height float32) {
	menu.WindowWidth = width
	menu.WindowHeight = height
	menu.Font.ResizeWindow(width, height)
}

func (menu *Menu) makeBufferData() {
	// index (0,0)
	menu.vboData[0] = menu.lowerLeft.X // position
	menu.vboData[1] = menu.lowerLeft.Y

	// index (1,0)
	menu.vboData[2] = menu.lowerLeft.X + menu.Width
	menu.vboData[3] = menu.lowerLeft.Y

	// index (1,1)
	menu.vboData[4] = menu.lowerLeft.X + menu.Width
	menu.vboData[5] = menu.lowerLeft.Y + menu.Height

	// index (0,1)
	menu.vboData[6] = menu.lowerLeft.X
	menu.vboData[7] = menu.lowerLeft.Y + menu.Height

	menu.eboData[0] = 0
	menu.eboData[1] = 1
	menu.eboData[2] = 2
	menu.eboData[3] = 0
	menu.eboData[4] = 2
	menu.eboData[5] = 3
}

func (menu *Menu) Release() {
	gl.DeleteBuffers(1, &menu.vbo)
	gl.DeleteBuffers(1, &menu.ebo)
	gl.DeleteBuffers(1, &menu.vao)
	for i := range menu.Labels {
		menu.Labels[i].Text.Release()
		if menu.Labels[i].Shadow != nil && menu.Labels[i].Shadow.Text != nil {
			menu.Labels[i].Shadow.Text.Release()
		}
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].Text.Release()
	}
}

func (menu *Menu) Draw() bool {
	if !menu.Visible {
		return menu.Visible
	}
	gl.UseProgram(menu.program)

	gl.UniformMatrix4fv(menu.glMatrix, 1, false, &menu.Font.OrthographicMatrix[0])
	gl.Uniform4fv(menu.backgroundUniform, 1, &menu.Background[0])

	gl.Enable(gl.BLEND)
	gl.BlendEquation(gl.FUNC_ADD)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)

	gl.BindVertexArray(menu.vao)
	gl.DrawElements(gl.TRIANGLES, int32(menu.eboIndexCount), gl.UNSIGNED_INT, nil)
	gl.BindVertexArray(0)
	gl.Disable(gl.BLEND)

	for i := range menu.Labels {
		if !menu.Labels[i].IsHover {
			if menu.Labels[i].OnNotHover != nil {
				menu.Labels[i].OnNotHover(menu.Labels[i])
				if menu.Labels[i].Shadow != nil {
					menu.Labels[i].OnNotHover(&menu.Labels[i].Shadow.Label)
				}
			}
		}
		menu.Labels[i].Draw()
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].Draw()
	}
	return menu.Visible
}

func (menu *Menu) MouseClick(xPos, yPos float64, button MouseClick) {
	if !menu.Visible {
		return
	}
	yPos = float64(menu.WindowHeight) - yPos
	for i := range menu.Labels {
		menu.Labels[i].IsClicked(xPos, yPos, button)
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].IsClicked(xPos, yPos, button)
	}
}

func (menu *Menu) MouseRelease(xPos, yPos float64, button MouseClick) {
	if !menu.Visible {
		return
	}
	yPos = float64(menu.WindowHeight) - yPos
	for i := range menu.Labels {
		menu.Labels[i].IsReleased(xPos, yPos, button)
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].IsReleased(xPos, yPos, button)
	}
}

func (menu *Menu) MouseHover(xPos, yPos float64) {
	if !menu.Visible {
		return
	}
	yPos = float64(menu.WindowHeight) - yPos
	for i := range menu.Labels {
		if menu.Labels[i].OnHover != nil {
			menu.Labels[i].IsHovered(xPos, yPos)
		}
	}
}

func (menu *Menu) findCenter() (lowerLeft Point) {
	menuWidthHalf := menu.Width / 2
	menuHeightHalf := menu.Height / 2

	lowerLeft.X = -menuWidthHalf
	lowerLeft.Y = -menuHeightHalf
	return
}

func (menu *Menu) KeyRelease(key glfw.Key, withShift bool) {
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].KeyRelease(key, withShift)
	}
	if menu.OnEnterRelease != nil && key == glfw.KeyEnter {
		menu.OnEnterRelease()
	}
}
<commit_msg>Allow repositioning the background using an offset from the screens center.<commit_after>package glmenu

import (
	"github.com/4ydx/gltext"
	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/go-gl/mathgl/mgl32"
	"os"
)

type Point struct {
	X, Y float32
}

var vertexShaderSource string = `
#version 330

uniform mat4 matrix;

in vec4 position;

void main() {
  gl_Position = matrix * position;
}
` + "\x00"

var fragmentShaderSource string = `
#version 330

uniform vec4 background;
out vec4 fragment_color;

void main() {
  fragment_color = background;
}
` + "\x00"

type MouseClick int

const (
	MouseUnclicked MouseClick = iota
	MouseLeft
	MouseRight
	MouseCenter
)

type Menu struct {
	//trigger
	OnShow         func()
	OnEnterRelease func()

	// options
	Visible      bool
	ShowOnKey    glfw.Key
	Height       float32
	Width        float32
	IsAutoCenter bool
	lowerLeft    Point

	backgroundUniform int32
	Background        mgl32.Vec4

	// interactive objects
	Font          *gltext.Font
	Labels        []*Label
	TextBoxes     []*TextBox
	TextScaleRate float32 // increment during a scale operation

	// opengl oriented
	WindowWidth   float32
	WindowHeight  float32
	program       uint32 // shader program
	glMatrix      int32  // ortho matrix
	position      uint32 // index location
	vao           uint32
	vbo           uint32
	ebo           uint32
	vboData       []float32
	vboIndexCount int
	eboData       []int32
	eboIndexCount int
}

func (menu *Menu) AddLabel(label *Label, str string) {
	label.Load(menu, menu.Font)
	label.SetString(str)
	label.Text.SetScale(1)
	label.Text.SetPosition(0, 0)
	label.Text.SetColor(0, 0, 0)
	menu.Labels = append(menu.Labels, label)
}

func (menu *Menu) AddTextBox(textbox *TextBox, str string, width int32, height int32, borderWidth int32) {
	textbox.Load(menu, width, height, borderWidth)
	textbox.SetString(str)
	textbox.Text.SetScale(1)
	textbox.Text.SetPosition(0, 0)
	textbox.Text.SetColor(0, 0, 0)
	menu.TextBoxes = append(menu.TextBoxes, textbox)
}

func (menu *Menu) Show() {
	for i := range menu.Labels {
		menu.Labels[i].Reset()
	}
	menu.Visible = true
	if menu.OnShow != nil {
		menu.OnShow()
	}
}

func (menu *Menu) Hide() {
	for i := range menu.Labels {
		menu.Labels[i].Reset()
	}
	menu.Visible = false
}

func (menu *Menu) Toggle() {
	for i := range menu.Labels {
		menu.Labels[i].Reset()
	}
	menu.Visible = !menu.Visible
}

// Load will draw a background centered on the screen or positioned based on offsetBy values
func (menu *Menu) Load(width float32, height float32, scale int32, offsetBy mgl32.Vec2) (err error) {
	glfloat_size := 4
	glint_size := 4

	menu.Visible = false
	menu.ShowOnKey = glfw.KeyM
	menu.Width = width
	menu.Height = height

	// load font
	fd, err := os.Open("font/luximr.ttf")
	if err != nil {
		return
	}
	defer fd.Close()

	menu.Font, err = gltext.LoadTruetype(fd, scale, 32, 127)
	if err != nil {
		return
	}

	// 2DO: make this time dependent rather than fps dependent
	menu.TextScaleRate = 0.01

	// create shader program and define attributes and uniforms
	menu.program, err = gltext.NewProgram(vertexShaderSource, fragmentShaderSource)
	if err != nil {
		return
	}
	menu.glMatrix = gl.GetUniformLocation(menu.program, gl.Str("matrix\x00"))
	menu.backgroundUniform = gl.GetUniformLocation(menu.program, gl.Str("background\x00"))
	menu.position = uint32(gl.GetAttribLocation(menu.program, gl.Str("position\x00")))

	gl.GenVertexArrays(1, &menu.vao)
	gl.GenBuffers(1, &menu.vbo)
	gl.GenBuffers(1, &menu.ebo)

	// vao
	gl.BindVertexArray(menu.vao)

	// 2DO: Change text depth to get it to render? For now this works.
	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LEQUAL)

	// vbo
	// specify the buffer for which the VertexAttribPointer calls apply
	gl.BindBuffer(gl.ARRAY_BUFFER, menu.vbo)

	gl.EnableVertexAttribArray(menu.position)
	gl.VertexAttribPointer(
		menu.position,
		2,
		gl.FLOAT,
		false,
		0, // no stride... yet
		gl.PtrOffset(0),
	)

	// ebo
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, menu.ebo)

	// i am guessing that order is important here
	gl.BindVertexArray(0)
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)

	// ebo, vbo data
	menu.vboIndexCount = 4 * 2 // four indices (2 points per index)
	menu.eboIndexCount = 6     // 6 triangle indices for a quad
	menu.vboData = make([]float32, menu.vboIndexCount, menu.vboIndexCount)
	menu.eboData = make([]int32, menu.eboIndexCount, menu.eboIndexCount)
	menu.lowerLeft = menu.findCenter(offsetBy)
	menu.makeBufferData()

	// setup context
	gl.BindVertexArray(menu.vao)
	gl.BindBuffer(gl.ARRAY_BUFFER, menu.vbo)
	gl.BufferData(
		gl.ARRAY_BUFFER, glfloat_size*menu.vboIndexCount, gl.Ptr(menu.vboData), gl.DYNAMIC_DRAW)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, menu.ebo)
	gl.BufferData(
		gl.ELEMENT_ARRAY_BUFFER, glint_size*menu.eboIndexCount, gl.Ptr(menu.eboData), gl.DYNAMIC_DRAW)
	gl.BindVertexArray(0)

	// not necesssary, but i just want to better understand using vertex arrays
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
	return nil
}

func (menu *Menu) ResizeWindow(width float32, height float32) {
	menu.WindowWidth = width
	menu.WindowHeight = height
	menu.Font.ResizeWindow(width, height)
}

func (menu *Menu) makeBufferData() {
	// index (0,0)
	menu.vboData[0] = menu.lowerLeft.X // position
	menu.vboData[1] = menu.lowerLeft.Y

	// index (1,0)
	menu.vboData[2] = menu.lowerLeft.X + menu.Width
	menu.vboData[3] = menu.lowerLeft.Y

	// index (1,1)
	menu.vboData[4] = menu.lowerLeft.X + menu.Width
	menu.vboData[5] = menu.lowerLeft.Y + menu.Height

	// index (0,1)
	menu.vboData[6] = menu.lowerLeft.X
	menu.vboData[7] = menu.lowerLeft.Y + menu.Height

	menu.eboData[0] = 0
	menu.eboData[1] = 1
	menu.eboData[2] = 2
	menu.eboData[3] = 0
	menu.eboData[4] = 2
	menu.eboData[5] = 3
}

func (menu *Menu) Release() {
	gl.DeleteBuffers(1, &menu.vbo)
	gl.DeleteBuffers(1, &menu.ebo)
	gl.DeleteBuffers(1, &menu.vao)
	for i := range menu.Labels {
		menu.Labels[i].Text.Release()
		if menu.Labels[i].Shadow != nil && menu.Labels[i].Shadow.Text != nil {
			menu.Labels[i].Shadow.Text.Release()
		}
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].Text.Release()
	}
}

func (menu *Menu) Draw() bool {
	if !menu.Visible {
		return menu.Visible
	}
	gl.UseProgram(menu.program)

	gl.UniformMatrix4fv(menu.glMatrix, 1, false, &menu.Font.OrthographicMatrix[0])
	gl.Uniform4fv(menu.backgroundUniform, 1, &menu.Background[0])

	gl.Enable(gl.BLEND)
	gl.BlendEquation(gl.FUNC_ADD)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)

	gl.BindVertexArray(menu.vao)
	gl.DrawElements(gl.TRIANGLES, int32(menu.eboIndexCount), gl.UNSIGNED_INT, nil)
	gl.BindVertexArray(0)
	gl.Disable(gl.BLEND)

	for i := range menu.Labels {
		if !menu.Labels[i].IsHover {
			if menu.Labels[i].OnNotHover != nil {
				menu.Labels[i].OnNotHover(menu.Labels[i])
				if menu.Labels[i].Shadow != nil {
					menu.Labels[i].OnNotHover(&menu.Labels[i].Shadow.Label)
				}
			}
		}
		menu.Labels[i].Draw()
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].Draw()
	}
	return menu.Visible
}

func (menu *Menu) MouseClick(xPos, yPos float64, button MouseClick) {
	if !menu.Visible {
		return
	}
	yPos = float64(menu.WindowHeight) - yPos
	for i := range menu.Labels {
		menu.Labels[i].IsClicked(xPos, yPos, button)
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].IsClicked(xPos, yPos, button)
	}
}

func (menu *Menu) MouseRelease(xPos, yPos float64, button MouseClick) {
	if !menu.Visible {
		return
	}
	yPos = float64(menu.WindowHeight) - yPos
	for i := range menu.Labels {
		menu.Labels[i].IsReleased(xPos, yPos, button)
	}
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].IsReleased(xPos, yPos, button)
	}
}

func (menu *Menu) MouseHover(xPos, yPos float64) {
	if !menu.Visible {
		return
	}
	yPos = float64(menu.WindowHeight) - yPos
	for i := range menu.Labels {
		if menu.Labels[i].OnHover != nil {
			menu.Labels[i].IsHovered(xPos, yPos)
		}
	}
}

func (menu *Menu) findCenter(offsetBy mgl32.Vec2) (lowerLeft Point) {
	menuWidthHalf := menu.Width / 2
	menuHeightHalf := menu.Height / 2

	lowerLeft.X = -menuWidthHalf + offsetBy.X()
	lowerLeft.Y = -menuHeightHalf + offsetBy.Y()
	return
}

func (menu *Menu) KeyRelease(key glfw.Key, withShift bool) {
	for i := range menu.TextBoxes {
		menu.TextBoxes[i].KeyRelease(key, withShift)
	}
	if menu.OnEnterRelease != nil && key == glfw.KeyEnter {
		menu.OnEnterRelease()
	}
}
<|endoftext|>


<commit_before>package rest

import (
	"encoding/json"
	"github.com/StefanKjartansson/eventhub"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"strconv"
	"strings"
)

type RESTService struct {
	databackend eventhub.DataBackend
}

func (r *RESTService) entityHandler(w http.ResponseWriter, req *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	vars := mux.Vars(req)
	entity := vars["entity"]
	id := vars["id"]
	filterParams := make(map[string]interface{})
	filterParams["Entities"] = []string{strings.Join([]string{entity, id}, "/")}
	events, err := r.databackend.FilterBy(filterParams)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	enc := json.NewEncoder(w)
	enc.Encode(events)

}

func (r *RESTService) retrieveHandler(w http.ResponseWriter, req *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	vars := mux.Vars(req)
	id := vars["id"]
	idAsInt, err := strconv.Atoi(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	event, err := r.databackend.GetById(idAsInt)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	enc := json.NewEncoder(w)
	enc.Encode(event)

}

func (r *RESTService) postHandler(w http.ResponseWriter, req *http.Request) {

	decoder := json.NewDecoder(req.Body)
	var e eventhub.Event
	err := decoder.Decode(&e)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = r.databackend.Save(&e)
	if err != nil {
		log.Println(err)
		http.Error(w, "Error", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
}

func (r *RESTService) updateHandler(w http.ResponseWriter, req *http.Request) {

	decoder := json.NewDecoder(req.Body)
	var e eventhub.Event
	err := decoder.Decode(&e)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if e.ID == 0 {
		http.Error(w, "No ID", http.StatusBadRequest)
		return
	}
	err = r.databackend.Save(&e)
	if err != nil {
		log.Println(err)
		http.Error(w, "Error", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusAccepted)
}

func (r *RESTService) GetRouter() (*mux.Router, error) {

	router := mux.NewRouter()
	router.HandleFunc("/{entity}/{id}/", r.entityHandler).Methods("GET")
	//router.HandleFunc("/{entity}/{id}/search", r.entitySearchHandler).Methods("GET")
	router.HandleFunc("/", r.postHandler).Methods("POST")
	router.HandleFunc("/{id}/", r.retrieveHandler).Methods("GET")
	router.HandleFunc("/{id}/", r.updateHandler).Methods("PUT")
	//router.HandleFunc("/search", r.searchHandler).Methods("GET")
	return router, nil
}

func NewRESTService(d eventhub.DataBackend) *RESTService {
	return &RESTService{d}
}
<commit_msg>a bit of refactoring<commit_after>package rest

import (
	"encoding/json"
	"github.com/StefanKjartansson/eventhub"
	"github.com/gorilla/mux"
	"io"
	"log"
	"net/http"
	"strconv"
	"strings"
)

type RESTService struct {
	databackend eventhub.DataBackend
}

func (r *RESTService) entityHandler(w http.ResponseWriter, req *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	vars := mux.Vars(req)
	entity := vars["entity"]
	id := vars["id"]
	filterParams := make(map[string]interface{})
	filterParams["Entities"] = []string{strings.Join([]string{entity, id}, "/")}
	events, err := r.databackend.FilterBy(filterParams)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	enc := json.NewEncoder(w)
	enc.Encode(events)

}

func (r *RESTService) retrieveHandler(w http.ResponseWriter, req *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	vars := mux.Vars(req)
	id := vars["id"]
	idAsInt, err := strconv.Atoi(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	event, err := r.databackend.GetById(idAsInt)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	enc := json.NewEncoder(w)
	enc.Encode(event)

}

func (r *RESTService) parseEvent(body io.ReadCloser) (eventhub.Event, error) {
	decoder := json.NewDecoder(body)
	defer body.Close()
	var e eventhub.Event
	err := decoder.Decode(&e)
	return e, err
}

func (r *RESTService) postHandler(w http.ResponseWriter, req *http.Request) {

	e, err := r.parseEvent(req.Body)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = r.databackend.Save(&e)
	if err != nil {
		log.Println(err)
		http.Error(w, "Error", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
}

func (r *RESTService) updateHandler(w http.ResponseWriter, req *http.Request) {

	e, err := r.parseEvent(req.Body)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if e.ID == 0 {
		http.Error(w, "No ID", http.StatusBadRequest)
		return
	}
	err = r.databackend.Save(&e)
	if err != nil {
		log.Println(err)
		http.Error(w, "Error", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusAccepted)
}

func (r *RESTService) GetRouter() (*mux.Router, error) {

	router := mux.NewRouter()
	router.HandleFunc("/{entity}/{id}/", r.entityHandler).Methods("GET")
	//router.HandleFunc("/{entity}/{id}/search", r.entitySearchHandler).Methods("GET")
	router.HandleFunc("/", r.postHandler).Methods("POST")
	router.HandleFunc("/{id}/", r.retrieveHandler).Methods("GET")
	router.HandleFunc("/{id}/", r.updateHandler).Methods("PUT")
	//router.HandleFunc("/search", r.searchHandler).Methods("GET")
	return router, nil
}

func NewRESTService(d eventhub.DataBackend) *RESTService {
	return &RESTService{d}
}
<|endoftext|>


<commit_before>// Copyright 2013 go-dockerclient 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 docker

import (
	"encoding/json"
	"net"
	"strings"

	"github.com/docker/docker/api/types/swarm"
)

// Version returns version information about the docker server.
//
// See https://goo.gl/mU7yje for more details.
func (c *Client) Version() (*Env, error) {
	resp, err := c.do("GET", "/version", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var env Env
	if err := env.Decode(resp.Body); err != nil {
		return nil, err
	}
	return &env, nil
}

// DockerInfo contains information about the Docker server
//
// See https://goo.gl/bHUoz9 for more details.
type DockerInfo struct {
	ID                 string
	Containers         int
	ContainersRunning  int
	ContainersPaused   int
	ContainersStopped  int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	SystemStatus       [][2]string
	Plugins            PluginsInfo
	MemoryLimit        bool
	SwapLimit          bool
	KernelMemory       bool
	CPUCfsPeriod       bool `json:"CpuCfsPeriod"`
	CPUCfsQuota        bool `json:"CpuCfsQuota"`
	CPUShares          bool
	CPUSet             bool
	IPv4Forwarding     bool
	BridgeNfIptables   bool
	BridgeNfIP6tables  bool `json:"BridgeNfIp6tables"`
	Debug              bool
	OomKillDisable     bool
	ExperimentalBuild  bool
	NFd                int
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	CgroupDriver       string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	OSType             string
	Architecture       string
	IndexServerAddress string
	RegistryConfig     *ServiceConfig
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HTTPProxy          string `json:"HttpProxy"`
	HTTPSProxy         string `json:"HttpsProxy"`
	NoProxy            string
	Name               string
	Labels             []string
	ServerVersion      string
	ClusterStore       string
	ClusterAdvertise   string
	Swarm              swarm.Info
}

// PluginsInfo is a struct with the plugins registered with the docker daemon
//
// for more information, see: https://goo.gl/bHUoz9
type PluginsInfo struct {
	// List of Volume plugins registered
	Volume []string
	// List of Network plugins registered
	Network []string
	// List of Authorization plugins registered
	Authorization []string
}

// ServiceConfig stores daemon registry services configuration.
//
// for more information, see: https://goo.gl/7iFFDz
type ServiceConfig struct {
	InsecureRegistryCIDRs []*NetIPNet
	IndexConfigs          map[string]*IndexInfo
	Mirrors               []string
}

// NetIPNet is the net.IPNet type, which can be marshalled and
// unmarshalled to JSON.
//
// for more information, see: https://goo.gl/7iFFDz
type NetIPNet net.IPNet

// MarshalJSON returns the JSON representation of the IPNet.
//
func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) {
	return json.Marshal((*net.IPNet)(ipnet).String())
}

// UnmarshalJSON sets the IPNet from a byte array of JSON.
//
func (ipnet *NetIPNet) UnmarshalJSON(b []byte) (err error) {
	var ipnetStr string
	if err = json.Unmarshal(b, &ipnetStr); err == nil {
		var cidr *net.IPNet
		if _, cidr, err = net.ParseCIDR(ipnetStr); err == nil {
			*ipnet = NetIPNet(*cidr)
		}
	}
	return
}

// IndexInfo contains information about a registry.
//
// for more information, see: https://goo.gl/7iFFDz
type IndexInfo struct {
	Name     string
	Mirrors  []string
	Secure   bool
	Official bool
}

// Info returns system-wide information about the Docker server.
//
// See https://goo.gl/ElTHi2 for more details.
func (c *Client) Info() (*DockerInfo, error) {
	resp, err := c.do("GET", "/info", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var info DockerInfo
	if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
		return nil, err
	}
	return &info, nil
}

// ParseRepositoryTag gets the name of the repository and returns it splitted
// in two parts: the repository and the tag. It ignores the digest when it is
// present.
//
// Some examples:
//
//     localhost.localdomain:5000/samalba/hipache:latest -> localhost.localdomain:5000/samalba/hipache, latest
//     localhost.localdomain:5000/samalba/hipache -> localhost.localdomain:5000/samalba/hipache, ""
//     busybox:latest@sha256:4a731fb46adc5cefe3ae374a8b6020fc1b6ad667a279647766e9a3cd89f6fa92 -> busybox, latest
func ParseRepositoryTag(repoTag string) (repository string, tag string) {
	parts := strings.SplitN(repoTag, "@", 2)
	repoTag = parts[0]
	n := strings.LastIndex(repoTag, ":")
	if n < 0 {
		return repoTag, ""
	}
	if tag := repoTag[n+1:]; !strings.Contains(tag, "/") {
		return repoTag[:n], tag
	}
	return repoTag, ""
}
<commit_msg>info: add some missing parameters from DockerInfo<commit_after>// Copyright 2013 go-dockerclient 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 docker

import (
	"encoding/json"
	"net"
	"strings"

	"github.com/docker/docker/api/types/swarm"
)

// Version returns version information about the docker server.
//
// See https://goo.gl/mU7yje for more details.
func (c *Client) Version() (*Env, error) {
	resp, err := c.do("GET", "/version", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var env Env
	if err := env.Decode(resp.Body); err != nil {
		return nil, err
	}
	return &env, nil
}

// DockerInfo contains information about the Docker server
//
// See https://goo.gl/bHUoz9 for more details.
type DockerInfo struct {
	ID                 string
	Containers         int
	ContainersRunning  int
	ContainersPaused   int
	ContainersStopped  int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	SystemStatus       [][2]string
	Plugins            PluginsInfo
	MemoryLimit        bool
	SwapLimit          bool
	KernelMemory       bool
	CPUCfsPeriod       bool `json:"CpuCfsPeriod"`
	CPUCfsQuota        bool `json:"CpuCfsQuota"`
	CPUShares          bool
	CPUSet             bool
	IPv4Forwarding     bool
	BridgeNfIptables   bool
	BridgeNfIP6tables  bool `json:"BridgeNfIp6tables"`
	Debug              bool
	OomKillDisable     bool
	ExperimentalBuild  bool
	NFd                int
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	CgroupDriver       string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	OSType             string
	Architecture       string
	IndexServerAddress string
	RegistryConfig     *ServiceConfig
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HTTPProxy          string `json:"HttpProxy"`
	HTTPSProxy         string `json:"HttpsProxy"`
	NoProxy            string
	Name               string
	Labels             []string
	ServerVersion      string
	ClusterStore       string
	ClusterAdvertise   string
	Isolation          string
	InitBinary         string
	DefaultRuntime     string
	LiveRestoreEnabled bool
	Swarm              swarm.Info
}

// PluginsInfo is a struct with the plugins registered with the docker daemon
//
// for more information, see: https://goo.gl/bHUoz9
type PluginsInfo struct {
	// List of Volume plugins registered
	Volume []string
	// List of Network plugins registered
	Network []string
	// List of Authorization plugins registered
	Authorization []string
}

// ServiceConfig stores daemon registry services configuration.
//
// for more information, see: https://goo.gl/7iFFDz
type ServiceConfig struct {
	InsecureRegistryCIDRs []*NetIPNet
	IndexConfigs          map[string]*IndexInfo
	Mirrors               []string
}

// NetIPNet is the net.IPNet type, which can be marshalled and
// unmarshalled to JSON.
//
// for more information, see: https://goo.gl/7iFFDz
type NetIPNet net.IPNet

// MarshalJSON returns the JSON representation of the IPNet.
//
func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) {
	return json.Marshal((*net.IPNet)(ipnet).String())
}

// UnmarshalJSON sets the IPNet from a byte array of JSON.
//
func (ipnet *NetIPNet) UnmarshalJSON(b []byte) (err error) {
	var ipnetStr string
	if err = json.Unmarshal(b, &ipnetStr); err == nil {
		var cidr *net.IPNet
		if _, cidr, err = net.ParseCIDR(ipnetStr); err == nil {
			*ipnet = NetIPNet(*cidr)
		}
	}
	return
}

// IndexInfo contains information about a registry.
//
// for more information, see: https://goo.gl/7iFFDz
type IndexInfo struct {
	Name     string
	Mirrors  []string
	Secure   bool
	Official bool
}

// Info returns system-wide information about the Docker server.
//
// See https://goo.gl/ElTHi2 for more details.
func (c *Client) Info() (*DockerInfo, error) {
	resp, err := c.do("GET", "/info", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var info DockerInfo
	if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
		return nil, err
	}
	return &info, nil
}

// ParseRepositoryTag gets the name of the repository and returns it splitted
// in two parts: the repository and the tag. It ignores the digest when it is
// present.
//
// Some examples:
//
//     localhost.localdomain:5000/samalba/hipache:latest -> localhost.localdomain:5000/samalba/hipache, latest
//     localhost.localdomain:5000/samalba/hipache -> localhost.localdomain:5000/samalba/hipache, ""
//     busybox:latest@sha256:4a731fb46adc5cefe3ae374a8b6020fc1b6ad667a279647766e9a3cd89f6fa92 -> busybox, latest
func ParseRepositoryTag(repoTag string) (repository string, tag string) {
	parts := strings.SplitN(repoTag, "@", 2)
	repoTag = parts[0]
	n := strings.LastIndex(repoTag, ":")
	if n < 0 {
		return repoTag, ""
	}
	if tag := repoTag[n+1:]; !strings.Contains(tag, "/") {
		return repoTag[:n], tag
	}
	return repoTag, ""
}
<|endoftext|>


<commit_before>package robots

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
)

var Robots = make(map[string]func() Robot)
var Config = new(Configuration)

func init() {
	flag.Parse()
	configFile = flag.String("c", "config.json", "Config file (default ./config.json)")
	config, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Println("open config: ", err)
	}

	err = json.Unmarshal(config, Config)
	if err != nil {
		log.Println("parse config: ", err)
	}
}

func RegisterRobot(command string, RobotInitFunction func() Robot) {
	if _, ok := Robots[command]; ok {
		log.Printf("There are two robots mapped to %s!", command)
	} else {
		log.Printf("Registered: %s", command)
		Robots[command] = RobotInitFunction
	}
}

func MakeIncomingWebhookCall(payload *IncomingWebhook) error {
	webhook := url.URL{
		Scheme: "https",
		Host:   Config.Domain + ".slack.com",
		Path:   "/services/hooks/incoming-webhook",
	}

	json_payload, err := json.Marshal(payload)
	if err != nil {
		return err
	}

	post_data := url.Values{}
	post_data.Set("payload", string(json_payload))
	post_data.Set("token", Config.Token)

	webhook.RawQuery = post_data.Encode()
	_, err = http.PostForm(webhook.String(), post_data)
	return err
}
<commit_msg>Fix assignment<commit_after>package robots

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
)

var Robots = make(map[string]func() Robot)
var Config = new(Configuration)

func init() {
	flag.Parse()
	configFile := flag.String("c", "config.json", "Config file (default ./config.json)")
	config, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Println("open config: ", err)
	}

	err = json.Unmarshal(config, Config)
	if err != nil {
		log.Println("parse config: ", err)
	}
}

func RegisterRobot(command string, RobotInitFunction func() Robot) {
	if _, ok := Robots[command]; ok {
		log.Printf("There are two robots mapped to %s!", command)
	} else {
		log.Printf("Registered: %s", command)
		Robots[command] = RobotInitFunction
	}
}

func MakeIncomingWebhookCall(payload *IncomingWebhook) error {
	webhook := url.URL{
		Scheme: "https",
		Host:   Config.Domain + ".slack.com",
		Path:   "/services/hooks/incoming-webhook",
	}

	json_payload, err := json.Marshal(payload)
	if err != nil {
		return err
	}

	post_data := url.Values{}
	post_data.Set("payload", string(json_payload))
	post_data.Set("token", Config.Token)

	webhook.RawQuery = post_data.Encode()
	_, err = http.PostForm(webhook.String(), post_data)
	return err
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "log"
    /*"os"*/
    "io/ioutil"
    "flag"
    "time"
    /*"math/big"
    crand "crypto/rand"*/
    "math/rand"
    "strings"
    /*"encoding/json"*/
)

// Declare command line arguments
var input_files = flag.String("i", "language.dict", "the dictionary input file(s)") // TODO enable support for more than one input file
var separator = flag.String("l", "\n", "the separator used to split the input file")
var fill = flag.String("f", "0,1,2,3,4,5,6,7,8,9,_,!,?", "comma separated list of random fill characters")
var fill_length_min = flag.Int("fill-length-min", 1, "minimum length of the random fill insert")
var fill_length_max = flag.Int("fill-length-max", 3, "maximum length of the random fill insert")
var fill_before = flag.Bool("fill-before", false, "whether to insert a fill character before or after a word")
/*var output_file = flag.String("o", "passphrases.csv", "the output file (csv passphrase list)") // TODO or simply pass the result to the bash so it can be re-directed to a file
var output_file_type = flag.String("o-type", "csv", "the output file type")*/
var min_pass_length = flag.Int("min", 30, "minimum passphrase length")
var number_gen_passp = flag.Int("n", 10, "number of passphrases to generate")
var replace_chars = flag.String("r", "u\",ue,a\",ae,o\",oe,A\",Ae,O\",Oe,U\",Ue", "comma separated list of old new characters to replace in every dictionary word that is used for an actual passphrase")
// TODO add argument to enable/disable hashing of passwords (to only get distinct results)
var distinct = flag.Bool("d", true, "whether the generated passphrases have to be distinct from each other.")

func main() {
    // Read the command line arguments.
    flag.Parse()

    fmt.Println(*distinct)

    /*flags := flag.Args()
    fmt.Println(flags)
    for key, _ := range flags {
        fmt.Println(flags[key])
    }*/

    // Seed the RNG
    rand.Seed(time.Now().UnixNano()) // only pseudo random, better use crypto/rand

    // Read the dictionary files.
    dict, err := readDictionary(*input_files, *separator)
    if err != nil {
        panic(err)
    }
    if len(dict) == 0 {
        log.Fatal("Input dictionary is empty. Exiting.")
    }

    output := []string{}
    // repeat until enough passphrases are generated
    for i := 0; i < *number_gen_passp; i++ {
        new_passphrase := generatePassphrase(dict, strings.Split(*fill, ","))
        if checkUniqueness(output, new_passphrase) {
            output = append(output, new_passphrase)
        } else {
            i--
        }
    }

    // write the passphrases to the console
    for key, _ := range output {
        fmt.Println(output[key])
    }
}

// Open and read the dictionary file and push it's contents into a string array
func readDictionary(dict_file string, sep string) (dict[]string, err error) {
    // TODO maybe better check the filesize first ...
    b, err := ioutil.ReadFile(dict_file)
    if err != nil {
        return nil, err
    }
    dict = strings.Split(string(b), sep)
    return
}

// Check if a given passphrase is already present in the output array
func checkUniqueness(output []string, new_passphrase string) (is_unique bool) {
    // TODO properly check for uniqueness
    if !*distinct {
        is_unique = true
        return
    }
    is_unique = true
    for _, value := range output {
        if new_passphrase == value {
            is_unique = false
        }
    }
    return
}

// Generate the actual passphrase
func generatePassphrase(words []string, fills []string) (gen_passphrase string) {
    if len(words) == 0 {
        log.Fatal("Dictionary import is empty. Exiting.")
    }
    // Create the passphrase string:
    gen_passphrase = ""
    for len(gen_passphrase) < *min_pass_length { // Check if the passphrase's length is equal or greater than the minimum length.
        // If fill_before = true insert y random characters (before the word)
        if *fill_before {
            for i := 0; i < getRandomInt(*fill_length_min, *fill_length_max); i++ {
                gen_passphrase += getRandomWord(fills)
            }
        }

        // Add the next word to the passphrase string.
        gen_passphrase += getRandomWord(words)

        // If fill_before = false insert y random characters (after the word)
        if !*fill_before {
            for i := 0; i < getRandomInt(*fill_length_min, *fill_length_max); i++ {
                gen_passphrase += getRandomWord(fills)
            }
        }
    }
    return
}

// Replace all chars in raw with replace_with (oldnew ...string)
func replaceSpecialChars(raw string, replace_with string) (fixed string) {
    r := strings.NewReplacer(strings.Split(replace_with, ",")...)
    fixed = r.Replace(raw)
    return
}

// Return a random word from dict
func getRandomWord(words []string) string {
    if len(words) == 0 {
        return ""
    }
    // math.rand implementation
    //cr, _ := crand.Int(crand.Reader, big.NewInt(int64(len(i))))
        // TODO: how to convert *big.Int to int64 / int ?
//    rand.Seed(time.Now().UnixNano())
    r := rand.Intn(len(words))

    if len(*replace_chars) != 0 {
        words[r] = replaceSpecialChars(words[r], *replace_chars)
    }

    // crypto.rand implementation (sadly this returns an int64 which I can't use to access my array index :(
    /*r, _ := rand.Int(rand.Reader, big.NewInt(int64(len(words))))
    r = r
    fmt.Println(r)*/

    return words[r]
}

// Return a random integer value r with min <= r <= max
func getRandomInt(min int, max int) (r int) {
    r = 0
    if (min == 0 && max == 0) || min >= max {
        return
    }
    r = rand.Intn(max-min)
    r += min
    return
}
<commit_msg>fixed empty dictionary check<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"strings"
	"time"
)

// Declare command line arguments
var input_files = flag.String("i", "language.dict", "the dictionary input file(s)") // TODO enable support for more than one input file
var separator = flag.String("l", "\n", "the separator used to split the input file")
var fill = flag.String("f", "0,1,2,3,4,5,6,7,8,9,_,!,?", "comma separated list of random fill characters")
var fill_length_min = flag.Int("fill-length-min", 1, "minimum length of the random fill insert")
var fill_length_max = flag.Int("fill-length-max", 3, "maximum length of the random fill insert")
var fill_before = flag.Bool("fill-before", false, "whether to insert a fill character before or after a word")

/*var output_file = flag.String("o", "passphrases.csv", "the output file (csv passphrase list)") // TODO or simply pass the result to the bash so it can be re-directed to a file
var output_file_type = flag.String("o-type", "csv", "the output file type")*/
var min_pass_length = flag.Int("min", 30, "minimum passphrase length")
var number_gen_passp = flag.Int("n", 10, "number of passphrases to generate")
var replace_chars = flag.String("r", "u\",ue,a\",ae,o\",oe,A\",Ae,O\",Oe,U\",Ue", "comma separated list of old new characters to replace in every dictionary word that is used for an actual passphrase")

// TODO add argument to enable/disable hashing of passwords (to only get distinct results)
var distinct = flag.Bool("d", true, "whether the generated passphrases have to be distinct from each other.")

func main() {
	// Read the command line arguments.
	flag.Parse()

	fmt.Println(*distinct)

	/*flags := flag.Args()
	  fmt.Println(flags)
	  for key, _ := range flags {
	      fmt.Println(flags[key])
	  }*/

	// Seed the RNG
	rand.Seed(time.Now().UnixNano()) // only pseudo random, better use crypto/rand

	// Read the dictionary files.
	dict, err := readDictionary(*input_files, *separator)
	if err != nil {
		panic(err)
	}

	output := []string{}
	// repeat until enough passphrases are generated
	for i := 0; i < *number_gen_passp; i++ {
		new_passphrase := generatePassphrase(dict, strings.Split(*fill, ","))
		if checkUniqueness(output, new_passphrase) {
			output = append(output, new_passphrase)
		} else {
			i--
		}
	}

	// write the passphrases to the console
	for key := range output {
		fmt.Println(output[key])
	}
}

// Open and read the dictionary file and push it's contents into a string array
func readDictionary(dict_file string, sep string) (dict []string, err error) {
	// TODO maybe better check the filesize first ...
	b, err := ioutil.ReadFile(dict_file)
	if err != nil {
		return nil, err
	}

	s := strings.TrimSpace(string(b))
	if s == "" {
		log.Fatal("Input dictionary is empty. Exiting.")
	}

	dict = strings.Split(s, sep)
	return
}

// Check if a given passphrase is already present in the output array
func checkUniqueness(output []string, new_passphrase string) (is_unique bool) {
	// TODO properly check for uniqueness
	if !*distinct {
		is_unique = true
		return
	}
	is_unique = true
	for _, value := range output {
		if new_passphrase == value {
			is_unique = false
		}
	}
	return
}

// Generate the actual passphrase
func generatePassphrase(words []string, fills []string) (gen_passphrase string) {

	// Create the passphrase string:
	gen_passphrase = ""
	for len(gen_passphrase) < *min_pass_length { // Check if the passphrase's length is equal or greater than the minimum length.
		// If fill_before = true insert y random characters (before the word)
		if *fill_before {
			for i := 0; i < getRandomInt(*fill_length_min, *fill_length_max); i++ {
				gen_passphrase += getRandomWord(fills)
			}
		}

		// Add the next word to the passphrase string.
		gen_passphrase += getRandomWord(words)

		// If fill_before = false insert y random characters (after the word)
		if !*fill_before {
			for i := 0; i < getRandomInt(*fill_length_min, *fill_length_max); i++ {
				gen_passphrase += getRandomWord(fills)
			}
		}
	}
	return
}

// Replace all chars in raw with replace_with (oldnew ...string)
func replaceSpecialChars(raw string, replace_with string) (fixed string) {
	r := strings.NewReplacer(strings.Split(replace_with, ",")...)
	fixed = r.Replace(raw)
	return
}

// Return a random word from dict
func getRandomWord(words []string) string {
	if len(words) == 0 {
		return ""
	}
	// math.rand implementation
	//cr, _ := crand.Int(crand.Reader, big.NewInt(int64(len(i))))
	// TODO: how to convert *big.Int to int64 / int ?
	//    rand.Seed(time.Now().UnixNano())
	r := rand.Intn(len(words))

	if len(*replace_chars) != 0 {
		words[r] = replaceSpecialChars(words[r], *replace_chars)
	}

	// crypto.rand implementation (sadly this returns an int64 which I can't use to access my array index :(
	/*r, _ := rand.Int(rand.Reader, big.NewInt(int64(len(words))))
	  r = r
	  fmt.Println(r)*/

	return words[r]
}

// Return a random integer value r with min <= r <= max
func getRandomInt(min int, max int) (r int) {
	r = 0
	if (min == 0 && max == 0) || min >= max {
		return
	}
	r = rand.Intn(max - min)
	r += min
	return
}
<|endoftext|>