<commit_before>/*
Copyright 2016 The Kubernetes 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 priorities

import (
	"reflect"
	"testing"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api/v1"
	schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
	"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
)

func TestMostRequested(t *testing.T) {
	labels1 := map[string]string{
		"foo": "bar",
		"baz": "blah",
	}
	labels2 := map[string]string{
		"bar": "foo",
		"baz": "blah",
	}
	noResources := v1.PodSpec{
		Containers: []v1.Container{},
	}
	cpuOnly := v1.PodSpec{
		NodeName: "machine1",
		Containers: []v1.Container{
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("1000m"),
						"memory": resource.MustParse("0"),
					},
				},
			},
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("2000m"),
						"memory": resource.MustParse("0"),
					},
				},
			},
		},
	}
	cpuOnly2 := cpuOnly
	cpuOnly2.NodeName = "machine2"
	cpuAndMemory := v1.PodSpec{
		NodeName: "machine2",
		Containers: []v1.Container{
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("1000m"),
						"memory": resource.MustParse("2000"),
					},
				},
			},
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("2000m"),
						"memory": resource.MustParse("3000"),
					},
				},
			},
		},
	}
	tests := []struct {
		pod          *v1.Pod
		pods         []*v1.Pod
		nodes        []*v1.Node
		expectedList schedulerapi.HostPriorityList
		test         string
	}{
		{
			/*
				Node1 scores (used resources) on 0-10 scale
				CPU Score: (0 * 10  / 4000 = 0
				Memory Score: (0 * 10) / 10000 = 0
				Node1 Score: (0 + 0) / 2 = 0

				Node2 scores (used resources) on 0-10 scale
				CPU Score: (0 * 10 / 4000 = 0
				Memory Score: (0 * 10 / 10000 = 0
				Node2 Score: (0 + 0) / 2 = 0
			*/
			pod:          &v1.Pod{Spec: noResources},
			nodes:        []*v1.Node{makeNode("machine1", 4000, 10000), makeNode("machine2", 4000, 10000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 0}, {Host: "machine2", Score: 0}},
			test:         "nothing scheduled, nothing requested",
		},
		{
			/*
				Node1 scores on 0-10 scale
				CPU Score: (3000 * 10 / 4000 = 7.5
				Memory Score: (5000 * 10) / 10000 = 5
				Node1 Score: (7.5 + 5) / 2 = 6

				Node2 scores on 0-10 scale
				CPU Score: (3000 * 10 / 6000 = 5
				Memory Score: (5000 * 10 / 10000 = 5
				Node2 Score: (5 + 5) / 2 = 5
			*/
			pod:          &v1.Pod{Spec: cpuAndMemory},
			nodes:        []*v1.Node{makeNode("machine1", 4000, 10000), makeNode("machine2", 6000, 10000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 6}, {Host: "machine2", Score: 5}},
			test:         "nothing scheduled, resources requested, differently sized machines",
		},
		{
			/*
				Node1 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (0 * 10) / 20000 = 10
				Node1 Score: (6 + 0) / 2 = 3

				Node2 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (5000 * 10) / 20000 = 2.5
				Node2 Score: (6 + 2.5) / 2 = 4
			*/
			pod:          &v1.Pod{Spec: noResources},
			nodes:        []*v1.Node{makeNode("machine1", 10000, 20000), makeNode("machine2", 10000, 20000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 3}, {Host: "machine2", Score: 4}},
			test:         "no resources requested, pods scheduled with resources",
			pods: []*v1.Pod{
				{Spec: cpuOnly, ObjectMeta: metav1.ObjectMeta{Labels: labels2}},
				{Spec: cpuOnly, ObjectMeta: metav1.ObjectMeta{Labels: labels1}},
				{Spec: cpuOnly2, ObjectMeta: metav1.ObjectMeta{Labels: labels1}},
				{Spec: cpuAndMemory, ObjectMeta: metav1.ObjectMeta{Labels: labels1}},
			},
		},
		{
			/*
				Node1 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (5000 * 10) / 20000 = 2.5
				Node1 Score: (6 + 2.5) / 2 = 4

				Node2 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (10000 * 10) / 20000 = 5
				Node2 Score: (6 + 5) / 2 = 5
			*/
			pod:          &v1.Pod{Spec: cpuAndMemory},
			nodes:        []*v1.Node{makeNode("machine1", 10000, 20000), makeNode("machine2", 10000, 20000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 4}, {Host: "machine2", Score: 5}},
			test:         "resources requested, pods scheduled with resources",
			pods: []*v1.Pod{
				{Spec: cpuOnly},
				{Spec: cpuAndMemory},
			},
		},
	}

	for _, test := range tests {
		nodeNameToInfo := schedulercache.CreateNodeNameToInfoMap(test.pods, test.nodes)
		list, err := priorityFunction(MostRequestedPriorityMap, nil)(test.pod, nodeNameToInfo, test.nodes)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if !reflect.DeepEqual(test.expectedList, list) {
			t.Errorf("%s: expected %#v, got %#v", test.test, test.expectedList, list)
		}
	}
}
<commit_msg>Improved code coverage for plugin/pkg/scheduler/algorithm/priorities/most_requested.go<commit_after>/*
Copyright 2016 The Kubernetes 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 priorities

import (
	"reflect"
	"testing"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api/v1"
	schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
	"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
)

func TestMostRequested(t *testing.T) {
	labels1 := map[string]string{
		"foo": "bar",
		"baz": "blah",
	}
	labels2 := map[string]string{
		"bar": "foo",
		"baz": "blah",
	}
	noResources := v1.PodSpec{
		Containers: []v1.Container{},
	}
	cpuOnly := v1.PodSpec{
		NodeName: "machine1",
		Containers: []v1.Container{
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("1000m"),
						"memory": resource.MustParse("0"),
					},
				},
			},
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("2000m"),
						"memory": resource.MustParse("0"),
					},
				},
			},
		},
	}
	cpuOnly2 := cpuOnly
	cpuOnly2.NodeName = "machine2"
	cpuAndMemory := v1.PodSpec{
		NodeName: "machine2",
		Containers: []v1.Container{
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("1000m"),
						"memory": resource.MustParse("2000"),
					},
				},
			},
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("2000m"),
						"memory": resource.MustParse("3000"),
					},
				},
			},
		},
	}
	bigCpuAndMemory := v1.PodSpec{
		NodeName: "machine1",
		Containers: []v1.Container{
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("2000m"),
						"memory": resource.MustParse("4000"),
					},
				},
			},
			{
				Resources: v1.ResourceRequirements{
					Requests: v1.ResourceList{
						"cpu":    resource.MustParse("3000m"),
						"memory": resource.MustParse("5000"),
					},
				},
			},
		},
	}
	tests := []struct {
		pod          *v1.Pod
		pods         []*v1.Pod
		nodes        []*v1.Node
		expectedList schedulerapi.HostPriorityList
		test         string
	}{
		{
			/*
				Node1 scores (used resources) on 0-10 scale
				CPU Score: (0 * 10  / 4000 = 0
				Memory Score: (0 * 10) / 10000 = 0
				Node1 Score: (0 + 0) / 2 = 0

				Node2 scores (used resources) on 0-10 scale
				CPU Score: (0 * 10 / 4000 = 0
				Memory Score: (0 * 10 / 10000 = 0
				Node2 Score: (0 + 0) / 2 = 0
			*/
			pod:          &v1.Pod{Spec: noResources},
			nodes:        []*v1.Node{makeNode("machine1", 4000, 10000), makeNode("machine2", 4000, 10000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 0}, {Host: "machine2", Score: 0}},
			test:         "nothing scheduled, nothing requested",
		},
		{
			/*
				Node1 scores on 0-10 scale
				CPU Score: (3000 * 10 / 4000 = 7.5
				Memory Score: (5000 * 10) / 10000 = 5
				Node1 Score: (7.5 + 5) / 2 = 6

				Node2 scores on 0-10 scale
				CPU Score: (3000 * 10 / 6000 = 5
				Memory Score: (5000 * 10 / 10000 = 5
				Node2 Score: (5 + 5) / 2 = 5
			*/
			pod:          &v1.Pod{Spec: cpuAndMemory},
			nodes:        []*v1.Node{makeNode("machine1", 4000, 10000), makeNode("machine2", 6000, 10000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 6}, {Host: "machine2", Score: 5}},
			test:         "nothing scheduled, resources requested, differently sized machines",
		},
		{
			/*
				Node1 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (0 * 10) / 20000 = 10
				Node1 Score: (6 + 0) / 2 = 3

				Node2 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (5000 * 10) / 20000 = 2.5
				Node2 Score: (6 + 2.5) / 2 = 4
			*/
			pod:          &v1.Pod{Spec: noResources},
			nodes:        []*v1.Node{makeNode("machine1", 10000, 20000), makeNode("machine2", 10000, 20000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 3}, {Host: "machine2", Score: 4}},
			test:         "no resources requested, pods scheduled with resources",
			pods: []*v1.Pod{
				{Spec: cpuOnly, ObjectMeta: metav1.ObjectMeta{Labels: labels2}},
				{Spec: cpuOnly, ObjectMeta: metav1.ObjectMeta{Labels: labels1}},
				{Spec: cpuOnly2, ObjectMeta: metav1.ObjectMeta{Labels: labels1}},
				{Spec: cpuAndMemory, ObjectMeta: metav1.ObjectMeta{Labels: labels1}},
			},
		},
		{
			/*
				Node1 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (5000 * 10) / 20000 = 2.5
				Node1 Score: (6 + 2.5) / 2 = 4

				Node2 scores on 0-10 scale
				CPU Score: (6000 * 10) / 10000 = 6
				Memory Score: (10000 * 10) / 20000 = 5
				Node2 Score: (6 + 5) / 2 = 5
			*/
			pod:          &v1.Pod{Spec: cpuAndMemory},
			nodes:        []*v1.Node{makeNode("machine1", 10000, 20000), makeNode("machine2", 10000, 20000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 4}, {Host: "machine2", Score: 5}},
			test:         "resources requested, pods scheduled with resources",
			pods: []*v1.Pod{
				{Spec: cpuOnly},
				{Spec: cpuAndMemory},
			},
		},
		{
			/*
				Node1 scores on 0-10 scale
				CPU Score: 5000 > 4000 return 0
				Memory Score: (9000 * 10) / 10000 = 9
				Node1 Score: (0 + 9) / 2 = 4

				Node2 scores on 0-10 scale
				CPU Score: (5000 * 10) / 10000 = 5
				Memory Score: 9000 > 8000 return 0
				Node2 Score: (5 + 0) / 2 = 2
			*/
			pod:          &v1.Pod{Spec: bigCpuAndMemory},
			nodes:        []*v1.Node{makeNode("machine1", 4000, 10000), makeNode("machine2", 10000, 8000)},
			expectedList: []schedulerapi.HostPriority{{Host: "machine1", Score: 4}, {Host: "machine2", Score: 2}},
			test:         "resources requested with more than the node, pods scheduled with resources",
		},
	}

	for _, test := range tests {
		nodeNameToInfo := schedulercache.CreateNodeNameToInfoMap(test.pods, test.nodes)
		list, err := priorityFunction(MostRequestedPriorityMap, nil)(test.pod, nodeNameToInfo, test.nodes)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if !reflect.DeepEqual(test.expectedList, list) {
			t.Errorf("%s: expected %#v, got %#v", test.test, test.expectedList, list)
		}
	}
}
<|endoftext|>


<commit_before>/* httpstress is a library for HTTP stress testing.
It launches one goroutine per concurrent connection and does not count successful attempts.

A CLI utility is avaliable at github.com/chillum/httpstress-go */
package httpstress

/* Copyright 2014 Chai Chillum

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. */

import (
	"errors"
	"net/http"
	"regexp"
)

// Library version
const Version = "1.1"

/* httpstress.Test launches {conn} goroutines to fetch HTTP/HTTPS locations in {urls} list.
If {max} is more than {conn}, more goroutines will spawn as other are finished,
resulting in {max} queries (but no more than {conn} in every moment).
Returns map: {url}/{failed} or error (failed URL message). Example:

	urls := []string{"https://google.com", "http://localhost"}

	out, err := httpstress.Test(2, 4, urls) // Makes 4 HTTP requests total, 2 concurrent.

	if err != nil {
		// Invalid arguments
	} else {
		if len(out) == 0 {
			// No failed requests.
		} else {
			// Process failed requests.
			for url, num := range out {
				log.Println(url, "failed", num, "times.")
			}
		}
	} */
