<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 lib

import (
	"github.com/webx-top/blog/app/base"
)

var (
	Name          = `admin`
	App           = base.Server.NewApp(Name, base.SessionMW, base.Xsrf.Middleware() /*, base.Jwt.Validate()*/)
	FuncMap       = base.Server.DefaultFuncMap()
	StaticPath    = `/assets`
	StaticAbsPath string
	ThemeAbsPath  string
)

func init() {
	App.InitRenderer(base.Config.BackendTemplate.Theme, base.Config.BackendTemplate.Engine, FuncMap)
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 lib

import (
	"github.com/webx-top/blog/app/base"
)

var (
	Name    = `admin`
	App     = base.Server.NewApp(Name, base.SessionMW, base.Xsrf.Middleware() /*, base.Jwt.Validate()*/)
	FuncMap = base.Server.DefaultFuncMap()
)

func init() {
	App.InitRenderer(base.Config.BackendTemplate.Theme, base.Config.BackendTemplate.Engine, FuncMap)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	mm "github.com/mattermost/platform/model"
	"time"
)

/*
main
Usage: go run main.go -u <username> -p <password> <server-url> [team-name]
Authenticates your login information, then gives you your AuthToken.
If the team name is unentered or invalid main shows valid team names.
*/
func main() {
	//Adds a  little clarity to the display
	fmt.Println("---------------------------------------------------------")
	defer fmt.Println("---------------------------------------------------------")
	//Sets up login
	username := flag.String("u", "", "Username")
	password := flag.String("p", "", "Password")
	flag.Parse()
	url := flag.Arg(0)
	teamName := flag.Arg(1)
	client := mm.NewClient(url)
	_, err := client.Login(*username, *password)
	if err != nil {
		fmt.Println(err)
		return
	}
	//Gathers all availible teams in a map,
	teamListResult, teamListAppError := client.GetAllTeamListings()
	teamMap := teamListResult.Data.(map[string]*mm.Team)
	if teamListAppError != nil {
		fmt.Println(teamListAppError)
		return
	}
	//Validates input team name
	teamObjMap, teamError := client.GetTeamByName(teamName)
	if teamError != nil {
		fmt.Println(teamError)
		return
	}
	//Creates team map that can be accessed without string key, then assigns team ID
	localTeamSlice := make([]*mm.Team, len(teamMap))
	i := 0
	for _, value := range teamMap {
		localTeamSlice[i] = value
		i++
	}
	client.SetTeamId(localTeamSlice[0].Id)
	//Gather map of channels availible
	channelResult, channelErr := client.GetChannels(teamObjMap.Etag)
	if channelErr != nil {
		fmt.Println("Channel Error")
		fmt.Println(channelErr)
		return
	}
	//List availible channels (direct messages appear as address string, still in progress)
	channelMap := channelResult.Data.(*mm.ChannelList)
	channelSlice := make([]*mm.Channel, len(*channelMap))
	fmt.Println("Channels:")
	index := 0
	for _, channel := range *channelMap {
		fmt.Print("\t", index, ": ")
		channelSlice[index] = channel
		fmt.Print(channelSlice[index].DisplayName)
		if channelSlice[index].Id == "d5gpjz3k3fyd7fhzqrafrxg6zr" {
			fmt.Print("*")
		}
		index++
		fmt.Println()
	}
	//Add a little clarity
	fmt.Println("---------------------------------------------------------")
	//TownSquare Channel ID: "d5gpjz3k3fyd7fhzqrafrxg6zr"
	//Gets mm.PostList since begining of time (?)
	postSinceDateResult, postsErr := client.GetPostsSince("d5gpjz3k3fyd7fhzqrafrxg6zr", 0)
	if postsErr != nil {
		fmt.Println(postsErr)
	}
	//Extracts PostList Object
	postSinceDate := postSinceDateResult.Data.(*mm.PostList)
	//parses of 4 most recent messages in selected Channel
	for i := 0; i < 4; i++ {
		// PostList.Order contains keys to the order of the posts. The most recent post gets stored at position 0
		postKey := postSinceDate.Order[4-i]
		post := postSinceDate.Posts[postKey]
		//Gets\Extracts username of each post.
		userResult, userErr := client.GetUser(post.UserId, client.Etag)
		if userErr != nil {
			fmt.Println(userErr)
		}
		//Prints username and message.
		user := userResult.Data.(*mm.User)
		fmt.Println(user.Username, time.Unix(post.UpdateAt, 0))
		fmt.Println("\t", post.Message, "\n")
	}
}
<commit_msg>we're working on it...<commit_after>package main

import (
	"flag"
	"fmt"
	mm "github.com/mattermost/platform/model"
	"time"
)

/*
main
Usage: go run main.go -u <username> -p <password> <server-url> [team-name]
Authenticates your login information, then gives you your AuthToken.
If the team name is unentered or invalid main shows valid team names.
*/
func main() {
	//Adds a  little clarity to the display
	fmt.Println("---------------------------------------------------------")
	defer fmt.Println("---------------------------------------------------------")
	//Sets up login
	username := flag.String("u", "", "Username")
	password := flag.String("p", "", "Password")
	flag.Parse()
	url := flag.Arg(0)
	teamName := flag.Arg(1)
	channelId := "d5gpjz3k3fyd7fhzqrafrxg6zr"
	userId := "pa7s3o674ib7bnp3bmdm58saca"
	client := mm.NewClient(url)
	_, err := client.Login(*username, *password)
	if err != nil {
		fmt.Println(err)
		return
	}
	//Gathers all availible teams in a map,
	teamListResult, teamListAppError := client.GetAllTeamListings()
	teamMap := teamListResult.Data.(map[string]*mm.Team)
	if teamListAppError != nil {
		fmt.Println(teamListAppError)
		return
	}
	//Validates input team name
	teamObjMap, teamError := client.GetTeamByName(teamName)
	if teamError != nil {
		fmt.Println(teamError)
		return
	}
	//Creates team map that can be accessed without string key, then assigns team ID
	localTeamSlice := make([]*mm.Team, len(teamMap))
	i := 0
	for _, value := range teamMap {
		localTeamSlice[i] = value
		i++
	}
	client.SetTeamId(localTeamSlice[0].Id)
	//Gather map of channels availible
	channelResult, channelErr := client.GetChannels(teamObjMap.Etag)
	if channelErr != nil {
		fmt.Println("Channel Error")
		fmt.Println(channelErr)
		return
	}
	//List availible channels (direct messages appear as address string, still in progress)
	channelMap := channelResult.Data.(*mm.ChannelList)
	channelSlice := make([]*mm.Channel, len(*channelMap))
	fmt.Println("Channels:")
	index := 0
	for _, channel := range *channelMap {
		fmt.Print("\t", index, ": ")
		channelSlice[index] = channel
		fmt.Print(channelSlice[index].DisplayName)
		if channelSlice[index].Id == channelId {
			fmt.Print("*")
		}
		index++
		fmt.Println()
	}
	//Add a little clarity
	fmt.Println("---------------------------------------------------------")
	postListResult, err := client.GetPosts(channelId, 0, 0, client.Etag)
	if err != nil {
		fmt.Println(err)
	}
	postList := postListResult.Data.(*mm.PostList)
	newPost := makePost(client, channelId, "Testing, please ignore.", userId)
	postList.AddPost(&newPost)
	printLastFourPosts( client, channelId)

}

func printLastFourPosts(client *mm.Client, channelId string) {
	//TownSquare Channel ID: "d5gpjz3k3fyd7fhzqrafrxg6zr"
	//Gets mm.PostList since begining of time (?)
	postSinceDateResult, postsErr := client.GetPostsSince(channelId, 0)
	if postsErr != nil {
		fmt.Println(postsErr)
	}
	//Extracts PostList Object
	postSinceDate := postSinceDateResult.Data.(*mm.PostList)
	//Parses of 4 most recent messages in selected Channel
	for i := 0; i < 4; i++ {
		// PostList.Order contains keys to the order of the posts. The most recent post gets stored at position 0
		postKey := postSinceDate.Order[i]
		post := postSinceDate.Posts[postKey]
		//Gets\Extracts username of each post.
		userResult, userErr := client.GetUser(post.UserId, client.Etag)
		if userErr != nil {
			fmt.Println(userErr)
		}
		//Prints username and message.
		user := userResult.Data.(*mm.User)
		fmt.Println(user.Username, user.Id, time.Unix(post.UpdateAt, 0))
		fmt.Println("\t", post.Message)
	}
}

func makePost(client *mm.Client, channelId string, message string, userId string) mm.Post {
	userResult, err := client.GetUser(userId, client.Etag)
	if err != nil {
		fmt.Println(err)
	}
	timeNow := new(time.Time)
	user := userResult.Data.(*mm.User)
	post := mm.Post{ChannelId: channelId, UserId: user.Id, Message: message, IsPinned: false, CreateAt: timeNow.Unix()}
	post.MakeNonNil()
	post.PreSave()
	err = post.IsValid()
	if err != nil {
		fmt.Println(err)
	}
	json := post.ToJson()
	fmt.Println("json return: ", json, "\n")

	return post

}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	dc "github.com/fsouza/go-dockerclient"
	"github.com/labstack/echo"
	mw "github.com/labstack/echo/middleware"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
)

type (
	// Template provides HTML template rendering
	Template struct {
		templates *template.Template
	}

	// user struct {
	// 	ID   string `json:"id"`
	// 	Name string `json:"name"`
	// }
)

// Template provides HTML template rendering
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

// Handler
func createDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment POST\n")
}

func getDeployment(c *echo.Context) error {

	// Init the client
	path := os.Getenv("DOCKER_CERT_PATH")
	ca := fmt.Sprintf("%s/ca.pem", path)
	cert := fmt.Sprintf("%s/cert.pem", path)
	key := fmt.Sprintf("%s/key.pem", path)

	docker, _ := dc.NewTLSClient(os.Getenv("DOCKER_HOST"), cert, key, ca)

	// Get only running containers
	containers, err := docker.ListContainers(dc.ListContainersOptions{All: false})
	if err != nil {
		log.Fatal(err)
	}

	return c.JSON(http.StatusOK, containers)
}

func updateDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment PATCH\n")
}

func deleteDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment DELETE\n")
}

func main() {
	// Echo instance
	e := echo.New()

	// Debug mode
	e.SetDebug(true)

	// Middleware
	e.Use(mw.Logger())
	e.Use(mw.Recover())

	// Routes
	e.Index("public/index.html")

	// Deployment Routes
	e.Post("/v1/deployments", createDeployment)
	e.Get("/v1/deployments", getDeployment)
	e.Get("/v1/deployments/:id", getDeployment)
	e.Patch("/v1/deployments/:id", updateDeployment)
	e.Delete("/v1/deployments/:id", deleteDeployment)

	// Start server
	e.Run(":1323")
}
<commit_msg>Add checks for required environment vars.<commit_after>package main

import (
	"fmt"
	dc "github.com/fsouza/go-dockerclient"
	"github.com/labstack/echo"
	mw "github.com/labstack/echo/middleware"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

type (
	// Template provides HTML template rendering
	Template struct {
		templates *template.Template
	}

	// user struct {
	// 	ID   string `json:"id"`
	// 	Name string `json:"name"`
	// }
)

// Template provides HTML template rendering
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

// Handler
func createDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment POST\n")
}

func getDeployment(c *echo.Context) error {

	// Init the client
	path := os.Getenv("DOCKER_CERT_PATH")
	ca := fmt.Sprintf("%s/ca.pem", path)
	cert := fmt.Sprintf("%s/cert.pem", path)
	key := fmt.Sprintf("%s/key.pem", path)

	docker, _ := dc.NewTLSClient(os.Getenv("DOCKER_HOST"), cert, key, ca)

	// Get only running containers
	containers, err := docker.ListContainers(dc.ListContainersOptions{All: false})
	if err != nil {
		log.Fatal(err)
	}

	return c.JSON(http.StatusOK, containers)
}

func updateDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment PATCH\n")
}

func deleteDeployment(c *echo.Context) error {
	return c.String(http.StatusOK, "Deployment DELETE\n")
}

func main() {

	// Check for required variables
	docker_host := os.Getenv("DOCKER_HOST")
	docker_cert_path := os.Getenv("DOCKER_CERT_PATH")

	if len(strings.TrimSpace(docker_host)) == 0 {
	  panic("Please set DOCKER_HOST!")
	}

	if len(strings.TrimSpace(docker_cert_path)) == 0 {
		panic("Please set DOCKER_CERT_PATH")
	}

	// Echo instance
	e := echo.New()

	// Debug mode
	e.SetDebug(true)

	// Middleware
	e.Use(mw.Logger())
	e.Use(mw.Recover())

	// Routes
	e.Index("public/index.html")

	// Deployment Routes
	e.Post("/v1/deployments", createDeployment)
	e.Get("/v1/deployments", getDeployment)
	e.Get("/v1/deployments/:id", getDeployment)
	e.Patch("/v1/deployments/:id", updateDeployment)
	e.Delete("/v1/deployments/:id", deleteDeployment)

	// Start server
	e.Run(":1323")
}
<|endoftext|>


<commit_before>package k8s_test

import (
	"time"

	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"

	. "github.com/concourse/concourse/topgun"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Worker lifecycle", func() {

	var (
		proxySession *gexec.Session
		atcEndpoint  string
		gracePeriod  string
	)

	JustBeforeEach(func() {
		setReleaseNameAndNamespace("wl")

		deployConcourseChart(releaseName,
			`--set=worker.replicas=1`,
			`--set=persistence.enabled=false`,
			`--set=worker.terminationGracePeriodSeconds=`+gracePeriod,
		)

		waitAllPodsInNamespaceToBeReady(namespace)

		By("Creating the web proxy")
		proxySession, atcEndpoint = startPortForwarding(
			namespace, "service/"+releaseName+"-web", "8080",
		)

		By("Logging in")
		fly.Login("test", "test", atcEndpoint)

		By("waiting for a running worker")
		Eventually(func() []Worker {
			return getRunningWorkers(fly.GetWorkers())
		}, 2*time.Minute, 10*time.Second).
			ShouldNot(HaveLen(0))

		fly.Run("set-pipeline", "-n",
			"-c", "../pipelines/task-waiting.yml",
			"-p", "some-pipeline",
		)

		fly.Run("unpause-pipeline", "-p", "some-pipeline")
		fly.Run("trigger-job", "-j", "some-pipeline/simple-job")

		By("waiting container to be created")
		Eventually(func() bool {
			containers := fly.GetContainers()

			for _, container := range containers {
				if container.Type == "task" && container.State == "created" {
					return true
				}
			}

			return false
		}, 2*time.Minute, 10*time.Second).
			Should(BeTrue())

		Run(nil, "kubectl", "scale", "--namespace", namespace,
			"statefulset", releaseName+"-worker", "--replicas=0",
		)
	})

	AfterEach(func() {
		cleanup(releaseName, namespace, proxySession)
	})

	Context("terminating the worker", func() {

		Context("gracefully", func() {
			BeforeEach(func() {
				gracePeriod = "600"
			})

			It("finishes tasks gracefully with termination", func() {
				By("seeing that the worker state is retiring")
				Eventually(func() string {
					workers := fly.GetWorkers()
					Expect(workers).To(HaveLen(1))
					return workers[0].State
				}, 10*time.Second, 2*time.Second).
					Should(Equal("retiring"))

				By("letting the task finish")
				fly.Run("hijack", "--verbose", "-j", "some-pipeline/simple-job",
					"--", "/bin/sh", "-ce",
					`touch /tmp/stop-waiting`,
				)

				By("seeing that there are no workers")
				Eventually(func() []Worker {
					return getRunningWorkers(fly.GetWorkers())
				}, 1*time.Minute, 1*time.Second).
					Should(HaveLen(0))

				By("seeing that the build succeeded")
				Eventually(func() *gbytes.Buffer {
					startSession := fly.Start("builds", "-j", "some-pipeline/simple-job")
					<-startSession.Exited
					return startSession.Out
				}, 1*time.Minute, 5*time.Second).
					Should(gbytes.Say("succeeded"))
			})
		})

		Context("ungracefully", func() {
			BeforeEach(func() {
				gracePeriod = "1"
			})

			It("interrupts the task execution", func() {
				By("seeing that there are no workers")

				Eventually(func() []Worker {
					return getRunningWorkers(fly.GetWorkers())
				}, 1*time.Minute, 1*time.Second).
					Should(HaveLen(0))

				By("seeing that the worker disappeared")
				startSession := fly.Start("watch", "-j", "some-pipeline/simple-job")
				<-startSession.Exited
				Expect(startSession.Out).To(gbytes.Say("disappeared"))
			})
		})
	})
})
<commit_msg>k8s/topgun/wl - more succint wait for success, wait for error when ungraceful<commit_after>package k8s_test

import (
	"time"

	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"

	. "github.com/concourse/concourse/topgun"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Worker lifecycle", func() {

	var (
		proxySession *gexec.Session
		atcEndpoint  string
		gracePeriod  string
	)

	JustBeforeEach(func() {
		setReleaseNameAndNamespace("wl")

		deployConcourseChart(releaseName,
			`--set=worker.replicas=1`,
			`--set=persistence.enabled=false`,
			`--set=worker.terminationGracePeriodSeconds=`+gracePeriod,
		)

		waitAllPodsInNamespaceToBeReady(namespace)

		By("Creating the web proxy")
		proxySession, atcEndpoint = startPortForwarding(
			namespace, "service/"+releaseName+"-web", "8080",
		)

		By("Logging in")
		fly.Login("test", "test", atcEndpoint)

		By("waiting for a running worker")
		Eventually(func() []Worker {
			return getRunningWorkers(fly.GetWorkers())
		}, 2*time.Minute, 10*time.Second).
			ShouldNot(HaveLen(0))

		fly.Run("set-pipeline", "-n",
			"-c", "../pipelines/task-waiting.yml",
			"-p", "some-pipeline",
		)

		fly.Run("unpause-pipeline", "-p", "some-pipeline")
		fly.Run("trigger-job", "-j", "some-pipeline/simple-job")

		By("waiting container to be created")
		Eventually(func() bool {
			containers := fly.GetContainers()

			for _, container := range containers {
				if container.Type == "task" && container.State == "created" {
					return true
				}
			}

			return false
		}, 2*time.Minute, 10*time.Second).
			Should(BeTrue())

		Run(nil, "kubectl", "scale", "--namespace", namespace,
			"statefulset", releaseName+"-worker", "--replicas=0",
		)
	})

	AfterEach(func() {
		cleanup(releaseName, namespace, proxySession)
	})

	Context("terminating the worker", func() {

		Context("gracefully", func() {
			BeforeEach(func() {
				gracePeriod = "600"
			})

			It("finishes tasks gracefully with termination", func() {
				By("seeing that the worker state is retiring")
				Eventually(func() string {
					workers := fly.GetWorkers()
					Expect(workers).To(HaveLen(1))
					return workers[0].State
				}, 10*time.Second, 2*time.Second).
					Should(Equal("retiring"))

				By("letting the task finish")
				fly.Run("hijack", "--verbose", "-j", "some-pipeline/simple-job",
					"--", "/bin/sh", "-ce",
					`touch /tmp/stop-waiting`,
				)

				By("seeing that there are no workers")
				Eventually(func() []Worker {
					return getRunningWorkers(fly.GetWorkers())
				}, 1*time.Minute, 1*time.Second).
					Should(HaveLen(0))

				By("seeing that the build succeeded")
				fly.Run("watch", "-j", "some-pipeline/simple-job")
			})
		})

		Context("ungracefully", func() {
			BeforeEach(func() {
				gracePeriod = "1"
			})

			It("interrupts the task execution", func() {
				By("seeing that there are no workers")

				Eventually(func() []Worker {
					return getRunningWorkers(fly.GetWorkers())
				}, 1*time.Minute, 1*time.Second).
					Should(HaveLen(0))

				By("seeing that the worker disappeared")
				startSession := fly.Start("watch", "-j", "some-pipeline/simple-job")
				<-startSession.Exited
				Expect(startSession.Out).To(gbytes.Say("errored"))
			})
		})
	})
})
<|endoftext|>


<commit_before>package interfaces

type RequestInterface interface {
	GetRepository() RepositoryInterface
}

type RepositoryInterface interface {
	GetName() string
}
<commit_msg>Add interface for user<commit_after>package interfaces

type RequestInterface interface {
	GetRepository() RepositoryInterface
	GetUser() (UserInterface, error)
}

type RepositoryInterface interface {
	GetName() string
}
type UserInterface interface {
	GetUsername() string
	GetName() string
	GetAvatarURL() string
}
<|endoftext|>


<commit_before>package handler

