<commit_before>/*
Copyright 2018 The Skaffold Authors

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 acr

import (
	"bufio"
	"context"
	"io"
	"net/http"
	"strings"
	"time"

	cr "github.com/Azure/azure-sdk-for-go/services/containerregistry/mgmt/2018-09-01/containerregistry"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/pkg/errors"
)

const BuildStatusHeader = "x-ms-meta-Complete"

func (b *Builder) Build(ctx context.Context, out io.Writer, tagger tag.Tagger, artifacts []*latest.Artifact) ([]build.Artifact, error) {
	return build.InParallel(ctx, out, tagger, artifacts, b.buildArtifact)
}

func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, tagger tag.Tagger, artifact *latest.Artifact) (string, error) {
	client, err := b.NewRegistriesClient()
	if err != nil {
		return "", errors.Wrap(err, "")
	}

	imageTag, err := tagger.GenerateFullyQualifiedImageName(artifact.Workspace, &tag.Options{
		Digest:    util.RandomID(),
		ImageName: artifact.ImageName,
	})
	if err != nil {
		return "", errors.Wrap(err, "create fully qualified image name")
	}
	registryName := getRegistryName(imageTag)

	resourceGroup, err := getResourceGroup(ctx, client, registryName)
	if err != nil {
		return "", errors.Wrap(err, "get resource group")
	}

	result, err := client.GetBuildSourceUploadURL(ctx, resourceGroup, registryName)
	if err != nil {
		return "", errors.Wrap(err, "build source upload url")
	}
	blob := NewBlobStorage(*result.UploadURL)

	err = docker.CreateDockerTarGzContext(ctx, blob.Buffer, artifact.Workspace, artifact.DockerArtifact)
	if err != nil {
		return "", errors.Wrap(err, "create context tar.gz")
	}

	err = blob.UploadFileToBlob()
	if err != nil {
		return "", errors.Wrap(err, "upload file to blob")
	}

	//acr needs the image tag formatted as <repository>:<tag>
	imageTag = getImageTagWithoutFQDN(imageTag)

	buildRequest := cr.DockerBuildRequest{
		ImageNames:     &[]string{imageTag},
		IsPushEnabled:  util.BoolPtr(true),
		SourceLocation: result.RelativePath,
		Platform: &cr.PlatformProperties{
			Variant:      cr.V8,
			Os:           cr.Linux,
			Architecture: cr.Amd64,
		},
		DockerFilePath: &artifact.DockerArtifact.DockerfilePath,
		Type:           cr.TypeDockerBuildRequest,
	}
	future, err := client.ScheduleRun(ctx, resourceGroup, registryName, buildRequest)
	if err != nil {
		return "", errors.Wrap(err, "schedule build request")
	}

	run, err := future.Result(*client)
	if err != nil {
		return "", errors.Wrap(err, "get run id")
	}
	runID := *run.RunID

	runsClient := cr.NewRunsClient(b.SubscriptionID)
	runsClient.Authorizer = client.Authorizer
	logURL, err := runsClient.GetLogSasURL(ctx, resourceGroup, registryName, runID)
	if err != nil {
		return "", errors.Wrap(err, "get log url")
	}

	err = streamBuildLogs(*logURL.LogLink, out)
	if err != nil {
		return "", errors.Wrap(err, "polling build status")
	}

	return imageTag, nil
}

func streamBuildLogs(logURL string, out io.Writer) error {
	offset := int32(0)
	for {
		resp, err := http.Get(logURL)
		if err != nil {
			return err
		}

		if resp.StatusCode == http.StatusNotFound {
			//if blob is not available yet, try again
			time.Sleep(2 * time.Second)
			continue
		}

		scanner := bufio.NewScanner(resp.Body)
		line := int32(0)
		for scanner.Scan() {
			if line >= offset {
				out.Write(scanner.Bytes())
				out.Write([]byte("\n"))
				offset++
			}
			line++
		}
		resp.Body.Close()

		if offset > 0 {
			switch resp.Header.Get(BuildStatusHeader) {
			case "":
				continue
			case "internalerror":
			case "failed":
				return errors.New("run failed")
			case "timedout":
				return errors.New("run timed out")
			case "canceled":
				return errors.New("run was canceled")
			default:
				return nil
			}
		}

		time.Sleep(2 * time.Second)
	}
}

func getResourceGroup(ctx context.Context, client *cr.RegistriesClient, registryName string) (string, error) {
	registryList, err := client.List(ctx)
	if err != nil {
		return "", err
	}

	for _, registry := range registryList.Values() {
		if strings.ToLower(*registry.Name) == registryName {
			//registry.ID returns the exact path to the container registry
			//e.g. /subscriptions/<subscriptionId>/resourceGroups/<resourceGroup>/...
			//so the resourceGroup is the fourth element of the split
			return strings.Split(*registry.ID, "/")[4], nil
		}
	}

	return "", errors.New("Couldn't find resource group of registry")
}

func getImageTagWithoutFQDN(imageTag string) string {
	return imageTag[strings.Index(imageTag, "/")+1:]
}

//acr URL is <registryname>.azurecr.io
func getRegistryName(imageTag string) string {
	return strings.ToLower(imageTag[:strings.Index(imageTag, ".")])
}
<commit_msg>Forgot the error message<commit_after>/*
Copyright 2018 The Skaffold Authors

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 acr

import (
	"bufio"
	"context"
	"io"
	"net/http"
	"strings"
	"time"

	cr "github.com/Azure/azure-sdk-for-go/services/containerregistry/mgmt/2018-09-01/containerregistry"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/pkg/errors"
)

const BuildStatusHeader = "x-ms-meta-Complete"

func (b *Builder) Build(ctx context.Context, out io.Writer, tagger tag.Tagger, artifacts []*latest.Artifact) ([]build.Artifact, error) {
	return build.InParallel(ctx, out, tagger, artifacts, b.buildArtifact)
}

func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, tagger tag.Tagger, artifact *latest.Artifact) (string, error) {
	client, err := b.NewRegistriesClient()
	if err != nil {
		return "", errors.Wrap(err, "get new registries client")
	}

	imageTag, err := tagger.GenerateFullyQualifiedImageName(artifact.Workspace, &tag.Options{
		Digest:    util.RandomID(),
		ImageName: artifact.ImageName,
	})
	if err != nil {
		return "", errors.Wrap(err, "create fully qualified image name")
	}
	registryName := getRegistryName(imageTag)

	resourceGroup, err := getResourceGroup(ctx, client, registryName)
	if err != nil {
		return "", errors.Wrap(err, "get resource group")
	}

	result, err := client.GetBuildSourceUploadURL(ctx, resourceGroup, registryName)
	if err != nil {
		return "", errors.Wrap(err, "build source upload url")
	}
	blob := NewBlobStorage(*result.UploadURL)

	err = docker.CreateDockerTarGzContext(ctx, blob.Buffer, artifact.Workspace, artifact.DockerArtifact)
	if err != nil {
		return "", errors.Wrap(err, "create context tar.gz")
	}

	err = blob.UploadFileToBlob()
	if err != nil {
		return "", errors.Wrap(err, "upload file to blob")
	}

	//acr needs the image tag formatted as <repository>:<tag>
	imageTag = getImageTagWithoutFQDN(imageTag)

	buildRequest := cr.DockerBuildRequest{
		ImageNames:     &[]string{imageTag},
		IsPushEnabled:  util.BoolPtr(true),
		SourceLocation: result.RelativePath,
		Platform: &cr.PlatformProperties{
			Variant:      cr.V8,
			Os:           cr.Linux,
			Architecture: cr.Amd64,
		},
		DockerFilePath: &artifact.DockerArtifact.DockerfilePath,
		Type:           cr.TypeDockerBuildRequest,
	}
	future, err := client.ScheduleRun(ctx, resourceGroup, registryName, buildRequest)
	if err != nil {
		return "", errors.Wrap(err, "schedule build request")
	}

	run, err := future.Result(*client)
	if err != nil {
		return "", errors.Wrap(err, "get run id")
	}
	runID := *run.RunID

	runsClient := cr.NewRunsClient(b.SubscriptionID)
	runsClient.Authorizer = client.Authorizer
	logURL, err := runsClient.GetLogSasURL(ctx, resourceGroup, registryName, runID)
	if err != nil {
		return "", errors.Wrap(err, "get log url")
	}

	err = streamBuildLogs(*logURL.LogLink, out)
	if err != nil {
		return "", errors.Wrap(err, "polling build status")
	}

	return imageTag, nil
}

func streamBuildLogs(logURL string, out io.Writer) error {
	offset := int32(0)
	for {
		resp, err := http.Get(logURL)
		if err != nil {
			return err
		}

		if resp.StatusCode == http.StatusNotFound {
			//if blob is not available yet, try again
			time.Sleep(2 * time.Second)
			continue
		}

		scanner := bufio.NewScanner(resp.Body)
		line := int32(0)
		for scanner.Scan() {
			if line >= offset {
				out.Write(scanner.Bytes())
				out.Write([]byte("\n"))
				offset++
			}
			line++
		}
		resp.Body.Close()

		if offset > 0 {
			switch resp.Header.Get(BuildStatusHeader) {
			case "":
				continue
			case "internalerror":
			case "failed":
				return errors.New("run failed")
			case "timedout":
				return errors.New("run timed out")
			case "canceled":
				return errors.New("run was canceled")
			default:
				return nil
			}
		}

		time.Sleep(2 * time.Second)
	}
}

func getResourceGroup(ctx context.Context, client *cr.RegistriesClient, registryName string) (string, error) {
	registryList, err := client.List(ctx)
	if err != nil {
		return "", err
	}

	for _, registry := range registryList.Values() {
		if strings.ToLower(*registry.Name) == registryName {
			//registry.ID returns the exact path to the container registry
			//e.g. /subscriptions/<subscriptionId>/resourceGroups/<resourceGroup>/...
			//so the resourceGroup is the fourth element of the split
			return strings.Split(*registry.ID, "/")[4], nil
		}
	}

	return "", errors.New("Couldn't find resource group of registry")
}

func getImageTagWithoutFQDN(imageTag string) string {
	return imageTag[strings.Index(imageTag, "/")+1:]
}

//acr URL is <registryname>.azurecr.io
func getRegistryName(imageTag string) string {
	return strings.ToLower(imageTag[:strings.Index(imageTag, ".")])
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"tarsum"
)

func main() {
	ts, err := tarsum.NewTarSum(os.Stdin, false, tarsum.Version1)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if _, err = io.Copy(ioutil.Discard, ts); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println(ts.Sum(nil))
}
<commit_msg>dockerTools: disable compression in tarsum.go<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"tarsum"
)

func main() {
	ts, err := tarsum.NewTarSum(os.Stdin, true, tarsum.Version1)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if _, err = io.Copy(ioutil.Discard, ts); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println(ts.Sum(nil))
}
<|endoftext|>


<commit_before>package openfirerest

type RosterItem struct {
	JID              string   `json:"jid" xml:"jid"`
	NickName         string   `json:"nickname" xml:"nickname"`
	SubscriptionType int      `json:"subscription_type" xml:"subscriptionType"`
	Groups           []string `json:"groups" xml:"groups"`
}

const EntpointPatternRoster string = "plugins/restapi/v1/users/%s/roster"
<commit_msg>add GetRoster, AddRoter api<commit_after>package openfirerest

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type RosterGroup struct {
	Group string `json:"group" xml:"group"`
}

type RosterItem struct {
	JID              string        `json:"jid" xml:"jid"`
	NickName         string        `json:"nickname" xml:"nickname"`
	SubscriptionType int           `json:"subscriptionType" xml:"subscriptionType"`
	Groups           []RosterGroup `json:"groups" xml:"groups"`
}

const EndpointPatternRoster string = "plugins/restapi/v1/users/%s/roster"

func GetRoster(username string) ([]RosterItem, error) {
	url := "http://127.0.0.1:9090/" + fmt.Sprintf(EndpointPatternRoster, username)

	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("Authorization", "Basic YWRtaW46YWRtaW4=")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	response, _ := ioutil.ReadAll(resp.Body)
	var rosters []RosterItem
	err = json.Unmarshal(response, rosters)
	return rosters, err
}

func AddRoster(username string, roster RosterItem) error {
	url := "http://127.0.0.1:9090/" + fmt.Sprintf(EndpointPatternRoster, username)

	fmt.Println(url)
	jsonStr, err := json.Marshal(roster)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Authorization", "Basic YWRtaW46YWRtaW4=")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	payload, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(payload))
	return nil
}
<|endoftext|>


<commit_before>package account

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"
	"strconv"

	"github.com/koding/bongo"
)

// lists followed channels of an account
func ListChannels(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) {

	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	query := request.GetQuery(u)
	if query.AccountId == 0 {
		query.AccountId = accountId
	}

	if query.Type == "" {
		query.Type = models.Channel_TYPE_TOPIC
	}

	a := &models.Account{Id: accountId}
	channels, err := a.FetchChannels(query)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cc := models.NewChannelContainers()
	cc.PopulateWith(channels, query.AccountId).AddUnreadCount(query.AccountId)

	return response.HandleResultAndError(cc, cc.Err())
}

func GetAccountFromSession(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) {
	if c.Client == nil || c.Client.Account == nil {
		return response.NewNotFound()
	}

	res := map[string]interface{}{
		"id":    strconv.FormatInt(c.Client.Account.Id, 10),
		"nick":  c.Client.Account.Nick,
		"token": c.Client.Account.Token,
	}
	return response.NewOK(res)
}

func ParticipatedChannelCount(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) {
	query := request.GetQuery(u)

	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if query.Type == "" {
		query.Type = models.Channel_TYPE_TOPIC
	}
	cp := models.NewChannelParticipant()
	a := &models.Account{Id: accountId}

	return response.HandleResultAndError(cp.ParticipatedChannelCount(a, query))
}

func ListPosts(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	query := request.GetQuery(u)
	buildMessageQuery := query.Clone()

	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	// Get Group Channel
	selector := map[string]interface{}{
		"group_name":    query.GroupName,
		"type_constant": models.Channel_TYPE_GROUP,
	}

	c := models.NewChannel()
	if err := c.One(bongo.NewQS(selector)); err != nil {
		return response.NewBadRequest(err)
	}
	// fetch only channel messages
	query.Type = models.ChannelMessage_TYPE_POST
	query.AccountId = accountId
	cm := models.NewChannelMessage()
	messages, err := cm.FetchMessagesByChannelId(c.Id, query)
	if err != nil {
		return response.NewBadRequest(err)
	}

	buildMessageQuery.Limit = 3
	return response.HandleResultAndError(
		cm.BuildMessages(buildMessageQuery, messages),
	)
}

func FetchPostCount(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	query := request.GetQuery(u)

	accountId, err := request.GetId(u)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// Get Group Channel
	selector := map[string]interface{}{
		"group_name":    query.GroupName,
		"type_constant": models.Channel_TYPE_GROUP,
	}

	// first check channel existence
	c := models.NewChannel()
	if err := c.One(bongo.NewQS(selector)); err != nil {
		return response.NewBadRequest(err)
	}

	// check if user can open the channel
	ok, err := c.CanOpen(accountId)
	if err != nil {
		return response.NewBadRequest(err)
	}

	if !ok {
		return response.NewAccessDenied(nil)
	}

	// fetch user post count in koding channel
	q := request.NewQuery()
	q.AccountId = accountId
	q.Type = models.ChannelMessage_TYPE_POST
	q.GroupChannelId = c.Id
	cm := models.NewChannelMessage()

	count, err := cm.FetchTotalMessageCount(q)
	if err != nil {
		return response.NewBadRequest(err)
	}

	res := new(models.CountResponse)
	res.TotalCount = count

	return response.NewOK(res)
}

func Follow(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {
	targetId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		req.Follow(targetId),
	)
}

func Register(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {

	if err := req.FetchOrCreate(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(req)
}

func Update(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {
	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if accountId == 0 {
		return response.NewBadRequest(models.ErrAccountIdIsNotSet)
	}

	acc := models.NewAccount()
	if err := acc.ById(accountId); err != nil {
		return response.NewBadRequest(err)
	}

	acc.Nick = req.Nick

	if err := models.ValidateAccount(acc); err != nil {
		if err != models.ErrGuestsAreNotAllowed {
			return response.NewBadRequest(err)
		}
	}

	if err := acc.Update(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(acc)
}

func Unfollow(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {
	targetId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(req.Unfollow(targetId))
}

func CheckOwnership(u *url.URL, h http.Header) (int, http.Header, interface{}, error) {
	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	query := request.GetQuery(u)

	ownershipResponse := func(err error) (int, http.Header, interface{}, error) {
		var success bool
		switch err {
		case bongo.RecordNotFound:
			success = false
		case nil:
			success = true
		default:
			return response.NewBadRequest(err)
		}
		return response.NewOK(map[string]bool{"success": success})
	}

	switch query.Type {
	case "channel":
		channel := models.NewChannel()
		err = channel.One(&bongo.Query{
			Selector: map[string]interface{}{
				"id":         query.ObjectId,
				"creator_id": accountId,
			},
		})
	case "channel-message":
		channelMessage := models.NewChannelMessage()
		err = channelMessage.One(&bongo.Query{
			Selector: map[string]interface{}{
				"id":         query.ObjectId,
				"account_id": accountId,
			},
		})
	}
	return ownershipResponse(err)
}
<commit_msg>geoip: sharelocation is added to update<commit_after>package account

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"
	"strconv"

	"github.com/koding/bongo"
)

// lists followed channels of an account
func ListChannels(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) {

	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	query := request.GetQuery(u)
	if query.AccountId == 0 {
		query.AccountId = accountId
	}

	if query.Type == "" {
		query.Type = models.Channel_TYPE_TOPIC
	}

	a := &models.Account{Id: accountId}
	channels, err := a.FetchChannels(query)
	if err != nil {
		return response.NewBadRequest(err)
	}

	cc := models.NewChannelContainers()
	cc.PopulateWith(channels, query.AccountId).AddUnreadCount(query.AccountId)

	return response.HandleResultAndError(cc, cc.Err())
}

func GetAccountFromSession(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) {
	if c.Client == nil || c.Client.Account == nil {
		return response.NewNotFound()
	}

	res := map[string]interface{}{
		"id":    strconv.FormatInt(c.Client.Account.Id, 10),
		"nick":  c.Client.Account.Nick,
		"token": c.Client.Account.Token,
	}
	return response.NewOK(res)
}

func ParticipatedChannelCount(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) {
	query := request.GetQuery(u)

	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if query.Type == "" {
		query.Type = models.Channel_TYPE_TOPIC
	}
	cp := models.NewChannelParticipant()
	a := &models.Account{Id: accountId}

	return response.HandleResultAndError(cp.ParticipatedChannelCount(a, query))
}

func ListPosts(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	query := request.GetQuery(u)
	buildMessageQuery := query.Clone()

	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	// Get Group Channel
	selector := map[string]interface{}{
		"group_name":    query.GroupName,
		"type_constant": models.Channel_TYPE_GROUP,
	}

	c := models.NewChannel()
	if err := c.One(bongo.NewQS(selector)); err != nil {
		return response.NewBadRequest(err)
	}
	// fetch only channel messages
	query.Type = models.ChannelMessage_TYPE_POST
	query.AccountId = accountId
	cm := models.NewChannelMessage()
	messages, err := cm.FetchMessagesByChannelId(c.Id, query)
	if err != nil {
		return response.NewBadRequest(err)
	}

	buildMessageQuery.Limit = 3
	return response.HandleResultAndError(
		cm.BuildMessages(buildMessageQuery, messages),
	)
}

func FetchPostCount(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	query := request.GetQuery(u)

	accountId, err := request.GetId(u)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// Get Group Channel
	selector := map[string]interface{}{
		"group_name":    query.GroupName,
		"type_constant": models.Channel_TYPE_GROUP,
	}

	// first check channel existence
	c := models.NewChannel()
	if err := c.One(bongo.NewQS(selector)); err != nil {
		return response.NewBadRequest(err)
	}

	// check if user can open the channel
	ok, err := c.CanOpen(accountId)
	if err != nil {
		return response.NewBadRequest(err)
	}

	if !ok {
		return response.NewAccessDenied(nil)
	}

	// fetch user post count in koding channel
	q := request.NewQuery()
	q.AccountId = accountId
	q.Type = models.ChannelMessage_TYPE_POST
	q.GroupChannelId = c.Id
	cm := models.NewChannelMessage()

	count, err := cm.FetchTotalMessageCount(q)
	if err != nil {
		return response.NewBadRequest(err)
	}

	res := new(models.CountResponse)
	res.TotalCount = count

	return response.NewOK(res)
}

func Follow(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {
	targetId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(
		req.Follow(targetId),
	)
}

func Register(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {

	if err := req.FetchOrCreate(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(req)
}

func Update(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {
	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if accountId == 0 {
		return response.NewBadRequest(models.ErrAccountIdIsNotSet)
	}

	acc := models.NewAccount()
	if err := acc.ById(accountId); err != nil {
		return response.NewBadRequest(err)
	}

	acc.Nick = req.Nick

	if err := models.ValidateAccount(acc); err != nil {
		if err != models.ErrGuestsAreNotAllowed {
			return response.NewBadRequest(err)
		}
	}

	acc.ShareLocation = req.ShareLocation

	if err := acc.Update(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(acc)
}

func Unfollow(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) {
	targetId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(req.Unfollow(targetId))
}

func CheckOwnership(u *url.URL, h http.Header) (int, http.Header, interface{}, error) {
	accountId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	query := request.GetQuery(u)

	ownershipResponse := func(err error) (int, http.Header, interface{}, error) {
		var success bool
		switch err {
		case bongo.RecordNotFound:
			success = false
		case nil:
			success = true
		default:
			return response.NewBadRequest(err)
		}
		return response.NewOK(map[string]bool{"success": success})
	}

	switch query.Type {
	case "channel":
		channel := models.NewChannel()
		err = channel.One(&bongo.Query{
			Selector: map[string]interface{}{
				"id":         query.ObjectId,
				"creator_id": accountId,
			},
		})
	case "channel-message":
		channelMessage := models.NewChannelMessage()
		err = channelMessage.One(&bongo.Query{
			Selector: map[string]interface{}{
				"id":         query.ObjectId,
				"account_id": accountId,
			},
		})
	}
	return ownershipResponse(err)
}
<|endoftext|>


<commit_before>// collaboration package provides the logical part for the long running
// operations of collaboration worker
package collaboration

import (
	"errors"
	"fmt"
	"socialapi/workers/collaboration/models"
	"strconv"
	"time"

	"socialapi/config"

	"github.com/cenkalti/backoff"
	"github.com/koding/logging"
	"github.com/koding/redis"
	"github.com/streadway/amqp"
)

const (
	// FireEventName is a unique event name for the collaboration ping messages
	FireEventName = "fire"

	// KeyPrefix for redis
	KeyPrefix = "collaboration"
)

var (
	// durations
	//
	// send pings every 15minutes
	pingDuration = time.Second * 15

	// offset should be smaller than a ping
	offsetDuration = time.Second * 10

	// session should be terminated after this duration
	terminateSessionDuration = pingDuration * 4

	// ExpireSessionKeyDuration redis key expiration duration
	ExpireSessionKeyDuration = pingDuration * 5

	// how long the go routine will sleep
	sleepTime = terminateSessionDuration + offsetDuration

	// every go routine should be completed in this duration
	deadLineDuration = sleepTime + time.Second*5

	// errors
	//
	errSessionInvalid  = errors.New("session is invalid")
	errDeadlineReached = errors.New("couldnt process the message in deadline")
)

// Controller holds the basic context data for handlers
type Controller struct {
	log   logging.Logger
	redis *redis.RedisSession
}

// New creates a controller
func New(log logging.Logger, redis *redis.RedisSession) *Controller {
	return &Controller{
		log:   log,
		redis: redis,
	}
}

// DefaultErrHandler handles the errors for collaboration worker
func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	delivery.Nack(false, true)
	return false
}

// Ping handles the pings coming from client side
func (c *Controller) Ping(ping *models.Ping) error {
	c.log.Debug("new ping %+v", ping)

	if ping.FileId == "" {
		c.log.Error("fileId is missing %+v", ping)
		return nil
	}

	if ping.AccountId == 0 {
		c.log.Error("accountId is missing %+v", ping)
		return nil
	}

	err := c.checkIfKeyIsValid(ping)
	if err != nil && err != errSessionInvalid {
		return err
	}

	if err == errSessionInvalid {
		// key should be there
		// end the collab session
		c.log.Info("session is not valid anymore, collab should be terminated")
		return nil
	}

	err = c.wait(ping) // wait syncronously
	if err != nil && err != errSessionInvalid {
		return err
	}

	if err == errSessionInvalid {
		// key should be there
		// end the collab session
		c.log.Info("session is not valid anymore, collab should be terminated")
		return nil
	}

	return nil
}

func (c *Controller) wait(ping *models.Ping) error {
	select {
	// wait for terminate
	// (session terminate duration + and some offset)
	case <-time.After(sleepTime):
		// check if another ping is set
		// if the key is deleted, it means someone already deleted it
		return c.checkIfKeyIsValid(ping)
	case <-time.After(deadLineDuration):
		return errDeadlineReached
	}
}

func (c *Controller) checkIfKeyIsValid(ping *models.Ping) error {
	var err error
	defer func() {
		if err != nil {
			c.log.Debug("ping: %+v is not valid %+v err: %+v", ping, err)
		}
	}()

	// check the redis key if it doesnt exist
	key := PrepareFileKey(ping.FileId)
	file, err := c.redis.Get(key)
	if err != nil && err != redis.ErrNil {
		return err
	}

	if err == redis.ErrNil {
		return errSessionInvalid // key is not there
	}

	unixSec, err := strconv.ParseInt(file, 10, 64)
	if err != nil {
		// discard this case, if the time is invalid, we should not try
		// to process it again
		return errSessionInvalid // key is not valid
	}

	t := time.Unix(unixSec, 0)

	newPingTime := ping.CreatedAt
	// if sum of previous ping time and terminate session duration is before the
	// current ping time, terminate the session
	if t.Add(terminateSessionDuration).Before(newPingTime) {
		return errSessionInvalid
	}

	// session is valid
	return nil
}

func (c *Controller) EndSession(ping *models.Ping) error {
	errChan := make(chan error, 3)
	c.goWithRetry(func() error {
		return c.EndPrivateMessage(ping)
	}, errChan)

	c.goWithRetry(func() error {
		return c.UnshareVM(ping)
	}, errChan)

	c.goWithRetry(func() error {
		return c.DeleteDriveDoc(ping)
	}, errChan)

	var err error

	for errC := range errChan {
		if err == nil && errC != nil {
			err = errC
		}
	}

	return err
}

func (c *Controller) goWithRetry(f func() error, errChan chan error) {
	go func() {
		bo := backoff.NewExponentialBackOff()
		bo.InitialInterval = time.Millisecond * 250
		bo.MaxInterval = time.Second * 1
		bo.MaxElapsedTime = time.Second * 10

		ticker := backoff.NewTicker(bo)
		defer ticker.Stop()

		var err error
		for _ = range ticker.C {
			if err = f(); err != nil {
				c.log.Error("err while connecting: %s  will retry...", err.Error())
				continue
			}

			break
		}

		if err != nil {
			errChan <- err
		}

		errChan <- nil
	}()
}

func (c *Controller) EndPrivateMessage(ping *models.Ping) error {
	return nil
}

func (c *Controller) UnshareVM(ping *models.Ping) error {
	return nil
}

func (c *Controller) DeleteDriveDoc(ping *models.Ping) error {
	return nil
}

// PrepareFileKey prepares a key for redis
func PrepareFileKey(fileId string) string {
	return fmt.Sprintf(
		"%s:%s:%s",
		config.MustGet().Environment,
		KeyPrefix,
		fileId,
	)
}
<commit_msg>Socialapi: increase durations for deadlines<commit_after>// collaboration package provides the logical part for the long running
// operations of collaboration worker
package collaboration

import (
	"errors"
	"fmt"
	"socialapi/workers/collaboration/models"
	"strconv"
	"time"

	"socialapi/config"

	"github.com/cenkalti/backoff"
	"github.com/koding/logging"
	"github.com/koding/redis"
	"github.com/streadway/amqp"
)

const (
	// FireEventName is a unique event name for the collaboration ping messages
	FireEventName = "fire"

	// KeyPrefix for redis
	KeyPrefix = "collaboration"
)

var (
	// durations
	//
	// send pings every 15minutes
	pingDuration = time.Second * 15

	// offset should be smaller than a ping
	offsetDuration = time.Second * 10

	// session should be terminated after this duration
	terminateSessionDuration = pingDuration * 4

	// ExpireSessionKeyDuration redis key expiration duration
	ExpireSessionKeyDuration = pingDuration * 5

	// how long the go routine will sleep
	sleepTime = terminateSessionDuration + offsetDuration

	// every go routine should be completed in this duration
	deadLineDuration = time.Minute * 3

	// errors
	//
	errSessionInvalid  = errors.New("session is invalid")
	errDeadlineReached = errors.New("couldnt process the message in deadline")
)

// Controller holds the basic context data for handlers
type Controller struct {
	log   logging.Logger
	redis *redis.RedisSession
	conf  *config.Config
}

// New creates a controller
func New(log logging.Logger, redis *redis.RedisSession, conf *config.Config) *Controller {
	return &Controller{
		log:   log,
		redis: redis,
		conf:  conf,
	}
}

// DefaultErrHandler handles the errors for collaboration worker
func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	delivery.Nack(false, true)
	return false
}

// Ping handles the pings coming from client side
func (c *Controller) Ping(ping *models.Ping) error {
	c.log.Debug("new ping %+v", ping)

	if ping.FileId == "" {
		c.log.Error("fileId is missing %+v", ping)
		return nil
	}

	if ping.AccountId == 0 {
		c.log.Error("accountId is missing %+v", ping)
		return nil
	}

	err := c.checkIfKeyIsValid(ping)
	if err != nil && err != errSessionInvalid {
		return err
	}

	if err == errSessionInvalid {
		// key should be there
		// end the collab session
		c.log.Info("session is not valid anymore, collab should be terminated")
		return nil
	}

	err = c.wait(ping) // wait syncronously
	if err != nil && err != errSessionInvalid {
		return err
	}

	if err == errSessionInvalid {
		// key should be there
		// end the collab session
		c.log.Info("session is not valid anymore, collab should be terminated")
		return nil
	}

	return nil
}

func (c *Controller) wait(ping *models.Ping) error {
	select {
	// wait for terminate
	// (session terminate duration + and some offset)
	case <-time.After(sleepTime):
		// check if another ping is set
		// if the key is deleted, it means someone already deleted it
		return c.checkIfKeyIsValid(ping)
	case <-time.After(deadLineDuration):
		return errDeadlineReached
	}
}

func (c *Controller) checkIfKeyIsValid(ping *models.Ping) error {
	var err error
	defer func() {
		if err != nil {
			c.log.Debug("ping: %+v is not valid %+v err: %+v", ping, err)
		}
	}()

	// check the redis key if it doesnt exist
	key := PrepareFileKey(ping.FileId)
	file, err := c.redis.Get(key)
	if err != nil && err != redis.ErrNil {
		return err
	}

	if err == redis.ErrNil {
		return errSessionInvalid // key is not there
	}

	unixSec, err := strconv.ParseInt(file, 10, 64)
	if err != nil {
		// discard this case, if the time is invalid, we should not try
		// to process it again
		return errSessionInvalid // key is not valid
	}

	t := time.Unix(unixSec, 0)

	newPingTime := ping.CreatedAt
	// if sum of previous ping time and terminate session duration is before the
	// current ping time, terminate the session
	if t.Add(terminateSessionDuration).Before(newPingTime) {
		return errSessionInvalid
	}

	// session is valid
	return nil
}

func (c *Controller) EndSession(ping *models.Ping) error {
	errChan := make(chan error, 3)
	c.goWithRetry(func() error {
		return c.EndPrivateMessage(ping)
	}, errChan)

	c.goWithRetry(func() error {
		return c.UnshareVM(ping)
	}, errChan)

	c.goWithRetry(func() error {
		return c.DeleteDriveDoc(ping)
	}, errChan)

	var err error

	for errC := range errChan {
		if err == nil && errC != nil {
			err = errC
		}
	}

	return err
}

func (c *Controller) goWithRetry(f func() error, errChan chan error) {
	go func() {
		bo := backoff.NewExponentialBackOff()
		bo.InitialInterval = time.Millisecond * 250
		bo.MaxInterval = time.Second * 1
		bo.MaxElapsedTime = time.Minute * 2 // channel message can take some time

		ticker := backoff.NewTicker(bo)
		defer ticker.Stop()

		var err error
		for _ = range ticker.C {
			if err = f(); err != nil {
				c.log.Error("err while connecting: %s  will retry...", err.Error())
				continue
			}

			break
		}

		if err != nil {
			errChan <- err
		}

		errChan <- nil
	}()
}

func (c *Controller) EndPrivateMessage(ping *models.Ping) error {
	return nil
}

func (c *Controller) UnshareVM(ping *models.Ping) error {
	return nil
}

func (c *Controller) DeleteDriveDoc(ping *models.Ping) error {
	return nil
}

// PrepareFileKey prepares a key for redis
func PrepareFileKey(fileId string) string {
	return fmt.Sprintf(
		"%s:%s:%s",
		config.MustGet().Environment,
		KeyPrefix,
		fileId,
	)
}
<|endoftext|>


<commit_before>package docker

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"syscall"
	"time"

	"google.golang.org/cloud/datastore"
)

// Config holds the configuration needed for a docker run
type Config struct {
	Image,
	Volume,
	Code,
	User string
	Challenge *datastore.Key
}

// Rusage is is a copy of syscall.Rusage for Linux.
// It is needed as syscall.Rusage built on Windows cannot be saved in Datastore
// because it holds unsigned integers. Runs are executed inside Docker and
// therefore will always generate this version of syscall.Rusage.
// See https://godoc.org/google.golang.org/cloud/datastore#Property
// See https://golang.org/src/syscall/syscall_windows.go
// See https://golang.org/src/syscall/ztypes_linux_amd64.go
type Rusage struct {
	Utime,
	Stime syscall.Timeval
	Maxrss,
	Ixrss,
	Idrss,
	Isrss,
	Minflt,
	Majflt,
	Nswap,
	Inblock,
	Oublock,
	Msgsnd,
	Msgrcv,
	Nsignals,
	Nvcsw,
	Nivcsw int64
}

const volumePattern string = "coduno-volume"
const imagePattern string = "coduno/fingerprint-"

// NewConfig constructs a Config to run the specfied image
// using the given volume.
// If volume is left blank, NewConfig will take care of
// creating a temporary directory.
func NewConfig(image, volume, code string) (c *Config, err error) {
	if volume == "" {
		volume, err = volumeDir()
	}
	c = &Config{
		Image:  image,
		Volume: volume,
		Code:   code,
	}
	return
}

// Result holds the results (standard output and standard error)
// of a Config that was run.
type Result struct {
	Config
	Stdout     string
	Stderr     string
	Rusage     Rusage
	Prepare    string
	Exit       string
	Start, End time.Time
}

// Run executes a Config and returns associated results.
func (c *Config) Run() (r *Result, err error) {
	r = &Result{Config: *c}
	dockerized, err := dockerize(c.Volume)

	if err != nil {
		return
	}

	cmd := exec.Command(
		"docker",
		"run",
		"-v",
		dockerized+":/run",
		c.Image,
	)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		return
	}
	r.Start = time.Now()
	if err = cmd.Start(); err != nil {
		return
	}

	bufout, buferr := new(bytes.Buffer), new(bytes.Buffer)

	go io.Copy(io.MultiWriter(os.Stdout, bufout), stdout)
	go io.Copy(io.MultiWriter(os.Stdout, buferr), stderr)

	err = cmd.Wait()
	if err != nil {
		r.Exit = err.Error()
	}
	r.End = time.Now()
	r.Stdout = bufout.String()
	r.Stderr = buferr.String()
	b, _ := ioutil.ReadFile(path.Join(c.Volume, "prepare.log"))
	r.Prepare = string(b)

	stats, _ := os.Open(path.Join(c.Volume, "stats.log"))
	json.NewDecoder(stats).Decode(&r.Rusage)
	return
}

// NewImage returns the correct docker image name for a
// specific language.
func NewImage(language string) string {
	return imagePattern + language
}
<commit_msg>hot: Stay calm if cmd fails<commit_after>package docker

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"syscall"
	"time"

	"google.golang.org/cloud/datastore"
)

// Config holds the configuration needed for a docker run
type Config struct {
	Image,
	Volume,
	Code,
	User string
	Challenge *datastore.Key
}

// Rusage is is a copy of syscall.Rusage for Linux.
// It is needed as syscall.Rusage built on Windows cannot be saved in Datastore
// because it holds unsigned integers. Runs are executed inside Docker and
// therefore will always generate this version of syscall.Rusage.
// See https://godoc.org/google.golang.org/cloud/datastore#Property
// See https://golang.org/src/syscall/syscall_windows.go
// See https://golang.org/src/syscall/ztypes_linux_amd64.go
type Rusage struct {
	Utime,
	Stime syscall.Timeval
	Maxrss,
	Ixrss,
	Idrss,
	Isrss,
	Minflt,
	Majflt,
	Nswap,
	Inblock,
	Oublock,
	Msgsnd,
	Msgrcv,
	Nsignals,
	Nvcsw,
	Nivcsw int64
}

const volumePattern string = "coduno-volume"
const imagePattern string = "coduno/fingerprint-"

// NewConfig constructs a Config to run the specfied image
// using the given volume.
// If volume is left blank, NewConfig will take care of
// creating a temporary directory.
func NewConfig(image, volume, code string) (c *Config, err error) {
	if volume == "" {
		volume, err = volumeDir()
	}
	c = &Config{
		Image:  image,
		Volume: volume,
		Code:   code,
	}
	return
}

// Result holds the results (standard output and standard error)
// of a Config that was run.
type Result struct {
	Config
	Stdout     string
	Stderr     string
	Rusage     Rusage
	Prepare    string
	Exit       string
	Start, End time.Time
}

// Run executes a Config and returns associated results.
func (c *Config) Run() (r *Result, err error) {
	r = &Result{Config: *c}
	dockerized, err := dockerize(c.Volume)

	if err != nil {
		return
	}

	cmd := exec.Command(
		"docker",
		"run",
		"-v",
		dockerized+":/run",
		c.Image,
	)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		return
	}
	r.Start = time.Now()
	if err = cmd.Start(); err != nil {
		return
	}

	bufout, buferr := new(bytes.Buffer), new(bytes.Buffer)

	go io.Copy(io.MultiWriter(os.Stdout, bufout), stdout)
	go io.Copy(io.MultiWriter(os.Stdout, buferr), stderr)

	cmdErr := cmd.Wait()
	if cmdErr != nil {
		r.Exit = cmdErr.Error()
	}
	r.End = time.Now()
	r.Stdout = bufout.String()
	r.Stderr = buferr.String()
	b, _ := ioutil.ReadFile(path.Join(c.Volume, "prepare.log"))
	r.Prepare = string(b)

	stats, _ := os.Open(path.Join(c.Volume, "stats.log"))
	json.NewDecoder(stats).Decode(&r.Rusage)
	return
}

// NewImage returns the correct docker image name for a
// specific language.
func NewImage(language string) string {
	return imagePattern + language
}
<|endoftext|>


<commit_before>package docker

import (
	"bufio"
	"bytes"
	"context"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
)

const host = `DOCKER_HOST`
const version = `DOCKER_VERSION`
const configurationFile = `./users`

var commaByte = []byte(`,`)
var listRequest = regexp.MustCompile(`/containers/?$`)
var containerRequest = regexp.MustCompile(`/containers/([^/]+)/?$`)
var startRequest = regexp.MustCompile(`/containers/([^/]+)/start`)
var stopRequest = regexp.MustCompile(`/containers/([^/]+)/stop`)
var restartRequest = regexp.MustCompile(`/containers/([^/]+)/restart`)
var logRequest = regexp.MustCompile(`/containers/([^/]+)/logs`)

type results struct {
	Results interface{} `json:"results"`
}

type user struct {
	username string
	password string
}

var docker *client.Client
var users map[string]*user

func handleError(w http.ResponseWriter, err error) {
	log.Print(err)
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

func readConfiguration(path string) map[string]*user {
	configFile, err := os.Open(path)
	defer configFile.Close()

	if err != nil {
		log.Print(err)
		return nil
	}

	users := make(map[string]*user)

	scanner := bufio.NewScanner(configFile)
	for scanner.Scan() {
		parts := bytes.Split(scanner.Bytes(), commaByte)
		user := user{string(parts[0]), string(parts[1])}

		users[strings.ToLower(user.username)] = &user
	}

	return users
}

func init() {
	users = readConfiguration(configurationFile)

	client, err := client.NewClient(os.Getenv(host), os.Getenv(version), nil, nil)
	if err != nil {
		log.Fatal(err)
	} else {
		docker = client
	}
}

func inspectContainer(w http.ResponseWriter, containerID []byte) {
	if container, err := docker.ContainerInspect(context.Background(), string(containerID)); err != nil {
		handleError(w, err)
	} else {
		jsonHttp.ResponseJSON(w, container)
	}
}

func startContainer(w http.ResponseWriter, containerID []byte) {
	if err := docker.ContainerStart(context.Background(), string(containerID), types.ContainerStartOptions{}); err != nil {
		handleError(w, err)
	} else {
		w.Write(nil)
	}
}

func stopContainer(w http.ResponseWriter, containerID []byte) {
	if err := docker.ContainerStop(context.Background(), string(containerID), nil); err != nil {
		handleError(w, err)
	} else {
		w.Write(nil)
	}
}

func restartContainer(w http.ResponseWriter, containerID []byte) {
	if err := docker.ContainerRestart(context.Background(), string(containerID), nil); err != nil {
		handleError(w, err)
	} else {
		w.Write(nil)
	}
}

func logContainer(w http.ResponseWriter, containerID []byte) {
	logs, err := docker.ContainerLogs(context.Background(), string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: false})
	if err != nil {
		handleError(w, err)
		return
	}

	logReader := bufio.NewReader(logs)
	logLines := make([][]byte)
	logLine, err := logReader.ReadBytes(byte(`\n`))
	for err != nil {
		logLines = append(logLines, logLine[8:])
		logLine, err = logReader.ReadBytes(byte(`\n`))
	}

	w.Write(logLines)
}

func listContainers(w http.ResponseWriter) {
	if containers, err := docker.ContainerList(context.Background(), types.ContainerListOptions{}); err != nil {
		handleError(w, err)
	} else {
		jsonHttp.ResponseJSON(w, results{containers})
	}
}

func isAuthenticated(r *http.Request) bool {
	username, password, ok := r.BasicAuth()

	if ok {
		user, ok := users[strings.ToLower(username)]

		if ok && user.password == password {
			return true
		}
	}

	return false
}

func unauthorized(w http.ResponseWriter) {
	http.Error(w, `Authentication required`, http.StatusUnauthorized)
}

// Handler for Hello request. Should be use with net/http
type Handler struct {
}

func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add(`Access-Control-Allow-Origin`, `*`)
	w.Header().Add(`Access-Control-Allow-Headers`, `Content-Type, Authorization`)
	w.Header().Add(`Access-Control-Allow-Methods`, `GET, POST`)
	w.Header().Add(`X-Content-Type-Options`, `nosniff`)

	if r.Method == http.MethodOptions {
		w.Write(nil)
		return
	}

	urlPath := []byte(r.URL.Path)

	if listRequest.Match(urlPath) && r.Method == http.MethodGet {
		listContainers(w)
	} else if isAuthenticated(r) {
		if containerRequest.Match(urlPath) && r.Method == http.MethodGet {
			inspectContainer(w, containerRequest.FindSubmatch(urlPath)[1])
		} else if startRequest.Match(urlPath) && r.Method == http.MethodPost {
			startContainer(w, startRequest.FindSubmatch(urlPath)[1])
		} else if stopRequest.Match(urlPath) && r.Method == http.MethodPost {
			stopContainer(w, stopRequest.FindSubmatch(urlPath)[1])
		} else if restartRequest.Match(urlPath) && r.Method == http.MethodPost {
			restartContainer(w, restartRequest.FindSubmatch(urlPath)[1])
		} else if logRequest.Match(urlPath) && r.Method == http.MethodGet {
			logContainer(w, logRequest.FindSubmatch(urlPath)[1])
		}
	} else {
		unauthorized(w)
	}
}
<commit_msg>Update docker.go<commit_after>package docker

import (
	"bufio"
	"bytes"
	"context"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
)

const host = `DOCKER_HOST`
const version = `DOCKER_VERSION`
const configurationFile = `./users`

const carriageReturn = []byte(`\n`)[0]

var commaByte = []byte(`,`)
var listRequest = regexp.MustCompile(`/containers/?$`)
var containerRequest = regexp.MustCompile(`/containers/([^/]+)/?$`)
var startRequest = regexp.MustCompile(`/containers/([^/]+)/start`)
var stopRequest = regexp.MustCompile(`/containers/([^/]+)/stop`)
var restartRequest = regexp.MustCompile(`/containers/([^/]+)/restart`)
var logRequest = regexp.MustCompile(`/containers/([^/]+)/logs`)

type results struct {
	Results interface{} `json:"results"`
}

type user struct {
	username string
	password string
}

var docker *client.Client
var users map[string]*user

func handleError(w http.ResponseWriter, err error) {
	log.Print(err)
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

func readConfiguration(path string) map[string]*user {
	configFile, err := os.Open(path)
	defer configFile.Close()

	if err != nil {
		log.Print(err)
		return nil
	}

	users := make(map[string]*user)

	scanner := bufio.NewScanner(configFile)
	for scanner.Scan() {
		parts := bytes.Split(scanner.Bytes(), commaByte)
		user := user{string(parts[0]), string(parts[1])}

		users[strings.ToLower(user.username)] = &user
	}

	return users
}

func init() {
	users = readConfiguration(configurationFile)

	client, err := client.NewClient(os.Getenv(host), os.Getenv(version), nil, nil)
	if err != nil {
		log.Fatal(err)
	} else {
		docker = client
	}
}

func inspectContainer(w http.ResponseWriter, containerID []byte) {
	if container, err := docker.ContainerInspect(context.Background(), string(containerID)); err != nil {
		handleError(w, err)
	} else {
		jsonHttp.ResponseJSON(w, container)
	}
}

func startContainer(w http.ResponseWriter, containerID []byte) {
	if err := docker.ContainerStart(context.Background(), string(containerID), types.ContainerStartOptions{}); err != nil {
		handleError(w, err)
	} else {
		w.Write(nil)
	}
}

func stopContainer(w http.ResponseWriter, containerID []byte) {
	if err := docker.ContainerStop(context.Background(), string(containerID), nil); err != nil {
		handleError(w, err)
	} else {
		w.Write(nil)
	}
}

func restartContainer(w http.ResponseWriter, containerID []byte) {
	if err := docker.ContainerRestart(context.Background(), string(containerID), nil); err != nil {
		handleError(w, err)
	} else {
		w.Write(nil)
	}
}

func logContainer(w http.ResponseWriter, containerID []byte) {
	logs, err := docker.ContainerLogs(context.Background(), string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: false})
	if err != nil {
		handleError(w, err)
		return
	}

	logReader := bufio.NewReader(logs)
	logLines := make([][]byte)
	logLine, err := logReader.ReadBytes(carriageReturn)
	for err != nil {
		logLines = append(logLines, logLine[8:])
		logLine, err = logReader.ReadBytes(carriageReturn)
	}

	w.Write(logLines)
}

func listContainers(w http.ResponseWriter) {
	if containers, err := docker.ContainerList(context.Background(), types.ContainerListOptions{}); err != nil {
		handleError(w, err)
	} else {
		jsonHttp.ResponseJSON(w, results{containers})
	}
}

func isAuthenticated(r *http.Request) bool {
	username, password, ok := r.BasicAuth()

	if ok {
		user, ok := users[strings.ToLower(username)]

		if ok && user.password == password {
			return true
		}
	}

	return false
}

func unauthorized(w http.ResponseWriter) {
	http.Error(w, `Authentication required`, http.StatusUnauthorized)
}

// Handler for Hello request. Should be use with net/http
type Handler struct {
}

func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add(`Access-Control-Allow-Origin`, `*`)
	w.Header().Add(`Access-Control-Allow-Headers`, `Content-Type, Authorization`)
	w.Header().Add(`Access-Control-Allow-Methods`, `GET, POST`)
	w.Header().Add(`X-Content-Type-Options`, `nosniff`)

	if r.Method == http.MethodOptions {
		w.Write(nil)
		return
	}

	urlPath := []byte(r.URL.Path)

	if listRequest.Match(urlPath) && r.Method == http.MethodGet {
		listContainers(w)
	} else if isAuthenticated(r) {
		if containerRequest.Match(urlPath) && r.Method == http.MethodGet {
			inspectContainer(w, containerRequest.FindSubmatch(urlPath)[1])
		} else if startRequest.Match(urlPath) && r.Method == http.MethodPost {
			startContainer(w, startRequest.FindSubmatch(urlPath)[1])
		} else if stopRequest.Match(urlPath) && r.Method == http.MethodPost {
			stopContainer(w, stopRequest.FindSubmatch(urlPath)[1])
		} else if restartRequest.Match(urlPath) && r.Method == http.MethodPost {
			restartContainer(w, restartRequest.FindSubmatch(urlPath)[1])
		} else if logRequest.Match(urlPath) && r.Method == http.MethodGet {
			logContainer(w, logRequest.FindSubmatch(urlPath)[1])
		}
	} else {
		unauthorized(w)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Alex Browne and Soroush Pour.
// Allrights reserved. Use of this source code is
// governed by the MIT license, which can be found
// in the LICENSE file.

package router

import (
	"log"
	"regexp"
	"strings"

	"github.com/go-humble/detect"
	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/dom"
)

var (
	// browserSupportsPushState will be true if the current browser
	// supports history.pushState and the onpopstate event.
	browserSupportsPushState bool
	document                 dom.HTMLDocument
)

func init() {
	if detect.IsBrowser() {
		// We only want to initialize certain things if we are running
		// inside a browser. Otherwise, they will cause the program to
		// panic.
		var ok bool
		document, ok = dom.GetWindow().Document().(dom.HTMLDocument)
		if !ok {
			panic("Could not convert document to dom.HTMLDocument")
		}
		browserSupportsPushState = (js.Global.Get("onpopstate") != js.Undefined) &&
			(js.Global.Get("history") != js.Undefined) &&
			(js.Global.Get("history").Get("pushState") != js.Undefined)
	}
}

// Router is responsible for handling routes. If history.pushState is
// supported, it uses it to navigate from page to page and will listen
// to the "onpopstate" event. Otherwise, it sets the hash component of the
// url and listens to changes via the "onhashchange" event.
type Router struct {
	// routes is the set of routes for this router.
	routes []*route
	// ShouldInterceptLinks tells the router whether or not to intercept click events
	// on links and call the Navigate method instead of the default behavior.
	// If it is set to true, the router will automatically intercept links when
	// Start, Navigate, or Back are called, or when the onpopstate event is triggered.
	ShouldInterceptLinks bool
	// ForceHashURL tells the router to use the hash component of the url to
	// represent different routes, even if history.pushState is supported.
	ForceHashURL bool
	// Verbose determines whether or not the router will log to console.log.
	// If true, the router will log a message if, e.g., a match cannot be found for
	// a particular path.
	Verbose bool
	// listener is the js.Object representation of a listener callback.
	// It is required in order to use the RemoveEventListener method
	listener func(*js.Object)
}

// Context is used as an argument to Handlers
type Context struct {
	// Params is the parameters from the url as a map of names to values.
	Params map[string]string
	// Path is the path that triggered this particular route. If the hash
	// fallback is being used, the value of path does not include the '#'
	// symbol.
	Path string
	// InitialLoad is true iff this route was triggered during the initial
	// page load. I.e. it is true if this is the first path that the browser
	// was visiting when the javascript finished loading.
	InitialLoad bool
}

// Handler is a function which is run in response to a specific
// route. A Handler takes a Context as an argument, which gives
// handler functions access to path parameters and other important
// information.
type Handler func(context *Context)

// New creates and returns a new router
func New() *Router {
	return &Router{
		routes: []*route{},
	}
}

// route is a representation of a specific route
type route struct {
	// regex is a regex pattern that matches route
	regex *regexp.Regexp
	// paramNames is an ordered list of parameters expected
	// by route handler
	paramNames []string
	// handler called when route is matched
	handler Handler
}

// HandleFunc will cause the router to call f whenever window.location.pathname
// (or window.location.hash, if history.pushState is not supported) matches path.
// path can contain any number of parameters which are denoted with curly brackets.
// So, for example, a path argument of "users/{id}" will be triggered when the user
// visits users/123 and will call the handler function with params["id"] = "123".
func (r *Router) HandleFunc(path string, handler Handler) {
	r.routes = append(r.routes, newRoute(path, handler))
}

// newRoute returns a route with the given arguments. paramNames and regex
// are calculated from the path
func newRoute(path string, handler Handler) *route {
	route := &route{
		handler: handler,
	}
	strs := strings.Split(path, "/")
	strs = removeEmptyStrings(strs)
	pattern := `^`
	for _, str := range strs {
		if str[0] == '{' && str[len(str)-1] == '}' {
			pattern += `/`
			pattern += `([\w+-]*)`
			route.paramNames = append(route.paramNames, str[1:(len(str)-1)])
		} else {
			pattern += `/`
			pattern += str
		}
	}
	pattern += `/?$`
	route.regex = regexp.MustCompile(pattern)
	return route
}

// Start causes the router to listen for changes to window.location and
// trigger the appropriate handler whenever there is a change.
func (r *Router) Start() {
	if browserSupportsPushState && !r.ForceHashURL {
		r.pathChanged(getPath(), true)
		r.watchHistory()
	} else {
		r.setInitialHash()
		r.watchHash()
	}
	if r.ShouldInterceptLinks {
		r.InterceptLinks()
	}
}

// Stop causes the router to stop listening for changes, and therefore
// the router will not trigger any more router.Handler functions.
func (r *Router) Stop() {
	if browserSupportsPushState && !r.ForceHashURL {
		js.Global.Set("onpopstate", nil)
	} else {
		js.Global.Set("onhashchange", nil)
	}
}

// Navigate will trigger the handler associated with the given path
// and update window.location accordingly. If the browser supports
// history.pushState, that will be used. Otherwise, Navigate will
// set the hash component of window.location to the given path.
func (r *Router) Navigate(path string) {
	if browserSupportsPushState && !r.ForceHashURL {
		pushState(path)
		r.pathChanged(path, false)
	} else {
		setHash(path)
	}
	if r.ShouldInterceptLinks {
		r.InterceptLinks()
	}
}

// CanNavigate returns true if the specified path can be navigated by the
// router, and false otherwise
func (r *Router) CanNavigate(path string) bool {
	if bestRoute, _ := r.findBestRoute(path); bestRoute != nil {
		return true
	}
	return false
}

// Back will cause the browser to go back to the previous page.
// It has the same effect as the user pressing the back button,
// and is just a wrapper around history.back()
func (r *Router) Back() {
	js.Global.Get("history").Call("back")
	if r.ShouldInterceptLinks {
		r.InterceptLinks()
	}
}

// InterceptLinks intercepts click events on links of the form
// and calls router.Navigate("/foo") instead, which triggers the appropriate Handler
// instead of requesting a new page from the server. Since InterceptLinks works by
// setting event listeners in the DOM, you must call this function whenever the DOM
// is changed. Alternatively, you can set r.ShouldInterceptLinks to true, which will
// trigger this function whenever Start, Navigate, or Back are called, or when the
// onpopstate event is triggered. Even with r.ShouldInterceptLinks set to true, you
// may still need to call this function if you change the DOM manually without
// triggering a route.
func (r *Router) InterceptLinks() {
	for _, link := range document.Links() {
		href := link.GetAttribute("href")
		switch {
		case href == "":

		case strings.HasPrefix(href, "http://"), strings.HasPrefix(href, "https://"), strings.HasPrefix(href, "//"):
			// These are external links and should behave normally.

		case strings.HasPrefix(href, "#"):
			// These are anchor links and should behave normally.
			// Recall that even when we are using the hash trick, href
			// attributes should be relative paths without the "#" and
			// router will handle them appropriately.

		case strings.HasPrefix(href, "/"):
			// These are relative links. The kind that we want to intercept.
			if r.listener != nil {
				// Remove the old listener (if any)
				link.RemoveEventListener("click", true, r.listener)
			}
			r.listener = link.AddEventListener("click", true, r.interceptLink)
		}
	}
}

// interceptLink is intended to be used as a callback function. It stops
// the default behavior of event and instead calls r.Navigate, passing through
// the link's href property.
func (r *Router) interceptLink(event dom.Event) {
	path := event.CurrentTarget().GetAttribute("href")
	// Only intercept the click event if we have a route which matches
	// Otherwise, just do the default.
	if bestRoute, _ := r.findBestRoute(path); bestRoute != nil {
		event.PreventDefault()
		go r.Navigate(path)
	}
}

// setInitialHash will set hash to / if there is currently no hash.
func (r *Router) setInitialHash() {
	if getHash() == "" {
		setHash("/")
	} else {
		r.pathChanged(getPathFromHash(getHash()), true)
	}
}

// pathChanged should be called whenever the path changes and will trigger
// the appropriate handler. initial should be true iff this is the first
// time the javascript is loaded on the page.
func (r *Router) pathChanged(path string, initial bool) {
	bestRoute, tokens := r.findBestRoute(path)
	// If no routes match, we throw console error and no handlers are called
	if bestRoute == nil {
		if r.Verbose {
			log.Println("Could not find route to match: " + path)
		}
		return
	}
	// Create the context and pass it through to the handler
	c := &Context{
		Path:        path,
		InitialLoad: initial,
		Params:      map[string]string{},
	}
	for i, token := range tokens {
		c.Params[bestRoute.paramNames[i]] = token
	}
	bestRoute.handler(c)
}

// findBestRoute compares the given path against regex patterns of routes.
// Preference given to routes with most literal (non-parameter) matches. For
// example if we have the following:
//   Route 1: /todos/work
//   Route 2: /todos/{category}
// And the path argument is "/todos/work", the bestRoute would be todos/work
// because the string "work" matches the literal in Route 1.
func (r Router) findBestRoute(path string) (bestRoute *route, tokens []string) {
	leastParams := -1
	for _, route := range r.routes {
		matches := route.regex.FindStringSubmatch(path)
		if matches != nil {
			if (leastParams == -1) || (len(matches) < leastParams) {
				leastParams = len(matches)
				bestRoute = route
				tokens = matches[1:]
			}
		}
	}
	return bestRoute, tokens
}

// removeEmptyStrings removes any empty strings from strings
func removeEmptyStrings(strings []string) []string {
	result := []string{}
	for _, s := range strings {
		if s != "" {
			result = append(result, s)
		}
	}
	return result
}

// watchHash listens to the onhashchange event and calls r.pathChanged when
// it changes
func (r *Router) watchHash() {
	js.Global.Set("onhashchange", func() {
		go func() {
			path := getPathFromHash(getHash())
			r.pathChanged(path, false)
		}()
	})
}

// watchHistory listens to the onpopstate event and calls r.pathChanged when
// it changes
func (r *Router) watchHistory() {
	js.Global.Set("onpopstate", func() {
		go func() {
			r.pathChanged(getPath(), false)
			if r.ShouldInterceptLinks {
				r.InterceptLinks()
			}
		}()
	})
}

// getPathFromHash returns everything after the "#" character in hash.
func getPathFromHash(hash string) string {
	return strings.SplitN(hash, "#", 2)[1]
}

// getHash is an alias for js.Global.Get("location").Get("hash").String()
func getHash() string {
	return js.Global.Get("location").Get("hash").String()
}

// setHash is an alias for js.Global.Get("location").Set("hash", hash)
func setHash(hash string) {
	js.Global.Get("location").Set("hash", hash)
}

// getPath is an alias for js.Global.Get("location").Get("pathname").String()
func getPath() string {
	return js.Global.Get("location").Get("pathname").String()
}

// pushState is an alias for js.Global.Get("history").Call("pushState", nil, "", path)
func pushState(path string) {
	js.Global.Get("history").Call("pushState", nil, "", path)
}
<commit_msg>add continue to IterateLinks, for clarity<commit_after>// Copyright 2015 Alex Browne and Soroush Pour.
// Allrights reserved. Use of this source code is
// governed by the MIT license, which can be found
// in the LICENSE file.

package router

import (
	"log"
	"regexp"
	"strings"

	"github.com/go-humble/detect"
	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/dom"
)

var (
	// browserSupportsPushState will be true if the current browser
	// supports history.pushState and the onpopstate event.
	browserSupportsPushState bool
	document                 dom.HTMLDocument
)

func init() {
	if detect.IsBrowser() {
		// We only want to initialize certain things if we are running
		// inside a browser. Otherwise, they will cause the program to
		// panic.
		var ok bool
		document, ok = dom.GetWindow().Document().(dom.HTMLDocument)
		if !ok {
			panic("Could not convert document to dom.HTMLDocument")
		}
		browserSupportsPushState = (js.Global.Get("onpopstate") != js.Undefined) &&
			(js.Global.Get("history") != js.Undefined) &&
			(js.Global.Get("history").Get("pushState") != js.Undefined)
	}
}

// Router is responsible for handling routes. If history.pushState is
// supported, it uses it to navigate from page to page and will listen
// to the "onpopstate" event. Otherwise, it sets the hash component of the
// url and listens to changes via the "onhashchange" event.
type Router struct {
	// routes is the set of routes for this router.
	routes []*route
	// ShouldInterceptLinks tells the router whether or not to intercept click events
	// on links and call the Navigate method instead of the default behavior.
	// If it is set to true, the router will automatically intercept links when
	// Start, Navigate, or Back are called, or when the onpopstate event is triggered.
	ShouldInterceptLinks bool
	// ForceHashURL tells the router to use the hash component of the url to
	// represent different routes, even if history.pushState is supported.
	ForceHashURL bool
	// Verbose determines whether or not the router will log to console.log.
	// If true, the router will log a message if, e.g., a match cannot be found for
	// a particular path.
	Verbose bool
	// listener is the js.Object representation of a listener callback.
	// It is required in order to use the RemoveEventListener method
	listener func(*js.Object)
}

// Context is used as an argument to Handlers
type Context struct {
	// Params is the parameters from the url as a map of names to values.
	Params map[string]string
	// Path is the path that triggered this particular route. If the hash
	// fallback is being used, the value of path does not include the '#'
	// symbol.
	Path string
	// InitialLoad is true iff this route was triggered during the initial
	// page load. I.e. it is true if this is the first path that the browser
	// was visiting when the javascript finished loading.
	InitialLoad bool
}

// Handler is a function which is run in response to a specific
// route. A Handler takes a Context as an argument, which gives
// handler functions access to path parameters and other important
// information.
type Handler func(context *Context)

// New creates and returns a new router
func New() *Router {
	return &Router{
		routes: []*route{},
	}
}

// route is a representation of a specific route
type route struct {
	// regex is a regex pattern that matches route
	regex *regexp.Regexp
	// paramNames is an ordered list of parameters expected
	// by route handler
	paramNames []string
	// handler called when route is matched
	handler Handler
}

// HandleFunc will cause the router to call f whenever window.location.pathname
// (or window.location.hash, if history.pushState is not supported) matches path.
// path can contain any number of parameters which are denoted with curly brackets.
// So, for example, a path argument of "users/{id}" will be triggered when the user
// visits users/123 and will call the handler function with params["id"] = "123".
func (r *Router) HandleFunc(path string, handler Handler) {
	r.routes = append(r.routes, newRoute(path, handler))
}

// newRoute returns a route with the given arguments. paramNames and regex
// are calculated from the path
func newRoute(path string, handler Handler) *route {
	route := &route{
		handler: handler,
	}
	strs := strings.Split(path, "/")
	strs = removeEmptyStrings(strs)
	pattern := `^`
	for _, str := range strs {
		if str[0] == '{' && str[len(str)-1] == '}' {
			pattern += `/`
			pattern += `([\w+-]*)`
			route.paramNames = append(route.paramNames, str[1:(len(str)-1)])
		} else {
			pattern += `/`
			pattern += str
		}
	}
	pattern += `/?$`
	route.regex = regexp.MustCompile(pattern)
	return route
}

// Start causes the router to listen for changes to window.location and
// trigger the appropriate handler whenever there is a change.
func (r *Router) Start() {
	if browserSupportsPushState && !r.ForceHashURL {
		r.pathChanged(getPath(), true)
		r.watchHistory()
	} else {
		r.setInitialHash()
		r.watchHash()
	}
	if r.ShouldInterceptLinks {
		r.InterceptLinks()
	}
}

// Stop causes the router to stop listening for changes, and therefore
// the router will not trigger any more router.Handler functions.
func (r *Router) Stop() {
	if browserSupportsPushState && !r.ForceHashURL {
		js.Global.Set("onpopstate", nil)
	} else {
		js.Global.Set("onhashchange", nil)
	}
}

// Navigate will trigger the handler associated with the given path
// and update window.location accordingly. If the browser supports
// history.pushState, that will be used. Otherwise, Navigate will
// set the hash component of window.location to the given path.
func (r *Router) Navigate(path string) {
	if browserSupportsPushState && !r.ForceHashURL {
		pushState(path)
		r.pathChanged(path, false)
	} else {
		setHash(path)
	}
	if r.ShouldInterceptLinks {
		r.InterceptLinks()
	}
}

// CanNavigate returns true if the specified path can be navigated by the
// router, and false otherwise
func (r *Router) CanNavigate(path string) bool {
	if bestRoute, _ := r.findBestRoute(path); bestRoute != nil {
		return true
	}
	return false
}

// Back will cause the browser to go back to the previous page.
// It has the same effect as the user pressing the back button,
// and is just a wrapper around history.back()
func (r *Router) Back() {
	js.Global.Get("history").Call("back")
	if r.ShouldInterceptLinks {
		r.InterceptLinks()
	}
}

// InterceptLinks intercepts click events on links of the form
// and calls router.Navigate("/foo") instead, which triggers the appropriate Handler
// instead of requesting a new page from the server. Since InterceptLinks works by
// setting event listeners in the DOM, you must call this function whenever the DOM
// is changed. Alternatively, you can set r.ShouldInterceptLinks to true, which will
// trigger this function whenever Start, Navigate, or Back are called, or when the
// onpopstate event is triggered. Even with r.ShouldInterceptLinks set to true, you
// may still need to call this function if you change the DOM manually without
// triggering a route.
func (r *Router) InterceptLinks() {
	for _, link := range document.Links() {
		href := link.GetAttribute("href")
		switch {
		case href == "":
			continue

		case strings.HasPrefix(href, "http://"), strings.HasPrefix(href, "https://"), strings.HasPrefix(href, "//"):
			// These are external links and should behave normally.
			continue

		case strings.HasPrefix(href, "#"):
			// These are anchor links and should behave normally.
			// Recall that even when we are using the hash trick, href
			// attributes should be relative paths without the "#" and
			// router will handle them appropriately.
			continue

		case strings.HasPrefix(href, "/"):
			// These are relative links. The kind that we want to intercept.
			if r.listener != nil {
				// Remove the old listener (if any)
				link.RemoveEventListener("click", true, r.listener)
			}
			r.listener = link.AddEventListener("click", true, r.interceptLink)
		}
	}
}

// interceptLink is intended to be used as a callback function. It stops
// the default behavior of event and instead calls r.Navigate, passing through
// the link's href property.
func (r *Router) interceptLink(event dom.Event) {
	path := event.CurrentTarget().GetAttribute("href")
	// Only intercept the click event if we have a route which matches
	// Otherwise, just do the default.
	if bestRoute, _ := r.findBestRoute(path); bestRoute != nil {
		event.PreventDefault()
		go r.Navigate(path)
	}
}

// setInitialHash will set hash to / if there is currently no hash.
func (r *Router) setInitialHash() {
	if getHash() == "" {
		setHash("/")
	} else {
		r.pathChanged(getPathFromHash(getHash()), true)
	}
}

// pathChanged should be called whenever the path changes and will trigger
// the appropriate handler. initial should be true iff this is the first
// time the javascript is loaded on the page.
func (r *Router) pathChanged(path string, initial bool) {
	bestRoute, tokens := r.findBestRoute(path)
	// If no routes match, we throw console error and no handlers are called
	if bestRoute == nil {
		if r.Verbose {
			log.Println("Could not find route to match: " + path)
		}
		return
	}
	// Create the context and pass it through to the handler
	c := &Context{
		Path:        path,
		InitialLoad: initial,
		Params:      map[string]string{},
	}
	for i, token := range tokens {
		c.Params[bestRoute.paramNames[i]] = token
	}
	bestRoute.handler(c)
}

// findBestRoute compares the given path against regex patterns of routes.
// Preference given to routes with most literal (non-parameter) matches. For
// example if we have the following:
//   Route 1: /todos/work
//   Route 2: /todos/{category}
// And the path argument is "/todos/work", the bestRoute would be todos/work
// because the string "work" matches the literal in Route 1.
func (r Router) findBestRoute(path string) (bestRoute *route, tokens []string) {
	leastParams := -1
	for _, route := range r.routes {
		matches := route.regex.FindStringSubmatch(path)
		if matches != nil {
			if (leastParams == -1) || (len(matches) < leastParams) {
				leastParams = len(matches)
				bestRoute = route
				tokens = matches[1:]
			}
		}
	}
	return bestRoute, tokens
}

// removeEmptyStrings removes any empty strings from strings
func removeEmptyStrings(strings []string) []string {
	result := []string{}
	for _, s := range strings {
		if s != "" {
			result = append(result, s)
		}
	}
	return result
}

// watchHash listens to the onhashchange event and calls r.pathChanged when
// it changes
func (r *Router) watchHash() {
	js.Global.Set("onhashchange", func() {
		go func() {
			path := getPathFromHash(getHash())
			r.pathChanged(path, false)
		}()
	})
}

// watchHistory listens to the onpopstate event and calls r.pathChanged when
// it changes
func (r *Router) watchHistory() {
	js.Global.Set("onpopstate", func() {
		go func() {
			r.pathChanged(getPath(), false)
			if r.ShouldInterceptLinks {
				r.InterceptLinks()
			}
		}()
	})
}

// getPathFromHash returns everything after the "#" character in hash.
func getPathFromHash(hash string) string {
	return strings.SplitN(hash, "#", 2)[1]
}

// getHash is an alias for js.Global.Get("location").Get("hash").String()
func getHash() string {
	return js.Global.Get("location").Get("hash").String()
}

// setHash is an alias for js.Global.Get("location").Set("hash", hash)
func setHash(hash string) {
	js.Global.Get("location").Set("hash", hash)
}

// getPath is an alias for js.Global.Get("location").Get("pathname").String()
func getPath() string {
	return js.Global.Get("location").Get("pathname").String()
}

// pushState is an alias for js.Global.Get("history").Call("pushState", nil, "", path)
func pushState(path string) {
	js.Global.Get("history").Call("pushState", nil, "", path)
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "net"
    "time"
    "log"
    "io/ioutil"
    "os/exec"
    "encoding/json"
    "github.com/twmb/algoimpl/go/graph"
    "strconv"
)

//Router This struct represents a router and contains it's properties

type Neighbour struct{
    IP string
    Port int
    Weight int

}

// type Neighbours struct{
//     ne
// }

type Router struct{
    IP string
    Port int
    Neighbours []Neighbour
}

type SpanningTree struct{

}

func listenForRouter(router Router) {
    println("listening")
    for true {
        In, err := net.Listen("tcp", ":" + strconv.Itoa(router.Port))
        checkError(err)
        for {
            _, err := In.Accept()
            if err != nil {
                checkError(err)
            }
            println("hi")

        }
    }
}

func main(){

   clear()
   println("ʕ◔ϖ◔ʔ  Welcome to the GO NetSim, Router Process!!!  ʕ◔ϖ◔ʔ")

   data, err := ioutil.ReadFile("routerinfo.json")
   checkError(err)
   var testRouter Router

   err = json.Unmarshal(data,&testRouter)
   checkError(err)
    /*
        testRouter := Router {
            IP: "192.168.1.1",
            Port: 1232,
            Neighbours: []Neighbour{

                Neighbour {
                IP: "192.168.1.2",
                Port: 1233,
                Weight:1},

                Neighbour {
                IP: "192.168.1.3",
                Port: 1234,
                Weight:2},

                Neighbour {
                IP: "192.168.1.5",
                Port: 1235,
                Weight:3},

                },

          }//end of struct Declaration
          */
          go listenForRouter(testRouter)

           b, _ := json.Marshal(testRouter);
           s := string(b)

           //fmt.Println(s)

           tree := graph.New(graph.Undirected)
           nodes := make(map[string]graph.Node, 0)
           nodeWeIs := testRouter.IP + ":" + strconv.Itoa(testRouter.Port)
           nodes[nodeWeIs] = tree.MakeNode()
           for i := 0; i < len(testRouter.Neighbours); i++ {

               currentProcessingNode := testRouter.Neighbours[i].IP + ":" + strconv.Itoa(testRouter.Neighbours[i].Port)
               nodes[currentProcessingNode] = tree.MakeNode()
               tree.MakeEdgeWeight(nodes[nodeWeIs], nodes[currentProcessingNode], testRouter.Neighbours[i].Weight)

           }

           for key, node := range nodes {
                *node.Value = key
            }

           mst := tree.DijkstraSearch(nodes[nodeWeIs])

           b, _ = json.Marshal(mst);
           s = string(b)

           fmt.Println(s)
           boot(testRouter)
           for true {

           }
    }
 func boot(myRouter Router) {
     // for node in neighbors
     //    are you alive
     for i:=0; i < len(myRouter.Neighbours); i++ {
         fmt.Println(myRouter.Neighbours[i].IP)
         _, err:= net.DialTimeout("tcp", myRouter.Neighbours[i].IP + ":" + strconv.Itoa(myRouter.Neighbours[i].Port), time.Duration(1) * time.Second)
         //checkError(err)
         if(err != nil && err.(net.Error).Timeout()) {
             println("ʕ◔ϖ◔ʔ halp, we timed the fuck out ʕ◔ϖ◔ʔ")
         }
     }

 }

