<commit_before>/*
Copyright (c) 2017 Bitnami

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"

	"github.com/kubeapps/ratesvc/response"
	log "github.com/sirupsen/logrus"

	jwt "github.com/dgrijalva/jwt-go"
	"gopkg.in/mgo.v2/bson"
)

const itemCollection = "items"

type item struct {
	// Instead of bson.ObjectID, we use a human-friendly identifier (e.g. "stable/wordpress")
	ID string `json:"id" bson:"_id,omitempty"`
	// Type could be "chart", "function", etc.
	Type string `json:"type"`
	// List of IDs of Stargazers that will be stored in the database
	StargazersIDs []bson.ObjectId `json:"-" bson:"stargazers_ids"`
	// Count of the Stargazers which is only exposed in the JSON response
	StargazersCount int `json:"stargazers_count" bson:"-"`
	// Whether the current user has starred the item, only exposed in the JSON response
	HasStarred bool `json:"has_starred" bson:"-"`
}

// GetStars returns a list of starred items
func GetStars(w http.ResponseWriter, req *http.Request) {
	db, closer := dbSession.DB()
	defer closer()
	var items []*item
	if err := db.C(itemCollection).Find(nil).All(&items); err != nil {
		log.WithError(err).Error("could not fetch all items")
		response.NewErrorResponse(http.StatusInternalServerError, "could not fetch all items").Write(w)
		return
	}
	for _, it := range items {
		it.StargazersCount = len(it.StargazersIDs)
		if currentUser, err := getCurrentUserID(req); err == nil {
			it.HasStarred = hasStarred(it, currentUser)
		}
	}
	response.NewDataResponse(items).Write(w)
}

// UpdateStar updates the HasStarred attribute on an item
func UpdateStar(w http.ResponseWriter, req *http.Request) {
	db, closer := dbSession.DB()
	defer closer()

	uid, err := getCurrentUserID(req)
	if err != nil {
		response.NewErrorResponse(http.StatusUnauthorized, "unauthorized").Write(w)
	}

	// Params validation
	var params *item
	if err := json.NewDecoder(req.Body).Decode(&params); err != nil {
		log.WithError(err).Error("could not parse request body")
		response.NewErrorResponse(http.StatusBadRequest, "could not parse request body").Write(w)
		return
	}

	if params.ID == "" {
		response.NewErrorResponse(http.StatusBadRequest, "id missing in request body").Write(w)
		return
	}

	if params.Type == "" {
		params.Type = "chart"
	}

	var it item
	err = db.C(itemCollection).FindId(params.ID).One(&it)

	if err != nil {
		// Create the item if inexistant
		it = *params
		if params.HasStarred {
			it.StargazersIDs = []bson.ObjectId{uid}
		}
		if err := db.C(itemCollection).Insert(it); err != nil {
			log.WithError(err).Error("could not insert item")
			response.NewErrorResponse(http.StatusInternalServerError, "internal server error").Write(w)
			return
		}
	} else {
		// Otherwise we just need to update the database
		op := "$pull"
		if params.HasStarred {
			// no-op if item is already starred by user
			if hasStarred(&it, uid) {
				response.NewDataResponse(it).WithCode(http.StatusCreated).Write(w)
				return
			}
			op = "$push"
		}

		if err := db.C(itemCollection).UpdateId(it.ID, bson.M{op: bson.M{"stargazers_ids": uid}}); err != nil {
			log.WithError(err).Error("could not update item")
			response.NewErrorResponse(http.StatusInternalServerError, "internal server error").Write(w)
			return
		}
	}

	response.NewDataResponse(it).WithCode(http.StatusCreated).Write(w)
}

// GetComments returns a list of comments for an item
func GetComments(w http.ResponseWriter, req *http.Request) {
	panic("not implemented")
}

// CreateComment creates a comment for an item
func CreateComment(w http.ResponseWriter, req *http.Request) {
	panic("not implemented")
}

type userClaims struct {
	ID bson.ObjectId
	jwt.StandardClaims
}

var getCurrentUserID = func(req *http.Request) (bson.ObjectId, error) {
	jwtKey, ok := os.LookupEnv("JWT_KEY")
	if !ok {
		return "", errors.New("JWT_KEY not set")
	}

	cookie, err := req.Cookie("ka_auth")
	if err != nil {
		return "", err
	}

	token, err := jwt.ParseWithClaims(cookie.Value, &userClaims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(jwtKey), nil
	})
	if err != nil {
		return "", err
	}

	if claims, ok := token.Claims.(*userClaims); ok && token.Valid {
		return claims.ID, nil
	}
	return "", errors.New("invalid token")
}

// hasStarred returns true if item is starred by the user
func hasStarred(it *item, user bson.ObjectId) bool {
	for _, id := range it.StargazersIDs {
		if id == user {
			return true
		}
	}
	return false
}
<commit_msg>return status code OK on no-op<commit_after>/*
Copyright (c) 2017 Bitnami

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"

	"github.com/kubeapps/ratesvc/response"
	log "github.com/sirupsen/logrus"

	jwt "github.com/dgrijalva/jwt-go"
	"gopkg.in/mgo.v2/bson"
)

const itemCollection = "items"

type item struct {
	// Instead of bson.ObjectID, we use a human-friendly identifier (e.g. "stable/wordpress")
	ID string `json:"id" bson:"_id,omitempty"`
	// Type could be "chart", "function", etc.
	Type string `json:"type"`
	// List of IDs of Stargazers that will be stored in the database
	StargazersIDs []bson.ObjectId `json:"-" bson:"stargazers_ids"`
	// Count of the Stargazers which is only exposed in the JSON response
	StargazersCount int `json:"stargazers_count" bson:"-"`
	// Whether the current user has starred the item, only exposed in the JSON response
	HasStarred bool `json:"has_starred" bson:"-"`
}

// GetStars returns a list of starred items
func GetStars(w http.ResponseWriter, req *http.Request) {
	db, closer := dbSession.DB()
	defer closer()
	var items []*item
	if err := db.C(itemCollection).Find(nil).All(&items); err != nil {
		log.WithError(err).Error("could not fetch all items")
		response.NewErrorResponse(http.StatusInternalServerError, "could not fetch all items").Write(w)
		return
	}
	for _, it := range items {
		it.StargazersCount = len(it.StargazersIDs)
		if currentUser, err := getCurrentUserID(req); err == nil {
			it.HasStarred = hasStarred(it, currentUser)
		}
	}
	response.NewDataResponse(items).Write(w)
}

// UpdateStar updates the HasStarred attribute on an item
func UpdateStar(w http.ResponseWriter, req *http.Request) {
	db, closer := dbSession.DB()
	defer closer()

	uid, err := getCurrentUserID(req)
	if err != nil {
		response.NewErrorResponse(http.StatusUnauthorized, "unauthorized").Write(w)
	}

	// Params validation
	var params *item
	if err := json.NewDecoder(req.Body).Decode(&params); err != nil {
		log.WithError(err).Error("could not parse request body")
		response.NewErrorResponse(http.StatusBadRequest, "could not parse request body").Write(w)
		return
	}

	if params.ID == "" {
		response.NewErrorResponse(http.StatusBadRequest, "id missing in request body").Write(w)
		return
	}

	if params.Type == "" {
		params.Type = "chart"
	}

	var it item
	err = db.C(itemCollection).FindId(params.ID).One(&it)

	if err != nil {
		// Create the item if inexistant
		it = *params
		if params.HasStarred {
			it.StargazersIDs = []bson.ObjectId{uid}
		}
		if err := db.C(itemCollection).Insert(it); err != nil {
			log.WithError(err).Error("could not insert item")
			response.NewErrorResponse(http.StatusInternalServerError, "internal server error").Write(w)
			return
		}
	} else {
		// Otherwise we just need to update the database
		op := "$pull"
		if params.HasStarred {
			// no-op if item is already starred by user
			if hasStarred(&it, uid) {
				response.NewDataResponse(it).WithCode(http.StatusOK).Write(w)
				return
			}
			op = "$push"
		}

		if err := db.C(itemCollection).UpdateId(it.ID, bson.M{op: bson.M{"stargazers_ids": uid}}); err != nil {
			log.WithError(err).Error("could not update item")
			response.NewErrorResponse(http.StatusInternalServerError, "internal server error").Write(w)
			return
		}
	}

	response.NewDataResponse(it).WithCode(http.StatusCreated).Write(w)
}

// GetComments returns a list of comments for an item
func GetComments(w http.ResponseWriter, req *http.Request) {
	panic("not implemented")
}

// CreateComment creates a comment for an item
func CreateComment(w http.ResponseWriter, req *http.Request) {
	panic("not implemented")
}

type userClaims struct {
	ID bson.ObjectId
	jwt.StandardClaims
}

var getCurrentUserID = func(req *http.Request) (bson.ObjectId, error) {
	jwtKey, ok := os.LookupEnv("JWT_KEY")
	if !ok {
		return "", errors.New("JWT_KEY not set")
	}

	cookie, err := req.Cookie("ka_auth")
	if err != nil {
		return "", err
	}

	token, err := jwt.ParseWithClaims(cookie.Value, &userClaims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(jwtKey), nil
	})
	if err != nil {
		return "", err
	}

	if claims, ok := token.Claims.(*userClaims); ok && token.Valid {
		return claims.ID, nil
	}
	return "", errors.New("invalid token")
}

// hasStarred returns true if item is starred by the user
func hasStarred(it *item, user bson.ObjectId) bool {
	for _, id := range it.StargazersIDs {
		if id == user {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package statuscake

import (
	"strings"
)

type autheticationErrorResponse struct {
	ErrNo int
	Error string
}

type updateResponse struct {
	Issues   interface{} `json:"Issues"`
	Success  bool        `json:"Success"`
	Message  string      `json:"Message"`
	InsertID int         `json:"InsertID"`
}

type deleteResponse struct {
	Success bool   `json:"Success"`
	Error   string `json:"Error"`
}

type detailResponse struct {
	Method          string   `json:"Method"`
	TestID          int      `json:"TestID"`
	TestType        string   `json:"TestType"`
	Paused          bool     `json:"Paused"`
	WebsiteName     string   `json:"WebsiteName"`
	URI             string   `json:"URI"`
	ContactID       int      `json:"ContactID"`
	Status          string   `json:"Status"`
	Uptime          float64  `json:"Uptime"`
	CustomHeader    string   `json:"CustomHeader"`
	CheckRate       int      `json:"CheckRate"`
	Timeout         int      `json:"Timeout"`
	LogoImage       string   `json:"LogoImage"`
	Confirmation    int      `json:"Confirmation,string"`
	WebsiteHost     string   `json:"WebsiteHost"`
	NodeLocations   []string `json:"NodeLocations"`
	FindString      string   `json:"FindString"`
	DoNotFind       bool     `json:"DoNotFind"`
	LastTested      string   `json:"LastTested"`
	NextLocation    string   `json:"NextLocation"`
	Port            int      `json:"Port"`
	Processing      bool     `json:"Processing"`
	ProcessingState string   `json:"ProcessingState"`
	ProcessingOn    string   `json:"ProcessingOn"`
	DownTimes       int      `json:"DownTimes,string"`
	Sensitive       bool     `json:"Sensitive"`
	TriggerRate     int      `json:"TriggerRate,string"`
	UseJar          bool     `json:"UseJar"`
	PostRaw         string   `json:"PostRaw"`
	StatusCodes     []string `json:"StatusCodes"`
}

func (d *detailResponse) test() *Test {
	return &Test{
		TestID:        d.TestID,
		TestType:      d.TestType,
		Paused:        d.Paused,
		WebsiteName:   d.WebsiteName,
		WebsiteURL:    d.URI,
		CustomHeader:  d.CustomHeader,
		ContactID:     d.ContactID,
		Status:        d.Status,
		Uptime:        d.Uptime,
		CheckRate:     d.CheckRate,
		Timeout:       d.Timeout,
		LogoImage:     d.LogoImage,
		Confirmation:  d.Confirmation,
		WebsiteHost:   d.WebsiteHost,
		NodeLocations: d.NodeLocations,
		FindString:    d.FindString,
		DoNotFind:     d.DoNotFind,
		Port:          d.Port,
		TriggerRate:   d.TriggerRate,
		UseJar:        d.UseJar,
		PostRaw:       d.PostRaw,
		StatusCodes:   strings.Join(d.StatusCodes[:],", "),
	}
}
<commit_msg>Update responses.go<commit_after>package statuscake

import (
	"strings"
)

type autheticationErrorResponse struct {
	ErrNo int
	Error string
}

type updateResponse struct {
	Issues   interface{} `json:"Issues"`
	Success  bool        `json:"Success"`
	Message  string      `json:"Message"`
	InsertID int         `json:"InsertID"`
}

type deleteResponse struct {
	Success bool   `json:"Success"`
	Error   string `json:"Error"`
}

type detailResponse struct {
	Method          string   `json:"Method"`
	TestID          int      `json:"TestID"`
	TestType        string   `json:"TestType"`
	Paused          bool     `json:"Paused"`
	WebsiteName     string   `json:"WebsiteName"`
	URI             string   `json:"URI"`
	ContactID       int      `json:"ContactID"`
	Status          string   `json:"Status"`
	Uptime          float64  `json:"Uptime"`
	CustomHeader    string   `json:"CustomHeader"`
	CheckRate       int      `json:"CheckRate"`
	Timeout         int      `json:"Timeout"`
	LogoImage       string   `json:"LogoImage"`
	Confirmation    int      `json:"Confirmation,string"`
	WebsiteHost     string   `json:"WebsiteHost"`
	NodeLocations   []string `json:"NodeLocations"`
	FindString      string   `json:"FindString"`
	DoNotFind       bool     `json:"DoNotFind"`
	LastTested      string   `json:"LastTested"`
	NextLocation    string   `json:"NextLocation"`
	Port            int      `json:"Port"`
	Processing      bool     `json:"Processing"`
	ProcessingState string   `json:"ProcessingState"`
	ProcessingOn    string   `json:"ProcessingOn"`
	DownTimes       int      `json:"DownTimes,string"`
	Sensitive       bool     `json:"Sensitive"`
	TriggerRate     int      `json:"TriggerRate,string"`
	UseJar          bool     `json:"UseJar"`
	PostRaw         string   `json:"PostRaw"`
	StatusCodes     []string `json:"StatusCodes"`
}

func (d *detailResponse) test() *Test {
	return &Test{
		TestID:        d.TestID,
		TestType:      d.TestType,
		Paused:        d.Paused,
		WebsiteName:   d.WebsiteName,
		WebsiteURL:    d.URI,
		CustomHeader:  d.CustomHeader,
		ContactID:     d.ContactID,
		Status:        d.Status,
		Uptime:        d.Uptime,
		CheckRate:     d.CheckRate,
		Timeout:       d.Timeout,
		LogoImage:     d.LogoImage,
		Confirmation:  d.Confirmation,
		WebsiteHost:   d.WebsiteHost,
		NodeLocations: d.NodeLocations,
		FindString:    d.FindString,
		DoNotFind:     d.DoNotFind,
		Port:          d.Port,
		TriggerRate:   d.TriggerRate,
		UseJar:        d.UseJar,
		PostRaw:       d.PostRaw,
		StatusCodes:   strings.Join(d.StatusCodes[:],","),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"math/rand"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gorilla/mux"
	"gopkg.in/unrolled/render.v1"
)

// TransitEdge is a direct transportation between two locations.
type TransitEdge struct {
	VoyageNumber string    `json:"voyage"`
	Origin       string    `json:"origin"`
	Destination  string    `json:"destination"`
	Departure    time.Time `json:"departure"`
	Arrival      time.Time `json:"arrival"`
}

// TransitPath is a series of transit edges.
type TransitPath struct {
	Edges []TransitEdge `json:"edges"`
}

// FindShortestPath computes the shortest paths between two locations.
func FindShortestPath(origin, destination string) []TransitPath {

	var candidates []TransitPath

	for p := range generateCandidates(origin, destination, 3+rand.Intn(3)) {
		candidates = append(candidates, p)
	}

	return candidates
}

// generateCandidates generates new candidates and pushes them into a channel.
// Finding each candidate is potentially time-consuming, so we compute them in
// parallel.
func generateCandidates(origin, destination string, n int) chan TransitPath {
	ch := make(chan TransitPath)

	var wg sync.WaitGroup
	wg.Add(n)

	for i := 0; i < n; i++ {
		go func() {
			ch <- findCandidate(origin, destination, nextDate(time.Now()))
			wg.Done()
		}()
	}

	go func() {
		wg.Wait()
		close(ch)
	}()

	return ch
}

// findCandidate finds a random path between two locations starting from a
// given time.
func findCandidate(origin, destination string, start time.Time) TransitPath {
	v := allVertices(origin, destination)
	v = randChunk(v)

	var edges []TransitEdge

	edges, start = appendEdge(edges, origin, v[0], start)

	for j := 0; j < len(v)-1; j++ {
		edges, start = appendEdge(edges, v[j], v[j+1], start)
	}

	edges, _ = appendEdge(edges, v[len(v)-1], destination, start)

	return TransitPath{Edges: edges}
}

func appendEdge(edges []TransitEdge, curr, next string, date time.Time) ([]TransitEdge, time.Time) {
	var (
		from = nextDate(date)
		to   = nextDate(from)
	)

	edges = append(edges, TransitEdge{
		VoyageNumber: randVoyageNumber(),
		Origin:       curr,
		Destination:  next,
		Departure:    from,
		Arrival:      to,
	})

	return edges, nextDate(to)
}

func allVertices(origin, destination string) []string {
	locations := []string{"CNHKG", "AUMEL", "SESTO", "FIHEL", "USCHI", "JNTKO", "DEHAM", "CNSHA", "NLRTM", "SEGOT", "CNHGH", "USNYC", "USDAL"}
	for i, l := range locations {
		if l == origin {
			locations = append(locations[:i], locations[i+1:]...)
		}
	}
	for i, l := range locations {
		if l == destination {
			locations = append(locations[:i], locations[i+1:]...)
		}
	}
	return locations
}

func randVoyageNumber() string {
	switch rand.Intn(5) {
	case 0:
		return "0100S"
	case 1:
		return "0200T"
	case 2:
		return "0300A"
	case 3:
		return "0301S"
	}
	return "0400S"
}

func randChunk(locations []string) []string {
	// TODO: Shuffle the locations first for even more randomness.

	t := len(locations)

	var c int
	if t > 4 {
		c = 1 + rand.Intn(5)
	} else {
		c = t
	}

	return locations[:c]
}

func nextDate(t time.Time) time.Time {
	n := time.Duration(rand.Intn(1000) - 500)
	return t.Add(24 * time.Hour).Add(n * time.Minute)
}

var port int

func main() {
	flag.IntVar(&port, "port", 8080, "the server port")
	flag.Parse()

	r := render.New(render.Options{IndentJSON: true})
	router := mux.NewRouter()

	router.HandleFunc("/paths", func(w http.ResponseWriter, req *http.Request) {
		from := req.URL.Query().Get("from")
		to := req.URL.Query().Get("to")

		if len(from) == 0 || len(to) == 0 {
			r.JSON(w, http.StatusBadRequest, map[string]interface{}{"error": "missing parameters"})
			return
		}

		r.JSON(w, http.StatusOK, FindShortestPath(from, to))
	}).Methods("GET")

	http.Handle("/", router)

	http.ListenAndServe(":"+strconv.Itoa(port), nil)
}
<commit_msg>Add some more randomness.<commit_after>package main

import (
	"flag"
	"math/rand"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gorilla/mux"
	"gopkg.in/unrolled/render.v1"
)

// TransitEdge is a direct transportation between two locations.
type TransitEdge struct {
	VoyageNumber string    `json:"voyage"`
	Origin       string    `json:"origin"`
	Destination  string    `json:"destination"`
	Departure    time.Time `json:"departure"`
	Arrival      time.Time `json:"arrival"`
}

// TransitPath is a series of transit edges.
type TransitPath struct {
	Edges []TransitEdge `json:"edges"`
}

// FindShortestPath computes the shortest paths between two locations.
func FindShortestPath(origin, destination string) []TransitPath {

	var candidates []TransitPath

	for p := range generateCandidates(origin, destination, 3+rand.Intn(3)) {
		candidates = append(candidates, p)
	}

	return candidates
}

// generateCandidates generates new candidates and pushes them into a channel.
// Finding each candidate is potentially time-consuming, so we compute them in
// parallel.
func generateCandidates(origin, destination string, n int) chan TransitPath {
	ch := make(chan TransitPath)

	var wg sync.WaitGroup
	wg.Add(n)

	for i := 0; i < n; i++ {
		go func() {
			ch <- findCandidate(origin, destination, nextDate(time.Now()))
			wg.Done()
		}()
	}

	go func() {
		wg.Wait()
		close(ch)
	}()

	return ch
}

// findCandidate finds a random path between two locations starting from a
// given time.
func findCandidate(origin, destination string, start time.Time) TransitPath {
	v := allVertices(origin, destination)
	v = randChunk(v)

	var edges []TransitEdge

	edges, start = appendEdge(edges, origin, v[0], start)

	for j := 0; j < len(v)-1; j++ {
		edges, start = appendEdge(edges, v[j], v[j+1], start)
	}

	edges, _ = appendEdge(edges, v[len(v)-1], destination, start)

	return TransitPath{Edges: edges}
}

func appendEdge(edges []TransitEdge, curr, next string, date time.Time) ([]TransitEdge, time.Time) {
	var (
		from = nextDate(date)
		to   = nextDate(from)
	)

	edges = append(edges, TransitEdge{
		VoyageNumber: randVoyageNumber(),
		Origin:       curr,
		Destination:  next,
		Departure:    from,
		Arrival:      to,
	})

	return edges, nextDate(to)
}

func allVertices(origin, destination string) []string {
	locations := []string{"CNHKG", "AUMEL", "SESTO", "FIHEL", "USCHI", "JNTKO", "DEHAM", "CNSHA", "NLRTM", "SEGOT", "CNHGH", "USNYC", "USDAL"}
	for i, l := range locations {
		if l == origin {
			locations = append(locations[:i], locations[i+1:]...)
		}
	}
	for i, l := range locations {
		if l == destination {
			locations = append(locations[:i], locations[i+1:]...)
		}
	}
	return locations
}

func randVoyageNumber() string {
	switch rand.Intn(5) {
	case 0:
		return "0100S"
	case 1:
		return "0200T"
	case 2:
		return "0300A"
	case 3:
		return "0301S"
	}
	return "0400S"
}

func randChunk(locations []string) []string {

	shuffle(locations)

	t := len(locations)

	var c int
	if t > 4 {
		c = 1 + rand.Intn(5)
	} else {
		c = t
	}

	return locations[:c]
}

func shuffle(slc []string) {
	for i := 1; i < len(slc); i++ {
		r := rand.Intn(i + 1)
		if i != r {
			slc[r], slc[i] = slc[i], slc[r]
		}
	}
}

func nextDate(t time.Time) time.Time {
	n := time.Duration(rand.Intn(1000) - 500)
	return t.Add(24 * time.Hour).Add(n * time.Minute)
}

var port int

func main() {
	flag.IntVar(&port, "port", 8080, "the server port")
	flag.Parse()

	rand.Seed(time.Now().UnixNano())

	r := render.New(render.Options{IndentJSON: true})
	router := mux.NewRouter()

	router.HandleFunc("/paths", func(w http.ResponseWriter, req *http.Request) {
		from := req.URL.Query().Get("from")
		to := req.URL.Query().Get("to")

		if len(from) == 0 || len(to) == 0 {
			r.JSON(w, http.StatusBadRequest, map[string]interface{}{"error": "missing parameters"})
			return
		}

		r.JSON(w, http.StatusOK, FindShortestPath(from, to))
	}).Methods("GET")

	http.Handle("/", router)

	http.ListenAndServe(":"+strconv.Itoa(port), nil)
}
<|endoftext|>


<commit_before>package dockertest

import (
	"errors"
	"fmt"
	"log"
	"time"
)

// SetupRethinkDBContainer sets up a real RethinkDB instance for testing purposes,
// using a Docker container. It returns the container ID and its IP address,
// or makes the test fail on error.
func SetupRethinkDBContainer() (c ContainerID, ip string, port int, err error) {
	port = RandomPort()
	forward := fmt.Sprintf("%d:%d", port, 28015)
	if BindDockerToLocalhost != "" {
		forward = "127.0.0.1:" + forward
	}
	c, ip, err = SetupContainer(MongoDBImageName, port, 10*time.Second, func() (string, error) {
		res, err := run("--name", GenerateContainerID(), "-d", "-P", "-p", forward, RethinkDBImageName)
		return res, err
	})
	return
}

// ConnectToRethinkDB starts a RethinkDB image and passes the database url to the connector callback.
// The url will match the ip:port pattern (e.g. 123.123.123.123:4241)
func ConnectToRethinkDB(tries int, delay time.Duration, connector func(url string) bool) (c ContainerID, err error) {
	c, ip, port, err := SetupRethinkDBContainer()
	if err != nil {
		return c, fmt.Errorf("Could not set up RethinkDB container: %v", err)
	}

	for try := 0; try <= tries; try++ {
		time.Sleep(delay)
		url := fmt.Sprintf("%s:%d", ip, port)
		if connector(url) {
			return c, nil
		}
		log.Printf("Try %d failed. Retrying.", try)
	}
	return c, errors.New("Could not set up RethinkDB container.")
}
<commit_msg>Update rethinkdb.go<commit_after>package dockertest

import (
	"errors"
	"fmt"
	"log"
	"time"
)

// SetupRethinkDBContainer sets up a real RethinkDB instance for testing purposes,
// using a Docker container. It returns the container ID and its IP address,
// or makes the test fail on error.
func SetupRethinkDBContainer() (c ContainerID, ip string, port int, err error) {
	port = RandomPort()
	forward := fmt.Sprintf("%d:%d", port, 28015)
	if BindDockerToLocalhost != "" {
		forward = "127.0.0.1:" + forward
	}
	c, ip, err = SetupContainer(RethinkDBImageName, port, 10*time.Second, func() (string, error) {
		res, err := run("--name", GenerateContainerID(), "-d", "-P", "-p", forward, RethinkDBImageName)
		return res, err
	})
	return
}

// ConnectToRethinkDB starts a RethinkDB image and passes the database url to the connector callback.
// The url will match the ip:port pattern (e.g. 123.123.123.123:4241)
func ConnectToRethinkDB(tries int, delay time.Duration, connector func(url string) bool) (c ContainerID, err error) {
	c, ip, port, err := SetupRethinkDBContainer()
	if err != nil {
		return c, fmt.Errorf("Could not set up RethinkDB container: %v", err)
	}

	for try := 0; try <= tries; try++ {
		time.Sleep(delay)
		url := fmt.Sprintf("%s:%d", ip, port)
		if connector(url) {
			return c, nil
		}
		log.Printf("Try %d failed. Retrying.", try)
	}
	return c, errors.New("Could not set up RethinkDB container.")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"golang.org/x/oauth2"
	"gopkg.in/authboss.v0"
	_ "gopkg.in/authboss.v0/auth"
	_ "gopkg.in/authboss.v0/confirm"
	_ "gopkg.in/authboss.v0/lock"
	aboauth "gopkg.in/authboss.v0/oauth2"
	_ "gopkg.in/authboss.v0/recover"
	_ "gopkg.in/authboss.v0/register"
	_ "gopkg.in/authboss.v0/remember"

	"github.com/aarondl/tpl"
	"github.com/gorilla/mux"
	"github.com/gorilla/schema"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"github.com/justinas/alice"
	"github.com/justinas/nosurf"
)

var funcs = template.FuncMap{
	"formatDate": func(date time.Time) string {
		return date.Format("2006/01/02 03:04pm")
	},
	"yield": func() string { return "" },
}

var (
	ab        = authboss.New()
	database  = NewMemStorer()
	templates = tpl.Must(tpl.Load("views", "views/partials", "layout.html.tpl", funcs))
	schemaDec = schema.NewDecoder()
)

func setupAuthboss() {
	ab.Storer = database
	ab.OAuth2Storer = database
	ab.MountPath = "/auth"
	ab.ViewsPath = "ab_views"
	ab.RootURL = `http://localhost:3000`

	ab.LayoutDataMaker = layoutData

	ab.OAuth2Providers = map[string]authboss.OAuth2Provider{
		"google": authboss.OAuth2Provider{
			OAuth2Config: &oauth2.Config{
				ClientID:     ``,
				ClientSecret: ``,
				Scopes:       []string{`profile`, `email`},
				Endpoint:     aboauth.GoogleEndpoint,
			},
			Callback: aboauth.Google,
		},
	}

	b, err := ioutil.ReadFile(filepath.Join("views", "layout.html.tpl"))
	if err != nil {
		panic(err)
	}
	ab.Layout = template.Must(template.New("layout").Funcs(funcs).Parse(string(b)))

	ab.XSRFName = "csrf_token"
	ab.XSRFMaker = func(_ http.ResponseWriter, r *http.Request) string {
		return nosurf.Token(r)
	}

	ab.CookieStoreMaker = NewCookieStorer
	ab.SessionStoreMaker = NewSessionStorer

	ab.Mailer = authboss.LogMailer(os.Stdout)

	if err := ab.Init(); err != nil {
		log.Fatal(err)
	}
}

func main() {
	// Initialize Sessions and Cookies
	// Typically gorilla securecookie and sessions packages require
	// highly random secret keys that are not divulged to the public.
	//
	// In this example we use keys generated one time (if these keys ever become
	// compromised the gorilla libraries allow for key rotation, see gorilla docs)
	// The keys are 64-bytes as recommended for HMAC keys as per the gorilla docs.
	//
	// These values MUST be changed for any new project as these keys are already "compromised"
	// as they're in the public domain, if you do not change these your application will have a fairly
	// wide-opened security hole. You can generate your own with the code below, or using whatever method
	// you prefer:
	//
	//    func main() {
	//        fmt.Println(base64.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(64)))
	//    }
	//
	// We store them in base64 in the example to make it easy if we wanted to move them later to
	// a configuration environment var or file.
	cookieStoreKey, _ := base64.StdEncoding.DecodeString(`NpEPi8pEjKVjLGJ6kYCS+VTCzi6BUuDzU0wrwXyf5uDPArtlofn2AG6aTMiPmN3C909rsEWMNqJqhIVPGP3Exg==`)
	sessionStoreKey, _ := base64.StdEncoding.DecodeString(`AbfYwmmt8UCwUuhd9qvfNA9UCuN1cVcKJN1ofbiky6xCyyBj20whe40rJa3Su0WOWLWcPpO1taqJdsEI/65+JA==`)
	cookieStore = securecookie.New(cookieStoreKey, nil)
	sessionStore = sessions.NewCookieStore(sessionStoreKey)

	// Initialize ab.
	setupAuthboss()

	// Set up our router
	schemaDec.IgnoreUnknownKeys(true)
	mux := mux.NewRouter()

	// Routes
	gets := mux.Methods("GET").Subrouter()
	posts := mux.Methods("POST").Subrouter()

	mux.PathPrefix("/auth").Handler(ab.NewRouter())

	gets.Handle("/blogs/new", authProtect(newblog))
	gets.Handle("/blogs/{id}/edit", authProtect(edit))
	gets.HandleFunc("/blogs", index)
	gets.HandleFunc("/", index)

	posts.Handle("/blogs/{id}/edit", authProtect(update))
	posts.Handle("/blogs/new", authProtect(create))

	// This should actually be a DELETE but I can't be bothered to make a proper
	// destroy link using javascript atm.
	gets.HandleFunc("/blogs/{id}/destroy", destroy)

	mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, "Not found")
	})

	// Set up our middleware chain
	stack := alice.New(logger /*nosurfing,*/, ab.ExpireMiddleware).Then(mux)

	// Start the server
	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "8080"
	}
	log.Println(http.ListenAndServe("localhost:"+port, stack))
}