import (
	"context"
	"fmt"
	"os"
	"strconv"
	"strings"

	log "github.com/sirupsen/logrus"

	gitalyauth "gitlab.com/gitlab-org/gitaly/auth"
	"gitlab.com/gitlab-org/gitaly/client"
	pb "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb"
	"gitlab.com/gitlab-org/gitlab-shell/internal/config"
	"gitlab.com/gitlab-org/gitlab-shell/internal/executable"
	"gitlab.com/gitlab-org/gitlab-shell/internal/gitlabnet/accessverifier"
	"gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
	"gitlab.com/gitlab-org/labkit/correlation"
	grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc"
	"gitlab.com/gitlab-org/labkit/tracing"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

// GitalyHandlerFunc implementations are responsible for making
// an appropriate Gitaly call using the provided client and context
// and returning an error from the Gitaly call.
type GitalyHandlerFunc func(ctx context.Context, client *grpc.ClientConn) (int32, error)

type GitalyConn struct {
	ctx   context.Context
	conn  *grpc.ClientConn
	close func()
}

type GitalyCommand struct {
	Config      *config.Config
	ServiceName string
	Address     string
	Token       string
	Features    map[string]string
}

// RunGitalyCommand provides a bootstrap for Gitaly commands executed
// through GitLab-Shell. It ensures that logging, tracing and other
// common concerns are configured before executing the `handler`.
func (gc *GitalyCommand) RunGitalyCommand(handler GitalyHandlerFunc) error {
	gitalyConn, err := getConn(gc)

	if err != nil {
		return err
	}

	_, err = handler(gitalyConn.ctx, gitalyConn.conn)

	gitalyConn.close()

	return err
}

// PrepareContext wraps a given context with a correlation ID and logs the command to
// be run.
func (gc *GitalyCommand) PrepareContext(ctx context.Context, repository *pb.Repository, response *accessverifier.Response, env sshenv.Env) (context.Context, context.CancelFunc) {
	ctx, cancel := context.WithCancel(ctx)

	gc.LogExecution(repository, response, env)

	if response.CorrelationID != "" {
		ctx = correlation.ContextWithCorrelation(ctx, response.CorrelationID)
	}

	md, ok := metadata.FromOutgoingContext(ctx)
	if !ok {
		md = metadata.New(nil)
	}
	md.Append("key_id", strconv.Itoa(response.KeyId))
	md.Append("key_type", response.KeyType)
	md.Append("user_id", response.UserId)
	md.Append("username", response.Username)
	md.Append("remote_ip", env.RemoteAddr)
	ctx = metadata.NewOutgoingContext(ctx, md)

	return ctx, cancel
}

func (gc *GitalyCommand) LogExecution(repository *pb.Repository, response *accessverifier.Response, env sshenv.Env) {
	fields := log.Fields{
		"command":         gc.ServiceName,
		"correlation_id":  response.CorrelationID,
		"gl_project_path": repository.GlProjectPath,
		"gl_repository":   repository.GlRepository,
		"user_id":         response.UserId,
		"username":        response.Username,
		"git_protocol":    env.GitProtocolVersion,
		"remote_ip":       env.RemoteAddr,
		"gl_key_type":     response.KeyType,
		"gl_key_id":       response.KeyId,
	}

	log.WithFields(fields).Info("executing git command")
}

func withOutgoingMetadata(ctx context.Context, features map[string]string) context.Context {
	md := metadata.New(nil)
	for k, v := range features {
		if !strings.HasPrefix(k, "gitaly-feature-") {
			continue
		}
		md.Append(k, v)
	}

	return metadata.NewOutgoingContext(ctx, md)
}

func getConn(gc *GitalyCommand) (*GitalyConn, error) {
	if gc.Address == "" {
		return nil, fmt.Errorf("no gitaly_address given")
	}

	connOpts := client.DefaultDialOpts
	connOpts = append(connOpts,
		grpc.WithStreamInterceptor(
			grpccorrelation.StreamClientCorrelationInterceptor(
				grpccorrelation.WithClientName(executable.GitlabShell),
			),
		),
		grpc.WithUnaryInterceptor(
			grpccorrelation.UnaryClientCorrelationInterceptor(
				grpccorrelation.WithClientName(executable.GitlabShell),
			),
		))

	if gc.Token != "" {
		connOpts = append(connOpts,
			grpc.WithPerRPCCredentials(gitalyauth.RPCCredentialsV2(gc.Token)),
		)
	}

	// Use a working directory that won't get removed or unmounted.
	if err := os.Chdir("/"); err != nil {
		return nil, err
	}

	// Configure distributed tracing
	serviceName := fmt.Sprintf("gitlab-shell-%v", gc.ServiceName)
	closer := tracing.Initialize(
		tracing.WithServiceName(serviceName),

		// For GitLab-Shell, we explicitly initialize tracing from a config file
		// instead of the default environment variable (using GITLAB_TRACING)
		// This decision was made owing to the difficulty in passing environment
		// variables into GitLab-Shell processes.
		//
		// Processes are spawned as children of the SSH daemon, which tightly
		// controls environment variables; doing this means we don't have to
		// enable PermitUserEnvironment
		tracing.WithConnectionString(gc.Config.GitlabTracing),
	)

	ctx, finished := tracing.ExtractFromEnv(context.Background())
	ctx = withOutgoingMetadata(ctx, gc.Features)

	conn, err := client.Dial(gc.Address, connOpts)
	if err != nil {
		return nil, err
	}

	finish := func() {
		finished()
		closer.Close()
		conn.Close()
	}

	return &GitalyConn{ctx: ctx, conn: conn, close: finish}, nil
}
<commit_msg>Stop changing directory to the filesystem root<commit_after>package handler

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	log "github.com/sirupsen/logrus"

	gitalyauth "gitlab.com/gitlab-org/gitaly/auth"
	"gitlab.com/gitlab-org/gitaly/client"
	pb "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb"
	"gitlab.com/gitlab-org/gitlab-shell/internal/config"
	"gitlab.com/gitlab-org/gitlab-shell/internal/executable"
	"gitlab.com/gitlab-org/gitlab-shell/internal/gitlabnet/accessverifier"
	"gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
	"gitlab.com/gitlab-org/labkit/correlation"
	grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc"
	"gitlab.com/gitlab-org/labkit/tracing"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

// GitalyHandlerFunc implementations are responsible for making
// an appropriate Gitaly call using the provided client and context
// and returning an error from the Gitaly call.
type GitalyHandlerFunc func(ctx context.Context, client *grpc.ClientConn) (int32, error)

type GitalyConn struct {
	ctx   context.Context
	conn  *grpc.ClientConn
	close func()
}

type GitalyCommand struct {
	Config      *config.Config
	ServiceName string
	Address     string
	Token       string
	Features    map[string]string
}

// RunGitalyCommand provides a bootstrap for Gitaly commands executed
// through GitLab-Shell. It ensures that logging, tracing and other
// common concerns are configured before executing the `handler`.
func (gc *GitalyCommand) RunGitalyCommand(handler GitalyHandlerFunc) error {
	gitalyConn, err := getConn(gc)

	if err != nil {
		return err
	}

	_, err = handler(gitalyConn.ctx, gitalyConn.conn)

	gitalyConn.close()

	return err
}

// PrepareContext wraps a given context with a correlation ID and logs the command to
// be run.
func (gc *GitalyCommand) PrepareContext(ctx context.Context, repository *pb.Repository, response *accessverifier.Response, env sshenv.Env) (context.Context, context.CancelFunc) {
	ctx, cancel := context.WithCancel(ctx)

	gc.LogExecution(repository, response, env)

	if response.CorrelationID != "" {
		ctx = correlation.ContextWithCorrelation(ctx, response.CorrelationID)
	}

	md, ok := metadata.FromOutgoingContext(ctx)
	if !ok {
		md = metadata.New(nil)
	}
	md.Append("key_id", strconv.Itoa(response.KeyId))
	md.Append("key_type", response.KeyType)
	md.Append("user_id", response.UserId)
	md.Append("username", response.Username)
	md.Append("remote_ip", env.RemoteAddr)
	ctx = metadata.NewOutgoingContext(ctx, md)

	return ctx, cancel
}

func (gc *GitalyCommand) LogExecution(repository *pb.Repository, response *accessverifier.Response, env sshenv.Env) {
	fields := log.Fields{
		"command":         gc.ServiceName,
		"correlation_id":  response.CorrelationID,
		"gl_project_path": repository.GlProjectPath,
		"gl_repository":   repository.GlRepository,
		"user_id":         response.UserId,
		"username":        response.Username,
		"git_protocol":    env.GitProtocolVersion,
		"remote_ip":       env.RemoteAddr,
		"gl_key_type":     response.KeyType,
		"gl_key_id":       response.KeyId,
	}

	log.WithFields(fields).Info("executing git command")
}

func withOutgoingMetadata(ctx context.Context, features map[string]string) context.Context {
	md := metadata.New(nil)
	for k, v := range features {
		if !strings.HasPrefix(k, "gitaly-feature-") {
			continue
		}
		md.Append(k, v)
	}

	return metadata.NewOutgoingContext(ctx, md)
}

func getConn(gc *GitalyCommand) (*GitalyConn, error) {
	if gc.Address == "" {
		return nil, fmt.Errorf("no gitaly_address given")
	}

	connOpts := client.DefaultDialOpts
	connOpts = append(connOpts,
		grpc.WithStreamInterceptor(
			grpccorrelation.StreamClientCorrelationInterceptor(
				grpccorrelation.WithClientName(executable.GitlabShell),
			),
		),
		grpc.WithUnaryInterceptor(
			grpccorrelation.UnaryClientCorrelationInterceptor(
				grpccorrelation.WithClientName(executable.GitlabShell),
			),
		))

	if gc.Token != "" {
		connOpts = append(connOpts,
			grpc.WithPerRPCCredentials(gitalyauth.RPCCredentialsV2(gc.Token)),
		)
	}

	// Configure distributed tracing
	serviceName := fmt.Sprintf("gitlab-shell-%v", gc.ServiceName)
	closer := tracing.Initialize(
		tracing.WithServiceName(serviceName),

		// For GitLab-Shell, we explicitly initialize tracing from a config file
		// instead of the default environment variable (using GITLAB_TRACING)
		// This decision was made owing to the difficulty in passing environment
		// variables into GitLab-Shell processes.
		//
		// Processes are spawned as children of the SSH daemon, which tightly
		// controls environment variables; doing this means we don't have to
		// enable PermitUserEnvironment
		tracing.WithConnectionString(gc.Config.GitlabTracing),
	)

	ctx, finished := tracing.ExtractFromEnv(context.Background())
	ctx = withOutgoingMetadata(ctx, gc.Features)

	conn, err := client.Dial(gc.Address, connOpts)
	if err != nil {
		return nil, err
	}

	finish := func() {
		finished()
		closer.Close()
		conn.Close()
	}

	return &GitalyConn{ctx: ctx, conn: conn, close: finish}, nil
}
<|endoftext|>


<commit_before>package ldap

import (
	"encoding/json"
	"os"
	"strings"

	"io"

	"sort"

	"github.com/go-ldap/ldap"
)

// Mappings ...
type Mappings struct {
	Mappings []Mapping
	// Attributes is a list of all unique attributes that appear in mappings
	// that needs to be retrieved from server to make comparison.
	Attributes []string
}

// Mapping ...
type Mapping struct {
	From       map[string][]string `json:"from"`
	To         MappingTo           `json:"to"`
	attributes []string
}

// MappingTo ...
type MappingTo struct {
	IsStaff     bool
	Groups      []string `json:"groups"`
	Permissions []string `json:"permissions"`
}

// NewMappings ...
func NewMappings(r io.Reader) (*Mappings, error) {
	var m Mappings
	if err := json.NewDecoder(r).Decode(&m.Mappings); err != nil {
		return nil, err
	}

	for _, mapping := range m.Mappings {
		for attr := range mapping.From {
			m.Attributes = append(m.Attributes, attr)
		}
	}

	removeDuplicates(&m.Attributes)
	sort.Sort(sort.StringSlice(m.Attributes))

	return &m, nil
}

// NewMappingsFromFile reads json file and allocates new Mappings based on the output.
func NewMappingsFromFile(p string) (*Mappings, error) {
	if p == "" {
		return &Mappings{}, nil
	}

	file, err := os.Open(p)
	if err != nil {
		return nil, err
	}

	return NewMappings(file)
}

// Map search groups and permissions that given LDAP entry match.
func (m *Mappings) Map(attrs []*ldap.EntryAttribute) (*MappingTo, bool) {
	var (
		to              MappingTo
		expected, valid int
		found           bool
	)

MappingLoop:
	for _, mapping := range m.Mappings {
		expected, valid = 0, 0
		for _, values := range mapping.From {
			if len(values) > 0 {
				expected++
			}
		}

	AttributesLoop:
		for _, attr := range attrs {
			if valid >= expected {
				break AttributesLoop
			}

			for attrName, from := range mapping.From {
				if attr.Name != attrName {
					continue
				}
				if !m.compare(attr.Values, from) {
					continue MappingLoop
				}

				valid++
			}
		}

		if valid >= expected {
			found = true
			if mapping.To.IsStaff {
				to.IsStaff = true
			}
			to.Groups = append(to.Groups, mapping.To.Groups...)
			to.Permissions = append(to.Permissions, mapping.To.Permissions...)
		}
	}

	return &to, found
}

func (lm *Mappings) compare(given, expected []string) bool {
	if len(expected) == 0 {
		return true
	}
	var (
		match, localMatch int
	)
	for _, giv := range given {
		parts := strings.Split(giv, ",")

		// if longer than 1 than probably its memberOf type of attribute
		switch len(parts) {
		case 1:
			for _, exp := range expected {
				if giv == exp {
					match++
				}
			}
		default:
			for _, part := range parts {
				for _, exp := range expected {
					if part == exp {
						localMatch++
					}
				}
			}
			if localMatch == len(expected) {
				return true
			}
			localMatch = 0
		}
	}

	return match == len(expected)
}

func removeDuplicates(xs *[]string) {
	found := make(map[string]bool)
	j := 0
	for i, x := range *xs {
		if !found[x] {
			found[x] = true
			(*xs)[j] = (*xs)[i]
			j++
		}
	}
	*xs = (*xs)[:j]
}
<commit_msg>ldap mapping missing struct tag<commit_after>package ldap

import (
	"encoding/json"
	"os"
	"strings"

	"io"

	"sort"

	"github.com/go-ldap/ldap"
)

// Mappings ...
type Mappings struct {
	Mappings []Mapping
	// Attributes is a list of all unique attributes that appear in mappings
	// that needs to be retrieved from server to make comparison.
	Attributes []string
}

// Mapping ...
type Mapping struct {
	From       map[string][]string `json:"from"`
	To         MappingTo           `json:"to"`
	attributes []string
}

// MappingTo ...
type MappingTo struct {
	IsStaff     bool     `json:"isStaff"`
	Groups      []string `json:"groups"`
	Permissions []string `json:"permissions"`
}

// NewMappings ...
func NewMappings(r io.Reader) (*Mappings, error) {
	var m Mappings
	if err := json.NewDecoder(r).Decode(&m.Mappings); err != nil {
		return nil, err
	}

	for _, mapping := range m.Mappings {
		for attr := range mapping.From {
			m.Attributes = append(m.Attributes, attr)
		}
	}

	removeDuplicates(&m.Attributes)
	sort.Sort(sort.StringSlice(m.Attributes))

	return &m, nil
}

// NewMappingsFromFile reads json file and allocates new Mappings based on the output.
func NewMappingsFromFile(p string) (*Mappings, error) {
	if p == "" {
		return &Mappings{}, nil
	}

	file, err := os.Open(p)
	if err != nil {
		return nil, err
	}

	return NewMappings(file)
}

// Map search groups and permissions that given LDAP entry match.
func (m *Mappings) Map(attrs []*ldap.EntryAttribute) (*MappingTo, bool) {
	var (
		to              MappingTo
		expected, valid int
		found           bool
	)

MappingLoop:
	for _, mapping := range m.Mappings {
		expected, valid = 0, 0
		for _, values := range mapping.From {
			if len(values) > 0 {
				expected++
			}
		}

	AttributesLoop:
		for _, attr := range attrs {
			if valid >= expected {
				break AttributesLoop
			}

			for attrName, from := range mapping.From {
				if attr.Name != attrName {
					continue
				}
				if !m.compare(attr.Values, from) {
					continue MappingLoop
				}

				valid++
			}
		}

		if valid >= expected {
			found = true
			if mapping.To.IsStaff {
				to.IsStaff = true
			}
			to.Groups = append(to.Groups, mapping.To.Groups...)
			to.Permissions = append(to.Permissions, mapping.To.Permissions...)
		}
	}

	return &to, found
}

func (lm *Mappings) compare(given, expected []string) bool {
	if len(expected) == 0 {
		return true
	}
	var (
		match, localMatch int
	)
	for _, giv := range given {
		parts := strings.Split(giv, ",")

		// if longer than 1 than probably its memberOf type of attribute
		switch len(parts) {
		case 1:
			for _, exp := range expected {
				if giv == exp {
					match++
				}
			}
		default:
			for _, part := range parts {
				for _, exp := range expected {
					if part == exp {
						localMatch++
					}
				}
			}
			if localMatch == len(expected) {
				return true
			}
			localMatch = 0
		}
	}

	return match == len(expected)
}

func removeDuplicates(xs *[]string) {
	found := make(map[string]bool)
	j := 0
	for i, x := range *xs {
		if !found[x] {
			found[x] = true
			(*xs)[j] = (*xs)[i]
			j++
		}
	}
	*xs = (*xs)[:j]
}
<|endoftext|>


<commit_before>package manpage

import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/Debian/debiman/internal/tag"
	"golang.org/x/text/language"
	"pault.ag/go/debian/version"
)