func println(dis string) {
    dis = "ʕ◔ϖ◔ʔ " + dis + " ʕ◔ϖ◔ʔ"
    fmt.Println(dis)
}

//General Error Catching
func checkError(err error)  {
    if err != nil {
        log.Fatal(err)
    }
}

func clear(){

	cmd := exec.Command("clear")
	stdout, err := cmd.Output()

	if err != nil {
		println(err.Error())
		return
	}

	print(string(stdout))

}<commit_msg>Added comments to help with readability.<commit_after>package main

import (
    "fmt"
    "net"
    "time"
    "log"
    "io/ioutil"
    "os/exec"
    "encoding/json"
    "github.com/twmb/algoimpl/go/graph"
    "strconv"
)

//Router This struct represents a router and contains it's properties

type Neighbour struct{
    IP string
    Port int
    Weight int

}

// type Neighbours struct{
//     ne
// }

type Router struct{
    IP string
    Port int
    Neighbours []Neighbour
}

type SpanningTree struct{

}

func listenForRouter(router Router) {
    println("listening")
    for true {
        In, err := net.Listen("tcp", ":" + strconv.Itoa(router.Port))
        checkError(err)
        for {
            _, err := In.Accept()
            if err != nil {
                checkError(err)
            }
            println("hi")

        }
    }
}