func Test(conn int, max int, urls []string) (results map[string]int, err error) {
	for _, i := range urls {
		if m, _ := regexp.MatchString("^https?://", i); !m {
			err = errors.New("Not a HTTPS? URL: " + i)
			return
		}
	}

	results = make(map[string]int)
	failures := make(chan string)
	finished := make(chan bool)
	total := len(urls) - 1
	trans := &http.Transport{MaxIdleConnsPerHost: conn} // Use persistent connections.
	client := &http.Client{Transport: trans}
	n := 0
	i := 0

	go logger(failures, results)
	for ; i < conn; i++ { // Launch initial workers.
		go worker(&urls[n], failures, finished, client)

		if n < total {
			n++
		} else {
			n = 0
		}
	}
	for ; i < max; i++ { // Launch more workers as initial finish.
		if <-finished {
			go worker(&urls[n], failures, finished, client)

			if n < total {
				n++
			} else {
				n = 0
			}
		}
	}
	for i := 0; i < conn; i++ { // Wait for active workers.
		<-finished
	}
	return
}

func logger(failures <-chan string, results map[string]int) {
	for {
		select {
		case url := <-failures:
			results[url]++
		}
	}
}

func worker(url *string, failures chan<- string, finished chan<- bool, client *http.Client) {
	resp, err := client.Get(*url)
	if err != nil {
		failures <- *url
	}
	if resp != nil {
		resp.Body.Close()
	}
	finished <- true
}
<commit_msg>Revert back the error message<commit_after>/* httpstress is a library for HTTP stress testing.
It launches one goroutine per concurrent connection and does not count successful attempts.

A CLI utility is avaliable at github.com/chillum/httpstress-go */
package httpstress

/* Copyright 2014 Chai Chillum

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. */

import (
	"errors"
	"net/http"
	"regexp"
)

// Library version
const Version = "1.1"

/* httpstress.Test launches {conn} goroutines to fetch HTTP/HTTPS locations in {urls} list.
If {max} is more than {conn}, more goroutines will spawn as other are finished,
resulting in {max} queries (but no more than {conn} in every moment).
Returns map: {url}/{failed} or error (failed URL message). Example:

	urls := []string{"https://google.com", "http://localhost"}

	out, err := httpstress.Test(2, 4, urls) // Makes 4 HTTP requests total, 2 concurrent.

	if err != nil {
		// Invalid arguments
	} else {
		if len(out) == 0 {
			// No failed requests.
		} else {
			// Process failed requests.
			for url, num := range out {
				log.Println(url, "failed", num, "times.")
			}
		}
	} */
func Test(conn int, max int, urls []string) (results map[string]int, err error) {
	for _, i := range urls {
		if m, _ := regexp.MatchString("^https?://", i); !m {
			err = errors.New("Not a HTTP/HTTPS URL: " + i)
			return
		}
	}

	results = make(map[string]int)
	failures := make(chan string)
	finished := make(chan bool)
	total := len(urls) - 1
	trans := &http.Transport{MaxIdleConnsPerHost: conn} // Use persistent connections.
	client := &http.Client{Transport: trans}
	n := 0
	i := 0

	go logger(failures, results)
	for ; i < conn; i++ { // Launch initial workers.
		go worker(&urls[n], failures, finished, client)

		if n < total {
			n++
		} else {
			n = 0
		}
	}
	for ; i < max; i++ { // Launch more workers as initial finish.
		if <-finished {
			go worker(&urls[n], failures, finished, client)

			if n < total {
				n++
			} else {
				n = 0
			}
		}
	}
	for i := 0; i < conn; i++ { // Wait for active workers.
		<-finished
	}
	return
}

func logger(failures <-chan string, results map[string]int) {
	for {
		select {
		case url := <-failures:
			results[url]++
		}
	}
}

func worker(url *string, failures chan<- string, finished chan<- bool, client *http.Client) {
	resp, err := client.Get(*url)
	if err != nil {
		failures <- *url
	}
	if resp != nil {
		resp.Body.Close()
	}
	finished <- true
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Intel Corporation
//
// 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 virtcontainers

import (
	"fmt"
	"math/rand"
	"path/filepath"
	"syscall"
	"time"

	"github.com/golang/glog"

	hyperJson "github.com/hyperhq/runv/hyperstart/api/json"
	"github.com/sameo/virtcontainers/hyperstart"
)

var defaultSockPathTemplates = []string{"/tmp/hyper-pod-%s.sock", "/tmp/tty-pod%s.sock"}
var defaultChannelTemplate = "sh.hyper.channel.%d"
var defaultDeviceIDTemplate = "channel%d"
var defaultIDTemplate = "charch%d"
var defaultSharedDir = "/tmp/hyper/shared/pods/"
var mountTag = "hyperShared"

const (
	unixSocket = "unix"
)

// HyperConfig is a structure storing information needed for
// hyperstart agent initialization.
type HyperConfig struct {
	SockCtlName string
	SockTtyName string
	Volumes     []Volume
	Sockets     []Socket
}

func (c *HyperConfig) validate(pod Pod) bool {
	if len(c.Sockets) == 0 {
		glog.Infof("No sockets from configuration\n")

		podSocketPaths := []string{
			fmt.Sprintf(defaultSockPathTemplates[0], pod.id),
			fmt.Sprintf(defaultSockPathTemplates[1], pod.id),
		}

		c.SockCtlName = podSocketPaths[0]
		c.SockTtyName = podSocketPaths[1]

		for i := 0; i < len(podSocketPaths); i++ {
			s := Socket{
				DeviceID: fmt.Sprintf(defaultDeviceIDTemplate, i),
				ID:       fmt.Sprintf(defaultIDTemplate, i),
				HostPath: podSocketPaths[i],
				Name:     fmt.Sprintf(defaultChannelTemplate, i),
			}
			c.Sockets = append(c.Sockets, s)
		}
	}

	if len(c.Sockets) != 2 {
		return false
	}

	glog.Infof("Hyperstart config %v\n", c)

	return true
}

// hyper is the Agent interface implementation for hyperstart.
type hyper struct {
	pod    Pod
	config HyperConfig

	hyperstart *hyperstart.Hyperstart
}

// ExecInfo is the structure corresponding to the format
// expected by hyperstart to execute a command on the guest.
type ExecInfo struct {
	Container string            `json:"container"`
	Process   hyperJson.Process `json:"process"`
}

func (h *hyper) retryConnectSocket(retry int) error {
	var err error

	for i := 0; i < retry; i++ {
		err = h.hyperstart.OpenSockets()
		if err == nil {
			break
		}

		select {
		case <-time.After(100 * time.Millisecond):
			break
		}
	}

	return err
}

func (h *hyper) buildHyperContainerProcess(cmd Cmd) (hyperJson.Process, error) {
	var envVars []hyperJson.EnvironmentVar

	for _, e := range cmd.Envs {
		envVar := hyperJson.EnvironmentVar{
			Env:   e.Var,
			Value: e.Value,
		}

		envVars = append(envVars, envVar)
	}

	process := hyperJson.Process{
		User:    cmd.User,
		Group:   cmd.Group,
		Stdio:   uint64(rand.Int63()),
		Stderr:  uint64(rand.Int63()),
		Args:    cmd.Args,
		Envs:    envVars,
		Workdir: cmd.WorkDir,
	}

	return process, nil
}

func bindMountContainerRootfs(pod Pod, container ContainerConfig) error {
	rootfsDest := filepath.Join(defaultSharedDir, pod.id, container.ID)

	return bindMount(container.RootFs, rootfsDest)
}

func bindUnmountAllRootfs(pod Pod) {
	for _, c := range pod.containers {
		rootfsDest := filepath.Join(defaultSharedDir, pod.id, c.ID)
		syscall.Unmount(rootfsDest, 0)
	}
}

// init is the agent initialization implementation for hyperstart.
func (h *hyper) init(pod Pod, config interface{}) error {
	switch c := config.(type) {
	case HyperConfig:
		if c.validate(pod) == false {
			return fmt.Errorf("Invalid configuration\n")
		}
		h.config = c
	default:
		return fmt.Errorf("Invalid config type\n")
	}

	h.pod = pod

	for _, volume := range h.config.Volumes {
		err := h.pod.hypervisor.addDevice(volume, fsDev)
		if err != nil {
			return err
		}
	}

	for _, socket := range h.config.Sockets {
		err := h.pod.hypervisor.addDevice(socket, serialPortDev)
		if err != nil {
			return err
		}
	}

	for _, c := range pod.containers {
		err := bindMountContainerRootfs(pod, c)
		if err != nil {
			bindUnmountAllRootfs(pod)
			return err
		}
	}

	// Adding the hyper shared volume.
	// This volume contains all bind mounted container bundles.
	sharedVolume := Volume{
		MountTag: mountTag,
		HostPath: filepath.Join(defaultSharedDir, pod.id),
	}

	err := h.pod.hypervisor.addDevice(sharedVolume, fsDev)
	if err != nil {
		return err
	}

	h.hyperstart = hyperstart.NewHyperstart(h.config.SockCtlName, h.config.SockTtyName, unixSocket)

	return nil
}

// start is the agent starting implementation for hyperstart.
func (h *hyper) startAgent() error {
	if h.hyperstart.IsStarted() == true {
		return nil
	}

	err := h.retryConnectSocket(1000)
	if err != nil {
		return err
	}

	_, err = h.hyperstart.SendCtlMessage(hyperstart.Ping, nil)
	if err != nil {
		return err
	}

	return nil
}

// exec is the agent command execution implementation for hyperstart.
func (h *hyper) exec(podID string, contID string, cmd Cmd) error {
	process, err := h.buildHyperContainerProcess(cmd)
	if err != nil {
		return err
	}

	execInfo := ExecInfo{
		Container: contID,
		Process:   process,
	}

	payload, err := hyperstart.FormatMessage(execInfo)
	if err != nil {
		return err
	}

	_, err = h.hyperstart.SendCtlMessage(hyperstart.ExecCmd, payload)
	if err != nil {
		return err
	}

	return nil
}

// startPod is the agent Pod starting implementation for hyperstart.
func (h *hyper) startPod(config PodConfig) error {
	var containers []hyperJson.Container

	for _, c := range config.Containers {
		process, err := h.buildHyperContainerProcess(c.Cmd)
		if err != nil {
			return err
		}

		container := hyperJson.Container{
			Id:      c.ID,
			Image:   c.ID,
			Rootfs:  "rootfs",
			Process: process,
		}

		containers = append(containers, container)
	}

	hyperPod := hyperJson.Pod{
		Hostname:   config.ID,
		Containers: containers,
		ShareDir:   mountTag,
	}

	payload, err := hyperstart.FormatMessage(hyperPod)
	if err != nil {
		return err
	}

	_, err = h.hyperstart.SendCtlMessage(hyperstart.StartPod, payload)
	if err != nil {
		return err
	}

	return nil
}

// stopPod is the agent Pod stopping implementation for hyperstart.
func (h *hyper) stopPod(config PodConfig) error {
	_, err := h.hyperstart.SendCtlMessage(hyperstart.DestroyPod, nil)
	if err != nil {
		return err
	}

	return nil
}

// stop is the agent stopping implementation for hyperstart.
func (h *hyper) stopAgent() error {
	err := h.hyperstart.CloseSockets()
	if err != nil {
		return err
	}

	bindUnmountAllRootfs(h.pod)

	return nil
}

// startContainer is the agent Container starting implementation for hyperstart.
func (h *hyper) startContainer(podConfig PodConfig, contConfig ContainerConfig) error {
	return nil
}

// stopContainer is the agent Container stopping implementation for hyperstart.
func (h *hyper) stopContainer(podConfig PodConfig, contConfig ContainerConfig) error {
	return nil
}
<commit_msg>agent: hyperstart: Implement StartContainer and StopContainer<commit_after>//
// Copyright (c) 2016 Intel Corporation
//
// 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 virtcontainers

import (
	"fmt"
	"math/rand"
	"path/filepath"
	"syscall"
	"time"

	"github.com/golang/glog"

	hyperJson "github.com/hyperhq/runv/hyperstart/api/json"
	"github.com/sameo/virtcontainers/hyperstart"
)

var defaultSockPathTemplates = []string{"/tmp/hyper-pod-%s.sock", "/tmp/tty-pod%s.sock"}
var defaultChannelTemplate = "sh.hyper.channel.%d"
var defaultDeviceIDTemplate = "channel%d"
var defaultIDTemplate = "charch%d"
var defaultSharedDir = "/tmp/hyper/shared/pods/"
var mountTag = "hyperShared"

const (
	unixSocket = "unix"
)

// HyperConfig is a structure storing information needed for
// hyperstart agent initialization.
type HyperConfig struct {
	SockCtlName string
	SockTtyName string
	Volumes     []Volume
	Sockets     []Socket
}

func (c *HyperConfig) validate(pod Pod) bool {
	if len(c.Sockets) == 0 {
		glog.Infof("No sockets from configuration\n")

		podSocketPaths := []string{
			fmt.Sprintf(defaultSockPathTemplates[0], pod.id),
			fmt.Sprintf(defaultSockPathTemplates[1], pod.id),
		}

		c.SockCtlName = podSocketPaths[0]
		c.SockTtyName = podSocketPaths[1]

		for i := 0; i < len(podSocketPaths); i++ {
			s := Socket{
				DeviceID: fmt.Sprintf(defaultDeviceIDTemplate, i),
				ID:       fmt.Sprintf(defaultIDTemplate, i),
				HostPath: podSocketPaths[i],
				Name:     fmt.Sprintf(defaultChannelTemplate, i),
			}
			c.Sockets = append(c.Sockets, s)
		}
	}

	if len(c.Sockets) != 2 {
		return false
	}

	glog.Infof("Hyperstart config %v\n", c)

	return true
}

// hyper is the Agent interface implementation for hyperstart.
type hyper struct {
	pod    Pod
	config HyperConfig

	hyperstart *hyperstart.Hyperstart
}

// ExecInfo is the structure corresponding to the format
// expected by hyperstart to execute a command on the guest.
type ExecInfo struct {
	Container string            `json:"container"`
	Process   hyperJson.Process `json:"process"`
}

func (h *hyper) retryConnectSocket(retry int) error {
	var err error

	for i := 0; i < retry; i++ {
		err = h.hyperstart.OpenSockets()
		if err == nil {
			break
		}

		select {
		case <-time.After(100 * time.Millisecond):
			break
		}
	}

	return err
}

func (h *hyper) buildHyperContainerProcess(cmd Cmd) (hyperJson.Process, error) {
	var envVars []hyperJson.EnvironmentVar

	for _, e := range cmd.Envs {
		envVar := hyperJson.EnvironmentVar{
			Env:   e.Var,
			Value: e.Value,
		}

		envVars = append(envVars, envVar)
	}

	process := hyperJson.Process{
		User:    cmd.User,
		Group:   cmd.Group,
		Stdio:   uint64(rand.Int63()),
		Stderr:  uint64(rand.Int63()),
		Args:    cmd.Args,
		Envs:    envVars,
		Workdir: cmd.WorkDir,
	}

	return process, nil
}

func bindMountContainerRootfs(pod Pod, container ContainerConfig) error {
	rootfsDest := filepath.Join(defaultSharedDir, pod.id, container.ID)

	return bindMount(container.RootFs, rootfsDest)
}

func bindUnmountAllRootfs(pod Pod) {
	for _, c := range pod.containers {
		rootfsDest := filepath.Join(defaultSharedDir, pod.id, c.ID)
		syscall.Unmount(rootfsDest, 0)
	}
}

// init is the agent initialization implementation for hyperstart.
func (h *hyper) init(pod Pod, config interface{}) error {
	switch c := config.(type) {
	case HyperConfig:
		if c.validate(pod) == false {
			return fmt.Errorf("Invalid configuration\n")
		}
		h.config = c
	default:
		return fmt.Errorf("Invalid config type\n")
	}

	h.pod = pod

	for _, volume := range h.config.Volumes {
		err := h.pod.hypervisor.addDevice(volume, fsDev)
		if err != nil {
			return err
		}
	}

	for _, socket := range h.config.Sockets {
		err := h.pod.hypervisor.addDevice(socket, serialPortDev)
		if err != nil {
			return err
		}
	}

	for _, c := range pod.containers {
		err := bindMountContainerRootfs(pod, c)
		if err != nil {
			bindUnmountAllRootfs(pod)
			return err
		}
	}

	// Adding the hyper shared volume.
	// This volume contains all bind mounted container bundles.
	sharedVolume := Volume{
		MountTag: mountTag,
		HostPath: filepath.Join(defaultSharedDir, pod.id),
	}

	err := h.pod.hypervisor.addDevice(sharedVolume, fsDev)
	if err != nil {
		return err
	}

	h.hyperstart = hyperstart.NewHyperstart(h.config.SockCtlName, h.config.SockTtyName, unixSocket)

	return nil
}

// start is the agent starting implementation for hyperstart.
func (h *hyper) startAgent() error {
	if h.hyperstart.IsStarted() == true {
		return nil
	}

	err := h.retryConnectSocket(1000)
	if err != nil {
		return err
	}

	_, err = h.hyperstart.SendCtlMessage(hyperstart.Ping, nil)
	if err != nil {
		return err
	}

	return nil
}

// exec is the agent command execution implementation for hyperstart.
func (h *hyper) exec(podID string, contID string, cmd Cmd) error {
	process, err := h.buildHyperContainerProcess(cmd)
	if err != nil {
		return err
	}

	execInfo := ExecInfo{
		Container: contID,
		Process:   process,
	}

	payload, err := hyperstart.FormatMessage(execInfo)
	if err != nil {
		return err
	}

	_, err = h.hyperstart.SendCtlMessage(hyperstart.ExecCmd, payload)
	if err != nil {
		return err
	}

	return nil
}

// startPod is the agent Pod starting implementation for hyperstart.
func (h *hyper) startPod(config PodConfig) error {
	var containers []hyperJson.Container

	for _, c := range config.Containers {
		process, err := h.buildHyperContainerProcess(c.Cmd)
		if err != nil {
			return err
		}

		container := hyperJson.Container{
			Id:      c.ID,
			Image:   c.ID,
			Rootfs:  "rootfs",
			Process: process,
		}

		containers = append(containers, container)
	}

	hyperPod := hyperJson.Pod{
		Hostname:   config.ID,
		Containers: containers,
		ShareDir:   mountTag,
	}

	payload, err := hyperstart.FormatMessage(hyperPod)
	if err != nil {
		return err
	}

	_, err = h.hyperstart.SendCtlMessage(hyperstart.StartPod, payload)
	if err != nil {
		return err
	}

	return nil
}

// stopPod is the agent Pod stopping implementation for hyperstart.
func (h *hyper) stopPod(config PodConfig) error {
	_, err := h.hyperstart.SendCtlMessage(hyperstart.DestroyPod, nil)
	if err != nil {
		return err
	}

	return nil
}

// stop is the agent stopping implementation for hyperstart.
func (h *hyper) stopAgent() error {
	err := h.hyperstart.CloseSockets()
	if err != nil {
		return err
	}

	bindUnmountAllRootfs(h.pod)

	return nil
}

// startContainer is the agent Container starting implementation for hyperstart.
func (h *hyper) startContainer(podConfig PodConfig, contConfig ContainerConfig) error {
	process, err := h.buildHyperContainerProcess(contConfig.Cmd)
	if err != nil {
		return err
	}

	container := hyperJson.Container{
		Id:      contConfig.ID,
		Image:   contConfig.ID,
		Rootfs:  contConfig.RootFs,
		Process: process,
	}

	payload, err := hyperstart.FormatMessage(container)
	if err != nil {
		return err
	}

	_, err = h.hyperstart.SendCtlMessage(hyperstart.NewContainer, payload)
	if err != nil {
		return err
	}

	return nil
}

// stopContainer is the agent Container stopping implementation for hyperstart.
func (h *hyper) stopContainer(podConfig PodConfig, contConfig ContainerConfig) error {
	payload := []byte(fmt.Sprintf("{\"container\":\"%s\",\"signal\":\"9\"}", contConfig.ID))

	_, err := h.hyperstart.SendCtlMessage(hyperstart.KillContainer, payload)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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
//
//     https://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 snippets

// [START compute_reset_instance]
import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
)

// resetInstance resets a stopped Google Compute Engine instance (with unencrypted disks).
func resetInstance(w io.Writer, projectID, zone, instanceName string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"

	ctx := context.Background()
	instancesClient, err := compute.NewInstancesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewInstancesRESTClient: %v", err)
	}
	defer instancesClient.Close()

	req := &computepb.ResetInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
	}

	op, err := instancesClient.Reset(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to reset instance: %v", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %v", err)
	}

	fmt.Fprintf(w, "Instance reset\n")

	return nil
}