type PkgMeta struct {
	Binarypkg string

	// Version is used by the templates when rendering.
	Version version.Version

	// Suite is the Debian suite in which this binary package was
	// found.
	Suite string
}

type Meta struct {
	// Name is e.g. “w3m”, or “systemd.service”.
	Name string

	// Package is the Debian binary package from which this manpage
	// was extracted.
	Package *PkgMeta

	// Section is the man section to which this manpage belongs,
	// e.g. 1, 3pm, …
	Section string

	// Language is the locale-like language directory
	// (i.e. language[_territory][.codeset][@modifier], with language coming
	// from ISO639 and territory coming from ISO3166) in which this
	// manpage was found.
	Language    string
	LanguageTag language.Tag
}

// FromManPath constructs a manpage, gathering details from path (relative underneath /usr/share/man).
func FromManPath(path string, p *PkgMeta) (*Meta, error) {
	// man pages are in /usr/share/man/(<lang>/|)man<section>/<name>.<section>.gz

	lang := "C"

	parts := strings.Split(path, "/")
	if len(parts) == 3 {
		// Language-specific subdirectory
		lang = parts[0]
		// Strip the codeset, if any
		if idx := strings.Index(lang, "."); idx > -1 {
			lidx := strings.LastIndex(lang, "@")
			if lidx == -1 {
				lidx = len(lang)
			}
			lang = lang[:idx] + lang[lidx:len(lang)]
		}
		parts = parts[1:]
	}

	// Both C and POSIX are to be treated as english. TODO: add reference
	if lang == "C" || lang == "POSIX" {
		lang = "en"
	}

	tag, err := tag.FromLocale(lang)
	if err != nil {
		return nil, fmt.Errorf("Cannot parse language %q: %v", lang, err)
	}

	if len(parts) != 2 {
		return nil, fmt.Errorf("Unexpected path format %q", path)
	}

	if !strings.HasSuffix(parts[1], ".gz") {
		parts[1] = parts[1] + ".gz"
	}

	section := strings.TrimPrefix(parts[0], "man")
	re := regexp.MustCompile(fmt.Sprintf(`\.%s([^.]*)\.gz$`, section))
	matches := re.FindStringSubmatch(parts[1])
	if matches == nil {
		return nil, fmt.Errorf("file name (%q) does not match regexp %v", parts[1], re)
	}
	if len(matches) > 1 {
		section = section + matches[1]
	}

	return &Meta{
		Name:        strings.TrimSuffix(parts[1], "."+section+".gz"),
		Package:     p,
		Section:     section,
		Language:    lang,
		LanguageTag: tag,
	}, nil
}

// FromServingPath constructs a manpage, gathering details from path
func FromServingPath(servingDir, path string) (*Meta, error) {
	// *servingDir/<suite>/<binarypkg>/<name>.<section>.<lang>
	relpath := strings.TrimPrefix(path, filepath.Clean(servingDir)+"/")
	pparts := strings.Split(relpath, "/")
	if len(pparts) != 3 {
		return nil, fmt.Errorf("Unexpected path format %q", relpath)
	}

	base := strings.TrimSuffix(filepath.Base(path), ".gz")
	// the first part can contain dots, so we need to “split from the right”
	// TODO: this can be implemented more efficiently
	allbparts := strings.Split(base, ".")
	if len(allbparts) < 3 {
		return nil, fmt.Errorf("Unexpected file name format %q", base)
	}
	bparts := []string{
		strings.Join(allbparts[:len(allbparts)-2], "."),
		allbparts[len(allbparts)-2],
		allbparts[len(allbparts)-1],
	}

	tag, err := tag.FromLocale(bparts[2])
	if err != nil {
		return nil, fmt.Errorf("Cannot parse language %q (in path %q): %v", bparts[2], path, err)
	}

	if len(bparts) != 3 {
		return nil, fmt.Errorf("Unexpected file name format %q", base)
	}

	return &Meta{
		Name: bparts[0],
		Package: &PkgMeta{
			Binarypkg: pparts[1],
			Suite:     pparts[0],
		},
		Section:     bparts[1],
		Language:    bparts[2],
		LanguageTag: tag,
	}, nil
}

func (m *Meta) String() string {
	return m.ServingPath()
}

func (m *Meta) ServingPath() string {
	return m.Package.Suite + "/" + m.Package.Binarypkg + "/" + m.Name + "." + m.Section + "." + m.Language
}

// RawPath returns the path to access the raw manpage equivalent of
// what is currently being served, i.e. locked to the current
// language.
func (m *Meta) RawPath() string {
	return m.Package.Suite + "/" + m.Package.Binarypkg + "/" + m.Name + "." + m.Section + "." + m.Language + ".gz"
}

func (m *Meta) PermaLink() string {
	return m.Package.Suite + "/" + m.Package.Binarypkg + "/" + m.Name + "." + m.Section
}

func (m *Meta) MainSection() string {
	return m.Section[:1]
}
<commit_msg>lower-case section name (e.g. 3SSL → 3ssl) for consistency<commit_after>package manpage

import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/Debian/debiman/internal/tag"
	"golang.org/x/text/language"
	"pault.ag/go/debian/version"
)

type PkgMeta struct {
	Binarypkg string

	// Version is used by the templates when rendering.
	Version version.Version

	// Suite is the Debian suite in which this binary package was
	// found.
	Suite string
}

type Meta struct {
	// Name is e.g. “w3m”, or “systemd.service”.
	Name string

	// Package is the Debian binary package from which this manpage
	// was extracted.
	Package *PkgMeta

	// Section is the man section to which this manpage belongs,
	// e.g. 1, 3pm, …
	Section string

	// Language is the locale-like language directory
	// (i.e. language[_territory][.codeset][@modifier], with language coming
	// from ISO639 and territory coming from ISO3166) in which this
	// manpage was found.
	Language    string
	LanguageTag language.Tag
}

// FromManPath constructs a manpage, gathering details from path (relative underneath /usr/share/man).
func FromManPath(path string, p *PkgMeta) (*Meta, error) {
	// man pages are in /usr/share/man/(<lang>/|)man<section>/<name>.<section>.gz

	lang := "C"

	parts := strings.Split(path, "/")
	if len(parts) == 3 {
		// Language-specific subdirectory
		lang = parts[0]
		// Strip the codeset, if any
		if idx := strings.Index(lang, "."); idx > -1 {
			lidx := strings.LastIndex(lang, "@")
			if lidx == -1 {
				lidx = len(lang)
			}
			lang = lang[:idx] + lang[lidx:len(lang)]
		}
		parts = parts[1:]
	}

	// Both C and POSIX are to be treated as english. TODO: add reference
	if lang == "C" || lang == "POSIX" {
		lang = "en"
	}

	tag, err := tag.FromLocale(lang)
	if err != nil {
		return nil, fmt.Errorf("Cannot parse language %q: %v", lang, err)
	}

	if len(parts) != 2 {
		return nil, fmt.Errorf("Unexpected path format %q", path)
	}

	if !strings.HasSuffix(parts[1], ".gz") {
		parts[1] = parts[1] + ".gz"
	}

	section := strings.TrimPrefix(parts[0], "man")
	re := regexp.MustCompile(fmt.Sprintf(`\.%s([^.]*)\.gz$`, section))
	matches := re.FindStringSubmatch(parts[1])
	if matches == nil {
		return nil, fmt.Errorf("file name (%q) does not match regexp %v", parts[1], re)
	}
	if len(matches) > 1 {
		section = section + matches[1]
	}

	return &Meta{
		Name:        strings.TrimSuffix(parts[1], "."+section+".gz"),
		Package:     p,
		Section:     strings.ToLower(section),
		Language:    lang,
		LanguageTag: tag,
	}, nil
}

// FromServingPath constructs a manpage, gathering details from path
func FromServingPath(servingDir, path string) (*Meta, error) {
	// *servingDir/<suite>/<binarypkg>/<name>.<section>.<lang>
	relpath := strings.TrimPrefix(path, filepath.Clean(servingDir)+"/")
	pparts := strings.Split(relpath, "/")
	if len(pparts) != 3 {
		return nil, fmt.Errorf("Unexpected path format %q", relpath)
	}

	base := strings.TrimSuffix(filepath.Base(path), ".gz")
	// the first part can contain dots, so we need to “split from the right”
	// TODO: this can be implemented more efficiently
	allbparts := strings.Split(base, ".")
	if len(allbparts) < 3 {
		return nil, fmt.Errorf("Unexpected file name format %q", base)
	}
	bparts := []string{
		strings.Join(allbparts[:len(allbparts)-2], "."),
		allbparts[len(allbparts)-2],
		allbparts[len(allbparts)-1],
	}

	tag, err := tag.FromLocale(bparts[2])
	if err != nil {
		return nil, fmt.Errorf("Cannot parse language %q (in path %q): %v", bparts[2], path, err)
	}

	if len(bparts) != 3 {
		return nil, fmt.Errorf("Unexpected file name format %q", base)
	}

	return &Meta{
		Name: bparts[0],
		Package: &PkgMeta{
			Binarypkg: pparts[1],
			Suite:     pparts[0],
		},
		Section:     bparts[1],
		Language:    bparts[2],
		LanguageTag: tag,
	}, nil
}