func main(){

   clear()
   println("ʕ◔ϖ◔ʔ  Welcome to the GO NetSim, Router Process!!!  ʕ◔ϖ◔ʔ")

   //Read in JSON file to create the router Struct
   data, err := ioutil.ReadFile("routerinfo.json")
   checkError(err)

   //Create Router Struct and turn json into Struct
   var testRouter Router
   err = json.Unmarshal(data,&testRouter)
   checkError(err)

    //Create a Go Routine that listens for other routers that are trying to comunicate
    go listenForRouter(testRouter)

    //Turn our Router to json , this was for testing
    //b, _ := json.Marshal(testRouter);
    // s := string(b)

    //fmt.Println(s)

    //Create Graph undirected weighted graph to represent the current network
    tree := graph.New(graph.Undirected)
    nodes := make(map[string]graph.Node, 0)
    nodeWeIs := testRouter.IP + ":" + strconv.Itoa(testRouter.Port)
    nodes[nodeWeIs] = tree.MakeNode()

    //Interate through the nodes in the router(the one read from json) and add them to the graph
    for i := 0; i < len(testRouter.Neighbours); i++ {

        currentProcessingNode := testRouter.Neighbours[i].IP + ":" + strconv.Itoa(testRouter.Neighbours[i].Port)
        nodes[currentProcessingNode] = tree.MakeNode()
        tree.MakeEdgeWeight(nodes[nodeWeIs], nodes[currentProcessingNode], testRouter.Neighbours[i].Weight)

    }
    //Set values of all nodes to key???????? Clarification needed.
    for key, node := range nodes {
        *node.Value = key
    }

    //Test to find the minimum spanning tree.
    mst := tree.DijkstraSearch(nodes[nodeWeIs])

    //Turn that tree to json for sending
    b, _ = json.Marshal(mst);
    s = string(b)
    //Print out the json for testing
    fmt.Println(s)

    //This function trys to initiates connection to the other routers and updates the tree if they are connected
    boot(testRouter)

    //inifinate loop to keep the program running while the go routines do their thing
    for true {

    }

    }
 func boot(myRouter Router) {
     // for node in neighbors
     //    are you alive
     for i:=0; i < len(myRouter.Neighbours); i++ {
         fmt.Println(myRouter.Neighbours[i].IP)
         _, err:= net.DialTimeout("tcp", myRouter.Neighbours[i].IP + ":" + strconv.Itoa(myRouter.Neighbours[i].Port), time.Duration(1) * time.Second)
         //checkError(err)
         if(err != nil && err.(net.Error).Timeout()) {
             println("ʕ◔ϖ◔ʔ halp, we timed the fuck out ʕ◔ϖ◔ʔ")
         }
     }

 }