func layoutData(w http.ResponseWriter, r *http.Request) authboss.HTMLData {
	currentUserName := ""
	userInter, err := ab.CurrentUser(w, r)
	if userInter != nil && err == nil {
		currentUserName = userInter.(*User).Name
	}

	return authboss.HTMLData{
		"loggedin":               userInter != nil,
		"username":               "",
		authboss.FlashSuccessKey: ab.FlashSuccess(w, r),
		authboss.FlashErrorKey:   ab.FlashError(w, r),
		"current_user_name":      currentUserName,
	}
}

func index(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("posts", blogs)
	mustRender(w, r, "index", data)
}

func newblog(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("post", Blog{})
	mustRender(w, r, "new", data)
}

var nextID = len(blogs) + 1

func create(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	// TODO: Validation

	var b Blog
	if badRequest(w, schemaDec.Decode(&b, r.PostForm)) {
		return
	}

	b.ID = nextID
	nextID++
	b.Date = time.Now()
	b.AuthorID = "Zeratul"

	blogs = append(blogs, b)

	http.Redirect(w, r, "/", http.StatusFound)
}

func edit(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	data := layoutData(w, r).MergeKV("post", blogs.Get(id))
	mustRender(w, r, "edit", data)
}

func update(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	id, ok := blogID(w, r)
	if !ok {
		return
	}

	// TODO: Validation

	var b = blogs.Get(id)
	if badRequest(w, schemaDec.Decode(b, r.PostForm)) {
		return
	}

	b.Date = time.Now()

	http.Redirect(w, r, "/", http.StatusFound)
}