func (m *Meta) String() string {
	return m.ServingPath()
}

func (m *Meta) ServingPath() string {
	return m.Package.Suite + "/" + m.Package.Binarypkg + "/" + m.Name + "." + m.Section + "." + m.Language
}

// RawPath returns the path to access the raw manpage equivalent of
// what is currently being served, i.e. locked to the current
// language.
func (m *Meta) RawPath() string {
	return m.Package.Suite + "/" + m.Package.Binarypkg + "/" + m.Name + "." + m.Section + "." + m.Language + ".gz"
}

func (m *Meta) PermaLink() string {
	return m.Package.Suite + "/" + m.Package.Binarypkg + "/" + m.Name + "." + m.Section
}

func (m *Meta) MainSection() string {
	return m.Section[:1]
}
<|endoftext|>


<commit_before>package ndpcmd

import (
	"fmt"
	"io"
	"log"
	"net"
	"strings"

	"github.com/mdlayher/ndp"
)

func printMessage(ll *log.Logger, m ndp.Message, from net.IP) {
	switch m := m.(type) {
	case *ndp.NeighborAdvertisement:
		printNA(ll, m, from)
	case *ndp.NeighborSolicitation:
		printNS(ll, m, from)
	case *ndp.RouterAdvertisement:
		printRA(ll, m, from)
	case *ndp.RouterSolicitation:
		printRS(ll, m, from)
	default:
		ll.Printf("%s %#v", from, m)
	}
}

func printRA(ll *log.Logger, ra *ndp.RouterAdvertisement, from net.IP) {
	var flags []string
	if ra.ManagedConfiguration {
		flags = append(flags, "managed")
	}
	if ra.OtherConfiguration {
		flags = append(flags, "other")
	}
	if ra.MobileIPv6HomeAgent {
		flags = append(flags, "mobile")
	}
	if ra.NeighborDiscoveryProxy {
		flags = append(flags, "proxy")
	}

	var s strings.Builder
	writef(&s, "router advertisement from: %s:\n", from)

	if ra.CurrentHopLimit > 0 {
		writef(&s, "  - hop limit:        %d\n", ra.CurrentHopLimit)
	}
	if len(flags) > 0 {
		writef(&s, "  - flags:            [%s]\n", strings.Join(flags, ", "))
	}

	writef(&s, "  - preference:       %s\n", ra.RouterSelectionPreference)

	if ra.RouterLifetime > 0 {
		writef(&s, "  - router lifetime:  %s\n", ra.RouterLifetime)
	}
	if ra.ReachableTime != 0 {
		writef(&s, "  - reachable time:   %s\n", ra.ReachableTime)
	}
	if ra.RetransmitTimer != 0 {
		writef(&s, "  - retransmit timer: %s\n", ra.RetransmitTimer)
	}

	_, _ = s.WriteString(optionsString(ra.Options))

	ll.Print(s.String())
}

func printRS(ll *log.Logger, rs *ndp.RouterSolicitation, from net.IP) {
	s := fmt.Sprintf(
		rsFormat,
		from.String(),
	)

	ll.Print(s + optionsString(rs.Options))
}

const rsFormat = "router solicitation from %s:\n"

func printNA(ll *log.Logger, na *ndp.NeighborAdvertisement, from net.IP) {
	s := fmt.Sprintf(
		naFormat,
		from.String(),
		na.Router,
		na.Solicited,
		na.Override,
		na.TargetAddress.String(),
	)

	ll.Print(s + optionsString(na.Options))
}

const naFormat = `neighbor advertisement from %s:
  - router:         %t
  - solicited:      %t
  - override:       %t
  - target address: %s
`

func printNS(ll *log.Logger, ns *ndp.NeighborSolicitation, from net.IP) {
	s := fmt.Sprintf(
		nsFormat,
		from.String(),
		ns.TargetAddress.String(),
	)

	ll.Print(s + optionsString(ns.Options))
}

const nsFormat = `neighbor solicitation from %s:
  - target address: %s
`

func optionsString(options []ndp.Option) string {
	if len(options) == 0 {
		return ""
	}

	var s strings.Builder
	s.WriteString("  - options:\n")

	for _, o := range options {
		writef(&s, "    - %s\n", optStr(o))
	}

	return s.String()
}

func optStr(o ndp.Option) string {
	switch o := o.(type) {
	case *ndp.LinkLayerAddress:
		dir := "source"
		if o.Direction == ndp.Target {
			dir = "target"
		}

		return fmt.Sprintf("%s link-layer address: %s", dir, o.Addr.String())
	case *ndp.MTU:
		return fmt.Sprintf("MTU: %d", *o)
	case *ndp.PrefixInformation:
		var flags []string
		if o.OnLink {
			flags = append(flags, "on-link")
		}
		if o.AutonomousAddressConfiguration {
			flags = append(flags, "autonomous")
		}

		return fmt.Sprintf("prefix information: %s/%d, flags: [%s], valid: %s, preferred: %s",
			o.Prefix.String(),
			o.PrefixLength,
			strings.Join(flags, ", "),
			o.ValidLifetime,
			o.PreferredLifetime,
		)
	case *ndp.RawOption:
		return fmt.Sprintf("type: %03d, value: %v", o.Type, o.Value)
	case *ndp.RecursiveDNSServer:
		var ss []string
		for _, s := range o.Servers {
			ss = append(ss, s.String())
		}
		servers := strings.Join(ss, ", ")

		return fmt.Sprintf("recursive DNS servers: lifetime: %s, servers: %s", o.Lifetime, servers)
	case *ndp.DNSSearchList:
		return fmt.Sprintf("DNS search list: lifetime: %s, domain names: %s", o.Lifetime, strings.Join(o.DomainNames, ", "))
	default:
		panic(fmt.Sprintf("unrecognized option: %v", o))
	}
}

func writef(sw io.StringWriter, format string, a ...interface{}) {
	_, _ = sw.WriteString(fmt.Sprintf(format, a...))
}
<commit_msg>internal/ndpcmd: allow printing route information<commit_after>package ndpcmd

import (
	"fmt"
	"io"
	"log"
	"net"
	"strings"

	"github.com/mdlayher/ndp"
)

func printMessage(ll *log.Logger, m ndp.Message, from net.IP) {
	switch m := m.(type) {
	case *ndp.NeighborAdvertisement:
		printNA(ll, m, from)
	case *ndp.NeighborSolicitation:
		printNS(ll, m, from)
	case *ndp.RouterAdvertisement:
		printRA(ll, m, from)
	case *ndp.RouterSolicitation:
		printRS(ll, m, from)
	default:
		ll.Printf("%s %#v", from, m)
	}
}

func printRA(ll *log.Logger, ra *ndp.RouterAdvertisement, from net.IP) {
	var flags []string
	if ra.ManagedConfiguration {
		flags = append(flags, "managed")
	}
	if ra.OtherConfiguration {
		flags = append(flags, "other")
	}
	if ra.MobileIPv6HomeAgent {
		flags = append(flags, "mobile")
	}
	if ra.NeighborDiscoveryProxy {
		flags = append(flags, "proxy")
	}

	var s strings.Builder
	writef(&s, "router advertisement from: %s:\n", from)

	if ra.CurrentHopLimit > 0 {
		writef(&s, "  - hop limit:        %d\n", ra.CurrentHopLimit)
	}
	if len(flags) > 0 {
		writef(&s, "  - flags:            [%s]\n", strings.Join(flags, ", "))
	}

	writef(&s, "  - preference:       %s\n", ra.RouterSelectionPreference)

	if ra.RouterLifetime > 0 {
		writef(&s, "  - router lifetime:  %s\n", ra.RouterLifetime)
	}
	if ra.ReachableTime != 0 {
		writef(&s, "  - reachable time:   %s\n", ra.ReachableTime)
	}
	if ra.RetransmitTimer != 0 {
		writef(&s, "  - retransmit timer: %s\n", ra.RetransmitTimer)
	}

	_, _ = s.WriteString(optionsString(ra.Options))

	ll.Print(s.String())
}

func printRS(ll *log.Logger, rs *ndp.RouterSolicitation, from net.IP) {
	s := fmt.Sprintf(
		rsFormat,
		from.String(),
	)

	ll.Print(s + optionsString(rs.Options))
}

const rsFormat = "router solicitation from %s:\n"

func printNA(ll *log.Logger, na *ndp.NeighborAdvertisement, from net.IP) {
	s := fmt.Sprintf(
		naFormat,
		from.String(),
		na.Router,
		na.Solicited,
		na.Override,
		na.TargetAddress.String(),
	)

	ll.Print(s + optionsString(na.Options))
}

const naFormat = `neighbor advertisement from %s:
  - router:         %t
  - solicited:      %t
  - override:       %t
  - target address: %s
`

func printNS(ll *log.Logger, ns *ndp.NeighborSolicitation, from net.IP) {
	s := fmt.Sprintf(
		nsFormat,
		from.String(),
		ns.TargetAddress.String(),
	)

	ll.Print(s + optionsString(ns.Options))
}

const nsFormat = `neighbor solicitation from %s:
  - target address: %s
`

func optionsString(options []ndp.Option) string {
	if len(options) == 0 {
		return ""
	}

	var s strings.Builder
	s.WriteString("  - options:\n")

	for _, o := range options {
		writef(&s, "    - %s\n", optStr(o))
	}

	return s.String()
}

func optStr(o ndp.Option) string {
	switch o := o.(type) {
	case *ndp.LinkLayerAddress:
		dir := "source"
		if o.Direction == ndp.Target {
			dir = "target"
		}

		return fmt.Sprintf("%s link-layer address: %s", dir, o.Addr.String())
	case *ndp.MTU:
		return fmt.Sprintf("MTU: %d", *o)
	case *ndp.PrefixInformation:
		var flags []string
		if o.OnLink {
			flags = append(flags, "on-link")
		}
		if o.AutonomousAddressConfiguration {
			flags = append(flags, "autonomous")
		}

		return fmt.Sprintf("prefix information: %s/%d, flags: [%s], valid: %s, preferred: %s",
			o.Prefix.String(),
			o.PrefixLength,
			strings.Join(flags, ", "),
			o.ValidLifetime,
			o.PreferredLifetime,
		)
	case *ndp.RawOption:
		return fmt.Sprintf("type: %03d, value: %v", o.Type, o.Value)
	case *ndp.RouteInformation:
		return fmt.Sprintf("route information: %s/%d, preference: %s, lifetime: %s",
			o.Prefix.String(),
			o.PrefixLength,
			o.Preference.String(),
			o.RouteLifetime,
		)
	case *ndp.RecursiveDNSServer:
		var ss []string
		for _, s := range o.Servers {
			ss = append(ss, s.String())
		}
		servers := strings.Join(ss, ", ")

		return fmt.Sprintf("recursive DNS servers: lifetime: %s, servers: %s", o.Lifetime, servers)
	case *ndp.DNSSearchList:
		return fmt.Sprintf("DNS search list: lifetime: %s, domain names: %s", o.Lifetime, strings.Join(o.DomainNames, ", "))
	default:
		panic(fmt.Sprintf("unrecognized option: %v", o))
	}
}

func writef(sw io.StringWriter, format string, a ...interface{}) {
	_, _ = sw.WriteString(fmt.Sprintf(format, a...))
}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"
	"fmt"
	"github.com/revel/revel"
	//"goassimp/app/routes"
	"io"
	"os"
)

type Convert struct {
	App
}

func (c *Convert) List() revel.Result {
	var id string = c.Params.Get("id")
	fmt.Println(id)
	return c.Render()
}