// [END compute_reset_instance]
<commit_msg>fix: Fix typo on function comment (#2683)<commit_after>// Copyright 2021 Google LLC
//
// 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
//
//     https://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 snippets

// [START compute_reset_instance]
import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
)

// resetInstance resets a running Google Compute Engine instance (with unencrypted disks).
func resetInstance(w io.Writer, projectID, zone, instanceName string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"

	ctx := context.Background()
	instancesClient, err := compute.NewInstancesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewInstancesRESTClient: %v", err)
	}
	defer instancesClient.Close()

	req := &computepb.ResetInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
	}

	op, err := instancesClient.Reset(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to reset instance: %v", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %v", err)
	}

	fmt.Fprintf(w, "Instance reset\n")

	return nil
}

// [END compute_reset_instance]
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"
)

type roomInitializeFunc func(arwServer *ARWServer)

type Room struct {
	tag               string
	name              string
	password          string
	id                int
	cappacity         int
	maxVariableCount  int
	userList          []User
	roomVariables     []RoomVariable
	extensionHandlers []ExtensionRequest
	InitializeMethod  roomInitializeFunc
}

func (room *Room) Init(arwServer *ARWServer) {
	room.userList = make([]User, 0, room.cappacity)
	room.roomVariables = make([]RoomVariable, 0, room.maxVariableCount)

	if room.InitializeMethod != nil {
		room.InitializeMethod(arwServer)
	}
}

func (room *Room) AddUserToRoom(arwServer *ARWServer, u User) {
	room.userList = append(room.userList, u)

	var arwObj ARWObject

	arwObj.requestName = Join_Room
	arwObj.eventParams.PutString("RoomName", room.name)
	arwObj.eventParams.PutString("RoomTag", room.tag)

	arwServer.SendRequestToUser(u, arwObj)

	var arwObjforTheOthers ARWObject
	arwObjforTheOthers.requestName = User_Enter_Room
	arwObjforTheOthers.eventParams.PutString("userName", u.name)
	arwObjforTheOthers.eventParams.PutInt("userId", u.id)
	arwObjforTheOthers.eventParams.PutString("isMe", "false")

	room.SendRequestAllUserWithoutMe(*arwServer, arwObjforTheOthers, u)
	fmt.Println("User join Room - User Name : ", u.name)
}

func (room *Room) IsFull() bool {
	if len(room.userList) < cap(room.userList) {
		return true
	}
	return false
}

func (room *Room) AddRoomVariables(variables []RoomVariable) {
	varIsExist := false
	for ii := 0; ii < len(variables); ii++ {
		for jj := 0; jj < len(room.roomVariables); jj++ {

			if variables[ii].key == room.roomVariables[jj].key {
				varIsExist = true
				room.roomVariables[jj].value = variables[ii].value
				break
			}
		}

		if !varIsExist {
			room.roomVariables = append(room.roomVariables, variables[ii])
		}
	}
}

func (room *Room) GetStringVariable(key string) (string, error) {
	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			return room.roomVariables[ii].value, errors.New("")
		}
	}

	return "", errors.New("Variable does not exist")
}

func (room *Room) GetIntVariable(key string) (int, error) {

	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			value, err := strconv.Atoi(room.roomVariables[ii].value)
			return value, err
		}
	}

	return 0, errors.New("Variable does not exist")
}

func (room *Room) GetFloatVariable(key string) (float64, error) {

	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			value, err := strconv.ParseFloat(room.roomVariables[ii].value, 64)
			return value, err
		}
	}

	return 0, errors.New("Variable does not exist")
}

func (room *Room) GetBoolVariable(key string) (bool, error) {

	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			value, err := strconv.ParseBool(room.roomVariables[ii].value)
			return value, err
		}
	}

	return false, errors.New("Variable does not exist")
}

func (room *Room) SendRequestAllUserWithoutMe(arwServer ARWServer, arwObj ARWObject, user User) {

	if len(room.userList) == 0 {
		return
	}

	for ii := range room.userList {
		if room.userList[ii].id != user.id {
			arwServer.SendRequestToUser(room.userList[ii], arwObj)
		}
	}
}