func destroy(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	blogs.Delete(id)

	http.Redirect(w, r, "/", http.StatusFound)
}

func blogID(w http.ResponseWriter, r *http.Request) (int, bool) {
	vars := mux.Vars(r)
	str := vars["id"]

	id, err := strconv.Atoi(str)
	if err != nil {
		log.Println("Error parsing blog id:", err)
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	if id <= 0 {
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	return id, true
}

func mustRender(w http.ResponseWriter, r *http.Request, name string, data authboss.HTMLData) {
	data.MergeKV("csrf_token", nosurf.Token(r))
	err := templates.Render(w, name, data)
	if err == nil {
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintln(w, "Error occurred rendering template:", err)
}

func badRequest(w http.ResponseWriter, err error) bool {
	if err == nil {
		return false
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, "Bad request:", err)

	return true
}
<commit_msg>Fix validation for sample<commit_after>package main

import (
	"encoding/base64"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"golang.org/x/oauth2"
	"gopkg.in/authboss.v0"
	_ "gopkg.in/authboss.v0/auth"
	_ "gopkg.in/authboss.v0/confirm"
	_ "gopkg.in/authboss.v0/lock"
	aboauth "gopkg.in/authboss.v0/oauth2"
	_ "gopkg.in/authboss.v0/recover"
	_ "gopkg.in/authboss.v0/register"
	_ "gopkg.in/authboss.v0/remember"

	"github.com/aarondl/tpl"
	"github.com/gorilla/mux"
	"github.com/gorilla/schema"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"github.com/justinas/alice"
	"github.com/justinas/nosurf"
)

var funcs = template.FuncMap{
	"formatDate": func(date time.Time) string {
		return date.Format("2006/01/02 03:04pm")
	},
	"yield": func() string { return "" },
}

var (
	ab        = authboss.New()
	database  = NewMemStorer()
	templates = tpl.Must(tpl.Load("views", "views/partials", "layout.html.tpl", funcs))
	schemaDec = schema.NewDecoder()
)

func setupAuthboss() {
	ab.Storer = database
	ab.OAuth2Storer = database
	ab.MountPath = "/auth"
	ab.ViewsPath = "ab_views"
	ab.RootURL = `http://localhost:3000`

	ab.LayoutDataMaker = layoutData

	ab.OAuth2Providers = map[string]authboss.OAuth2Provider{
		"google": authboss.OAuth2Provider{
			OAuth2Config: &oauth2.Config{
				ClientID:     ``,
				ClientSecret: ``,
				Scopes:       []string{`profile`, `email`},
				Endpoint:     aboauth.GoogleEndpoint,
			},
			Callback: aboauth.Google,
		},
	}

	b, err := ioutil.ReadFile(filepath.Join("views", "layout.html.tpl"))
	if err != nil {
		panic(err)
	}
	ab.Layout = template.Must(template.New("layout").Funcs(funcs).Parse(string(b)))

	ab.XSRFName = "csrf_token"
	ab.XSRFMaker = func(_ http.ResponseWriter, r *http.Request) string {
		return nosurf.Token(r)
	}

	ab.CookieStoreMaker = NewCookieStorer
	ab.SessionStoreMaker = NewSessionStorer

	ab.Mailer = authboss.LogMailer(os.Stdout)

	ab.Policies = []authboss.Validator{
		authboss.Rules{
			FieldName:       "email",
			Required:        true,
			AllowWhitespace: false,
		},
		authboss.Rules{
			FieldName:       "password",
			Required:        true,
			MinLength:       4,
			MaxLength:       8,
			AllowWhitespace: false,
		},
	}

	if err := ab.Init(); err != nil {
		log.Fatal(err)
	}
}

func main() {
	// Initialize Sessions and Cookies
	// Typically gorilla securecookie and sessions packages require
	// highly random secret keys that are not divulged to the public.
	//
	// In this example we use keys generated one time (if these keys ever become
	// compromised the gorilla libraries allow for key rotation, see gorilla docs)
	// The keys are 64-bytes as recommended for HMAC keys as per the gorilla docs.
	//
	// These values MUST be changed for any new project as these keys are already "compromised"
	// as they're in the public domain, if you do not change these your application will have a fairly
	// wide-opened security hole. You can generate your own with the code below, or using whatever method
	// you prefer:
	//
	//    func main() {
	//        fmt.Println(base64.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(64)))
	//    }
	//
	// We store them in base64 in the example to make it easy if we wanted to move them later to
	// a configuration environment var or file.
	cookieStoreKey, _ := base64.StdEncoding.DecodeString(`NpEPi8pEjKVjLGJ6kYCS+VTCzi6BUuDzU0wrwXyf5uDPArtlofn2AG6aTMiPmN3C909rsEWMNqJqhIVPGP3Exg==`)
	sessionStoreKey, _ := base64.StdEncoding.DecodeString(`AbfYwmmt8UCwUuhd9qvfNA9UCuN1cVcKJN1ofbiky6xCyyBj20whe40rJa3Su0WOWLWcPpO1taqJdsEI/65+JA==`)
	cookieStore = securecookie.New(cookieStoreKey, nil)
	sessionStore = sessions.NewCookieStore(sessionStoreKey)

	// Initialize ab.
	setupAuthboss()

	// Set up our router
	schemaDec.IgnoreUnknownKeys(true)
	mux := mux.NewRouter()

	// Routes
	gets := mux.Methods("GET").Subrouter()
	posts := mux.Methods("POST").Subrouter()

	mux.PathPrefix("/auth").Handler(ab.NewRouter())

	gets.Handle("/blogs/new", authProtect(newblog))
	gets.Handle("/blogs/{id}/edit", authProtect(edit))
	gets.HandleFunc("/blogs", index)
	gets.HandleFunc("/", index)

	posts.Handle("/blogs/{id}/edit", authProtect(update))
	posts.Handle("/blogs/new", authProtect(create))

	// This should actually be a DELETE but I can't be bothered to make a proper
	// destroy link using javascript atm.
	gets.HandleFunc("/blogs/{id}/destroy", destroy)

	mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, "Not found")
	})

	// Set up our middleware chain
	stack := alice.New(logger /*nosurfing,*/, ab.ExpireMiddleware).Then(mux)

	// Start the server
	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "8080"
	}
	log.Println(http.ListenAndServe("localhost:"+port, stack))
}