func (c *Convert) Convert(source[]byte) revel.Result {
	dstDir := "public/tmp"
	dstName := c.Params.Files["source"][0].Filename
	dst, err := os.Create(dstDir + "/" + dstName)
	if err != nil {
		panic(err)
	}
	defer dst.Close()

	_, err = io.Copy(dst, bytes.NewReader(source))
	if err != nil {
		panic(err)
	}

	fmt.Println("Status: Successfully uploaded")

	return c.RenderJson(map[string]interface{}{
		"Status": "Successfully uploaded",
	})
}
<commit_msg>commentを追加<commit_after>package controllers

import (
	"bytes"
	"fmt"
	"github.com/revel/revel"
	//"goassimp/app/routes"
	"io"
	"os"
)

type Convert struct {
	App
}

func (c *Convert) List() revel.Result {
	var id string = c.Params.Get("id")
	fmt.Println(id)
	// 情報出力
	// Zset順
	return c.Render()
}

func (c *Convert) Convert(source[]byte) revel.Result {
	// 画像保存
	dstDir := "public/tmp"
	dstName := c.Params.Files["source"][0].Filename
	dst, err := os.Create(dstDir + "/" + dstName)
	if err != nil {
		panic(err)
	}
	defer dst.Close()

	_, err = io.Copy(dst, bytes.NewReader(source))
	if err != nil {
		panic(err)
	}

	// 情報登録
	// uuid, path, created_at
	// Zset順

	fmt.Println("Status: Successfully uploaded")

	return c.RenderJson(map[string]interface{}{
		"Status": "Successfully uploaded",
	})
}
<|endoftext|>


<commit_before>package invdendpoint

// type Invoices struct {
// 	Invoices []Invoice `json:"invoices"`
// }

const InvoicesEndPoint = "/invoices"

type Invoices []Invoice

type Invoice struct {
	CreatedAt              int64          `json:"created_at,omitempty"`
	UpdatedAt              int64          `json:"updated_at,omitempty"`
	Id                     int64          `json:"id,omitempty"`
	Customer               int64          `json:"customer,omitempty"`
	Name                   string         `json:"name,omitempty"`
	Currency               string         `json:"currency,omitempty"`
	Draft                  bool           `json:"draft,omitempty"`
	Sent                   bool           `json:"sent,omitempty"`
	Closed                 bool           `json:"closed,omitempty"`
	Paid                   bool           `json:"paid,omitempty"`
	Status                 string         `json:"status,omitempty"`
	Chase                  bool           `json:"chase,omitempty"`
	NextChaseOn            string         `json:"next_chase_on,omitempty"`
	AutoBilled             bool           `json:"auto_billed,omitempty"`
	AttemptCount           int64          `json:"attempt_count,omitempty"`
	NextPaymentAttempt     string         `json:"next_payment_attempt,omitempty"`
	Theme                  int64          `json:"theme,omitempty"`
	DisabledPaymentMethods *PaymentMethod `json:"disabled_payment_methods,omitempty"`
	//Estimate                     int64          `json:"estimate,omitempty"`
	Subscription                 *int64      `json:"subscription,omitempty"`
	Number                       string      `json:"number,omitempty"`
	Date                         int64       `json:"date,omitempty"`
	DueDate                      int64       `json:"duedate,omitempty"`
	PaymentTerms                 string      `json:"payment_terms,omitempty"`
	PurchaseOrder                string      `json:"purchaseorder,omitempty"`
	Items                        []LineItem  `json:"items,omitempty"`
	Terms                        string      `json:"terms,omitempty"`
	Notes                        string      `json:"notes,omitempty"`
	Subtotal                     float64     `json:"subtotal,omitempty"`
	Discounts                    []Discount  `json:"discounts,omitempty"`
	Taxes                        []Tax       `json:"taxes,omitempty"`
	Shipping                     []Rate      `json:"shipping,omitempty"`
	Total                        float64     `json:"total,omitempty"`
	AmountPaid                   float64     `json:"amountpaid,omitempty"`
	AmountAdjusted               float64     `json:"amountadjusted,omitempty"`
	Balance                      float64     `json:"balance,omitempty"`
	Url                          string      `json:"url,omitempty"`
	PdfUrl                       string      `json:"pdf_url,omitempty"`
	CSVUrl                       string      `json:"csv_url,omitempty"`
	LatePaymentRemindersDisabled bool        `json:"late_payment_reminders_disabled,omitempty"`
	MetaData                     interface{} `json:"metadata,omitempty"`
	//add disabled payment methods
}
<commit_msg>Changed invoice->theme to string from int64<commit_after>package invdendpoint

// type Invoices struct {
// 	Invoices []Invoice `json:"invoices"`
// }

const InvoicesEndPoint = "/invoices"

type Invoices []Invoice

type Invoice struct {
	CreatedAt                    int64          `json:"created_at,omitempty"`
	UpdatedAt                    int64          `json:"updated_at,omitempty"`
	Id                           int64          `json:"id,omitempty"`
	Customer                     int64          `json:"customer,omitempty"`
	Name                         string         `json:"name,omitempty"`
	Currency                     string         `json:"currency,omitempty"`
	Draft                        bool           `json:"draft,omitempty"`
	Sent                         bool           `json:"sent,omitempty"`
	Closed                       bool           `json:"closed,omitempty"`
	Paid                         bool           `json:"paid,omitempty"`
	Status                       string         `json:"status,omitempty"`
	Chase                        bool           `json:"chase,omitempty"`
	NextChaseOn                  string         `json:"next_chase_on,omitempty"`
	AutoBilled                   bool           `json:"auto_billed,omitempty"`
	AttemptCount                 int64          `json:"attempt_count,omitempty"`
	NextPaymentAttempt           string         `json:"next_payment_attempt,omitempty"`
	Theme                        string         `json:"theme,omitempty"`
	DisabledPaymentMethods       *PaymentMethod `json:"disabled_payment_methods,omitempty"`
	Subscription                 *int64         `json:"subscription,omitempty"`
	Number                       string         `json:"number,omitempty"`
	Date                         int64          `json:"date,omitempty"`
	DueDate                      int64          `json:"duedate,omitempty"`
	PaymentTerms                 string         `json:"payment_terms,omitempty"`
	PurchaseOrder                string         `json:"purchaseorder,omitempty"`
	Items                        []LineItem     `json:"items,omitempty"`
	Terms                        string         `json:"terms,omitempty"`
	Notes                        string         `json:"notes,omitempty"`
	Subtotal                     float64        `json:"subtotal,omitempty"`
	Discounts                    []Discount     `json:"discounts,omitempty"`
	Taxes                        []Tax          `json:"taxes,omitempty"`
	Shipping                     []Rate         `json:"shipping,omitempty"`
	Total                        float64        `json:"total,omitempty"`
	AmountPaid                   float64        `json:"amountpaid,omitempty"`
	AmountAdjusted               float64        `json:"amountadjusted,omitempty"`
	Balance                      float64        `json:"balance,omitempty"`
	Url                          string         `json:"url,omitempty"`
	PdfUrl                       string         `json:"pdf_url,omitempty"`
	CSVUrl                       string         `json:"csv_url,omitempty"`
	LatePaymentRemindersDisabled bool           `json:"late_payment_reminders_disabled,omitempty"`
	MetaData                     interface{}    `json:"metadata,omitempty"`
	//add disabled payment methods
}
<|endoftext|>


<commit_before>package kcp

import (
	"io"
	"sync"
	"time"

	"github.com/v2ray/v2ray-core/common/alloc"
)

type ReceivingWindow struct {
	start uint32
	size  uint32
	list  []*DataSegment
}

func NewReceivingWindow(size uint32) *ReceivingWindow {
	return &ReceivingWindow{
		start: 0,
		size:  size,
		list:  make([]*DataSegment, size),
	}
}

func (this *ReceivingWindow) Size() uint32 {
	return this.size
}

func (this *ReceivingWindow) Position(idx uint32) uint32 {
	return (idx + this.start) % this.size
}

func (this *ReceivingWindow) Set(idx uint32, value *DataSegment) bool {
	pos := this.Position(idx)
	if this.list[pos] != nil {
		return false
	}
	this.list[pos] = value
	return true
}

func (this *ReceivingWindow) Remove(idx uint32) *DataSegment {
	pos := this.Position(idx)
	e := this.list[pos]
	this.list[pos] = nil
	return e
}

func (this *ReceivingWindow) RemoveFirst() *DataSegment {
	return this.Remove(0)
}

func (this *ReceivingWindow) Advance() {
	this.start++
	if this.start == this.size {
		this.start = 0
	}
}

type ReceivingQueue struct {
	sync.RWMutex
	closed  bool
	cache   *alloc.Buffer
	queue   chan *alloc.Buffer
	timeout time.Time
}

func NewReceivingQueue() *ReceivingQueue {
	return &ReceivingQueue{
		queue: make(chan *alloc.Buffer, effectiveConfig.ReadBuffer/effectiveConfig.Mtu),
	}
}

func (this *ReceivingQueue) Read(buf []byte) (int, error) {
	if this.cache.Len() > 0 {
		nBytes, err := this.cache.Read(buf)
		if this.cache.IsEmpty() {
			this.cache.Release()
			this.cache = nil
		}
		return nBytes, err
	}

	var totalBytes int

L:
	for totalBytes < len(buf) {
		timeToSleep := time.Millisecond
		select {
		case payload, open := <-this.queue:
			if !open {
				return totalBytes, io.EOF
			}
			nBytes, err := payload.Read(buf)
			totalBytes += nBytes
			if err != nil {
				return totalBytes, err
			}
			if !payload.IsEmpty() {
				this.cache = payload
			}
			buf = buf[nBytes:]
		case <-time.After(timeToSleep):
			if totalBytes > 0 {
				break L
			}
			this.RLock()
			if !this.timeout.IsZero() && this.timeout.Before(time.Now()) {
				this.RUnlock()
				return totalBytes, errTimeout
			}
			this.RUnlock()
			timeToSleep += 500 * time.Millisecond
		}
	}

	return totalBytes, nil
}

func (this *ReceivingQueue) Put(payload *alloc.Buffer) {
	this.queue <- payload
}

func (this *ReceivingQueue) SetReadDeadline(t time.Time) error {
	this.Lock()
	defer this.Unlock()

	this.timeout = t
	return nil
}

func (this *ReceivingQueue) Close() {
	this.Lock()
	defer this.Unlock()

	if this.closed {
		return
	}
	this.closed = true
	close(this.queue)
}

type ACKList struct {
	timestamps []uint32
	numbers    []uint32
}

func (this *ACKList) Add(number uint32, timestamp uint32) {
	this.timestamps = append(this.timestamps, timestamp)
	this.numbers = append(this.numbers, number)
}

func (this *ACKList) Clear(una uint32) bool {
	count := 0
	for i := 0; i < len(this.numbers); i++ {
		if this.numbers[i] >= una {
			if i != count {
				this.numbers[count] = this.numbers[i]
				this.timestamps[count] = this.timestamps[i]
			}
			count++
		}
	}
	if count < len(this.numbers) {
		this.numbers = this.numbers[:count]
		this.timestamps = this.timestamps[:count]
		return true
	}
	return false
}

func (this *ACKList) AsSegment() *ACKSegment {
	count := len(this.numbers)
	if count == 0 {
		return nil
	}

	if count > 128 {
		count = 128
	}
	seg := &ACKSegment{
		Count:         byte(count),
		NumberList:    this.numbers[:count],
		TimestampList: this.timestamps[:count],
	}
	//this.numbers = nil
	//this.timestamps = nil
	return seg
}
<commit_msg>locker protected ReceivingQueue.Put<commit_after>package kcp

import (
	"io"
	"sync"
	"time"

	"github.com/v2ray/v2ray-core/common/alloc"
)

type ReceivingWindow struct {
	start uint32
	size  uint32
	list  []*DataSegment
}

func NewReceivingWindow(size uint32) *ReceivingWindow {
	return &ReceivingWindow{
		start: 0,
		size:  size,
		list:  make([]*DataSegment, size),
	}
}