func (room *Room) SendRequestAllUser(arwServer ARWServer, arwObj ARWObject) {

	if len(room.userList) == 0 {
		return
	}

	for ii := range room.userList {
		arwServer.SendRequestToUser(room.userList[ii], arwObj)
	}
}

func (room *Room) AddExtensionHandler(cmd string, handler ExtensionHandler) {
	if len(room.extensionHandlers) != 0 {
		for ii := 0; ii < len(room.extensionHandlers); ii++ {
			if cmd == room.extensionHandlers[ii].cmd {
				return
			}
		}
	}

	var newExtension *ExtensionRequest
	newExtension.cmd = cmd
	newExtension.handler = handler

	room.extensionHandlers = append(room.extensionHandlers, *newExtension)
}
<commit_msg>Initialize Func<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"
)

type roomInitializeFunc func(arwServer *ARWServer, room *Room)

type Room struct {
	tag               string
	name              string
	password          string
	id                int
	cappacity         int
	maxVariableCount  int
	userList          []User
	roomVariables     []RoomVariable
	extensionHandlers []ExtensionRequest
	InitializeMethod  roomInitializeFunc
}

func (room *Room) Init(arwServer *ARWServer) {
	room.userList = make([]User, 0, room.cappacity)
	room.roomVariables = make([]RoomVariable, 0, room.maxVariableCount)

	if room.InitializeMethod != nil {
		room.InitializeMethod(arwServer, room)
	}
}

func (room *Room) AddUserToRoom(arwServer *ARWServer, u User) {
	room.userList = append(room.userList, u)

	var arwObj ARWObject

	arwObj.requestName = Join_Room
	arwObj.eventParams.PutString("RoomName", room.name)
	arwObj.eventParams.PutString("RoomTag", room.tag)

	arwServer.SendRequestToUser(u, arwObj)

	var arwObjforTheOthers ARWObject
	arwObjforTheOthers.requestName = User_Enter_Room
	arwObjforTheOthers.eventParams.PutString("userName", u.name)
	arwObjforTheOthers.eventParams.PutInt("userId", u.id)
	arwObjforTheOthers.eventParams.PutString("isMe", "false")

	room.SendRequestAllUserWithoutMe(*arwServer, arwObjforTheOthers, u)
	fmt.Println("User join Room - User Name : ", u.name)
}

func (room *Room) IsFull() bool {
	if len(room.userList) < cap(room.userList) {
		return true
	}
	return false
}

func (room *Room) AddRoomVariables(variables []RoomVariable) {
	varIsExist := false
	for ii := 0; ii < len(variables); ii++ {
		for jj := 0; jj < len(room.roomVariables); jj++ {

			if variables[ii].key == room.roomVariables[jj].key {
				varIsExist = true
				room.roomVariables[jj].value = variables[ii].value
				break
			}
		}

		if !varIsExist {
			room.roomVariables = append(room.roomVariables, variables[ii])
		}
	}
}

func (room *Room) GetStringVariable(key string) (string, error) {
	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			return room.roomVariables[ii].value, errors.New("")
		}
	}

	return "", errors.New("Variable does not exist")
}

func (room *Room) GetIntVariable(key string) (int, error) {

	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			value, err := strconv.Atoi(room.roomVariables[ii].value)
			return value, err
		}
	}

	return 0, errors.New("Variable does not exist")
}

func (room *Room) GetFloatVariable(key string) (float64, error) {

	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			value, err := strconv.ParseFloat(room.roomVariables[ii].value, 64)
			return value, err
		}
	}

	return 0, errors.New("Variable does not exist")
}

func (room *Room) GetBoolVariable(key string) (bool, error) {

	for ii := 0; ii < len(room.roomVariables); ii++ {
		if room.roomVariables[ii].key == key {
			value, err := strconv.ParseBool(room.roomVariables[ii].value)
			return value, err
		}
	}

	return false, errors.New("Variable does not exist")
}

func (room *Room) SendRequestAllUserWithoutMe(arwServer ARWServer, arwObj ARWObject, user User) {

	if len(room.userList) == 0 {
		return
	}

	for ii := range room.userList {
		if room.userList[ii].id != user.id {
			arwServer.SendRequestToUser(room.userList[ii], arwObj)
		}
	}
}

func (room *Room) SendRequestAllUser(arwServer ARWServer, arwObj ARWObject) {

	if len(room.userList) == 0 {
		return
	}

	for ii := range room.userList {
		arwServer.SendRequestToUser(room.userList[ii], arwObj)
	}
}

func (room *Room) AddExtensionHandler(cmd string, handler ExtensionHandler) {
	if len(room.extensionHandlers) != 0 {
		for ii := 0; ii < len(room.extensionHandlers); ii++ {
			if cmd == room.extensionHandlers[ii].cmd {
				return
			}
		}
	}

	var newExtension *ExtensionRequest
	newExtension.cmd = cmd
	newExtension.handler = handler

	room.extensionHandlers = append(room.extensionHandlers, *newExtension)
}
<|endoftext|>


<commit_before>// Package apex provides Lambda support for Go via a
// Node.js shim and this package for operating over
// stdio.
package apex

import (
	"encoding/json"
	"io"
	"log"
	"os"
)

// Handler handles Lambda events.
type Handler interface {
	Handle(json.RawMessage, *Context) (interface{}, error)
}

// HandlerFunc implements Handler.
type HandlerFunc func(json.RawMessage, *Context) (interface{}, error)

// Handle Lambda event.
func (h HandlerFunc) Handle(event json.RawMessage, ctx *Context) (interface{}, error) {
	return h(event, ctx)
}

// Context represents the context data provided by a Lambda invocation.
type Context struct {
	InvokeID                 string          `json:"invokeid"`
	RequestID                string          `json:"awsRequestId"`
	FunctionName             string          `json:"functionName"`
	FunctionVersion          string          `json:"functionVersion"`
	LogGroupName             string          `json:"logGroupName"`
	LogStreamName            string          `json:"logStreamName"`
	MemoryLimitInMB          string          `json:"memoryLimitInMB"`
	IsDefaultFunctionVersion bool            `json:"isDefaultFunctionVersion"`
	ClientContext            json.RawMessage `json:"clientContext"`
	Identity                 Identity        `json:"identity,omitempty"`
	InvokedFunctionARN       string          `json:"invokedFunctionArn"`
}

// Identity as defined in: http://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/lambda.html#identity-context
type Identity struct {
	CognitoIdentityID       string `json:"cognitoIdentityId"`
	CognitoIdentityIDPoolID string `json:"cognitoIdentityPoolId"`
}

// Handle Lambda events with the given handler.
func Handle(h Handler) {
	m := &manager{
		Reader:  os.Stdin,
		Writer:  os.Stdout,
		Handler: h,
	}

	m.Start()
}

// HandleFunc handles Lambda events with the given handler function.
func HandleFunc(h HandlerFunc) {
	Handle(h)
}

// input from the node shim.
type input struct {
	Event   json.RawMessage `json:"event"`
	Context *Context        `json:"context"`
}

// output for the node shim.
type output struct {
	Error string      `json:"error,omitempty"`
	Value interface{} `json:"value,omitempty"`
}

// manager for operating over stdio.
type manager struct {
	Reader  io.Reader
	Writer  io.Writer
	Handler Handler
}

// Start the manager.
func (m *manager) Start() {
	dec := json.NewDecoder(m.Reader)
	enc := json.NewEncoder(m.Writer)

	for {
		var msg input
		err := dec.Decode(&msg)

		if err == io.EOF {
			break
		}

		if err != nil {
			log.Printf("error decoding input: %s", err)
			break
		}

		v, err := m.Handler.Handle(msg.Event, msg.Context)
		out := output{Value: v}

		if err != nil {
			out.Error = err.Error()
		}

		if err := enc.Encode(out); err != nil {
			log.Printf("error encoding output: %s", err)
		}
	}
}
<commit_msg>shim: boomerang ID from input to allow multiplexed output<commit_after>// Package apex provides Lambda support for Go via a
// Node.js shim and this package for operating over
// stdio.
package apex

import (
	"encoding/json"
	"io"
	"log"
	"os"
)

// Handler handles Lambda events.
type Handler interface {
	Handle(json.RawMessage, *Context) (interface{}, error)
}

// HandlerFunc implements Handler.
type HandlerFunc func(json.RawMessage, *Context) (interface{}, error)

// Handle Lambda event.
func (h HandlerFunc) Handle(event json.RawMessage, ctx *Context) (interface{}, error) {
	return h(event, ctx)
}

// Context represents the context data provided by a Lambda invocation.
type Context struct {
	InvokeID                 string          `json:"invokeid"`
	RequestID                string          `json:"awsRequestId"`
	FunctionName             string          `json:"functionName"`
	FunctionVersion          string          `json:"functionVersion"`
	LogGroupName             string          `json:"logGroupName"`
	LogStreamName            string          `json:"logStreamName"`
	MemoryLimitInMB          string          `json:"memoryLimitInMB"`
	IsDefaultFunctionVersion bool            `json:"isDefaultFunctionVersion"`
	ClientContext            json.RawMessage `json:"clientContext"`
	Identity                 Identity        `json:"identity,omitempty"`
	InvokedFunctionARN       string          `json:"invokedFunctionArn"`
}

// Identity as defined in: http://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/lambda.html#identity-context
type Identity struct {
	CognitoIdentityID       string `json:"cognitoIdentityId"`
	CognitoIdentityIDPoolID string `json:"cognitoIdentityPoolId"`
}

// Handle Lambda events with the given handler.
func Handle(h Handler) {
	m := &manager{
		Reader:  os.Stdin,
		Writer:  os.Stdout,
		Handler: h,
	}

	m.Start()
}

// HandleFunc handles Lambda events with the given handler function.
func HandleFunc(h HandlerFunc) {
	Handle(h)
}

// input from the node shim.
type input struct {
	// ID is an itentifier that is boomeranged back to the called,
	// to allow for concurrent commands
	ID      string          `json:"id,omitempty"`
	Event   json.RawMessage `json:"event"`
	Context *Context        `json:"context"`
}

// output for the node shim.
type output struct {
	// The boomeranged ID from the caller
	ID    string      `json:"id,omitempty"`
	Error string      `json:"error,omitempty"`
	Value interface{} `json:"value,omitempty"`
}

// manager for operating over stdio.
type manager struct {
	Reader  io.Reader
	Writer  io.Writer
	Handler Handler
}

// Start the manager.
func (m *manager) Start() {
	dec := json.NewDecoder(m.Reader)
	enc := json.NewEncoder(m.Writer)

	for {
		var msg input
		err := dec.Decode(&msg)

		if err == io.EOF {
			break
		}

		if err != nil {
			log.Printf("error decoding input: %s", err)
			break
		}

		v, err := m.Handler.Handle(msg.Event, msg.Context)
		out := output{ID: msg.ID, Value: v}

		if err != nil {
			out.Error = err.Error()
		}

		if err := enc.Encode(out); err != nil {
			log.Printf("error encoding output: %s", err)
		}
	}
}
<|endoftext|>


<commit_before>package gcssync

import (
	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/google-api-go-client/storage/v1"
	"fmt"
	"net/http"
)

// ServiceConfig holds all informations about the bucket and project
type ServiceConfig struct {
	ProjectID  string
	BucketName string
}

// Client is connected to Google Cloud Storage bucket
type Client struct {
	service    *storage.Service
	projectId  string
	bucketName string
}

// GetBucketName return the name of the bucket the client is connected to
func (c *Client) GetBucketname() string {
	return c.bucketName
}

// NewClient connects to and authenficates against Google Cloud Storage
func NewClient(oauthConfig *oauth.Config, authCode string, serviceConfig *ServiceConfig) (*Client, error) {
	transport := &oauth.Transport{
		Config:    oauthConfig,
		Transport: http.DefaultTransport,
	}

	token, err := oauthConfig.TokenCache.Token()
	if err != nil {
		if authCode == "" {
			url := oauthConfig.AuthCodeURL("")
			fmt.Println("Visit URL to get a code then run again with -code=YOUR_CODE")
			fmt.Println(url)
			return &Client{}, fmt.Errorf("Could not get auth code")
		}
		token, err = transport.Exchange(authCode)
		if err != nil {
			return &Client{}, fmt.Errorf("Could not exchange token: %s", err.Error())
		}
		fmt.Printf("Token cached %s\n", oauthConfig.TokenCache)
	}

	transport.Token = token

	httpClient := transport.Client()

	service, err := storage.New(httpClient)

	if err != nil {
		return &Client{}, fmt.Errorf("Could not init client: %s", err.Error())
	}

	return &Client{
		service:    service,
		projectId:  serviceConfig.ProjectID,
		bucketName: serviceConfig.BucketName,
	}, nil
}
<commit_msg>refractor(doc): renamed according to golint<commit_after>package gcssync