func layoutData(w http.ResponseWriter, r *http.Request) authboss.HTMLData {
	currentUserName := ""
	userInter, err := ab.CurrentUser(w, r)
	if userInter != nil && err == nil {
		currentUserName = userInter.(*User).Name
	}

	return authboss.HTMLData{
		"loggedin":               userInter != nil,
		"username":               "",
		authboss.FlashSuccessKey: ab.FlashSuccess(w, r),
		authboss.FlashErrorKey:   ab.FlashError(w, r),
		"current_user_name":      currentUserName,
	}
}

func index(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("posts", blogs)
	mustRender(w, r, "index", data)
}

func newblog(w http.ResponseWriter, r *http.Request) {
	data := layoutData(w, r).MergeKV("post", Blog{})
	mustRender(w, r, "new", data)
}

var nextID = len(blogs) + 1

func create(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	// TODO: Validation

	var b Blog
	if badRequest(w, schemaDec.Decode(&b, r.PostForm)) {
		return
	}

	b.ID = nextID
	nextID++
	b.Date = time.Now()
	b.AuthorID = "Zeratul"

	blogs = append(blogs, b)

	http.Redirect(w, r, "/", http.StatusFound)
}

func edit(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	data := layoutData(w, r).MergeKV("post", blogs.Get(id))
	mustRender(w, r, "edit", data)
}

func update(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if badRequest(w, err) {
		return
	}

	id, ok := blogID(w, r)
	if !ok {
		return
	}

	// TODO: Validation

	var b = blogs.Get(id)
	if badRequest(w, schemaDec.Decode(b, r.PostForm)) {
		return
	}

	b.Date = time.Now()

	http.Redirect(w, r, "/", http.StatusFound)
}

func destroy(w http.ResponseWriter, r *http.Request) {
	id, ok := blogID(w, r)
	if !ok {
		return
	}

	blogs.Delete(id)

	http.Redirect(w, r, "/", http.StatusFound)
}