func (this *ReceivingWindow) Size() uint32 {
	return this.size
}

func (this *ReceivingWindow) Position(idx uint32) uint32 {
	return (idx + this.start) % this.size
}

func (this *ReceivingWindow) Set(idx uint32, value *DataSegment) bool {
	pos := this.Position(idx)
	if this.list[pos] != nil {
		return false
	}
	this.list[pos] = value
	return true
}

func (this *ReceivingWindow) Remove(idx uint32) *DataSegment {
	pos := this.Position(idx)
	e := this.list[pos]
	this.list[pos] = nil
	return e
}

func (this *ReceivingWindow) RemoveFirst() *DataSegment {
	return this.Remove(0)
}

func (this *ReceivingWindow) Advance() {
	this.start++
	if this.start == this.size {
		this.start = 0
	}
}

type ReceivingQueue struct {
	sync.RWMutex
	closed  bool
	cache   *alloc.Buffer
	queue   chan *alloc.Buffer
	timeout time.Time
}

func NewReceivingQueue() *ReceivingQueue {
	return &ReceivingQueue{
		queue: make(chan *alloc.Buffer, effectiveConfig.ReadBuffer/effectiveConfig.Mtu),
	}
}

func (this *ReceivingQueue) Read(buf []byte) (int, error) {
	if this.cache.Len() > 0 {
		nBytes, err := this.cache.Read(buf)
		if this.cache.IsEmpty() {
			this.cache.Release()
			this.cache = nil
		}
		return nBytes, err
	}

	var totalBytes int

L:
	for totalBytes < len(buf) {
		timeToSleep := time.Millisecond
		select {
		case payload, open := <-this.queue:
			if !open {
				return totalBytes, io.EOF
			}
			nBytes, err := payload.Read(buf)
			totalBytes += nBytes
			if err != nil {
				return totalBytes, err
			}
			if !payload.IsEmpty() {
				this.cache = payload
			}
			buf = buf[nBytes:]
		case <-time.After(timeToSleep):
			if totalBytes > 0 {
				break L
			}
			this.RLock()
			if !this.timeout.IsZero() && this.timeout.Before(time.Now()) {
				this.RUnlock()
				return totalBytes, errTimeout
			}
			this.RUnlock()
			timeToSleep += 500 * time.Millisecond
		}
	}

	return totalBytes, nil
}

func (this *ReceivingQueue) Put(payload *alloc.Buffer) {
	this.RLock()
	defer this.RUnlock()

	if this.closed {
		payload.Release()
		return
	}

	this.queue <- payload
}

func (this *ReceivingQueue) SetReadDeadline(t time.Time) error {
	this.Lock()
	defer this.Unlock()

	this.timeout = t
	return nil
}

func (this *ReceivingQueue) Close() {
	this.Lock()
	defer this.Unlock()

	if this.closed {
		return
	}
	this.closed = true
	close(this.queue)
}

type ACKList struct {
	timestamps []uint32
	numbers    []uint32
}

func (this *ACKList) Add(number uint32, timestamp uint32) {
	this.timestamps = append(this.timestamps, timestamp)
	this.numbers = append(this.numbers, number)
}

func (this *ACKList) Clear(una uint32) bool {
	count := 0
	for i := 0; i < len(this.numbers); i++ {
		if this.numbers[i] >= una {
			if i != count {
				this.numbers[count] = this.numbers[i]
				this.timestamps[count] = this.timestamps[i]
			}
			count++
		}
	}
	if count < len(this.numbers) {
		this.numbers = this.numbers[:count]
		this.timestamps = this.timestamps[:count]
		return true
	}
	return false
}

func (this *ACKList) AsSegment() *ACKSegment {
	count := len(this.numbers)
	if count == 0 {
		return nil
	}

	if count > 128 {
		count = 128
	}
	seg := &ACKSegment{
		Count:         byte(count),
		NumberList:    this.numbers[:count],
		TimestampList: this.timestamps[:count],
	}
	//this.numbers = nil
	//this.timestamps = nil
	return seg
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/captainju/gogal/util"
	"github.com/joho/godotenv"
	"github.com/nfnt/resize"
	"github.com/rwcarlsen/goexif/exif"
	"image/jpeg"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"sort"
	"strconv"
	"sync"
	"time"
)

var (
	wg sync.WaitGroup
	//mongoPhotoStore util.MongoPhotoStore
	jsonFilePhotoStore    util.JsonFilePhotoStore
	s3Manager             util.S3Manager
	cloudFrontManager     util.CloudFrontManager
	imageSourceFolderPath string
	httpPort              string
	cookieDomain          string
)

func main() {
	log.Println("Initializing...")
	loadEnvVars()
	initS3Manager()
	//initMongoPhotoStore()
	initJsonFilePhotoStore()
	initCloudFrontManager()
	log.Println("Init ok")

	back := flag.Bool("back", false, "detect, resize and upload pictures")
	eraseDB := flag.Bool("erasedb", false, "if running in back mode, replace data in DB")
	flag.Parse()

	if *back {
		runAsBack(*eraseDB)
	} else {
		runAsFront()
	}
}

func runAsFront() {
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
	serveSingle("/", "static/main.html")
	http.HandleFunc("/albums.json", albumsHandler)
	http.HandleFunc("/images.json", imagesHandler)
	log.Println("Listening... ", ":"+httpPort)
	log.Println(http.ListenAndServe(":"+httpPort, nil))
}

func albumsHandler(w http.ResponseWriter, r *http.Request) {
	albums := []string{}
PhtotSreamLoop:
	for _, photo := range jsonFilePhotoStore.GetAll() {
		timestamp := strconv.Itoa(photo.AlbumDateTime)
		for _, b := range albums {
			if b == timestamp {
				continue PhtotSreamLoop
			}
		}
		albums = append(albums, timestamp)
	}
	sort.Sort(sort.Reverse(sort.StringSlice(albums)))
	slcB, _ := json.Marshal(albums)
	w.Header().Set("Content-Type", "application/javascript")
	cloudFrontManager.WriteCookies(w, cookieDomain)
	fmt.Fprintf(w, string(slcB))
}

func imagesHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()

	photos := []util.Photo{}

	for _, photo := range jsonFilePhotoStore.GetAll() {
		photoAlbumTimestamp := strconv.Itoa(photo.AlbumDateTime)
		for _, albumTimestamp := range r.Form["albums"] {
			if albumTimestamp == photoAlbumTimestamp {
				photo.ThumbUrl = cloudFrontManager.BaseUrl + "/" + s3Manager.ThumbPath + photo.Filename
				photo.MediumUrl = cloudFrontManager.BaseUrl + "/" + s3Manager.MediumPath + photo.Filename
				photos = append(photos, photo)
			}
		}
	}

	sort.Sort(util.ByDateTime(photos))
	slcB, _ := json.Marshal(photos)
	w.Header().Set("Content-Type", "application/javascript")
	fmt.Fprintf(w, string(slcB))
}

func serveSingle(pattern string, filename string) {
	http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, filename)
	})
}

func runAsBack(eraseDb bool) {
	var res []os.FileInfo
	var err error
	res, err = ioutil.ReadDir(imageSourceFolderPath)
	if err != nil {
		panic(err)
	}

	if eraseDb {
		jsonFilePhotoStore.RemoveStorageFile()
		jsonFilePhotoStore.Touch()
	}

	for _, fileInfo := range res {
		if !fileInfo.IsDir() {
			wg.Add(1)
			go handleFile(fileInfo.Name())
		}
	}
	wg.Wait()
}

func loadEnvVars() {
	godotenv.Load()
	imageSourceFolderPath = os.Getenv("IMAGE_SOURCE_FOLDER_PATH")
	if imageSourceFolderPath == "" {
		panic("image source folder path not configured")
	}
	_, err := os.Open(imageSourceFolderPath)
	if err != nil {
		panic("can't access image source folder path : " + err.Error())
	}
	httpPort = os.Getenv("HTTP_PORT_LISTEN")
	if httpPort == "" {
		panic("http listen port not configured")
	}
	cookieDomain = os.Getenv("COOKIE_DOMAIN")
	if cookieDomain == "" {
		panic("cookie domain not configured")
	}
	log.Println("image folder ok")
}

func initS3Manager() {
	s3Manager = util.S3Manager{
		Bucket:              os.Getenv("S3_BUCKET"),
		Region:              os.Getenv("S3_REGION"),
		ImagePath:           os.Getenv("S3_IMAGE_FOLDER_PATH"),
		ThumbPath:           os.Getenv("S3_THUMB_FOLDER_PATH"),
		MediumPath:          os.Getenv("S3_MEDIUM_FOLDER_PATH"),
		NbConcurrentUploads: 2,
	}
	err := s3Manager.Connect()
	if err != nil {
		panic("Error S3 : " + err.Error())
	}
	log.Println("S3 ok")
}

/*func initMongoPhotoStore() {
	mongoPhotoStore = util.MongoPhotoStore{
		Url:            os.Getenv("MONGODB_URL"),
		DbName:         os.Getenv("MONGODB_DB_NAME"),
		CollectionName: os.Getenv("MONGODB_COLLECTION_NAME"),
	}
	err := mongoPhotoStore.Ping()
	if err != nil {
		panic("Error mongodb : " + err.Error())
	}
	log.Println("MongoDB ok")
}*/

func initJsonFilePhotoStore() {
	jsonFilePhotoStore = util.JsonFilePhotoStore{
		FileName: os.Getenv("JSON_FILE_NAME"),
	}
	err := jsonFilePhotoStore.Touch()
	if err != nil {
		panic("Error file : " + err.Error())
	}
	err = jsonFilePhotoStore.LoadFromFile()
	if err != nil {
		panic("Error loading photos : " + err.Error())
	}
	log.Println("JsonFilePhotoStore ok")
}

func initCloudFrontManager() {
	cloudFrontManager = util.CloudFrontManager{
		BaseUrl:        os.Getenv("CLOUDFRONT_BASE_URL"),
		PrivateKeyFile: os.Getenv("CLOUDFRONT_PRIVATE_KEY_FILE"),
		KeyId:          os.Getenv("CLOUDFRONT_KEY_ID"),
		Expiration:     1,
	}
	if cloudFrontManager.BaseUrl == "" || cloudFrontManager.PrivateKeyFile == "" || cloudFrontManager.KeyId == "" {
		panic("Error CloudFront : not configured")
	}
	err := cloudFrontManager.Init()
	if err != nil {
		panic("Error CloudFront : " + err.Error())
	}
	log.Println("CloudFront ok")
}

func handleFile(sourceFilename string) {
	defer wg.Done()

	photo, err := jsonFilePhotoStore.Get(sourceFilename)
	if err != nil {
		photo, err = createPhoto(sourceFilename)
		if err != nil {
			log.Printf("Can't create photo from %s : %s\n", sourceFilename, err.Error())
			return
		}
		err = jsonFilePhotoStore.Add(photo)
		if err != nil {
			log.Printf("Can't store photo from %s : %s\n", sourceFilename, err.Error())
			return
		}
		jsonFilePhotoStore.StoreToFile()
	}

	if !s3Manager.ExistsImage(sourceFilename) {
		f, err := os.Open(imageSourceFolderPath + sourceFilename)
		if err != nil {
			log.Println(err)
		} else {
			s3Manager.UploadImage(f, sourceFilename)
		}
	}

	if !s3Manager.ExistsThumb(sourceFilename) {
		f, err := os.Open(imageSourceFolderPath + sourceFilename)
		if err != nil {
			log.Println(err)
		} else {
			log.Printf("Resizing %s", sourceFilename)
			buf := bytes.NewBuffer(make([]byte, 0))
			resizeImg(f, buf, 0, 162)
			log.Printf("%s successfully resized", sourceFilename)
			r := bytes.NewReader(buf.Bytes())
			s3Manager.UploadThumb(r, sourceFilename)
		}
	}

	if !s3Manager.ExistsMedium(sourceFilename) {
		f, err := os.Open(imageSourceFolderPath + sourceFilename)
		if err != nil {
			log.Println(err)
		} else {
			log.Printf("Resizing %s", sourceFilename)
			buf := bytes.NewBuffer(make([]byte, 0))
			resizeImg(f, buf, 0, 768)
			log.Printf("%s successfully resized", sourceFilename)
			r := bytes.NewReader(buf.Bytes())
			s3Manager.UploadMedium(r, sourceFilename)
		}
	}
}