import (
	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/google-api-go-client/storage/v1"
	"fmt"
	"net/http"
)

// ServiceConfig holds all informations about the bucket and project
type ServiceConfig struct {
	ProjectID  string
	BucketName string
}

// Client is connected to Google Cloud Storage bucket
type Client struct {
	service    *storage.Service
	projectID  string
	bucketName string
}

// GetBucketName return the name of the bucket the client is connected to
func (c *Client) GetBucketname() string {
	return c.bucketName
}

// NewClient connects to and authenficates against Google Cloud Storage
func NewClient(oauthConfig *oauth.Config, authCode string, serviceConfig *ServiceConfig) (*Client, error) {
	transport := &oauth.Transport{
		Config:    oauthConfig,
		Transport: http.DefaultTransport,
	}

	token, err := oauthConfig.TokenCache.Token()
	if err != nil {
		if authCode == "" {
			url := oauthConfig.AuthCodeURL("")
			fmt.Println("Visit URL to get a code then run again with -code=YOUR_CODE")
			fmt.Println(url)
			return &Client{}, fmt.Errorf("Could not get auth code")
		}
		token, err = transport.Exchange(authCode)
		if err != nil {
			return &Client{}, fmt.Errorf("Could not exchange token: %s", err.Error())
		}
		fmt.Printf("Token cached %s\n", oauthConfig.TokenCache)
	}

	transport.Token = token

	httpClient := transport.Client()

	service, err := storage.New(httpClient)

	if err != nil {
		return &Client{}, fmt.Errorf("Could not init client: %s", err.Error())
	}

	return &Client{
		service:    service,
		projectID:  serviceConfig.ProjectID,
		bucketName: serviceConfig.BucketName,
	}, nil
}
<|endoftext|>


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

package main
import (
	"fmt"
	"encoding/json"
	"net/http"
	"log"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"strings"
)

type AccessToken struct {
 	Token  string
 	Expiry int64
}

func googleOAuth2Config(domain string) *oauth2.Config {
	appConf := configuration()
	conf := &oauth2.Config{
 		ClientID:     appConf.GoogleClientID,
		ClientSecret: appConf.GoogleClientSecret,
 		RedirectURL:  "postmessage",
		Scopes:       []string{"https://www.googleapis.com/auth/plus.profile.emails.read"},
		Endpoint: google.Endpoint,
 	}
	return conf
}

func readHttpBody(response *http.Response) string {
	fmt.Println("Reading body")
 	bodyBuffer := make([]byte, 5000)
 	var str string
 	count, err := response.Body.Read(bodyBuffer)
 	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {
 		if err != nil {

 		}
 		str += string(bodyBuffer[:count])
 	}
 	return str
 }

func oauth2callback(w http.ResponseWriter, r *http.Request) {
	code := r.FormValue("code")
	fmt.Println("oauth2callback - url: " + r.URL.RawQuery)
	fmt.Println("oauth2callback - code: " + code)

	newAccount := r.FormValue("new_account")
 	conf := googleOAuth2Config(domain(r))
	tok, err := conf.Exchange(oauth2.NoContext, code)
	if err != nil {
		log.Fatal(err)
	}
	client := conf.Client(oauth2.NoContext, tok)
 	response, err := client.Get("https://www.googleapis.com/plus/v1/people/me")
 	// handle err. You need to change this into something more robust
 	// such as redirect back to home page with error message
 	if err != nil {
 		w.Write([]byte(err.Error()))
 	}
 	str := readHttpBody(response)
	type Email struct {
		Value string
		Type string
	}
	type OAuth2Response struct {
		Kind string
		Emails []Email
	}
	fmt.Println("oauth2callback - response: " + str)
	dec := json.NewDecoder(strings.NewReader(str))
	var m OAuth2Response
	if err := dec.Decode(&m); err != nil {
		log.Fatal(err)
	}
	for _, v := range m.Emails {
		fmt.Println("email (value, type): " + v.Value + ", " + v.Type)
	}
	email := "dummy@dummy.com"
	if len(m.Emails) != 1 {
		fmt.Println("NO VALID EMAIL OR TOO MANY")

	} else {
		email = m.Emails[0].Value
	}
	if newAccount == "true" {
		fmt.Println("NEW ACCOUNT")
		dbCreate(email)
		dbInsert(email, "#1")
	}
	w.Write([]byte(email))
}

<commit_msg>Modify google account scope to email<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main
import (
	"fmt"
	"encoding/json"
	"net/http"
	"log"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"strings"
)

type AccessToken struct {
 	Token  string
 	Expiry int64
}

func googleOAuth2Config(domain string) *oauth2.Config {
	appConf := configuration()
	conf := &oauth2.Config{
 		ClientID:     appConf.GoogleClientID,
		ClientSecret: appConf.GoogleClientSecret,
 		RedirectURL:  "postmessage",
		Scopes:       []string{"email"},
		Endpoint: google.Endpoint,
 	}
	return conf
}

func readHttpBody(response *http.Response) string {
	fmt.Println("Reading body")
 	bodyBuffer := make([]byte, 5000)
 	var str string
 	count, err := response.Body.Read(bodyBuffer)
 	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {
 		if err != nil {

 		}
 		str += string(bodyBuffer[:count])
 	}
 	return str
 }

func oauth2callback(w http.ResponseWriter, r *http.Request) {
	code := r.FormValue("code")
	fmt.Println("oauth2callback - url: " + r.URL.RawQuery)
	fmt.Println("oauth2callback - code: " + code)

	newAccount := r.FormValue("new_account")
 	conf := googleOAuth2Config(domain(r))
	tok, err := conf.Exchange(oauth2.NoContext, code)
	if err != nil {
		log.Fatal(err)
	}
	client := conf.Client(oauth2.NoContext, tok)
 	response, err := client.Get("https://www.googleapis.com/plus/v1/people/me")
 	// handle err. You need to change this into something more robust
 	// such as redirect back to home page with error message
 	if err != nil {
 		w.Write([]byte(err.Error()))
 	}
 	str := readHttpBody(response)
	type Email struct {
		Value string
		Type string
	}
	type OAuth2Response struct {
		Kind string
		Emails []Email
	}
	fmt.Println("oauth2callback - response: " + str)
	dec := json.NewDecoder(strings.NewReader(str))
	var m OAuth2Response
	if err := dec.Decode(&m); err != nil {
		log.Fatal(err)
	}
	for _, v := range m.Emails {
		fmt.Println("email (value, type): " + v.Value + ", " + v.Type)
	}
	email := "dummy@dummy.com"
	if len(m.Emails) != 1 {
		fmt.Println("NO VALID EMAIL OR TOO MANY")

	} else {
		email = m.Emails[0].Value
	}
	if newAccount == "true" {
		fmt.Println("NEW ACCOUNT")
		dbCreate(email)
		dbInsert(email, "#1")
	}
	w.Write([]byte(email))
}

<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/gorilla/securecookie"

	"github.com/couchbaselabs/consolio/types"
)

const (
	BROWSERID_ENDPOINT = "https://verifier.login.persona.org/verify"
	AUTH_COOKIE        = "consolio"
)

var NotAUser = errors.New("not a user")

var alphabet []byte

func init() {
	letters := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
		"abcdefghijklmnopqrstuvwxyz" +
		"0123456789"

	for _, r := range letters {
		alphabet = append(alphabet, byte(r))
	}
}

func randstring(l int) string {
	stuff := make([]byte, l)
	_, err := io.ReadFull(rand.Reader, stuff)
	if err != nil {
		panic(err)
	}

	for i := range stuff {
		stuff[i] = alphabet[int(stuff[i])%len(alphabet)]
	}
	return string(stuff)
}

func getUser(email string) (consolio.User, error) {
	rv := consolio.User{}
	k := "u-" + email
	err := db.Get(k, &rv)
	if err == nil && rv.Type != "user" {
		return consolio.User{}, NotAUser
	}
	return rv, err
}

type browserIdData struct {
	Status   string
	Reason   string
	Email    string
	Audience string
	Expires  uint64
	Issuer   string
}

var secureCookie *securecookie.SecureCookie

func initSecureCookie(hashKey []byte) {
	secureCookie = securecookie.New(hashKey, nil)
}

func userFromCookie(cookie string) (consolio.User, error) {
	val := browserIdData{}
	err := secureCookie.Decode("consolio.User", cookie, &val)
	if err == nil {
		u, err := getUser(val.Email)
		if err != nil {
			u.Id = val.Email
		}
		return u, nil
	}
	return consolio.User{}, err
}

func whoami(r *http.Request) consolio.User {
	if cookie, err := r.Cookie(AUTH_COOKIE); err == nil {
		u, err := userFromCookie(cookie.Value)
		if err == nil {
			return u
		}
	}
	if ahdr := r.Header.Get("Authorization"); ahdr != "" {
		parts := strings.Split(ahdr, " ")
		if len(parts) < 2 {
			return consolio.User{}
		}
		decoded, err := base64.StdEncoding.DecodeString(parts[1])
		if err != nil {
			return consolio.User{}
		}
		userpass := strings.SplitN(string(decoded), ":", 2)

		user, err := getUser(userpass[0])
		if err != nil {
			return consolio.User{}
		}

		if user.AuthToken == userpass[1] {
			u, err := getUser(userpass[0])
			if err != nil {
				u.Id = userpass[0]
				u.Type = "User"
			}
			return u
		}
	}
	return consolio.User{}
}

func md5string(i string) string {
	h := md5.New()
	h.Write([]byte(i))
	return hex.EncodeToString(h.Sum(nil))
}

func performAuth(w http.ResponseWriter, r *http.Request) {
	assertion := r.FormValue("assertion")
	if assertion == "" {
		showError(w, r, "No assertion requested.", 400)
		return
	}
	data := map[string]string{
		"assertion": assertion,
		"audience":  r.FormValue("audience"),
	}

	body, err := json.Marshal(&data)
	if err != nil {
		showError(w, r, "Error encoding request: "+err.Error(), 500)
		return
	}

	req, err := http.NewRequest("POST", BROWSERID_ENDPOINT,
		bytes.NewReader(body))
	if err != nil {
		panic(err)
	}

	req.ContentLength = int64(len(body))
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)

	if err != nil {
		showError(w, r, "Error transmitting request: "+err.Error(), 500)
		return
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		showError(w, r, "Invalid response code from browserid: "+res.Status, 500)
		return
	}

	resdata := browserIdData{}

	d := json.NewDecoder(res.Body)
	err = d.Decode(&resdata)
	if err != nil {
		showError(w, r, "Error decoding browserid response: "+err.Error(), 500)
		return
	}

	if resdata.Status != "okay" {
		showError(w, r, "Browserid status was not OK: "+
			resdata.Status+"/"+resdata.Reason, 500)
		return
	}

	if time.Now().Unix()*1000 >= int64(resdata.Expires) {
		glog.Infof("browserId assertion had expired as of %v (current is %v)",
			resdata.Expires, time.Now().Unix())
		showError(w, r, "Browserid assertion is expired", 500)
		return
	}

	encoded, err := secureCookie.Encode("consolio.User", resdata)
	if err != nil {
		showError(w, r, "Couldn't encode cookie: "+err.Error(), 500)
		return
	}

	cookie := &http.Cookie{
		Name:  AUTH_COOKIE,
		Value: encoded,
		Path:  "/",
	}
	http.SetCookie(w, cookie)

	glog.Infof("Logged in %v", resdata.Email)

	mustEncode(w, map[string]interface{}{
		"email":    resdata.Email,
		"emailmd5": md5string(resdata.Email),
	})
}

func serveLogin(w http.ResponseWriter, r *http.Request) {
	me := whoami(r)

	if me.Id == "" {
		performAuth(w, r)
	} else {
		glog.Infof("Reusing existing thing: %v", me.Id)
		mustEncode(w, map[string]interface{}{
			"email":    me.Id,
			"emailmd5": md5string(me.Id),
			"prefs":    me.Prefs,
		})
	}
}

func serveLogout(w http.ResponseWriter, r *http.Request) {
	cookie := &http.Cookie{
		Name:  AUTH_COOKIE,
		Value: "",
		Path:  "/",
	}

	http.SetCookie(w, cookie)
}