func blogID(w http.ResponseWriter, r *http.Request) (int, bool) {
	vars := mux.Vars(r)
	str := vars["id"]

	id, err := strconv.Atoi(str)
	if err != nil {
		log.Println("Error parsing blog id:", err)
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	if id <= 0 {
		http.Redirect(w, r, "/", http.StatusFound)
		return 0, false
	}

	return id, true
}

func mustRender(w http.ResponseWriter, r *http.Request, name string, data authboss.HTMLData) {
	data.MergeKV("csrf_token", nosurf.Token(r))
	err := templates.Render(w, name, data)
	if err == nil {
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintln(w, "Error occurred rendering template:", err)
}

func badRequest(w http.ResponseWriter, err error) bool {
	if err == nil {
		return false
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, "Bad request:", err)

	return true
}
<|endoftext|>


<commit_before>package whoson

import (
	"fmt"
	"net"
	"net/textproto"
	"strings"
	"time"

	"github.com/pkg/errors"
)

type Session struct {
	protocol ProtocolType

	udpconn    *net.UDPConn
	remoteAddr *net.UDPAddr
	b          *Buffer

	tcpserver *TCPServer
	conn      net.Conn
	tp        *textproto.Conn
	tpid      uint

	cmdMethod MethodType
	cmdIp     net.IP
	cmdArgs   string
}

func NewSessionUDP(c *net.UDPConn, r *net.UDPAddr, b *Buffer) *Session {
	return &Session{
		protocol:   pUDP,
		udpconn:    c,
		remoteAddr: r,
		b:          b,
	}
}

func NewSessionTCP(s *TCPServer, c net.Conn) *Session {
	return &Session{
		protocol:  pTCP,
		tcpserver: s,
		conn:      c,
		tp:        textproto.NewConn(c),
	}
}

func (ses *Session) setTpId() {
	ses.tpid = ses.tp.Next()
}

func (ses *Session) methodType(m string) MethodType {
	if v, ok := methodFromString[m]; ok {
		return v
	} else {
		return mUnkownMethod
	}
}

func (ses *Session) parseCmd(line string) error {
	var cmd []string

	if strings.TrimSpace(line) == "" {
		return errors.New("command parse error")
	}

	w := strings.Split(line, " ")
	for i := range w {
		if w[i] != "" {
			cmd = append(cmd, strings.TrimSpace(w[i]))
		}
	}

	ses.cmdMethod = ses.methodType(strings.ToUpper(cmd[0]))
	switch ses.cmdMethod {
	case mLogin, mLogout, mQuery:
		if ses.cmdIp = net.ParseIP(cmd[1]); ses.cmdIp == nil {
			return errors.New("command parse error")
		}
		ses.cmdArgs = strings.Join(cmd[2:], " ")
	case mQuit:
		//pp.Println("Quit")
		ses.cmdArgs = strings.Join(cmd[1:], " ")
	default:
		return errors.New("command not found")
	}
	return nil
}

func (ses *Session) readLine() (string, error) {
	ses.tp.StartRequest(ses.tpid)
	l1, err := ses.tp.ReadLine()
	if err != nil {
		return "", err
	}

	l2, err := ses.tp.ReadLine()
	if err != nil {
		return "", err
	}
	ses.tp.EndRequest(ses.tpid)

	if l1 != "" && l2 == "" {
		return l1, nil
	} else {
		return "", errors.New("session read error")
	}
}

func (ses *Session) sendLine(str string) error {
	var err error
	if ses.protocol == pTCP {
		ses.tp.StartResponse(ses.tpid)
		err = ses.tp.PrintfLine(str + CRLF)
		ses.tp.EndResponse(ses.tpid)
	} else {
		b := []byte(str + CRLF + CRLF)
		_, err = ses.udpconn.WriteToUDP(b, ses.remoteAddr)
	}
	return err
}

func (ses *Session) sendResponsePositive(str string) error {
	return ses.sendLine(fmt.Sprintf("%s%s", result[rPositive], str))
}

func (ses *Session) sendResponseNegative(str string) error {
	return ses.sendLine(fmt.Sprintf("%s%s", result[rNegative], str))
}

func (ses *Session) sendResponseBadRequest(str string) error {
	return ses.sendLine(fmt.Sprintf("%s%s", result[rBadRequest], str))
}

func (ses *Session) startHandler() bool {
	var err error

	if ses.protocol == pTCP {
		ses.setTpId()

		line, err := ses.readLine()
		if err != nil {
			if opError, ok := err.(*net.OpError); ok && opError.Timeout() {
				return false
			}
			if err.Error() == "EOF" {
				return false
			} else {
				ses.sendResponseBadRequest(err.Error())
				return true
			}
		}
		err = ses.parseCmd(line)
	} else {
		err = ses.parseCmd(string(ses.b.buf[:ses.b.count]))
	}
	if err != nil {
		ses.sendResponseBadRequest(err.Error())
		return true
	}

	switch ses.cmdMethod {
	case mLogin:
		ses.methodLogin()
	case mLogout:
		ses.methodLogout()
	case mQuery:
		ses.methodQuery()
	case mQuit:
		ses.methodQuit()
	default:
		err := errors.New("handler error")
		ses.sendResponseBadRequest(err.Error())
	}
	return true
}

func (ses *Session) methodLogin() {
	sd := &StoreData{
		Expire: time.Now().Add(StoreDataExpire),
		IP:     ses.cmdIp,
		Data:   ses.cmdArgs,
	}
	MainStore.Set(sd.Key(), sd)
	ses.sendResponsePositive("LOGIN OK")
}

func (ses *Session) methodLogout() {
	ok := MainStore.Del(ses.cmdIp.String())
	if ok {
		ses.sendResponsePositive("LOGOUT record deleted")
	} else {
		ses.sendResponsePositive("LOGOUT no such record, nothing done")
	}
}

func (ses *Session) methodQuery() {
	sd, err := MainStore.Get(ses.cmdIp.String())
	if err != nil {
		ses.sendResponseNegative("Not Logged in")
	} else {
		ses.sendResponsePositive(sd.Data)
	}
}

func (ses *Session) methodQuit() {
	ses.sendResponsePositive("QUIT OK")
	ses.conn.Close()
}

func (ses *Session) close() {
	if ses.protocol == pUDP {
		ses.b.Free()
	}
}
<commit_msg>Fix err handling<commit_after>package whoson

import (
	"fmt"
	"net"
	"net/textproto"
	"strings"
	"time"

	"github.com/pkg/errors"
)

type Session struct {
	protocol ProtocolType

	udpconn    *net.UDPConn
	remoteAddr *net.UDPAddr
	b          *Buffer

	tcpserver *TCPServer
	conn      net.Conn
	tp        *textproto.Conn
	tpid      uint

	cmdMethod MethodType
	cmdIp     net.IP
	cmdArgs   string
}

func NewSessionUDP(c *net.UDPConn, r *net.UDPAddr, b *Buffer) *Session {
	return &Session{
		protocol:   pUDP,
		udpconn:    c,
		remoteAddr: r,
		b:          b,
	}
}

func NewSessionTCP(s *TCPServer, c net.Conn) *Session {
	return &Session{
		protocol:  pTCP,
		tcpserver: s,
		conn:      c,
		tp:        textproto.NewConn(c),
	}
}

func (ses *Session) setTpId() {
	ses.tpid = ses.tp.Next()
}

func (ses *Session) methodType(m string) MethodType {
	if v, ok := methodFromString[m]; ok {
		return v
	} else {
		return mUnkownMethod
	}
}

func (ses *Session) parseCmd(line string) error {
	var cmd []string

	if strings.TrimSpace(line) == "" {
		return errors.New("command parse error")
	}

	w := strings.Split(line, " ")
	for i := range w {
		if w[i] != "" {
			cmd = append(cmd, strings.TrimSpace(w[i]))
		}
	}

	ses.cmdMethod = ses.methodType(strings.ToUpper(cmd[0]))
	switch ses.cmdMethod {
	case mLogin, mLogout, mQuery:
		if ses.cmdIp = net.ParseIP(cmd[1]); ses.cmdIp == nil {
			return errors.New("command parse error")
		}
		ses.cmdArgs = strings.Join(cmd[2:], " ")
	case mQuit:
		//pp.Println("Quit")
		ses.cmdArgs = strings.Join(cmd[1:], " ")
	default:
		return errors.New("command not found")
	}
	return nil
}

func (ses *Session) readLine() (string, error) {
	ses.tp.StartRequest(ses.tpid)
	l1, err := ses.tp.ReadLine()
	if err != nil {
		return "", err
	}

	l2, err := ses.tp.ReadLine()
	if err != nil {
		return "", err
	}
	ses.tp.EndRequest(ses.tpid)

	if l1 != "" && l2 == "" {
		return l1, nil
	} else {
		return "", errors.New("session read error")
	}
}

func (ses *Session) sendLine(str string) error {
	var err error
	if ses.protocol == pTCP {
		ses.tp.StartResponse(ses.tpid)
		err = ses.tp.PrintfLine(str + CRLF)
		ses.tp.EndResponse(ses.tpid)
	} else {
		b := []byte(str + CRLF + CRLF)
		_, err = ses.udpconn.WriteToUDP(b, ses.remoteAddr)
	}
	return err
}

func (ses *Session) sendResponsePositive(str string) error {
	return ses.sendLine(fmt.Sprintf("%s%s", result[rPositive], str))
}

func (ses *Session) sendResponseNegative(str string) error {
	return ses.sendLine(fmt.Sprintf("%s%s", result[rNegative], str))
}

func (ses *Session) sendResponseBadRequest(str string) error {
	return ses.sendLine(fmt.Sprintf("%s%s", result[rBadRequest], str))
}

func (ses *Session) startHandler() bool {
	var err error

	if ses.protocol == pTCP {
		ses.setTpId()

		line, err := ses.readLine()
		if err != nil {
			if opError, ok := err.(*net.OpError); ok && opError.Timeout() {
				return false
			}
			if err.Error() == "EOF" {
				return false
			} else {
				ses.sendResponseBadRequest(err.Error())
				return true
			}
		}
		err = ses.parseCmd(line)
		if err != nil {
			ses.sendResponseBadRequest(err.Error())
			return true
		}
	} else {
		err = ses.parseCmd(string(ses.b.buf[:ses.b.count]))
		if err != nil {
			ses.sendResponseBadRequest(err.Error())
			return true
		}
	}

	switch ses.cmdMethod {
	case mLogin:
		ses.methodLogin()
	case mLogout:
		ses.methodLogout()
	case mQuery:
		ses.methodQuery()
	case mQuit:
		ses.methodQuit()
	default:
		err := errors.New("handler error")
		ses.sendResponseBadRequest(err.Error())
	}
	return true
}

func (ses *Session) methodLogin() {
	sd := &StoreData{
		Expire: time.Now().Add(StoreDataExpire),
		IP:     ses.cmdIp,
		Data:   ses.cmdArgs,
	}
	MainStore.Set(sd.Key(), sd)
	ses.sendResponsePositive("LOGIN OK")
}

func (ses *Session) methodLogout() {
	ok := MainStore.Del(ses.cmdIp.String())
	if ok {
		ses.sendResponsePositive("LOGOUT record deleted")
	} else {
		ses.sendResponsePositive("LOGOUT no such record, nothing done")
	}
}

func (ses *Session) methodQuery() {
	sd, err := MainStore.Get(ses.cmdIp.String())
	if err != nil {
		ses.sendResponseNegative("Not Logged in")
	} else {
		ses.sendResponsePositive(sd.Data)
	}
}

func (ses *Session) methodQuit() {
	ses.sendResponsePositive("QUIT OK")
	ses.conn.Close()
}

func (ses *Session) close() {
	if ses.protocol == pUDP {
		ses.b.Free()
	}
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"fmt"
	"github.com/go-xorm/xorm"
	"github.com/nttdots/go-dots/dots_server/db_models"
	log "github.com/sirupsen/logrus"
)

/*
 * Stores a Blocker object to the database
 *
 * parameter:
 *  blocker Blocker
 * return:
 *  newBlocker db_models.Blocker
 *  err error
 */
func CreateBlocker(blocker Blocker) (newBlocker db_models.Blocker, err error) {

	var blockerParameters []db_models.BlockerParameter

	engine, err := ConnectDB()
	if err != nil {
		return
	}

	session := engine.NewSession()
	defer session.Close()

	err = session.Begin()
	if err != nil {
		return
	}

	newBlocker = db_models.Blocker{
		BlockerType: string(blocker.Type()),
		Load:        blocker.Load(),
		Capacity:    blocker.Capacity(),
	}
	_, err = session.Insert(&newBlocker)
	if err != nil {
		goto Rollback
	}

	if blocker.LoginProfile() != nil {
		err = createBlockerLoginProfile(session, *blocker.LoginProfile(), newBlocker.Id)
		if err != nil {
			goto Rollback
		}
	}
	blockerParameters = toBlockerParameters(blocker, newBlocker.Id)

	if len(blockerParameters) > 0 {
		_, err := session.InsertMulti(blockerParameters)
		if err != nil {
			goto Rollback
		}
	}

	session.Commit()
	return
Rollback:
	session.Rollback()
	return
}

/*
 * Stores a LoginInfo object related to a Blocker to the database.
 * Parameter:
 *  session session information
 *  login_info LoginProfile
 *  blocker_id  Blocker ID to which this loginInfo is related.
 * return:
 *  err error
 */
func createBlockerLoginProfile(session *xorm.Session, loginInfo LoginProfile, blockerId int64) (err error) {
	// registered LoginProfile
	newLoginProfile := db_models.LoginProfile{
		LoginMethod: loginInfo.LoginMethod,
		LoginName:   loginInfo.LoginName,
		Password:    loginInfo.Password,
		BlockerId:   blockerId,
	}

	_, err = session.Insert(&newLoginProfile)
	if err != nil {
		session.Rollback()
		log.Infof("LoginProfile insert err: %s", err)
		return
	}

	return
}

/*
 * Stores a Blocker parameters related to a Blocker to the database.
 * Parameter:
 *  session session information
 *  login_info LoginProfile
 *  blocker_id  Blocker ID to which this loginInfo is related.
 * return:
 *  err error
 */
func createBlockerParameters(session *xorm.Session, blockerParameters []db_models.BlockerParameter, blockerId int64) (err error) {
	// registered BlockerParameters
	for _, param := range blockerParameters {
		param.BlockerId = blockerId
		_, err = session.Insert(param)
		if err != nil {
			session.Rollback()
			log.Infof("LoginProfile insert err: %s", err)
			return
		}
	}

	return
}

/*
 * Obtain all the blocker information stored in the database.
 *
 * return:
 *  blockers a list of blockers
 *  error error
 */
func GetBlockers() (blockers []db_models.Blocker, err error) {
	// default value setting
	blockers = []db_models.Blocker{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	err = engine.Find(&blockers)
	if err != nil {
		return
	}

	return
}

/*
 * Obtain the blocker with the least load.
 * If the load values are same, capacity information are used to break the tie.
 */
func GetLowestLoadBlocker(blockerType string) (blocker db_models.Blocker, err error) {
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// ok, err := engine.Where("`load` < `capacity`").OrderBy("`load`, `capacity` desc").Get(&blocker)
	// get first blocker
	ok, err := engine.Where("blocker_type = ? AND `load` < `capacity`", blockerType).OrderBy("`load`, `capacity` desc").Get(&blocker)
	if err != nil {
		return
	}
	if !ok {
		blocker.Id = 0
	}
	return blocker, nil
}

/*
 * Obtain the designated BlockerParameters by the Blocker ID.
 *
 * parameter:
 *  blockerId  Blocker ID
 * return:
 *  BlockerParameter BlockerParameter
 *  error error
 */
func GetBlockerParameters(blockerId int64) (blockerParameters []db_models.BlockerParameter, err error) {
	// default value setting
	blockerParameters = []db_models.BlockerParameter{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	err = engine.Where("blocker_id = ?", blockerId).Find(&blockerParameters)
	if err != nil {
		return
	}

	return

}

/*
 * Obtain the designated BlockerConfigurationParameters by the Blocker COnfiguration ID.
 *
 * parameter:
 *  blockerConfigurationId  the Blocker Configuration ID
 * return:
 *  blockerConfigurationParameters the Blocker Configuration Parameter
 *  error error
 */
func GetBlockerConfigurationParameters(blockerConfigurationId int64) (blockerConfigurationParameters []db_models.BlockerConfigurationParameter, err error) {
	// default value setting
	blockerConfigurationParameters = []db_models.BlockerConfigurationParameter{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	err = engine.Where("blocker_configuration_id = ?", blockerConfigurationId).Find(&blockerConfigurationParameters)
	if err != nil {
		return
	}

	return
}

/*
 * Obtain the designated LoginProfile by the Blocker ID.
 *
 * parameter:
 *  blockerId  Blocker ID
 * return:
 *  LoginProfile LoginProfile
 *  error error
 */
func GetLoginProfile(blockerId int64) (loginProfile db_models.LoginProfile, err error) {
	// default value setting
	loginProfile = db_models.LoginProfile{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	ok, err := engine.Where("blocker_id = ?", blockerId).Get(&loginProfile)
	if err != nil {
		return
	}
	if !ok {
		// No data found
		log.WithField("blocker_id", blockerId).Warn("login_profile data not exist.")
		return
	}

	return

}

/*
 * Delete the Blocker by the Blocker ID.
 *
 * parameter:
 *  blockerId  Blocker ID
 * return:
 *  error error
 */
func DeleteBlockerById(blockerId int64) (err error) {
	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// transaction start
	session := engine.NewSession()
	defer session.Close()

	err = session.Begin()
	if err != nil {
		return
	}

	// Delete blocker_parameters table data
	_, err = session.Delete(db_models.BlockerParameter{BlockerId: blockerId})
	if err != nil {
		log.Errorf("delete blockerParameters error: %s", err)
		goto Rollback
	}

	// Delete login_profile table data
	_, err = session.Delete(db_models.LoginProfile{BlockerId: blockerId})
	if err != nil {
		log.Errorf("delete loginProfile error: %s", err)
		goto Rollback
	}

	// Delete blocker table data
	_, err = session.Id(blockerId).Delete(db_models.Blocker{})
	if err != nil {
		log.Errorf("delete blocker error: %s", err)
		goto Rollback
	}

	session.Commit()
	return
Rollback:
	session.Rollback()
	return
}

func GetBlockerById(blockerId int64) (blocker db_models.Blocker, err error) {
	engine, err := ConnectDB()
	if err != nil {
		return
	}

	ok, err := engine.Id(blockerId).Get(&blocker)
	if !ok {
		return db_models.Blocker{}, nil
	} else {
		return
	}
}

/*
 * Update the load value of a Blocker
 *
 * parameter:
 *  blockerId id
 *  diff diff of the load value
 * return:
 *  error error
 */
func UpdateBlockerLoad(blockerId int64, diff int) (err error) {

	engine, err := ConnectDB()
	if err != nil {
		return
	}
	session := engine.NewSession()
	err = session.Begin()
	if err != nil {
		return
	}
	blocker := db_models.Blocker{}

	ok, err := session.Id(blockerId).Get(&blocker)
	if err != nil {
		goto Rollback
	}

	if ok {
		blocker.Load += diff
		_, err = session.Id(blockerId).Cols("Load").Update(&blocker)
		if err != nil {
			goto Rollback
		}
	}

	session.Commit()
	return
Rollback:
	session.Rollback()
	return
}

func BlockerParametersToMap(params []db_models.BlockerParameter) map[string][]string {
	m := make(map[string][]string)

	for _, p := range params {
		a, ok := m[p.Key]
		if !ok {
			a = make([]string, 0)
		}
		a = append(a, p.Value)
		m[p.Key] = a
	}
	return m
}

func BlockerConfigurationParametersToMap(configParams []db_models.BlockerConfigurationParameter) map[string][]string {
	m := make(map[string][]string)

	for _, p := range configParams {
		a, ok := m[p.Key]
		if !ok {
			a = make([]string, 0)
		}
		a = append(a, p.Value)
		m[p.Key] = a
	}
	return m
}

func toBlocker(blocker db_models.Blocker, blockerConfig *db_models.BlockerConfiguration) (b Blocker, err error) {

	profile, err := GetLoginProfile(blocker.Id)
	if err != nil {
		return nil, err
	}

	base := BlockerBase{
		id:        blocker.Id,
		capacity:  blocker.Capacity,
		load:      blocker.Load,
		loginInfo: new(LoginProfile),
	}
	base.loginInfo.Load(profile)

	// Get blocker parameter and parse it to map
	params, err := GetBlockerParameters(blocker.Id)
	if err != nil {
		return nil, err
	}
	paramMap := BlockerParametersToMap(params)

	// Get blocker configuration parameter and parse it to map
	configParams, err := GetBlockerConfigurationParameters(blockerConfig.Id)
	if err != nil {
		return nil, err
	}
	configParamMap := BlockerConfigurationParametersToMap(configParams)

	switch blocker.BlockerType {
	case BLOCKER_TYPE_GoBGP_RTBH:
		b = NewGoBgpRtbhReceiver(base, paramMap)
	case BLOCKER_TYPE_GoBGP_FLOWSPEC:
		b = NewGoBgpFlowSpecReceiver(base, paramMap, configParamMap)
	case BLOCKER_TYPE_GO_ARISTA:
		b = NewGoAristaReceiver(base, configParamMap)
	default:
		err = errors.New(fmt.Sprintf("invalid blocker type: %s", blocker.BlockerType))
		return
	}

	log.Debugf("toBlocker result: [%T] %+v", b, b)
	return b, nil
}

/*
 * Get blocker configuration by customerID and targetType
 */
func GetBlockerConfiguration(customerId int, targetType string) (blockerConfiguration *db_models.BlockerConfiguration, err error){
	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Printf("database connect error: %s", err)
		return
	}
	blockerConfig := db_models.BlockerConfiguration{}

	_,err = engine.Where("customer_id = ? AND target_type = ?", customerId, targetType).Get(&blockerConfig)
	if err != nil {
		log.Printf("Get blocker_configuration error: %s\n", err)
		return
	}

	blockerConfiguration = &blockerConfig

	return blockerConfiguration, nil
}<commit_msg>Return an error if no blocker was found<commit_after>package models

import (
	"errors"
	"fmt"
	"github.com/go-xorm/xorm"
	"github.com/nttdots/go-dots/dots_server/db_models"
	log "github.com/sirupsen/logrus"
)

/*
 * Stores a Blocker object to the database
 *
 * parameter:
 *  blocker Blocker
 * return:
 *  newBlocker db_models.Blocker
 *  err error
 */
func CreateBlocker(blocker Blocker) (newBlocker db_models.Blocker, err error) {

	var blockerParameters []db_models.BlockerParameter

	engine, err := ConnectDB()
	if err != nil {
		return
	}

	session := engine.NewSession()
	defer session.Close()

	err = session.Begin()
	if err != nil {
		return
	}

	newBlocker = db_models.Blocker{
		BlockerType: string(blocker.Type()),
		Load:        blocker.Load(),
		Capacity:    blocker.Capacity(),
	}
	_, err = session.Insert(&newBlocker)
	if err != nil {
		goto Rollback
	}

	if blocker.LoginProfile() != nil {
		err = createBlockerLoginProfile(session, *blocker.LoginProfile(), newBlocker.Id)
		if err != nil {
			goto Rollback
		}
	}
	blockerParameters = toBlockerParameters(blocker, newBlocker.Id)

	if len(blockerParameters) > 0 {
		_, err := session.InsertMulti(blockerParameters)
		if err != nil {
			goto Rollback
		}
	}

	session.Commit()
	return
Rollback:
	session.Rollback()
	return
}

/*
 * Stores a LoginInfo object related to a Blocker to the database.
 * Parameter:
 *  session session information
 *  login_info LoginProfile
 *  blocker_id  Blocker ID to which this loginInfo is related.
 * return:
 *  err error
 */
func createBlockerLoginProfile(session *xorm.Session, loginInfo LoginProfile, blockerId int64) (err error) {
	// registered LoginProfile
	newLoginProfile := db_models.LoginProfile{
		LoginMethod: loginInfo.LoginMethod,
		LoginName:   loginInfo.LoginName,
		Password:    loginInfo.Password,
		BlockerId:   blockerId,
	}

	_, err = session.Insert(&newLoginProfile)
	if err != nil {
		session.Rollback()
		log.Infof("LoginProfile insert err: %s", err)
		return
	}

	return
}

/*
 * Stores a Blocker parameters related to a Blocker to the database.
 * Parameter:
 *  session session information
 *  login_info LoginProfile
 *  blocker_id  Blocker ID to which this loginInfo is related.
 * return:
 *  err error
 */
func createBlockerParameters(session *xorm.Session, blockerParameters []db_models.BlockerParameter, blockerId int64) (err error) {
	// registered BlockerParameters
	for _, param := range blockerParameters {
		param.BlockerId = blockerId
		_, err = session.Insert(param)
		if err != nil {
			session.Rollback()
			log.Infof("LoginProfile insert err: %s", err)
			return
		}
	}

	return
}

/*
 * Obtain all the blocker information stored in the database.
 *
 * return:
 *  blockers a list of blockers
 *  error error
 */
func GetBlockers() (blockers []db_models.Blocker, err error) {
	// default value setting
	blockers = []db_models.Blocker{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	err = engine.Find(&blockers)
	if err != nil {
		return
	}

	return
}

/*
 * Obtain the blocker with the least load.
 * If the load values are same, capacity information are used to break the tie.
 */
func GetLowestLoadBlocker(blockerType string) (blocker db_models.Blocker, err error) {
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// ok, err := engine.Where("`load` < `capacity`").OrderBy("`load`, `capacity` desc").Get(&blocker)
	// get first blocker
	ok, err := engine.Where("blocker_type = ? AND `load` < `capacity`", blockerType).OrderBy("`load`, `capacity` desc").Get(&blocker)
	if err != nil {
		return
	}
	if !ok {
		blocker.Id = 0
	}
	return blocker, nil
}

/*
 * Obtain the designated BlockerParameters by the Blocker ID.
 *
 * parameter:
 *  blockerId  Blocker ID
 * return:
 *  BlockerParameter BlockerParameter
 *  error error
 */
func GetBlockerParameters(blockerId int64) (blockerParameters []db_models.BlockerParameter, err error) {
	// default value setting
	blockerParameters = []db_models.BlockerParameter{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	err = engine.Where("blocker_id = ?", blockerId).Find(&blockerParameters)
	if err != nil {
		return
	}

	return

}

/*
 * Obtain the designated BlockerConfigurationParameters by the Blocker COnfiguration ID.
 *
 * parameter:
 *  blockerConfigurationId  the Blocker Configuration ID
 * return:
 *  blockerConfigurationParameters the Blocker Configuration Parameter
 *  error error
 */
func GetBlockerConfigurationParameters(blockerConfigurationId int64) (blockerConfigurationParameters []db_models.BlockerConfigurationParameter, err error) {
	// default value setting
	blockerConfigurationParameters = []db_models.BlockerConfigurationParameter{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	err = engine.Where("blocker_configuration_id = ?", blockerConfigurationId).Find(&blockerConfigurationParameters)
	if err != nil {
		return
	}

	return
}

/*
 * Obtain the designated LoginProfile by the Blocker ID.
 *
 * parameter:
 *  blockerId  Blocker ID
 * return:
 *  LoginProfile LoginProfile
 *  error error
 */
func GetLoginProfile(blockerId int64) (loginProfile db_models.LoginProfile, err error) {
	// default value setting
	loginProfile = db_models.LoginProfile{}

	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// Get blocker table data
	ok, err := engine.Where("blocker_id = ?", blockerId).Get(&loginProfile)
	if err != nil {
		return
	}
	if !ok {
		// No data found
		log.WithField("blocker_id", blockerId).Warn("login_profile data not exist.")
		return
	}

	return

}

/*
 * Delete the Blocker by the Blocker ID.
 *
 * parameter:
 *  blockerId  Blocker ID
 * return:
 *  error error
 */
func DeleteBlockerById(blockerId int64) (err error) {
	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Errorf("database connect error: %s", err)
		return
	}

	// transaction start
	session := engine.NewSession()
	defer session.Close()

	err = session.Begin()
	if err != nil {
		return
	}

	// Delete blocker_parameters table data
	_, err = session.Delete(db_models.BlockerParameter{BlockerId: blockerId})
	if err != nil {
		log.Errorf("delete blockerParameters error: %s", err)
		goto Rollback
	}

	// Delete login_profile table data
	_, err = session.Delete(db_models.LoginProfile{BlockerId: blockerId})
	if err != nil {
		log.Errorf("delete loginProfile error: %s", err)
		goto Rollback
	}

	// Delete blocker table data
	_, err = session.Id(blockerId).Delete(db_models.Blocker{})
	if err != nil {
		log.Errorf("delete blocker error: %s", err)
		goto Rollback
	}

	session.Commit()
	return
Rollback:
	session.Rollback()
	return
}

func GetBlockerById(blockerId int64) (blocker db_models.Blocker, err error) {
	engine, err := ConnectDB()
	if err != nil {
		return
	}

	ok, err := engine.Id(blockerId).Get(&blocker)
	if !ok {
		return db_models.Blocker{}, nil
	} else {
		return
	}
}

/*
 * Update the load value of a Blocker
 *
 * parameter:
 *  blockerId id
 *  diff diff of the load value
 * return:
 *  error error
 */
func UpdateBlockerLoad(blockerId int64, diff int) (err error) {

	engine, err := ConnectDB()
	if err != nil {
		return
	}
	session := engine.NewSession()
	err = session.Begin()
	if err != nil {
		return
	}
	blocker := db_models.Blocker{}

	ok, err := session.Id(blockerId).Get(&blocker)
	if err != nil {
		goto Rollback
	}

	if ok {
		blocker.Load += diff
		_, err = session.Id(blockerId).Cols("Load").Update(&blocker)
		if err != nil {
			goto Rollback
		}
	}

	session.Commit()
	return
Rollback:
	session.Rollback()
	return
}

func BlockerParametersToMap(params []db_models.BlockerParameter) map[string][]string {
	m := make(map[string][]string)

	for _, p := range params {
		a, ok := m[p.Key]
		if !ok {
			a = make([]string, 0)
		}
		a = append(a, p.Value)
		m[p.Key] = a
	}
	return m
}

func BlockerConfigurationParametersToMap(configParams []db_models.BlockerConfigurationParameter) map[string][]string {
	m := make(map[string][]string)

	for _, p := range configParams {
		a, ok := m[p.Key]
		if !ok {
			a = make([]string, 0)
		}
		a = append(a, p.Value)
		m[p.Key] = a
	}
	return m
}

func toBlocker(blocker db_models.Blocker, blockerConfig *db_models.BlockerConfiguration) (b Blocker, err error) {

	profile, err := GetLoginProfile(blocker.Id)
	if err != nil {
		return nil, err
	}

	base := BlockerBase{
		id:        blocker.Id,
		capacity:  blocker.Capacity,
		load:      blocker.Load,
		loginInfo: new(LoginProfile),
	}
	base.loginInfo.Load(profile)

	// Get blocker parameter and parse it to map
	params, err := GetBlockerParameters(blocker.Id)
	if err != nil {
		return nil, err
	}
	paramMap := BlockerParametersToMap(params)

	// Get blocker configuration parameter and parse it to map
	configParams, err := GetBlockerConfigurationParameters(blockerConfig.Id)
	if err != nil {
		return nil, err
	}
	configParamMap := BlockerConfigurationParametersToMap(configParams)

	switch blocker.BlockerType {
	case BLOCKER_TYPE_GoBGP_RTBH:
		b = NewGoBgpRtbhReceiver(base, paramMap)
	case BLOCKER_TYPE_GoBGP_FLOWSPEC:
		b = NewGoBgpFlowSpecReceiver(base, paramMap, configParamMap)
	case BLOCKER_TYPE_GO_ARISTA:
		b = NewGoAristaReceiver(base, configParamMap)
	default:
		err = errors.New(fmt.Sprintf("invalid blocker type: %s", blocker.BlockerType))
		return
	}

	log.Debugf("toBlocker result: [%T] %+v", b, b)
	return b, nil
}

/*
 * Get blocker configuration by customerID and targetType
 */
func GetBlockerConfiguration(customerId int, targetType string) (blockerConfiguration *db_models.BlockerConfiguration, err error){
	// database connection create
	engine, err := ConnectDB()
	if err != nil {
		log.Printf("database connect error: %s", err)
		return
	}
	blockerConfig := db_models.BlockerConfiguration{}

	_,err = engine.Where("customer_id = ? AND target_type = ?", customerId, targetType).Get(&blockerConfig)
	if err != nil {
		log.Printf("Get blocker_configuration error: %s\n", err)
		return
	}

    if (blockerConfig.CustomerId != customerId) {
        err = errors.New(fmt.Sprintf("No blocker found. customerId: %d targetType: %s", customerId, targetType))
        return
    }

	blockerConfiguration = &blockerConfig

	return blockerConfiguration, nil
}
<|endoftext|>


<commit_before>package resp

import (
	"bytes"
	"testing"
)

var (
	respSimpleString = Data{T:T_SimpleString, String:[]byte("OK")}
	respSimpleStringText = "+OK\r\n"

	respError = Data{T:T_Error, String:[]byte("Error message")}
	respErrorText = "-Error message\r\n"

	respBulkString = Data{T:T_BulkString, String:[]byte("foobar")}
	respBulkStringText = "$6\r\nfoobar\r\n"

	respNilBulkString = Data{T:T_BulkString, IsNil:true}
	respNilBulkStringText = "$-1\r\n"

	respInteger = Data{T:T_Integer, Integer:1000}
	respIntegerText = ":1000\r\n"

	respArray = Data{T:T_Array, Array:[]*Data{&respSimpleString, &respInteger}}
	respArrayText = "*2\r\n" + respSimpleStringText + respIntegerText
)

var validCommand map[string]string
var validData map[string]Data

func TestValidData(t *testing.T) {
	for text, data := range validData {
		buf := bytes.NewReader([]byte(text))
		//test read
		d, err := ReadData(buf)
		if nil!=err || d.T != data.T {
			t.Error(err)
		}

		if false == eqData(*d, data) {
			t.Error(text, *d, data)
		}

		//test format
		if text != string(data.Format()) {
			t.Error(text, data)
		}
	}
}

func eqData(d1, d2 Data) bool {
	eqType := d1.T == d2.T
	eqString := 0==bytes.Compare(d1.String, d2.String)
	eqInteger := d1.Integer == d2.Integer
	eqNil := d1.IsNil == d2.IsNil
	eqArrayLen := len(d1.Array) == len(d2.Array)
	eqArray := true
	if len(d1.Array) > 0 && eqArrayLen {
		for index := range d1.Array {
			if false == eqData(*d1.Array[index], *d2.Array[index]) {
				eqArray = false
				break
			}
		}
	}
	return eqType && eqString && eqInteger && eqNil && eqArrayLen && eqArray
}

func TestValidCommand(t *testing.T) {
	for input, cmd := range validCommand {
		reader := bytes.NewReader([]byte(input))
		c, err := ReadCommand(reader)
		if nil != err {
			t.Error("read command error", err)
		} else if c.Name() != cmd {
			t.Error("read command error", c.Name(), cmd)
		}
	}
}

func _validCommand(tb testing.TB) {
	for input, cmd := range validCommand {
		reader := bytes.NewReader([]byte(input))
		c, err := ReadCommand(reader)
		if nil != err {
			tb.Error("read command error", err)
		} else if c.Name() != cmd {
			tb.Error("read command error", c.Name(), cmd)
		}
	}

}

func BenchmarkValidCommand(b *testing.B) {
	for i:=0; i<b.N; i++ {
		_validCommand(b)
	}
}

func testCommandFormat(t *testing.T) {
	cmd, _ := NewCommand("LLEN", "walu.cc")
	if "*2\r\n$7\r\nwalu.cc\r\n" != string(cmd.Format()) {
		t.Error("cmd format error")
	}

}

func BenchmarkCommandFormat(b *testing.B) {
	cmd, _ := NewCommand("LLEN", "walu.cc")
	for i:=0; i< b.N; i++ {
		cmd.Format()
	}
}

func init() {
	validCommand = map[string]string{
		"PING" : "PING",
		"PING\n" : "PING",
		"PING\r" : "PING",
		"  PING ": "PING",
		"*2\r\n$4\r\nLLEN\r\n$6\r\nmysist\r\n" : "LLEN",
	}

	validData = map[string]Data {
		respSimpleStringText : respSimpleString,
		respErrorText : respError,
		respBulkStringText : respBulkString,
		respNilBulkStringText : respNilBulkString,
		respIntegerText : respInteger,
		respArrayText : respArray,
	}
}
<commit_msg>add benchmark case for Data.Format<commit_after>package resp

import (
	"bytes"
	"testing"
)

var (
	respSimpleString = Data{T:T_SimpleString, String:[]byte("OK")}
	respSimpleStringText = "+OK\r\n"

	respError = Data{T:T_Error, String:[]byte("Error message")}
	respErrorText = "-Error message\r\n"

	respBulkString = Data{T:T_BulkString, String:[]byte("foobar")}
	respBulkStringText = "$6\r\nfoobar\r\n"

	respNilBulkString = Data{T:T_BulkString, IsNil:true}
	respNilBulkStringText = "$-1\r\n"

	respInteger = Data{T:T_Integer, Integer:1000}
	respIntegerText = ":1000\r\n"

	respArray = Data{T:T_Array, Array:[]*Data{&respSimpleString, &respInteger}}
	respArrayText = "*2\r\n" + respSimpleStringText + respIntegerText
)

var validCommand map[string]string
var validData map[string]Data

func TestValidData(t *testing.T) {
	for text, data := range validData {
		buf := bytes.NewReader([]byte(text))
		//test read
		d, err := ReadData(buf)
		if nil!=err || d.T != data.T {
			t.Error(err)
		}

		if false == eqData(*d, data) {
			t.Error(text, *d, data)
		}

		//test format
		if text != string(data.Format()) {
			t.Error(text, data)
		}
	}
}

func BenchmarkDataFormat(b *testing.B) {
	for i:=0; i<b.N; i++ {
		for _, data := range validData {
			data.Format()
		}
	}
}

func eqData(d1, d2 Data) bool {
	eqType := d1.T == d2.T
	eqString := 0==bytes.Compare(d1.String, d2.String)
	eqInteger := d1.Integer == d2.Integer
	eqNil := d1.IsNil == d2.IsNil
	eqArrayLen := len(d1.Array) == len(d2.Array)
	eqArray := true
	if len(d1.Array) > 0 && eqArrayLen {
		for index := range d1.Array {
			if false == eqData(*d1.Array[index], *d2.Array[index]) {
				eqArray = false
				break
			}
		}
	}
	return eqType && eqString && eqInteger && eqNil && eqArrayLen && eqArray
}

func TestValidCommand(t *testing.T) {
	for input, cmd := range validCommand {
		reader := bytes.NewReader([]byte(input))
		c, err := ReadCommand(reader)
		if nil != err {
			t.Error("read command error", err)
		} else if c.Name() != cmd {
			t.Error("read command error", c.Name(), cmd)
		}
	}
}

func _validCommand(tb testing.TB) {
	for input, cmd := range validCommand {
		reader := bytes.NewReader([]byte(input))
		c, err := ReadCommand(reader)
		if nil != err {
			tb.Error("read command error", err)
		} else if c.Name() != cmd {
			tb.Error("read command error", c.Name(), cmd)
		}
	}

}

func BenchmarkValidCommand(b *testing.B) {
	for i:=0; i<b.N; i++ {
		_validCommand(b)
	}
}

func testCommandFormat(t *testing.T) {
	cmd, _ := NewCommand("LLEN", "walu.cc")
	if "*2\r\n$7\r\nwalu.cc\r\n" != string(cmd.Format()) {
		t.Error("cmd format error")
	}

}

func BenchmarkCommandFormat(b *testing.B) {
	cmd, _ := NewCommand("LLEN", "walu.cc")
	for i:=0; i< b.N; i++ {
		cmd.Format()
	}
}

func init() {
	validCommand = map[string]string{
		"PING" : "PING",
		"PING\n" : "PING",
		"PING\r" : "PING",
		"  PING ": "PING",
		"*2\r\n$4\r\nLLEN\r\n$6\r\nmysist\r\n" : "LLEN",
	}

	validData = map[string]Data {
		respSimpleStringText : respSimpleString,
		respErrorText : respError,
		respBulkStringText : respBulkString,
		respNilBulkStringText : respNilBulkString,
		respIntegerText : respInteger,
		respArrayText : respArray,
	}
}
<|endoftext|>


<commit_before>package sacloud

import "time"

// Instance type of instance
type Instance struct {
	Server Resource `json:",omitempty"`
	*EServerInstanceStatus
	StatusChangedAt   *time.Time `json:",omitempty"`
	MigrationProgress string     `json:",omitempty"`
	MigrationSchedule string     `json:",omitempty"`
	IsMigrating       bool       `json:",omitempty"`
	MigrationAllowed  string     `json:",omitempty"`
	ModifiedAt        *time.Time `json:",omitempty"`
	Host              struct {
		Name          string `json:",omitempty"`
		InfoURL       string `json:",omitempty"`
		Class         string `json:",omitempty"`
		Version       int    `json:",omitempty"`
		SystemVersion string `json:",omitempty"`
	} `json:",omitempty"`
	CDROM        *CDROM   `json:",omitempty"`
	CDROMStorage *Storage `json:",omitempty"`
}

// Storage type of Storage
type Storage struct {
	*Resource
	Class       string `json:",omitempty"`
	Name        string `json:",omitempty"`
	Description string `json:",omitempty"`
	Zone        *Zone  `json:",omitempty"`
	DiskPlan    struct {
		*NumberResource
		StorageClass string `json:",omitempty"`
		Name         string `json:",omitempty"`
	} `json:",omitempty"`
	//Capacity []string `json:",omitempty"`
}
<commit_msg>ResourceID type changed<commit_after>package sacloud

import "time"

// Instance type of instance
type Instance struct {
	Server Resource `json:",omitempty"`
	*EServerInstanceStatus
	StatusChangedAt   *time.Time `json:",omitempty"`
	MigrationProgress string     `json:",omitempty"`
	MigrationSchedule string     `json:",omitempty"`
	IsMigrating       bool       `json:",omitempty"`
	MigrationAllowed  string     `json:",omitempty"`
	ModifiedAt        *time.Time `json:",omitempty"`
	Host              struct {
		Name          string `json:",omitempty"`
		InfoURL       string `json:",omitempty"`
		Class         string `json:",omitempty"`
		Version       int    `json:",omitempty"`
		SystemVersion string `json:",omitempty"`
	} `json:",omitempty"`
	CDROM        *CDROM   `json:",omitempty"`
	CDROMStorage *Storage `json:",omitempty"`
}

// Storage type of Storage
type Storage struct {
	*NumberResource
	Class       string `json:",omitempty"`
	Name        string `json:",omitempty"`
	Description string `json:",omitempty"`
	Zone        *Zone  `json:",omitempty"`
	DiskPlan    struct {
		*NumberResource
		StorageClass string `json:",omitempty"`
		Name         string `json:",omitempty"`
	} `json:",omitempty"`
	//Capacity []string `json:",omitempty"`
}
<|endoftext|>


<commit_before>package perceptron
<commit_msg>"Perceptron" is a "Learner", which has a method called "Learn".<commit_after>package perceptron

type Perceptron struct {
	iteration int
}

func New(iteration byte) *Perceptron {
	p := &Perceptron{
		iteration: int(iteration),
	}

	return p
}

func (p *Perceptron) Learn(model Model, iter InstanceIter) error {
	// TODO: Implement this.
	return nil
}

type Learner interface {
	Learn(model Model, iter InstanceIter) error
}

type Model interface {
}

type Instance interface {
}

type InstanceIter interface {
}
<|endoftext|>


<commit_before>package charon

import (
	"bytes"
	"fmt"
)

const (
	UserCanCreate      Permission = "charon:user:can create"
	UserCanCreateStaff Permission = "charon:user:can create staff"

	UserCanDeleteAsStranger      Permission = "charon:user:can delete as stranger"
	UserCanDeleteAsOwner         Permission = "charon:user:can delete as owner"
	UserCanDeleteStaffAsStranger Permission = "charon:user:can delete staff as stranger"
	UserCanDeleteStaffAsOwner    Permission = "charon:user:can delete staff as owner"

	UserCanModifyAsStranger      Permission = "charon:user:can modify as stranger"
	UserCanModifyAsOwner         Permission = "charon:user:can modify as owner"
	UserCanModifyStaffAsStranger Permission = "charon:user:can modify staff as stranger"
	UserCanModifyStaffAsOwner    Permission = "charon:user:can modify staff as owner"

	UserCanRetrieveAsOwner         Permission = "charon:user:can retrieve as owner"
	UserCanRetrieveAsStranger      Permission = "charon:user:can retrieve as stranger"
	UserCanRetrieveStaffAsOwner    Permission = "charon:user:can retrieve staff as owner"
	UserCanRetrieveStaffAsStranger Permission = "charon:user:can retrieve staff as stranger"

	UserPermissionCanCreate   Permission = "charon:user_permission:can create"
	UserPermissionCanDelete   Permission = "charon:user_permission:can delete"
	UserPermissionCanModify   Permission = "charon:user_permission:can modify"
	UserPermissionCanRetrieve Permission = "charon:user_permission:can retrieve"

	UserGroupCanCheckBelongingAsStranger Permission = "charon:user_group:can check belonging as a stranger"
	UserGroupCanCheckGrantingAsStranger  Permission = "charon:user_group:can check granting as a stranger"

	PermissionCanCreate   Permission = "charon:permission:can create"
	PermissionCanDelete   Permission = "charon:permission:can delete"
	PermissionCanModify   Permission = "charon:permission:can modify"
	PermissionCanRetrieve Permission = "charon:permission:can retrieve"

	GroupCanCreate   Permission = "charon:group:can create"
	GroupCanDelete   Permission = "charon:group:can delete"
	GroupCanModify   Permission = "charon:group:can modify"
	GroupCanRetrieve Permission = "charon:group:can retrieve"

	GroupPermissionCanCreate   Permission = "charon:group_permission:can create"
	GroupPermissionCanDelete   Permission = "charon:group_permission:can delete"
	GroupPermissionCanModify   Permission = "charon:group_permission:can modify"
	GroupPermissionCanRetrieve Permission = "charon:group_permission:can retrieve"
)

var (
	// EmptyPermission is a shorthand
	EmptyPermission = Permission("")
	// AllPermissions ...
	AllPermissions = Permissions{
		UserCanCreate,
		UserCanCreateStaff,
		UserCanDeleteAsStranger,
		UserCanDeleteAsOwner,
		UserCanDeleteStaffAsStranger,
		UserCanDeleteStaffAsOwner,
		UserCanModifyAsStranger,
		UserCanModifyAsOwner,
		UserCanModifyStaffAsStranger,
		UserCanModifyStaffAsOwner,
		UserCanRetrieveAsOwner,
		UserCanRetrieveAsStranger,
		UserCanRetrieveStaffAsOwner,
		UserCanRetrieveStaffAsStranger,
		UserPermissionCanCreate,
		UserPermissionCanDelete,
		UserPermissionCanModify,
		UserPermissionCanRetrieve,
		PermissionCanCreate,
		PermissionCanDelete,
		PermissionCanModify,
		PermissionCanRetrieve,
		GroupCanCreate,
		GroupCanDelete,
		GroupCanModify,
		GroupCanRetrieve,
		GroupPermissionCanCreate,
		GroupPermissionCanDelete,
		GroupPermissionCanModify,
		GroupPermissionCanRetrieve,
	}
)

// Permission is a string that consist of subsystem, module/content type and an action.
type Permission string

// NewPermission allocate new Permission object using given string.
func NewPermission(s string) Permission {
	return Permission(s)
}

// String implements fmt.Stringer interface.
func (p Permission) String() string {
	return string(p)
}

// Split returns subsystem, module/content ty and action that describes single Permission.
func (p Permission) Split() (string, string, string) {
	if p == "" {
		return "", "", ""
	}

	parts := bytes.Split([]byte(p), []byte(":"))

	switch len(parts) {
	case 1:
		return "", "", string(parts[0])
	case 2:
		return "", string(parts[0]), string(parts[1])
	default:
		return string(parts[0]), string(parts[1]), string(parts[2])
	}
}

// Subsystem is a handy wrapper for Split method, that just returns sybsystem.
func (p Permission) Subsystem() (subsystem string) {
	subsystem, _, _ = p.Split()

	return
}

// Permission implements Permission interface.
func (p Permission) Permission() string {
	return string(p)
}

// MarshalJSON implements json.Marshaller interface.
func (p Permission) MarshalJSON() ([]byte, error) {
	return []byte(p), nil
}

// UnmarshalJSON implements json.Unmarshaler interface.
func (p *Permission) UnmarshalJSON(src interface{}) error {
	switch s := src.(type) {
	case string:
		*p = Permission(s)
	case []byte:
		*p = Permission(s)
	default:
		return fmt.Errorf("charon: permission expects string or slice of bytes, got %T", src)
	}

	return nil
}

type Permissions []Permission

// NewPermissions allocates new Permissions using given slice of strings.
// It maps each string in a slice into Permission.
func NewPermissions(ss ...string) Permissions {
	ps := make(Permissions, 0, len(ss))
	for _, s := range ss {
		ps = append(ps, Permission(s))
	}

	return ps
}

// Contains returns true if given Permission exists in the collection.
func (p Permissions) Contains(permission Permission) bool {
	for _, perm := range p {
		if perm == permission {
			return true
		}
	}

	return false
}

// Strings maps Permissions into slice of strings.
func (p Permissions) Strings() (strs []string) {
	strs = make([]string, 0, len(p))
	for _, pp := range p {
		strs = append(strs, pp.String())
	}

	return strs
}
<commit_msg>user group permissions + small fix<commit_after>package charon

import (
	"bytes"
	"fmt"
)

const (
	UserCanCreate      Permission = "charon:user:can create"
	UserCanCreateStaff Permission = "charon:user:can create staff"

	UserCanDeleteAsStranger      Permission = "charon:user:can delete as stranger"
	UserCanDeleteAsOwner         Permission = "charon:user:can delete as owner"
	UserCanDeleteStaffAsStranger Permission = "charon:user:can delete staff as stranger"
	UserCanDeleteStaffAsOwner    Permission = "charon:user:can delete staff as owner"

	UserCanModifyAsStranger      Permission = "charon:user:can modify as stranger"
	UserCanModifyAsOwner         Permission = "charon:user:can modify as owner"
	UserCanModifyStaffAsStranger Permission = "charon:user:can modify staff as stranger"
	UserCanModifyStaffAsOwner    Permission = "charon:user:can modify staff as owner"

	UserCanRetrieveAsOwner         Permission = "charon:user:can retrieve as owner"
	UserCanRetrieveAsStranger      Permission = "charon:user:can retrieve as stranger"
	UserCanRetrieveStaffAsOwner    Permission = "charon:user:can retrieve staff as owner"
	UserCanRetrieveStaffAsStranger Permission = "charon:user:can retrieve staff as stranger"

	UserPermissionCanCreate                  Permission = "charon:user_permission:can create"
	UserPermissionCanDelete                  Permission = "charon:user_permission:can delete"
	UserPermissionCanModify                  Permission = "charon:user_permission:can modify"
	UserPermissionCanRetrieve                Permission = "charon:user_permission:can retrieve"
	UserPermissionCanCheckGrantingAsStranger Permission = "charon:user_permission:can check granting as a stranger"

	UserGroupCanCreate                   Permission = "charon:user_group:can create"
	UserGroupCanDelete                   Permission = "charon:user_group:can delete"
	UserGroupCanModify                   Permission = "charon:user_group:can modify"
	UserGroupCanRetrieve                 Permission = "charon:user_group:can retrieve"
	UserGroupCanCheckBelongingAsStranger Permission = "charon:user_group:can check belonging as a stranger"

	PermissionCanCreate   Permission = "charon:permission:can create"
	PermissionCanDelete   Permission = "charon:permission:can delete"
	PermissionCanModify   Permission = "charon:permission:can modify"
	PermissionCanRetrieve Permission = "charon:permission:can retrieve"

	GroupCanCreate   Permission = "charon:group:can create"
	GroupCanDelete   Permission = "charon:group:can delete"
	GroupCanModify   Permission = "charon:group:can modify"
	GroupCanRetrieve Permission = "charon:group:can retrieve"

	GroupPermissionCanCreate   Permission = "charon:group_permission:can create"
	GroupPermissionCanDelete   Permission = "charon:group_permission:can delete"
	GroupPermissionCanModify   Permission = "charon:group_permission:can modify"
	GroupPermissionCanRetrieve Permission = "charon:group_permission:can retrieve"
)

var (
	// EmptyPermission is a shorthand
	EmptyPermission = Permission("")
	// AllPermissions ...
	AllPermissions = Permissions{
		UserCanCreate,
		UserCanCreateStaff,
		UserCanDeleteAsStranger,
		UserCanDeleteAsOwner,
		UserCanDeleteStaffAsStranger,
		UserCanDeleteStaffAsOwner,
		UserCanModifyAsStranger,
		UserCanModifyAsOwner,
		UserCanModifyStaffAsStranger,
		UserCanModifyStaffAsOwner,
		UserCanRetrieveAsOwner,
		UserCanRetrieveAsStranger,
		UserCanRetrieveStaffAsOwner,
		UserCanRetrieveStaffAsStranger,
		UserPermissionCanCreate,
		UserPermissionCanDelete,
		UserPermissionCanModify,
		UserPermissionCanRetrieve,
		PermissionCanCreate,
		PermissionCanDelete,
		PermissionCanModify,
		PermissionCanRetrieve,
		GroupCanCreate,
		GroupCanDelete,
		GroupCanModify,
		GroupCanRetrieve,
		GroupPermissionCanCreate,
		GroupPermissionCanDelete,
		GroupPermissionCanModify,
		GroupPermissionCanRetrieve,
	}
)

// Permission is a string that consist of subsystem, module/content type and an action.
type Permission string

// NewPermission allocate new Permission object using given string.
func NewPermission(s string) Permission {
	return Permission(s)
}

// String implements fmt.Stringer interface.
func (p Permission) String() string {
	return string(p)
}

// Split returns subsystem, module/content ty and action that describes single Permission.
func (p Permission) Split() (string, string, string) {
	if p == "" {
		return "", "", ""
	}

	parts := bytes.Split([]byte(p), []byte(":"))

	switch len(parts) {
	case 1:
		return "", "", string(parts[0])
	case 2:
		return "", string(parts[0]), string(parts[1])
	default:
		return string(parts[0]), string(parts[1]), string(parts[2])
	}
}

// Subsystem is a handy wrapper for Split method, that just returns sybsystem.
func (p Permission) Subsystem() (subsystem string) {
	subsystem, _, _ = p.Split()

	return
}

// Permission implements Permission interface.
func (p Permission) Permission() string {
	return string(p)
}

// MarshalJSON implements json.Marshaller interface.
func (p Permission) MarshalJSON() ([]byte, error) {
	return []byte(p), nil
}

// UnmarshalJSON implements json.Unmarshaler interface.
func (p *Permission) UnmarshalJSON(src interface{}) error {
	switch s := src.(type) {
	case string:
		*p = Permission(s)
	case []byte:
		*p = Permission(s)
	default:
		return fmt.Errorf("charon: permission expects string or slice of bytes, got %T", src)
	}

	return nil
}

type Permissions []Permission

// NewPermissions allocates new Permissions using given slice of strings.
// It maps each string in a slice into Permission.
func NewPermissions(ss ...string) Permissions {
	ps := make(Permissions, 0, len(ss))
	for _, s := range ss {
		ps = append(ps, Permission(s))
	}

	return ps
}

// Contains returns true if given Permission exists in the collection.
func (p Permissions) Contains(permission Permission) bool {
	for _, perm := range p {
		if perm == permission {
			return true
		}
	}

	return false
}

// Strings maps Permissions into slice of strings.
func (p Permissions) Strings() (strs []string) {
	strs = make([]string, 0, len(p))
	for _, pp := range p {
		strs = append(strs, pp.String())
	}

	return strs
}
<|endoftext|>