//Makes strings more gophery
func println(dis string) {
    dis = "ʕ◔ϖ◔ʔ " + dis + " ʕ◔ϖ◔ʔ"
    fmt.Println(dis)
}

//General Error Catching
func checkError(err error)  {
    if err != nil {
        log.Fatal(err)
    }
}

//All this function does is executes the clear command.
func clear(){

	cmd := exec.Command("clear")
	stdout, err := cmd.Output()

	if err != nil {
		println(err.Error())
		return
	}

	print(string(stdout))

}<|endoftext|>


<commit_before>package helm

import (
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

const (
	get     = "GET"
	head    = "HEAD"
	post    = "POST"
	put     = "PUT"
	patch   = "PATCH"
	deleteh = "DELETE"
)

// Handle is just like "net/http" Handlers, only takes params.
type Handle func(http.ResponseWriter, *http.Request, url.Values)

// Middleware is just like the Handle type, but has a boolean return. True
// means to keep processing the rest of the middleware chain, false means end.
// If you return false to end the request-response cycle you MUST
// write something back to the client, otherwise it will be left hanging.
type Middleware func(http.ResponseWriter, *http.Request, url.Values) bool

// Router name says it all.
type Router struct {
	tree           *node
	rootHandler    Handle
	middleware     []Middleware
	l              *log.Logger
	LoggingEnabled bool
}

// New creates a new router. Take the root/fall through route
// like how the default mux works. Only difference is in this case,
// you have to specific one.
func New(rootHandler Handle) *Router {

	node := node{component: "/", isNamedParam: false, methods: make(map[string]*route)}
	return &Router{tree: &node, rootHandler: rootHandler, l: log.New(os.Stdout, "[helm] ", 0), LoggingEnabled: true}
}

// Handle takes an http handler, method and pattern for a route.
func (r *Router) Handle(method, path string, handler Handle, middleware ...Middleware) {
	if path[0] != '/' {
		panic("Path has to start with a /.")
	}
	r.tree.addNode(method, path, handler, middleware...)
}

// GET same as Handle only the method is already implied.
func (r *Router) GET(path string, handler Handle, middleware ...Middleware) {
	r.Handle(get, path, handler, middleware...)
}

// HEAD same as Handle only the method is already implied.
func (r *Router) HEAD(path string, handler Handle, middleware ...Middleware) {
	r.Handle(head, path, handler, middleware...)
}

// POST same as Handle only the method is already implied.
func (r *Router) POST(path string, handler Handle, middleware ...Middleware) {
	r.Handle(post, path, handler, middleware...)
}

// PUT same as Handle only the method is already implied.
func (r *Router) PUT(path string, handler Handle, middleware ...Middleware) {
	r.Handle(put, path, handler, middleware...)
}

// PATCH same as Handle only the method is already implied.
func (r *Router) PATCH(path string, handler Handle, middleware ...Middleware) { // might make this and put one.
	r.Handle(patch, path, handler, middleware...)
}

// DELETE same as Handle only the method is already implied.
func (r *Router) DELETE(path string, handler Handle, middleware ...Middleware) {
	r.Handle(deleteh, path, handler, middleware...)
}

// Use adds middleware to all of the routes.
func (r *Router) Use(middleware ...Middleware) {
	r.middleware = append(r.middleware, middleware...)
}

// Run is a simple wrapper around http.ListenAndServe.
func (r *Router) Run(address string) {
	r.l.Println("Running on", address)
	http.ListenAndServe(address, r)
}

// runMiddleware loops over the slice of middleware and call to each of the middleware handlers.
func runMiddleware(w http.ResponseWriter, req *http.Request, params url.Values, middleware ...Middleware) bool {
	for _, m := range middleware {
		if !m(w, req, params) {
			return false // the middleware returned false, so end processing the chain.
		}
	}
	return true
}

// Needed by "net/http" to handle http requests and be a mux to http.ListenAndServe.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	cw := w
	if r.LoggingEnabled {
		r.l.Printf("Started %s %s", req.Method, req.URL.Path)
		cw = &responseWriter{w, 200}
		start := time.Now()
		defer func(time.Time) {
			status := cw.(*responseWriter).status
			r.l.Printf("Completed %d %s in %v", status, http.StatusText(status), time.Since(start))
		}(start)
	}

	err := req.ParseMultipartForm(2 * 1024 * 1024) // 2MB. Should probably make this configurable...
	if err != nil {
		r.l.Printf("ERROR parsing form " + err.Error())
	}
	params := req.Form
	if !runMiddleware(cw, req, params, r.middleware...) {
		return // end the chain.
	}
	node, _ := r.tree.traverse(strings.Split(req.URL.Path, "/")[1:], params)
	if handler := node.methods[req.Method]; handler != nil {
		if !runMiddleware(cw, req, params, handler.middleware...) {
			return
		}
		handler.handler(cw, req, params)
	} else {
		r.rootHandler(cw, req, params)
	}
}
<commit_msg>form fix<commit_after>package helm