func handleUserAuthToken(w http.ResponseWriter, r *http.Request) {
	me := whoami(r)
	// If the user doesn't have an auth token, make one.
	if me.AuthToken == "" {
		handleUpdateUserAuthToken(w, r)
		return
	}

	mustEncode(w, map[string]string{"token": me.AuthToken})
}

func handleUpdateUserAuthToken(w http.ResponseWriter, r *http.Request) {
	me := whoami(r)
	key := "u-" + me.Id
	user := consolio.User{}

	err := db.Update(key, 0, func(current []byte) ([]byte, error) {
		if len(current) > 0 {
			err := json.Unmarshal(current, &user)
			if err != nil {
				return nil, err
			}
		}

		// Common fields
		user.Id = me.Id
		user.Type = "user"

		user.AuthToken = randstring(16)

		return json.Marshal(user)
	})

	if err != nil {
		showError(w, r, err.Error(), 500)
		return
	}

	mustEncode(w, map[string]string{"token": user.AuthToken})
}
<commit_msg>Warn on expired auth session, but allow it to proceed<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/gorilla/securecookie"

	"github.com/couchbaselabs/consolio/types"
)

const (
	BROWSERID_ENDPOINT = "https://verifier.login.persona.org/verify"
	AUTH_COOKIE        = "consolio"
)

var NotAUser = errors.New("not a user")

var alphabet []byte

func init() {
	letters := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
		"abcdefghijklmnopqrstuvwxyz" +
		"0123456789"

	for _, r := range letters {
		alphabet = append(alphabet, byte(r))
	}
}

func randstring(l int) string {
	stuff := make([]byte, l)
	_, err := io.ReadFull(rand.Reader, stuff)
	if err != nil {
		panic(err)
	}

	for i := range stuff {
		stuff[i] = alphabet[int(stuff[i])%len(alphabet)]
	}
	return string(stuff)
}

func getUser(email string) (consolio.User, error) {
	rv := consolio.User{}
	k := "u-" + email
	err := db.Get(k, &rv)
	if err == nil && rv.Type != "user" {
		return consolio.User{}, NotAUser
	}
	return rv, err
}

type browserIdData struct {
	Status   string
	Reason   string
	Email    string
	Audience string
	Expires  uint64
	Issuer   string
}

var secureCookie *securecookie.SecureCookie

func initSecureCookie(hashKey []byte) {
	secureCookie = securecookie.New(hashKey, nil)
}

func userFromCookie(cookie string) (consolio.User, error) {
	val := browserIdData{}
	err := secureCookie.Decode("consolio.User", cookie, &val)
	if err == nil {
		u, err := getUser(val.Email)
		if err != nil {
			u.Id = val.Email
		}
		return u, nil
	}
	return consolio.User{}, err
}

func whoami(r *http.Request) consolio.User {
	if cookie, err := r.Cookie(AUTH_COOKIE); err == nil {
		u, err := userFromCookie(cookie.Value)
		if err == nil {
			return u
		}
	}
	if ahdr := r.Header.Get("Authorization"); ahdr != "" {
		parts := strings.Split(ahdr, " ")
		if len(parts) < 2 {
			return consolio.User{}
		}
		decoded, err := base64.StdEncoding.DecodeString(parts[1])
		if err != nil {
			return consolio.User{}
		}
		userpass := strings.SplitN(string(decoded), ":", 2)

		user, err := getUser(userpass[0])
		if err != nil {
			return consolio.User{}
		}

		if user.AuthToken == userpass[1] {
			u, err := getUser(userpass[0])
			if err != nil {
				u.Id = userpass[0]
				u.Type = "User"
			}
			return u
		}
	}
	return consolio.User{}
}

func md5string(i string) string {
	h := md5.New()
	h.Write([]byte(i))
	return hex.EncodeToString(h.Sum(nil))
}

func performAuth(w http.ResponseWriter, r *http.Request) {
	assertion := r.FormValue("assertion")
	if assertion == "" {
		showError(w, r, "No assertion requested.", 400)
		return
	}
	data := map[string]string{
		"assertion": assertion,
		"audience":  r.FormValue("audience"),
	}

	body, err := json.Marshal(&data)
	if err != nil {
		showError(w, r, "Error encoding request: "+err.Error(), 500)
		return
	}

	req, err := http.NewRequest("POST", BROWSERID_ENDPOINT,
		bytes.NewReader(body))
	if err != nil {
		panic(err)
	}

	req.ContentLength = int64(len(body))
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)

	if err != nil {
		showError(w, r, "Error transmitting request: "+err.Error(), 500)
		return
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		showError(w, r, "Invalid response code from browserid: "+res.Status, 500)
		return
	}

	resdata := browserIdData{}

	d := json.NewDecoder(res.Body)
	err = d.Decode(&resdata)
	if err != nil {
		showError(w, r, "Error decoding browserid response: "+err.Error(), 500)
		return
	}

	if resdata.Status != "okay" {
		showError(w, r, "Browserid status was not OK: "+
			resdata.Status+"/"+resdata.Reason, 500)
		return
	}

	if time.Now().Unix()*1000 >= int64(resdata.Expires) {
		glog.Warningf("browserId assertion had expired as of %v (current is %v)",
			resdata.Expires, time.Now().Unix())
		// This is a workaround for something not yet understood. - cbugg: bug-926
		// showError(w, r, "Browserid assertion is expired", 500)
		// return
	}

	encoded, err := secureCookie.Encode("consolio.User", resdata)
	if err != nil {
		showError(w, r, "Couldn't encode cookie: "+err.Error(), 500)
		return
	}

	cookie := &http.Cookie{
		Name:  AUTH_COOKIE,
		Value: encoded,
		Path:  "/",
	}
	http.SetCookie(w, cookie)

	glog.Infof("Logged in %v", resdata.Email)

	mustEncode(w, map[string]interface{}{
		"email":    resdata.Email,
		"emailmd5": md5string(resdata.Email),
	})
}

func serveLogin(w http.ResponseWriter, r *http.Request) {
	me := whoami(r)

	if me.Id == "" {
		performAuth(w, r)
	} else {
		glog.Infof("Reusing existing thing: %v", me.Id)
		mustEncode(w, map[string]interface{}{
			"email":    me.Id,
			"emailmd5": md5string(me.Id),
			"prefs":    me.Prefs,
		})
	}
}

func serveLogout(w http.ResponseWriter, r *http.Request) {
	cookie := &http.Cookie{
		Name:  AUTH_COOKIE,
		Value: "",
		Path:  "/",
	}

	http.SetCookie(w, cookie)
}

func handleUserAuthToken(w http.ResponseWriter, r *http.Request) {
	me := whoami(r)
	// If the user doesn't have an auth token, make one.
	if me.AuthToken == "" {
		handleUpdateUserAuthToken(w, r)
		return
	}

	mustEncode(w, map[string]string{"token": me.AuthToken})
}

func handleUpdateUserAuthToken(w http.ResponseWriter, r *http.Request) {
	me := whoami(r)
	key := "u-" + me.Id
	user := consolio.User{}

	err := db.Update(key, 0, func(current []byte) ([]byte, error) {
		if len(current) > 0 {
			err := json.Unmarshal(current, &user)
			if err != nil {
				return nil, err
			}
		}

		// Common fields
		user.Id = me.Id
		user.Type = "user"

		user.AuthToken = randstring(16)

		return json.Marshal(user)
	})

	if err != nil {
		showError(w, r, err.Error(), 500)
		return
	}

	mustEncode(w, map[string]string{"token": user.AuthToken})
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
)

type xmlRegistry struct {
	Types      []xmlType      `xml:"types>type"`
	Enums      []xmlEnumSet   `xml:"enums"`
	Commands   []xmlCommand   `xml:"commands>command"`
	Features   []xmlFeature   `xml:"feature"`
	Extensions []xmlExtension `xml:"extensions>extension"`
}

type xmlType struct {
	Name     string `xml:"name,attr"`
	Api      string `xml:"api,attr"`
	Requires string `xml:"requires,attr"`
	Raw      []byte `xml:",innerxml"`
}

type xmlEnumSet struct {
	Enums []xmlEnum `xml:"enum"`
}

type xmlEnum struct {
	Name  string `xml:"name,attr"`
	Value string `xml:"value,attr"`
	Api   string `xml:"api,attr"`
}

type xmlCommand struct {
	Prototype xmlProto   `xml:"proto"`
	Api       string     `xml:"api"`
	Params    []xmlParam `xml:"param"`
}

type xmlSignature []byte

type xmlProto struct {
	Raw xmlSignature `xml:",innerxml"`
}

type xmlParam struct {
	Raw xmlSignature `xml:",innerxml"`
}

type xmlFeature struct {
	Api      string       `xml:"api,attr"`
	Number   string       `xml:"number,attr"`
	Requires []xmlRequire `xml:"require"`
	Removes  []xmlRemove  `xml:"remove"`
}

type xmlRequire struct {
	Enums    []xmlEnumRef    `xml:"enum"`
	Commands []xmlCommandRef `xml:"command"`
}

type xmlRemove struct {
	Enums    []xmlEnumRef    `xml:"enum"`
	Commands []xmlCommandRef `xml:"command"`
}

type xmlEnumRef struct {
	Name string `xml:"name,attr"`
}

type xmlCommandRef struct {
	Name string `xml:"name,attr"`
}

type xmlExtension struct {
	Name      string       `xml:"name,attr"`
	Supported string       `xml:"supported,attr"`
	Requires  []xmlRequire `xml:"require"`
	Removes   []xmlRemove  `xml:"remove"`
}

type specRef struct {
	name string
	api  string
}

type specTypedef struct {
	typedef  *Typedef
	ordinal  int    // Relative declaration order of the typedef
	requires string // Optional name of the typedef required for this typedef
}

type specFunctions map[specRef]*Function
type specEnums map[specRef]*Enum
type specTypedefs map[specRef]*specTypedef

type specAddRemSet struct {
	addedCommands   []string
	addedEnums      []string
	removedCommands []string
	removedEnums    []string
}

// A Specification is a parsed version of an XML registry.
type Specification struct {
	Functions  specFunctions
	Enums      specEnums
	Typedefs   specTypedefs
	Features   []SpecificationFeature
	Extensions []SpecificationExtension
}

type SpecificationFeature struct {
	Api     string
	Version Version
	AddRem  specAddRemSet
}

type SpecificationExtension struct {
	Name       string
	ApisRegexp string
	AddRem     specAddRemSet
}

func readSpecFile(file string) (*xmlRegistry, error) {
	var registry xmlRegistry

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

	err = xml.NewDecoder(f).Decode(&registry)
	if err != nil {
		return nil, err
	}

	return &registry, nil
}

func parseFunctions(commands []xmlCommand) (specFunctions, error) {
	functions := make(specFunctions)
	for _, cmd := range commands {
		cmdName, cmdReturnType, err := parseSignature(cmd.Prototype.Raw)
		if err != nil {
			return functions, err
		}

		parameters := make([]Parameter, 0, len(cmd.Params))
		for _, param := range cmd.Params {
			paramName, paramType, err := parseSignature(param.Raw)
			if err != nil {
				return functions, err
			}
			parameter := Parameter{
				Name: paramName,
				Type: paramType}
			parameters = append(parameters, parameter)
		}

		fnRef := specRef{cmdName, cmd.Api}
		functions[fnRef] = &Function{
			Name:       cmdName,
			GoName:     TrimApiPrefix(cmdName),
			Parameters: parameters,
			Return:     cmdReturnType}
	}
	return functions, nil
}

func parseSignature(signature xmlSignature) (string, Type, error) {
	name := ""
	ctype := Type{}

	readingName := false
	readingType := false

	decoder := xml.NewDecoder(bytes.NewBuffer(signature))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return name, ctype, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := strings.Trim(string(t), " ")
			if readingName {
				name = raw
			} else if readingType {
				ctype.Name = raw
			} else {
				if strings.Contains(raw, "void") {
					ctype.Name = "void"
				}
				ctype.PointerLevel += strings.Count(raw, "*")
			}
			if !readingName {
				ctype.CDefinition += string(t)
			}
		case xml.StartElement:
			if t.Name.Local == "ptype" {
				readingType = true
			} else if t.Name.Local == "name" {
				readingName = true
			} else {
				return name, ctype, fmt.Errorf("Unexpected signature XML: %s", signature)
			}
		case xml.EndElement:
			if t.Name.Local == "ptype" {
				readingType = false
			} else if t.Name.Local == "name" {
				readingName = false
			}
		}
	}
	return name, ctype, nil
}