func createPhoto(sourceFilename string) (util.Photo, error) {
	photo := util.Photo{}

	f, err := os.Open(imageSourceFolderPath + sourceFilename)
	if err != nil {
		log.Println(err)
		return photo, err
	}

	x, err := exif.Decode(f)
	if err != nil {
		log.Println(sourceFilename, err)
		return photo, err
	}
	tm, _ := x.DateTime()
	if false {
		log.Println("Taken: ", tm)
	}

	albumTime := time.Date(tm.Year(), tm.Month(), tm.Day(), 0, 0, 0, 0, time.UTC)
	photo.AlbumDateTime = int(albumTime.Unix())
	photo.DateTime = int(tm.Unix())
	photo.Filename = sourceFilename
	return photo, nil
}

func resizeImg(r io.Reader, w io.Writer, width uint, height uint) {
	// decode jpeg into image.Image
	img, err := jpeg.Decode(r)
	if err != nil {
		log.Println(err)
		return
	}

	// resize using Lanczos resampling
	// and preserve aspect ratio
	m := resize.Resize(width, height, img, resize.Lanczos3)

	// write new image to file
	jpeg.Encode(w, m, nil)
}
<commit_msg>fcgi server<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/captainju/gogal/util"
	"github.com/joho/godotenv"
	"github.com/nfnt/resize"
	"github.com/rwcarlsen/goexif/exif"
	"image/jpeg"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/fcgi"
	"os"
	"sort"
	"strconv"
	"sync"
	"time"
)

var (
	wg sync.WaitGroup
	//mongoPhotoStore util.MongoPhotoStore
	jsonFilePhotoStore    util.JsonFilePhotoStore
	s3Manager             util.S3Manager
	cloudFrontManager     util.CloudFrontManager
	imageSourceFolderPath string
	httpPort              string
	cookieDomain          string
)

func main() {
	log.Println("Initializing...")
	loadEnvVars()
	initS3Manager()
	//initMongoPhotoStore()
	initJsonFilePhotoStore()
	initCloudFrontManager()
	log.Println("Init ok")

	back := flag.Bool("back", false, "detect, resize and upload pictures")
	eraseDB := flag.Bool("erasedb", false, "if running in back mode, replace data in DB")
	fcgiServer := flag.Bool("fcgi", false, "run as a FastCGI server")
	flag.Parse()

	if *back {
		runAsBack(*eraseDB)
	} else {
		runAsFront(*fcgiServer)
	}
}

type FastCGIServer struct{}

func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	resp.Write([]byte("
Hello, 世界
\n
Behold my Go web app.
"))
}

func runAsFront(fcgiServer bool) {
	if fcgiServer {
		listener, _ := net.Listen("tcp", ":"+httpPort)
		srv := new(FastCGIServer)
		log.Println("Running as a FastCGI server on", listener.Addr().String())
		log.Println(fcgi.Serve(listener, srv))
	} else {
		http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
		serveSingle("/", "static/main.html")
		http.HandleFunc("/albums.json", albumsHandler)
		http.HandleFunc("/images.json", imagesHandler)
		log.Println("Listening... ", ":"+httpPort)
		log.Println(http.ListenAndServe(":"+httpPort, nil))
	}
}

func albumsHandler(w http.ResponseWriter, r *http.Request) {
	albums := []string{}
PhtotSreamLoop:
	for _, photo := range jsonFilePhotoStore.GetAll() {
		timestamp := strconv.Itoa(photo.AlbumDateTime)
		for _, b := range albums {
			if b == timestamp {
				continue PhtotSreamLoop
			}
		}
		albums = append(albums, timestamp)
	}
	sort.Sort(sort.Reverse(sort.StringSlice(albums)))
	slcB, _ := json.Marshal(albums)
	w.Header().Set("Content-Type", "application/javascript")
	cloudFrontManager.WriteCookies(w, cookieDomain)
	fmt.Fprintf(w, string(slcB))
}

func imagesHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()

	photos := []util.Photo{}

	for _, photo := range jsonFilePhotoStore.GetAll() {
		photoAlbumTimestamp := strconv.Itoa(photo.AlbumDateTime)
		for _, albumTimestamp := range r.Form["albums"] {
			if albumTimestamp == photoAlbumTimestamp {
				photo.ThumbUrl = cloudFrontManager.BaseUrl + "/" + s3Manager.ThumbPath + photo.Filename
				photo.MediumUrl = cloudFrontManager.BaseUrl + "/" + s3Manager.MediumPath + photo.Filename
				photos = append(photos, photo)
			}
		}
	}

	sort.Sort(util.ByDateTime(photos))
	slcB, _ := json.Marshal(photos)
	w.Header().Set("Content-Type", "application/javascript")
	fmt.Fprintf(w, string(slcB))
}

func serveSingle(pattern string, filename string) {
	http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, filename)
	})
}

func runAsBack(eraseDb bool) {
	var res []os.FileInfo
	var err error
	res, err = ioutil.ReadDir(imageSourceFolderPath)
	if err != nil {
		panic(err)
	}

	if eraseDb {
		jsonFilePhotoStore.RemoveStorageFile()
		jsonFilePhotoStore.Touch()
	}

	for _, fileInfo := range res {
		if !fileInfo.IsDir() {
			wg.Add(1)
			//Todo : use a buffered channel for handling files
			go handleFile(fileInfo.Name())
		}
	}
	wg.Wait()
	jsonFilePhotoStore.StoreToFile()
}

func loadEnvVars() {
	godotenv.Load()
	imageSourceFolderPath = os.Getenv("IMAGE_SOURCE_FOLDER_PATH")
	if imageSourceFolderPath == "" {
		panic("image source folder path not configured")
	}
	_, err := os.Open(imageSourceFolderPath)
	if err != nil {
		panic("can't access image source folder path : " + err.Error())
	}
	httpPort = os.Getenv("HTTP_PORT_LISTEN")
	if httpPort == "" {
		panic("http listen port not configured")
	}
	cookieDomain = os.Getenv("COOKIE_DOMAIN")
	if cookieDomain == "" {
		panic("cookie domain not configured")
	}
	log.Println("image folder ok")
}

func initS3Manager() {
	s3Manager = util.S3Manager{
		Bucket:              os.Getenv("S3_BUCKET"),
		Region:              os.Getenv("S3_REGION"),
		ImagePath:           os.Getenv("S3_IMAGE_FOLDER_PATH"),
		ThumbPath:           os.Getenv("S3_THUMB_FOLDER_PATH"),
		MediumPath:          os.Getenv("S3_MEDIUM_FOLDER_PATH"),
		NbConcurrentUploads: 2,
	}
	err := s3Manager.Connect()
	if err != nil {
		panic("Error S3 : " + err.Error())
	}
	log.Println("S3 ok")
}

/*func initMongoPhotoStore() {
	mongoPhotoStore = util.MongoPhotoStore{
		Url:            os.Getenv("MONGODB_URL"),
		DbName:         os.Getenv("MONGODB_DB_NAME"),
		CollectionName: os.Getenv("MONGODB_COLLECTION_NAME"),
	}
	err := mongoPhotoStore.Ping()
	if err != nil {
		panic("Error mongodb : " + err.Error())
	}
	log.Println("MongoDB ok")
}*/

func initJsonFilePhotoStore() {
	jsonFilePhotoStore = util.JsonFilePhotoStore{
		FileName: os.Getenv("JSON_FILE_NAME"),
	}
	err := jsonFilePhotoStore.Touch()
	if err != nil {
		panic("Error file : " + err.Error())
	}
	err = jsonFilePhotoStore.LoadFromFile()
	if err != nil {
		panic("Error loading photos : " + err.Error())
	}
	log.Println("JsonFilePhotoStore ok")
}

func initCloudFrontManager() {
	cloudFrontManager = util.CloudFrontManager{
		BaseUrl:        os.Getenv("CLOUDFRONT_BASE_URL"),
		PrivateKeyFile: os.Getenv("CLOUDFRONT_PRIVATE_KEY_FILE"),
		KeyId:          os.Getenv("CLOUDFRONT_KEY_ID"),
		Expiration:     1,
	}
	if cloudFrontManager.BaseUrl == "" || cloudFrontManager.PrivateKeyFile == "" || cloudFrontManager.KeyId == "" {
		panic("Error CloudFront : not configured")
	}
	err := cloudFrontManager.Init()
	if err != nil {
		panic("Error CloudFront : " + err.Error())
	}
	log.Println("CloudFront ok")
}

func handleFile(sourceFilename string) {
	defer wg.Done()

	photo, err := jsonFilePhotoStore.Get(sourceFilename)
	if err != nil {
		photo, err = createPhoto(sourceFilename)
		if err != nil {
			log.Printf("Can't create photo from %s : %s\n", sourceFilename, err.Error())
			return
		}
		err = jsonFilePhotoStore.Add(photo)
		if err != nil {
			log.Printf("Can't store photo from %s : %s\n", sourceFilename, err.Error())
			return
		}
	}

	if !s3Manager.ExistsImage(sourceFilename) {
		f, err := os.Open(imageSourceFolderPath + sourceFilename)
		if err != nil {
			log.Println(err)
		} else {
			s3Manager.UploadImage(f, sourceFilename)
		}
	}

	if !s3Manager.ExistsThumb(sourceFilename) {
		f, err := os.Open(imageSourceFolderPath + sourceFilename)
		if err != nil {
			log.Println(err)
		} else {
			log.Printf("Resizing %s", sourceFilename)
			buf := bytes.NewBuffer(make([]byte, 0))
			resizeImg(f, buf, 0, 162)
			log.Printf("%s successfully resized", sourceFilename)
			r := bytes.NewReader(buf.Bytes())
			s3Manager.UploadThumb(r, sourceFilename)
		}
	}

	if !s3Manager.ExistsMedium(sourceFilename) {
		f, err := os.Open(imageSourceFolderPath + sourceFilename)
		if err != nil {
			log.Println(err)
		} else {
			log.Printf("Resizing %s", sourceFilename)
			buf := bytes.NewBuffer(make([]byte, 0))
			resizeImg(f, buf, 0, 768)
			log.Printf("%s successfully resized", sourceFilename)
			r := bytes.NewReader(buf.Bytes())
			s3Manager.UploadMedium(r, sourceFilename)
		}
	}
}

func createPhoto(sourceFilename string) (util.Photo, error) {
	photo := util.Photo{}

	f, err := os.Open(imageSourceFolderPath + sourceFilename)
	if err != nil {
		log.Println(err)
		return photo, err
	}

	x, err := exif.Decode(f)
	if err != nil {
		log.Println(sourceFilename, err)
		return photo, err
	}
	tm, _ := x.DateTime()
	if false {
		log.Println("Taken: ", tm)
	}

	albumTime := time.Date(tm.Year(), tm.Month(), tm.Day(), 0, 0, 0, 0, time.UTC)
	photo.AlbumDateTime = int(albumTime.Unix())
	photo.DateTime = int(tm.Unix())
	photo.Filename = sourceFilename
	return photo, nil
}

func resizeImg(r io.Reader, w io.Writer, width uint, height uint) {
	// decode jpeg into image.Image
	img, err := jpeg.Decode(r)
	if err != nil {
		log.Println(err)
		return
	}

	// resize using Lanczos resampling
	// and preserve aspect ratio
	m := resize.Resize(width, height, img, resize.Lanczos3)

	// write new image to file
	jpeg.Encode(w, m, nil)
}
<|endoftext|>