import (
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

const (
	get     = "GET"
	head    = "HEAD"
	post    = "POST"
	put     = "PUT"
	patch   = "PATCH"
	deleteh = "DELETE"
)

// Handle is just like "net/http" Handlers, only takes params.
type Handle func(http.ResponseWriter, *http.Request, url.Values)

// Middleware is just like the Handle type, but has a boolean return. True
// means to keep processing the rest of the middleware chain, false means end.
// If you return false to end the request-response cycle you MUST
// write something back to the client, otherwise it will be left hanging.
type Middleware func(http.ResponseWriter, *http.Request, url.Values) bool

// Router name says it all.
type Router struct {
	tree           *node
	rootHandler    Handle
	middleware     []Middleware
	l              *log.Logger
	LoggingEnabled bool
}

// New creates a new router. Take the root/fall through route
// like how the default mux works. Only difference is in this case,
// you have to specific one.
func New(rootHandler Handle) *Router {

	node := node{component: "/", isNamedParam: false, methods: make(map[string]*route)}
	return &Router{tree: &node, rootHandler: rootHandler, l: log.New(os.Stdout, "[helm] ", 0), LoggingEnabled: true}
}

// Handle takes an http handler, method and pattern for a route.
func (r *Router) Handle(method, path string, handler Handle, middleware ...Middleware) {
	if path[0] != '/' {
		panic("Path has to start with a /.")
	}
	r.tree.addNode(method, path, handler, middleware...)
}

// GET same as Handle only the method is already implied.
func (r *Router) GET(path string, handler Handle, middleware ...Middleware) {
	r.Handle(get, path, handler, middleware...)
}

// HEAD same as Handle only the method is already implied.
func (r *Router) HEAD(path string, handler Handle, middleware ...Middleware) {
	r.Handle(head, path, handler, middleware...)
}

// POST same as Handle only the method is already implied.
func (r *Router) POST(path string, handler Handle, middleware ...Middleware) {
	r.Handle(post, path, handler, middleware...)
}

// PUT same as Handle only the method is already implied.
func (r *Router) PUT(path string, handler Handle, middleware ...Middleware) {
	r.Handle(put, path, handler, middleware...)
}

// PATCH same as Handle only the method is already implied.
func (r *Router) PATCH(path string, handler Handle, middleware ...Middleware) { // might make this and put one.
	r.Handle(patch, path, handler, middleware...)
}

// DELETE same as Handle only the method is already implied.
func (r *Router) DELETE(path string, handler Handle, middleware ...Middleware) {
	r.Handle(deleteh, path, handler, middleware...)
}

// Use adds middleware to all of the routes.
func (r *Router) Use(middleware ...Middleware) {
	r.middleware = append(r.middleware, middleware...)
}

// Run is a simple wrapper around http.ListenAndServe.
func (r *Router) Run(address string) {
	r.l.Println("Running on", address)
	http.ListenAndServe(address, r)
}

// runMiddleware loops over the slice of middleware and call to each of the middleware handlers.
func runMiddleware(w http.ResponseWriter, req *http.Request, params url.Values, middleware ...Middleware) bool {
	for _, m := range middleware {
		if !m(w, req, params) {
			return false // the middleware returned false, so end processing the chain.
		}
	}
	return true
}

// Needed by "net/http" to handle http requests and be a mux to http.ListenAndServe.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	cw := w
	if r.LoggingEnabled {
		r.l.Printf("Started %s %s", req.Method, req.URL.Path)
		cw = &responseWriter{w, 200}
		start := time.Now()
		defer func(time.Time) {
			status := cw.(*responseWriter).status
			r.l.Printf("Completed %d %s in %v", status, http.StatusText(status), time.Since(start))
		}(start)
	}

	req.ParseMultipartForm(10 * 1024 * 1024) // 10MB. Should probably make this configurable...
	params := req.Form
	if !runMiddleware(cw, req, params, r.middleware...) {
		return // end the chain.
	}
	node, _ := r.tree.traverse(strings.Split(req.URL.Path, "/")[1:], params)
	if handler := node.methods[req.Method]; handler != nil {
		if !runMiddleware(cw, req, params, handler.middleware...) {
			return
		}
		handler.handler(cw, req, params)
	} else {
		r.rootHandler(cw, req, params)
	}
}
<|endoftext|>