func parseEnums(enumSets []xmlEnumSet) (specEnums, error) {
	enums := make(specEnums)
	for _, set := range enumSets {
		for _, enum := range set.Enums {
			enumRef := specRef{enum.Name, enum.Api}
			enums[enumRef] = &Enum{
				Name:   enum.Name,
				GoName: TrimApiPrefix(enum.Name),
				Value:  enum.Value}
		}
	}
	return enums, nil
}

func parseTypedefs(types []xmlType) (specTypedefs, error) {
	typedefs := make(specTypedefs)
	for i, xtype := range types {
		typedef, err := parseTypedef(xtype)
		if err != nil {
			return nil, err
		}
		typedefRef := specRef{typedef.Name, xtype.Api}
		typedefs[typedefRef] = &specTypedef{
			typedef:  typedef,
			ordinal:  i,
			requires: xtype.Requires}
	}
	return typedefs, nil
}

func parseTypedef(xmlType xmlType) (*Typedef, error) {
	typedef := &Typedef{
		Name:        xmlType.Name,
		CDefinition: ""}

	readingName := false
	decoder := xml.NewDecoder(bytes.NewBuffer(xmlType.Raw))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return typedef, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := string(t)
			typedef.CDefinition += raw
			if readingName {
				typedef.Name = raw
			}
		case xml.StartElement:
			if t.Name.Local == "name" {
				readingName = true
			} else if t.Name.Local == "apientry" {
				typedef.CDefinition += "APIENTRY"
			} else {
				return typedef, fmt.Errorf("Unexpected typedef XML: %s", xmlType.Raw)
			}
		case xml.EndElement:
			if t.Name.Local == "name" {
				readingName = false
			}
		default:
			return typedef, fmt.Errorf("Unexpected typedef XML: %s", xmlType.Raw)
		}
	}

	return typedef, nil
}

func parseFeatures(xmlFeatures []xmlFeature) ([]SpecificationFeature, error) {
	features := make([]SpecificationFeature, 0, len(xmlFeatures))
	for _, xmlFeature := range xmlFeatures {
		version, err := ParseVersion(xmlFeature.Number)
		if err != nil {
			return features, err
		}
		feature := SpecificationFeature{
			Api:     xmlFeature.Api,
			Version: version,
			AddRem:  parseAddRem(xmlFeature.Requires, xmlFeature.Removes),
		}
		features = append(features, feature)
	}
	return features, nil
}

func parseAddRem(requires []xmlRequire, removes []xmlRemove) specAddRemSet {
	addRem := specAddRemSet{
		addedEnums:      make([]string, 0),
		addedCommands:   make([]string, 0),
		removedEnums:    make([]string, 0),
		removedCommands: make([]string, 0),
	}
	for _, req := range requires {
		for _, cmd := range req.Commands {
			addRem.addedCommands = append(addRem.addedCommands, cmd.Name)
		}
		for _, enum := range req.Enums {
			addRem.addedEnums = append(addRem.addedEnums, enum.Name)
		}
	}
	for _, rem := range removes {
		for _, cmd := range rem.Commands {
			addRem.removedCommands = append(addRem.removedCommands, cmd.Name)
		}
		for _, enum := range rem.Enums {
			addRem.removedEnums = append(addRem.removedEnums, enum.Name)
		}
	}
	return addRem
}

func parseExtensions(xmlExtensions []xmlExtension) ([]SpecificationExtension, error) {
	extensions := make([]SpecificationExtension, 0, len(xmlExtensions))
	for _, xmlExtension := range xmlExtensions {
		if len(xmlExtension.Removes) > 0 {
			return nil, fmt.Errorf("Unexpected extension with removal requirement: %s", xmlExtension)
		}
		extension := SpecificationExtension{
			Name:       xmlExtension.Name,
			ApisRegexp: xmlExtension.Supported,
			AddRem:     parseAddRem(xmlExtension.Requires, xmlExtension.Removes),
		}
		extensions = append(extensions, extension)
	}
	return extensions, nil
}

func (functions specFunctions) get(name, api string) *Function {
	function, ok := functions[specRef{name, api}]
	if ok {
		return function
	}
	return functions[specRef{name, ""}]
}

func (enums specEnums) get(name, api string) *Enum {
	enum, ok := enums[specRef{name, api}]
	if ok {
		return enum
	}
	return enums[specRef{name, ""}]
}

func (typedefs specTypedefs) selectRequired(name, api string, requiredTypedefs []*Typedef) {
	specTypedef, ok := typedefs[specRef{name, api}]
	if !ok {
		specTypedef = typedefs[specRef{name, ""}]
	}
	if specTypedef != nil {
		requiredTypedefs[specTypedef.ordinal] = specTypedef.typedef
		if specTypedef.requires != "" {
			typedefs.selectRequired(specTypedef.requires, api, requiredTypedefs)
		}
	}
}

// NewSpecification creates a new specification based on an XML file.
func NewSpecification(file string) (*Specification, error) {
	registry, err := readSpecFile(file)
	if err != nil {
		return nil, err
	}

	functions, err := parseFunctions(registry.Commands)
	if err != nil {
		return nil, err
	}

	enums, err := parseEnums(registry.Enums)
	if err != nil {
		return nil, err
	}

	typedefs, err := parseTypedefs(registry.Types)
	if err != nil {
		return nil, err
	}

	features, err := parseFeatures(registry.Features)
	if err != nil {
		return nil, err
	}

	extensions, err := parseExtensions(registry.Extensions)
	if err != nil {
		return nil, err
	}

	spec := &Specification{
		Functions:  functions,
		Enums:      enums,
		Typedefs:   typedefs,
		Features:   features,
		Extensions: extensions,
	}
	return spec, nil
}

// HasPackage determines whether the specification can generate the specified package.
func (spec *Specification) HasPackage(pkgSpec PackageSpec) bool {
	for _, feature := range spec.Features {
		if pkgSpec.Api == feature.Api && pkgSpec.Version.Compare(feature.Version) == 0 {
			return true
		}
	}
	return false
}

// ToPackage generates a package from the specification.
func (spec *Specification) ToPackage(pkgSpec PackageSpec) *Package {
	pkg := &Package{
		Api:       pkgSpec.Api,
		Name:      pkgSpec.Api,
		Version:   pkgSpec.Version,
		Typedefs:  make([]*Typedef, len(spec.Typedefs)),
		Enums:     make(map[string]Enum),
		Functions: make(map[string]PackageFunction),
	}

	// Select the commands and enums relevant to the specified API version
	for _, feature := range spec.Features {
		// Skip features from a different API or future version
		if pkg.Api != feature.Api || pkg.Version.Compare(feature.Version) < 0 {
			continue
		}
		for _, cmd := range feature.AddRem.addedCommands {
			pkg.Functions[cmd] = PackageFunction{
				Function:   *spec.Functions.get(cmd, pkg.Api),
				Required:   true,
				Extensions: make([]string, 0),
			}
		}
		for _, enum := range feature.AddRem.addedEnums {
			pkg.Enums[enum] = *spec.Enums.get(enum, pkg.Api)
		}
		for _, cmd := range feature.AddRem.removedCommands {
			delete(pkg.Functions, cmd)
		}
		for _, enum := range feature.AddRem.removedEnums {
			delete(pkg.Enums, enum)
		}

	}

	// Select the extensions compatible with the specified API version
	for _, extension := range spec.Extensions {
		// Whitelist a test extension while working out typing issues
		// TODO Lift this restriction
		if extension.Name != "GL_ARB_compute_shader" && extension.Name != "GL_ARB_vertex_buffer_object" {
			continue
		}
		matched, err := regexp.MatchString(extension.ApisRegexp, pkg.Api)
		if !matched || err != nil {
			continue
		}
		for _, cmd := range extension.AddRem.addedCommands {
			fn, ok := pkg.Functions[cmd]
			if ok {
				fn.Extensions = append(fn.Extensions, extension.Name)
			} else {
				pkg.Functions[cmd] = PackageFunction{
					Function:   *spec.Functions.get(cmd, pkg.Api),
					Required:   false,
					Extensions: []string{TrimApiPrefix(extension.Name)},
				}
			}
		}
		for _, enum := range extension.AddRem.addedEnums {
			pkg.Enums[enum] = *spec.Enums.get(enum, pkg.Api)
		}
	}

	// Add the types necessary to declare the functions
	for _, fn := range pkg.Functions {
		spec.Typedefs.selectRequired(fn.Function.Return.Name, pkg.Api, pkg.Typedefs)
		for _, param := range fn.Function.Parameters {
			spec.Typedefs.selectRequired(param.Type.Name, pkg.Api, pkg.Typedefs)
		}
	}
	typedefCount := 0
	for _, typedef := range pkg.Typedefs {
		if typedef != nil {
			pkg.Typedefs[typedefCount] = typedef
			typedefCount++
		}
	}
	pkg.Typedefs = pkg.Typedefs[:typedefCount]

	return pkg
}
<commit_msg>Fix trimming API prefix for extensions.<commit_after>package main

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
)

type xmlRegistry struct {
	Types      []xmlType      `xml:"types>type"`
	Enums      []xmlEnumSet   `xml:"enums"`
	Commands   []xmlCommand   `xml:"commands>command"`
	Features   []xmlFeature   `xml:"feature"`
	Extensions []xmlExtension `xml:"extensions>extension"`
}

type xmlType struct {
	Name     string `xml:"name,attr"`
	Api      string `xml:"api,attr"`
	Requires string `xml:"requires,attr"`
	Raw      []byte `xml:",innerxml"`
}

type xmlEnumSet struct {
	Enums []xmlEnum `xml:"enum"`
}

type xmlEnum struct {
	Name  string `xml:"name,attr"`
	Value string `xml:"value,attr"`
	Api   string `xml:"api,attr"`
}

type xmlCommand struct {
	Prototype xmlProto   `xml:"proto"`
	Api       string     `xml:"api"`
	Params    []xmlParam `xml:"param"`
}

type xmlSignature []byte

type xmlProto struct {
	Raw xmlSignature `xml:",innerxml"`
}

type xmlParam struct {
	Raw xmlSignature `xml:",innerxml"`
}

type xmlFeature struct {
	Api      string       `xml:"api,attr"`
	Number   string       `xml:"number,attr"`
	Requires []xmlRequire `xml:"require"`
	Removes  []xmlRemove  `xml:"remove"`
}

type xmlRequire struct {
	Enums    []xmlEnumRef    `xml:"enum"`
	Commands []xmlCommandRef `xml:"command"`
}

type xmlRemove struct {
	Enums    []xmlEnumRef    `xml:"enum"`
	Commands []xmlCommandRef `xml:"command"`
}

type xmlEnumRef struct {
	Name string `xml:"name,attr"`
}

type xmlCommandRef struct {
	Name string `xml:"name,attr"`
}

type xmlExtension struct {
	Name      string       `xml:"name,attr"`
	Supported string       `xml:"supported,attr"`
	Requires  []xmlRequire `xml:"require"`
	Removes   []xmlRemove  `xml:"remove"`
}

type specRef struct {
	name string
	api  string
}

type specTypedef struct {
	typedef  *Typedef
	ordinal  int    // Relative declaration order of the typedef
	requires string // Optional name of the typedef required for this typedef
}

type specFunctions map[specRef]*Function
type specEnums map[specRef]*Enum
type specTypedefs map[specRef]*specTypedef

type specAddRemSet struct {
	addedCommands   []string
	addedEnums      []string
	removedCommands []string
	removedEnums    []string
}

// A Specification is a parsed version of an XML registry.
type Specification struct {
	Functions  specFunctions
	Enums      specEnums
	Typedefs   specTypedefs
	Features   []SpecificationFeature
	Extensions []SpecificationExtension
}

type SpecificationFeature struct {
	Api     string
	Version Version
	AddRem  specAddRemSet
}

type SpecificationExtension struct {
	Name       string
	ApisRegexp string
	AddRem     specAddRemSet
}

func readSpecFile(file string) (*xmlRegistry, error) {
	var registry xmlRegistry

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

	err = xml.NewDecoder(f).Decode(&registry)
	if err != nil {
		return nil, err
	}

	return &registry, nil
}

func parseFunctions(commands []xmlCommand) (specFunctions, error) {
	functions := make(specFunctions)
	for _, cmd := range commands {
		cmdName, cmdReturnType, err := parseSignature(cmd.Prototype.Raw)
		if err != nil {
			return functions, err
		}

		parameters := make([]Parameter, 0, len(cmd.Params))
		for _, param := range cmd.Params {
			paramName, paramType, err := parseSignature(param.Raw)
			if err != nil {
				return functions, err
			}
			parameter := Parameter{
				Name: paramName,
				Type: paramType}
			parameters = append(parameters, parameter)
		}

		fnRef := specRef{cmdName, cmd.Api}
		functions[fnRef] = &Function{
			Name:       cmdName,
			GoName:     TrimApiPrefix(cmdName),
			Parameters: parameters,
			Return:     cmdReturnType}
	}
	return functions, nil
}

func parseSignature(signature xmlSignature) (string, Type, error) {
	name := ""
	ctype := Type{}

	readingName := false
	readingType := false

	decoder := xml.NewDecoder(bytes.NewBuffer(signature))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return name, ctype, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := strings.Trim(string(t), " ")
			if readingName {
				name = raw
			} else if readingType {
				ctype.Name = raw
			} else {
				if strings.Contains(raw, "void") {
					ctype.Name = "void"
				}
				ctype.PointerLevel += strings.Count(raw, "*")
			}
			if !readingName {
				ctype.CDefinition += string(t)
			}
		case xml.StartElement:
			if t.Name.Local == "ptype" {
				readingType = true
			} else if t.Name.Local == "name" {
				readingName = true
			} else {
				return name, ctype, fmt.Errorf("Unexpected signature XML: %s", signature)
			}
		case xml.EndElement:
			if t.Name.Local == "ptype" {
				readingType = false
			} else if t.Name.Local == "name" {
				readingName = false
			}
		}
	}
	return name, ctype, nil
}

func parseEnums(enumSets []xmlEnumSet) (specEnums, error) {
	enums := make(specEnums)
	for _, set := range enumSets {
		for _, enum := range set.Enums {
			enumRef := specRef{enum.Name, enum.Api}
			enums[enumRef] = &Enum{
				Name:   enum.Name,
				GoName: TrimApiPrefix(enum.Name),
				Value:  enum.Value}
		}
	}
	return enums, nil
}

func parseTypedefs(types []xmlType) (specTypedefs, error) {
	typedefs := make(specTypedefs)
	for i, xtype := range types {
		typedef, err := parseTypedef(xtype)
		if err != nil {
			return nil, err
		}
		typedefRef := specRef{typedef.Name, xtype.Api}
		typedefs[typedefRef] = &specTypedef{
			typedef:  typedef,
			ordinal:  i,
			requires: xtype.Requires}
	}
	return typedefs, nil
}

func parseTypedef(xmlType xmlType) (*Typedef, error) {
	typedef := &Typedef{
		Name:        xmlType.Name,
		CDefinition: ""}

	readingName := false
	decoder := xml.NewDecoder(bytes.NewBuffer(xmlType.Raw))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return typedef, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := string(t)
			typedef.CDefinition += raw
			if readingName {
				typedef.Name = raw
			}
		case xml.StartElement:
			if t.Name.Local == "name" {
				readingName = true
			} else if t.Name.Local == "apientry" {
				typedef.CDefinition += "APIENTRY"
			} else {
				return typedef, fmt.Errorf("Unexpected typedef XML: %s", xmlType.Raw)
			}
		case xml.EndElement:
			if t.Name.Local == "name" {
				readingName = false
			}
		default:
			return typedef, fmt.Errorf("Unexpected typedef XML: %s", xmlType.Raw)
		}
	}

	return typedef, nil
}

func parseFeatures(xmlFeatures []xmlFeature) ([]SpecificationFeature, error) {
	features := make([]SpecificationFeature, 0, len(xmlFeatures))
	for _, xmlFeature := range xmlFeatures {
		version, err := ParseVersion(xmlFeature.Number)
		if err != nil {
			return features, err
		}
		feature := SpecificationFeature{
			Api:     xmlFeature.Api,
			Version: version,
			AddRem:  parseAddRem(xmlFeature.Requires, xmlFeature.Removes),
		}
		features = append(features, feature)
	}
	return features, nil
}

func parseAddRem(requires []xmlRequire, removes []xmlRemove) specAddRemSet {
	addRem := specAddRemSet{
		addedEnums:      make([]string, 0),
		addedCommands:   make([]string, 0),
		removedEnums:    make([]string, 0),
		removedCommands: make([]string, 0),
	}
	for _, req := range requires {
		for _, cmd := range req.Commands {
			addRem.addedCommands = append(addRem.addedCommands, cmd.Name)
		}
		for _, enum := range req.Enums {
			addRem.addedEnums = append(addRem.addedEnums, enum.Name)
		}
	}
	for _, rem := range removes {
		for _, cmd := range rem.Commands {
			addRem.removedCommands = append(addRem.removedCommands, cmd.Name)
		}
		for _, enum := range rem.Enums {
			addRem.removedEnums = append(addRem.removedEnums, enum.Name)
		}
	}
	return addRem
}

func parseExtensions(xmlExtensions []xmlExtension) ([]SpecificationExtension, error) {
	extensions := make([]SpecificationExtension, 0, len(xmlExtensions))
	for _, xmlExtension := range xmlExtensions {
		if len(xmlExtension.Removes) > 0 {
			return nil, fmt.Errorf("Unexpected extension with removal requirement: %s", xmlExtension)
		}
		extension := SpecificationExtension{
			Name:       xmlExtension.Name,
			ApisRegexp: xmlExtension.Supported,
			AddRem:     parseAddRem(xmlExtension.Requires, xmlExtension.Removes),
		}
		extensions = append(extensions, extension)
	}
	return extensions, nil
}

func (functions specFunctions) get(name, api string) *Function {
	function, ok := functions[specRef{name, api}]
	if ok {
		return function
	}
	return functions[specRef{name, ""}]
}

func (enums specEnums) get(name, api string) *Enum {
	enum, ok := enums[specRef{name, api}]
	if ok {
		return enum
	}
	return enums[specRef{name, ""}]
}

func (typedefs specTypedefs) selectRequired(name, api string, requiredTypedefs []*Typedef) {
	specTypedef, ok := typedefs[specRef{name, api}]
	if !ok {
		specTypedef = typedefs[specRef{name, ""}]
	}
	if specTypedef != nil {
		requiredTypedefs[specTypedef.ordinal] = specTypedef.typedef
		if specTypedef.requires != "" {
			typedefs.selectRequired(specTypedef.requires, api, requiredTypedefs)
		}
	}
}

// NewSpecification creates a new specification based on an XML file.
func NewSpecification(file string) (*Specification, error) {
	registry, err := readSpecFile(file)
	if err != nil {
		return nil, err
	}

	functions, err := parseFunctions(registry.Commands)
	if err != nil {
		return nil, err
	}

	enums, err := parseEnums(registry.Enums)
	if err != nil {
		return nil, err
	}

	typedefs, err := parseTypedefs(registry.Types)
	if err != nil {
		return nil, err
	}

	features, err := parseFeatures(registry.Features)
	if err != nil {
		return nil, err
	}

	extensions, err := parseExtensions(registry.Extensions)
	if err != nil {
		return nil, err
	}

	spec := &Specification{
		Functions:  functions,
		Enums:      enums,
		Typedefs:   typedefs,
		Features:   features,
		Extensions: extensions,
	}
	return spec, nil
}

// HasPackage determines whether the specification can generate the specified package.
func (spec *Specification) HasPackage(pkgSpec PackageSpec) bool {
	for _, feature := range spec.Features {
		if pkgSpec.Api == feature.Api && pkgSpec.Version.Compare(feature.Version) == 0 {
			return true
		}
	}
	return false
}

// ToPackage generates a package from the specification.
func (spec *Specification) ToPackage(pkgSpec PackageSpec) *Package {
	pkg := &Package{
		Api:       pkgSpec.Api,
		Name:      pkgSpec.Api,
		Version:   pkgSpec.Version,
		Typedefs:  make([]*Typedef, len(spec.Typedefs)),
		Enums:     make(map[string]Enum),
		Functions: make(map[string]PackageFunction),
	}

	// Select the commands and enums relevant to the specified API version
	for _, feature := range spec.Features {
		// Skip features from a different API or future version
		if pkg.Api != feature.Api || pkg.Version.Compare(feature.Version) < 0 {
			continue
		}
		for _, cmd := range feature.AddRem.addedCommands {
			pkg.Functions[cmd] = PackageFunction{
				Function:   *spec.Functions.get(cmd, pkg.Api),
				Required:   true,
				Extensions: make([]string, 0),
			}
		}
		for _, enum := range feature.AddRem.addedEnums {
			pkg.Enums[enum] = *spec.Enums.get(enum, pkg.Api)
		}
		for _, cmd := range feature.AddRem.removedCommands {
			delete(pkg.Functions, cmd)
		}
		for _, enum := range feature.AddRem.removedEnums {
			delete(pkg.Enums, enum)
		}
	}

	// Select the extensions compatible with the specified API version
	for _, extension := range spec.Extensions {
		// Whitelist a test extension while working out typing issues
		// TODO Lift this restriction
		if extension.Name != "GL_ARB_compute_shader" && extension.Name != "GL_ARB_vertex_buffer_object" {
			continue
		}
		matched, err := regexp.MatchString(extension.ApisRegexp, pkg.Api)
		if !matched || err != nil {
			continue
		}
		for _, cmd := range extension.AddRem.addedCommands {
			fn, ok := pkg.Functions[cmd]
			if ok {
				fn.Extensions = append(fn.Extensions, TrimApiPrefix(extension.Name))
			} else {
				pkg.Functions[cmd] = PackageFunction{
					Function:   *spec.Functions.get(cmd, pkg.Api),
					Required:   false,
					Extensions: []string{TrimApiPrefix(extension.Name)},
				}
			}
		}
		for _, enum := range extension.AddRem.addedEnums {
			pkg.Enums[enum] = *spec.Enums.get(enum, pkg.Api)
		}
	}

	// Add the types necessary to declare the functions
	for _, fn := range pkg.Functions {
		spec.Typedefs.selectRequired(fn.Function.Return.Name, pkg.Api, pkg.Typedefs)
		for _, param := range fn.Function.Parameters {
			spec.Typedefs.selectRequired(param.Type.Name, pkg.Api, pkg.Typedefs)
		}
	}
	typedefCount := 0
	for _, typedef := range pkg.Typedefs {
		if typedef != nil {
			pkg.Typedefs[typedefCount] = typedef
			typedefCount++
		}
	}
	pkg.Typedefs = pkg.Typedefs[:typedefCount]

	return pkg
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/bwmarrin/discordgo"
    "github.com/sn0w/Karen/logger"
    "time"
)

var BETA_GUILDS = [...]string{
    "259831440064118784", // FADED's Sandbox
    "180818466847064065", // Karen's Sandbox
    "172041631258640384", // P0WERPLANT
    "161637499939192832", // Coding Lounge
    "225168913808228352", // Emily's Space
    "267186654312136704", // Shinda Sekai Sensen
}

// Automatically leaves guilds that are not registered beta testers
func autoLeaver(session *discordgo.Session) {
    for {
        for _, guild := range session.State.Guilds {
            match := false

            for _, betaGuild := range BETA_GUILDS {
                if guild.ID == betaGuild {
                    match = true
                    break
                }
            }

            if !match {
                logger.WARNING.L("beta", "Leaving guild " + guild.ID + " (" + guild.Name + ") because it didn't apply for the beta")
                session.GuildLeave(guild.ID)
            }
        }

        time.Sleep(10 * time.Second)
    }
}
<commit_msg>Enable the SEKAI guild<commit_after>package main

import (
    "github.com/bwmarrin/discordgo"
    "github.com/sn0w/Karen/logger"
    "time"
)

var BETA_GUILDS = [...]string{
    "259831440064118784", // FADED's Sandbox
    "180818466847064065", // Karen's Sandbox
    "172041631258640384", // P0WERPLANT
    "161637499939192832", // Coding Lounge
    "225168913808228352", // Emily's Space
    "267186654312136704", // Shinda Sekai Sensen
    "244110097599430667", // S E K A I
}

// Automatically leaves guilds that are not registered beta testers
func autoLeaver(session *discordgo.Session) {
    for {
        for _, guild := range session.State.Guilds {
            match := false

            for _, betaGuild := range BETA_GUILDS {
                if guild.ID == betaGuild {
                    match = true
                    break
                }
            }

            if !match {
                logger.WARNING.L("beta", "Leaving guild " + guild.ID + " (" + guild.Name + ") because it didn't apply for the beta")
                session.GuildLeave(guild.ID)
            }
        }

        time.Sleep(10 * time.Second)
    }
}
<|endoftext|>