<commit_before>// Copyright 2018 the u-root 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 builder

import (
	"testing"

	"github.com/u-root/u-root/pkg/golang"
	"github.com/u-root/u-root/pkg/uroot/initramfs"
)

func TestBBBuild(t *testing.T) {
	dir := t.TempDir()

	opts := Opts{
		Env: golang.Default(),
		Packages: []string{
			"github.com/u-root/u-root/pkg/uroot/test/foo",
			"github.com/u-root/u-root/cmds/core/elvish",
		},
		TempDir:   dir,
		BinaryDir: "bbin",
	}
	af := initramfs.NewFiles()
	var bbb BBBuilder
	if err := bbb.Build(af, opts); err != nil {
		t.Error(err)
	}

	mustContain := []string{
		"bbin/elvish",
		"bbin/foo",
	}
	for _, name := range mustContain {
		if !af.Contains(name) {
			t.Errorf("expected files to include %q; archive: %v", name, af)
		}
	}
}
<commit_msg>pkg/uroot/builder/bb_test.go: Only run if GO111MODULE=off<commit_after>// Copyright 2018 the u-root 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 builder

import (
	"os"
	"testing"

	"github.com/u-root/u-root/pkg/golang"
	"github.com/u-root/u-root/pkg/uroot/initramfs"
)

func TestBBBuild(t *testing.T) {
	// Only run this test when we are not using modules.
	if os.Getenv("GO111MODULE") != "off" {
		t.Skipf("Skipping non-modular test")
	}
	dir := t.TempDir()
	opts := Opts{
		Env: golang.Default(),
		Packages: []string{
			"github.com/u-root/u-root/pkg/uroot/test/foo",
			"github.com/u-root/u-root/cmds/core/elvish",
		},
		TempDir:   dir,
		BinaryDir: "bbin",
	}
	af := initramfs.NewFiles()
	var bbb BBBuilder
	if err := bbb.Build(af, opts); err != nil {
		t.Error(err)
	}

	mustContain := []string{
		"bbin/elvish",
		"bbin/foo",
	}
	for _, name := range mustContain {
		if !af.Contains(name) {
			t.Errorf("expected files to include %q; archive: %v", name, af)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 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

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

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

package main

import (
	"context"
	"flag"
	"os"

	"cloud.google.com/go/compute/metadata"
	"github.com/GoogleCloudPlatform/gke-autoneg-controller/controllers"
	"google.golang.org/api/compute/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"
	// +kubebuilder:scaffold:imports
)

var (
	scheme   = runtime.NewScheme()
	setupLog = ctrl.Log.WithName("setup")
)

func init() {
	_ = clientgoscheme.AddToScheme(scheme)

	_ = corev1.AddToScheme(scheme)
	// +kubebuilder:scaffold:scheme
}

func main() {
	var metricsAddr string
	var enableLeaderElection bool
	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
		"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
	flag.Parse()

	ctrl.SetLogger(zap.Logger(true))

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	s, err := compute.NewService(ctx)
	if err != nil {
		setupLog.Error(err, "can't request Google compute service")
		os.Exit(1)
	}

	project := getProject()
	if project == "" {
		setupLog.Error(err, "can't determine project ID")
		os.Exit(1)
	}

	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:             scheme,
		MetricsBindAddress: metricsAddr,
		LeaderElection:     enableLeaderElection,
	})
	if err != nil {
		setupLog.Error(err, "unable to start manager")
		os.Exit(1)
	}

	if err = (&controllers.ServiceReconciler{
		Client:            mgr.GetClient(),
		BackendController: controllers.NewBackendController(project, s),
		Recorder:          mgr.GetEventRecorderFor("autoneg-controller"),
		Log:               ctrl.Log.WithName("controllers").WithName("Service"),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "Service")
		os.Exit(1)
	}
	// +kubebuilder:scaffold:builder

	setupLog.Info("starting manager")
	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}
}

func getProject() string {
	// probe metadata service for project, or fall back to PROJECT_ID in environment
	p, err := metadata.ProjectID()
	if err == nil {
		return p
	}
	return os.Getenv("PROJECT_ID")
}
<commit_msg>Adding user-agent<commit_after>/*
Copyright 2019 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

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

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

package main

import (
	"context"
	"flag"
	"os"

	"cloud.google.com/go/compute/metadata"
	"github.com/GoogleCloudPlatform/gke-autoneg-controller/controllers"
	"google.golang.org/api/compute/v1"
	"google.golang.org/api/option"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"
	// +kubebuilder:scaffold:imports
)

const useragent = "google-pso-tool/gke-autoneg-controller/0.9.0"

var (
	scheme   = runtime.NewScheme()
	setupLog = ctrl.Log.WithName("setup")
)

func init() {
	_ = clientgoscheme.AddToScheme(scheme)

	_ = corev1.AddToScheme(scheme)
	// +kubebuilder:scaffold:scheme
}

func main() {
	var metricsAddr string
	var enableLeaderElection bool
	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
		"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
	flag.Parse()

	ctrl.SetLogger(zap.Logger(true))

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	s, err := compute.NewService(ctx, option.WithUserAgent(useragent))
	if err != nil {
		setupLog.Error(err, "can't request Google compute service")
		os.Exit(1)
	}

	project := getProject()
	if project == "" {
		setupLog.Error(err, "can't determine project ID")
		os.Exit(1)
	}

	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:             scheme,
		MetricsBindAddress: metricsAddr,
		LeaderElection:     enableLeaderElection,
	})
	if err != nil {
		setupLog.Error(err, "unable to start manager")
		os.Exit(1)
	}

	if err = (&controllers.ServiceReconciler{
		Client:            mgr.GetClient(),
		BackendController: controllers.NewBackendController(project, s),
		Recorder:          mgr.GetEventRecorderFor("autoneg-controller"),
		Log:               ctrl.Log.WithName("controllers").WithName("Service"),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "Service")
		os.Exit(1)
	}
	// +kubebuilder:scaffold:builder

	setupLog.Info("starting manager")
	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}
}

func getProject() string {
	// probe metadata service for project, or fall back to PROJECT_ID in environment
	p, err := metadata.ProjectID()
	if err == nil {
		return p
	}
	return os.Getenv("PROJECT_ID")
}
<|endoftext|>


<commit_before>package updater

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/blang/semver"
	"github.com/sabakaio/k8s-updater/pkg/registry"
	"github.com/sabakaio/k8s-updater/pkg/util"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/batch"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/labels"
	"strings"
	"time"
)

// GetDeploymentName returns the deployment name
func (c *Container) GetDeploymentName() string {
	return c.deployment.Name
}

// GetName returns the container name
func (c *Container) GetName() string {
	return c.container.Name
}

// GetImageName returns the container image name
func (c *Container) GetImageName() string {
	return c.container.Image
}

// GetImageVersion returns `registry.Version` for current container image
func (c *Container) GetImageVersion() (version *registry.Version, err error) {
	image := strings.SplitN(c.GetImageName(), ":", 2)
	if len(image) != 2 {
		err = fmt.Errorf("invalid image name, could not extract version: %s", c.GetImageName())
		return
	}
	semver, err := semver.ParseTolerant(image[1])
	if err != nil {
		return
	}
	version = &registry.Version{
		Tag:    image[1],
		Semver: semver,
	}
	return
}

// SetImageVersion updates Deployment template with the set version. It does not save the deployment.
// NOTE a version is passed by the value to avoid nil pointer errors
func (c *Container) SetImageVersion(v registry.Version) (*Container, error) {
	image := strings.SplitN(c.GetImageName(), ":", 2)
	newImage := image[0] + ":" + v.String()
	c.container.Image = newImage
	for i, dc := range c.deployment.Spec.Template.Spec.Containers {
		if dc.Name == c.GetName() {
			c.deployment.Spec.Template.Spec.Containers[i].Image = newImage
		}
	}
	return c, nil
}

// GetLatestVersion returns a latest image version from repository
func (c *Container) GetLatestVersion() (*registry.Version, error) {
	return c.repository.GetLatestVersion()
}

// SetRepositoryFrom iterate over registries list to match containers image repository
func (c *Container) SetRepositoryFrom(registries *registry.RegistryList) error {
	image := c.GetImageName()
	// Choose a registry for container by the name
	for _, r := range registries.Items {
		if strings.HasPrefix(image, r.Name+"/") {
			c.repository = registry.NewRepository(image, r)
			return nil
		}
	}
	if defaultRegistry, err := registries.Get("default"); err == nil {
		c.repository = registry.NewRepository(image, defaultRegistry)
		return nil
	}
	return fmt.Errorf("cannot match registry for container '%s'", c.GetName())
}

// NewList list containers to check for updates
func NewList(k *client.Client, namespace string) (containers *ContainerList, err error) {
	// List all deployments lebled with `autoupdate`
	selector, err := labels.Parse("autoupdate")
	if err != nil {
		return
	}
	opts := api.ListOptions{
		LabelSelector: selector,
	}
	deployments, err := k.Deployments(namespace).List(opts)
	if err != nil {
		return
	}

	// Iterate over the list of deployments to get a list of containers
	containers = new(ContainerList)
	for _, d := range deployments.Items {
		// Get deployment spec registries
		registries, e := registry.GetRegistries(k, &d)
		if e != nil {
			err = e
			return
		}

		// Get deployment annotations to use as config for updater
		annotations := d.GetAnnotations()

		// Iterate over pod containers to get update targets
		for _, c := range d.Spec.Template.Spec.Containers {
			var container = &Container{
				container:  &c,
				deployment: &d,
			}

			if err := container.SetRepositoryFrom(registries); err != nil {
				log.Errorln(err.Error())
				continue
			}
			log.Debugf("container '%s' of deployment '%s' uses '%s' repository", c.Name, d.Name, container.repository.Name)

			hook_key := "before_autoupdate_" + c.Name
			hook_name, ok := annotations[hook_key]
			if ok {
				job, e := k.Batch().Jobs(d.Namespace).Get(hook_name)
				if e == nil {
					container.beforeUpdate = job
					log.Debugf("before update hook for '%s' container: %s", c.Name, job.Name)
				}
			}

			containers.Items = append(containers.Items, container)
		}
	}

	return
}

// UpdateDeployment updates Deployment version on the cluster
func (c *Container) UpdateDeployment(k *client.Client, v registry.Version) (err error) {
	namespace := c.deployment.Namespace

	// Update image version for container
	newContainer, err := c.SetImageVersion(v)
	if err != nil {
		return err
	}

	// Perform preupdate hook if exists
	hook := newContainer.GetBeforeUpdateJob()
	if hook != nil {
		// Create a job by hook spec
		createdJob, e := k.Batch().Jobs(namespace).Create(hook)
		if e != nil {
			err = e
			return
		}
		job_name := createdJob.GetName()
		log.Debugln("before update hook job created with name", job_name)

		// Defer job delete
		defer func() {
			if e := util.DeletePodsInJob(k, createdJob); e != nil {
				log.Errorf("could not delete pods related to job: %s", e.Error())
			}
			deleteOptions := &api.DeleteOptions{}
			if e := k.Batch().Jobs(namespace).Delete(job_name, deleteOptions); e != nil {
				log.Errorf("could not cleanup job: %s", e.Error())
			} else {
				log.Debugf("job %s deleted", job_name)
			}
		}()

		// Wait the job to complete
		for {
			runningJob, e := k.Batch().Jobs(namespace).Get(job_name)
			if e != nil {
				err = e
				return
			}
			if runningJob.Status.Failed > 0 {
				err = fmt.Errorf("job %s failed")
				return
			}
			if runningJob.Status.Succeeded > 0 {
				break
			}
			time.Sleep(time.Second * 3)
		}
	}
	return

	_, err = k.Deployments(namespace).Update(newContainer.deployment)
	// TODO: what to do with the new deployment? Update our memory store?

	return
}

// GetBeforeUpdateJob returns configuration for a job to run before deployment update.
// It copies the original job and fix it's container image version.
func (c *Container) GetBeforeUpdateJob() (job *batch.Job) {
	if c.beforeUpdate == nil {
		return
	}
	hook := c.beforeUpdate

	job = &batch.Job{}
	job.Spec.Template.Spec = hook.Spec.Template.Spec
	for i, jobContainer := range job.Spec.Template.Spec.Containers {
		jobImage := strings.SplitN(jobContainer.Image, ":", 2)[0]
		if strings.HasPrefix(c.GetImageName(), jobImage+":") {
			job.Spec.Template.Spec.Containers[i].Image = c.GetImageName()
			log.Debugln("update job container image to", c.GetImageName())
		}
	}

	genName := c.GetName() + "-" + hook.GetName() + "-"
	job.ObjectMeta.SetGenerateName(genName)

	return
}
<commit_msg>drop early return<commit_after>package updater

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/blang/semver"
	"github.com/sabakaio/k8s-updater/pkg/registry"
	"github.com/sabakaio/k8s-updater/pkg/util"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/batch"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/labels"
	"strings"
	"time"
)

// GetDeploymentName returns the deployment name
func (c *Container) GetDeploymentName() string {
	return c.deployment.Name
}

// GetName returns the container name
func (c *Container) GetName() string {
	return c.container.Name
}

// GetImageName returns the container image name
func (c *Container) GetImageName() string {
	return c.container.Image
}

// GetImageVersion returns `registry.Version` for current container image
func (c *Container) GetImageVersion() (version *registry.Version, err error) {
	image := strings.SplitN(c.GetImageName(), ":", 2)
	if len(image) != 2 {
		err = fmt.Errorf("invalid image name, could not extract version: %s", c.GetImageName())
		return
	}
	semver, err := semver.ParseTolerant(image[1])
	if err != nil {
		return
	}
	version = &registry.Version{
		Tag:    image[1],
		Semver: semver,
	}
	return
}

// SetImageVersion updates Deployment template with the set version. It does not save the deployment.
// NOTE a version is passed by the value to avoid nil pointer errors
func (c *Container) SetImageVersion(v registry.Version) (*Container, error) {
	image := strings.SplitN(c.GetImageName(), ":", 2)
	newImage := image[0] + ":" + v.String()
	c.container.Image = newImage
	for i, dc := range c.deployment.Spec.Template.Spec.Containers {
		if dc.Name == c.GetName() {
			c.deployment.Spec.Template.Spec.Containers[i].Image = newImage
		}
	}
	return c, nil
}

// GetLatestVersion returns a latest image version from repository
func (c *Container) GetLatestVersion() (*registry.Version, error) {
	return c.repository.GetLatestVersion()
}

// SetRepositoryFrom iterate over registries list to match containers image repository
func (c *Container) SetRepositoryFrom(registries *registry.RegistryList) error {
	image := c.GetImageName()
	// Choose a registry for container by the name
	for _, r := range registries.Items {
		if strings.HasPrefix(image, r.Name+"/") {
			c.repository = registry.NewRepository(image, r)
			return nil
		}
	}
	if defaultRegistry, err := registries.Get("default"); err == nil {
		c.repository = registry.NewRepository(image, defaultRegistry)
		return nil
	}
	return fmt.Errorf("cannot match registry for container '%s'", c.GetName())
}

// NewList list containers to check for updates
func NewList(k *client.Client, namespace string) (containers *ContainerList, err error) {
	// List all deployments lebled with `autoupdate`
	selector, err := labels.Parse("autoupdate")
	if err != nil {
		return
	}
	opts := api.ListOptions{
		LabelSelector: selector,
	}
	deployments, err := k.Deployments(namespace).List(opts)
	if err != nil {
		return
	}

	// Iterate over the list of deployments to get a list of containers
	containers = new(ContainerList)
	for _, d := range deployments.Items {
		// Get deployment spec registries
		registries, e := registry.GetRegistries(k, &d)
		if e != nil {
			err = e
			return
		}

		// Get deployment annotations to use as config for updater
		annotations := d.GetAnnotations()

		// Iterate over pod containers to get update targets
		for _, c := range d.Spec.Template.Spec.Containers {
			var container = &Container{
				container:  &c,
				deployment: &d,
			}

			if err := container.SetRepositoryFrom(registries); err != nil {
				log.Errorln(err.Error())
				continue
			}
			log.Debugf("container '%s' of deployment '%s' uses '%s' repository", c.Name, d.Name, container.repository.Name)

			hook_key := "before_autoupdate_" + c.Name
			hook_name, ok := annotations[hook_key]
			if ok {
				job, e := k.Batch().Jobs(d.Namespace).Get(hook_name)
				if e == nil {
					container.beforeUpdate = job
					log.Debugf("before update hook for '%s' container: %s", c.Name, job.Name)
				}
			}

			containers.Items = append(containers.Items, container)
		}
	}

	return
}

// UpdateDeployment updates Deployment version on the cluster
func (c *Container) UpdateDeployment(k *client.Client, v registry.Version) (err error) {
	namespace := c.deployment.Namespace

	// Update image version for container
	newContainer, err := c.SetImageVersion(v)
	if err != nil {
		return err
	}

	// Perform preupdate hook if exists
	hook := newContainer.GetBeforeUpdateJob()
	if hook != nil {
		// Create a job by hook spec
		createdJob, e := k.Batch().Jobs(namespace).Create(hook)
		if e != nil {
			err = e
			return
		}
		job_name := createdJob.GetName()
		log.Debugln("before update hook job created with name", job_name)

		// Defer job delete
		defer func() {
			if e := util.DeletePodsInJob(k, createdJob); e != nil {
				log.Errorf("could not delete pods related to job: %s", e.Error())
			}
			deleteOptions := &api.DeleteOptions{}
			if e := k.Batch().Jobs(namespace).Delete(job_name, deleteOptions); e != nil {
				log.Errorf("could not cleanup job: %s", e.Error())
			} else {
				log.Debugf("job %s deleted", job_name)
			}
		}()

		// Wait the job to complete
		for {
			runningJob, e := k.Batch().Jobs(namespace).Get(job_name)
			if e != nil {
				err = e
				return
			}
			if runningJob.Status.Failed > 0 {
				err = fmt.Errorf("job %s failed")
				return
			}
			if runningJob.Status.Succeeded > 0 {
				break
			}
			time.Sleep(time.Second * 3)
		}
	}

	_, err = k.Deployments(namespace).Update(newContainer.deployment)
	// TODO: what to do with the new deployment? Update our memory store?

	return
}

// GetBeforeUpdateJob returns configuration for a job to run before deployment update.
// It copies the original job and fix it's container image version.
func (c *Container) GetBeforeUpdateJob() (job *batch.Job) {
	if c.beforeUpdate == nil {
		return
	}
	hook := c.beforeUpdate

	job = &batch.Job{}
	job.Spec.Template.Spec = hook.Spec.Template.Spec
	for i, jobContainer := range job.Spec.Template.Spec.Containers {
		jobImage := strings.SplitN(jobContainer.Image, ":", 2)[0]
		if strings.HasPrefix(c.GetImageName(), jobImage+":") {
			job.Spec.Template.Spec.Containers[i].Image = c.GetImageName()
			log.Debugln("update job container image to", c.GetImageName())
		}
	}

	genName := c.GetName() + "-" + hook.GetName() + "-"
	job.ObjectMeta.SetGenerateName(genName)

	return
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"

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

type Config struct {
	SlackToken    string
	HttpPath      string
	BasicUser     string
	BasicPassword string
}

func readJSON(fn string, v interface{}) {
	file, _ := os.Open(fn)
	defer file.Close()
	decoder := json.NewDecoder(file)
	err := decoder.Decode(v)
	if err != nil {
		log.Println("error:", err)
	}
}

var config Config

func main() {

	config = Config{}
	readJSON("config.json", &config)

	api := slack.New(config.SlackToken)

	rtm := api.NewRTM()
	go rtm.ManageConnection()

	log.Println("Slackbot started")

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			case *slack.HelloEvent:
				// Ignore hello
			case *slack.ConnectedEvent:
				log.Println("Connection counter:", ev.ConnectionCount)
			case *slack.MessageEvent:
				if ev.Msg.User == "" {
					continue
				}

				// only direct channels reply
				if !strings.HasPrefix(ev.Msg.Channel, "D") {
					continue
				}
				_, _, userChannel, err := rtm.OpenIMChannel(ev.Msg.User)
				if err != nil {
					log.Printf("Get channel Error: %v\n", err)
					continue
				}
				if userChannel != ev.Msg.Channel {
					continue
				}

				userInfo, err := rtm.GetUserInfo(ev.Msg.User)
				if err != nil {
					log.Printf("User info Error: %v\n", err)
					continue
				}

				log.Printf("User: %v; Message: %v\n", userInfo.Profile.Email, ev.Msg.Text) // ev.Msg.User, ev.Msg.Channel

				client := &http.Client{}
				parameters := url.Values{}
				parameters.Add("user", ev.Msg.User)
				parameters.Add("message", ev.Msg.Text)
				parameters.Add("email", userInfo.Profile.Email)
				req, err := http.NewRequest("POST", config.HttpPath, strings.NewReader(parameters.Encode()))

				if config.BasicUser != "" {
					req.SetBasicAuth(config.BasicUser, config.BasicPassword)
				}

				resp, err := client.Do(req)
				if err != nil {
					log.Printf("HTTP request Error: %v\n", err)
					continue
				}
				defer resp.Body.Close()

				body, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					log.Printf("HTTP read Error %v\n", err)
				} else {
					log.Printf("HTTP response: %+v\n", string(body))
					rtm.SendMessage(rtm.NewOutgoingMessage(string(body), ev.Msg.Channel))
				}

			case *slack.InvalidAuthEvent:
				log.Printf("Invalid credentials")
				break Loop

			default:
				// Ignore other events..
			}
		}
	}
}
<commit_msg>slack api updates<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"

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

type Config struct {
	SlackToken    string
	HttpPath      string
	BasicUser     string
	BasicPassword string
}

func readJSON(fn string, v interface{}) {
	file, _ := os.Open(fn)
	defer file.Close()
	decoder := json.NewDecoder(file)
	err := decoder.Decode(v)
	if err != nil {
		log.Println("error:", err)
	}
}

var config Config

func main() {

	config = Config{}
	readJSON("config.json", &config)

	api := slack.New(config.SlackToken)

	rtm := api.NewRTM()
	go rtm.ManageConnection()

	log.Println("Slackbot started")

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			case *slack.HelloEvent:
				// Ignore hello
			case *slack.ConnectedEvent:
				log.Println("Connection counter:", ev.ConnectionCount)
			case *slack.MessageEvent:
				if ev.Msg.User == "" {
					continue
				}

				// only direct channels reply
				if !strings.HasPrefix(ev.Msg.Channel, "D") {
					continue
				}
				params := slack.OpenConversationParameters{ChannelID: ev.Msg.Channel}
				userChannel, _, _, err := rtm.OpenConversation(&params)
				if err != nil {
					log.Printf("Get channel Error: %v\n", err)
					continue
				}
				if userChannel.ID != ev.Msg.Channel {
					continue
				}

				userInfo, err := rtm.GetUserInfo(ev.Msg.User)
				if err != nil {
					log.Printf("User info Error: %v\n", err)
					continue
				}

				log.Printf("User: %v (%v); Message: %v\n", ev.Msg.User, userInfo.Profile.Email, ev.Msg.Text) // ev.Msg.User, ev.Msg.Channel

				client := &http.Client{}
				parameters := url.Values{}
				parameters.Add("user", ev.Msg.User)
				parameters.Add("message", ev.Msg.Text)
				parameters.Add("email", userInfo.Profile.Email)
				req, err := http.NewRequest("POST", config.HttpPath, strings.NewReader(parameters.Encode()))

				if config.BasicUser != "" {
					req.SetBasicAuth(config.BasicUser, config.BasicPassword)
				}

				resp, err := client.Do(req)
				if err != nil {
					log.Printf("HTTP request Error: %v\n", err)
					continue
				}
				defer resp.Body.Close()

				body, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					log.Printf("HTTP read Error %v\n", err)
				} else {
					log.Printf("HTTP response: %+v\n", string(body))
					rtm.SendMessage(rtm.NewOutgoingMessage(string(body), ev.Msg.Channel))
				}

			case *slack.InvalidAuthEvent:
				log.Printf("Invalid credentials")
				break Loop

			default:
				// Ignore other events..
			}
		}
	}
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"strings"
	"time"

	"fmt"

	"github.com/zalando-incubator/postgres-operator/pkg/spec"
)

// CRD describes CustomResourceDefinition specific configuration parameters
type CRD struct {
	ReadyWaitInterval time.Duration `name:"ready_wait_interval" default:"4s"`
	ReadyWaitTimeout  time.Duration `name:"ready_wait_timeout" default:"30s"`
	ResyncPeriod      time.Duration `name:"resync_period" default:"5m"`
}

// Resources describes kubernetes resource specific configuration parameters
type Resources struct {
	ResourceCheckInterval   time.Duration     `name:"resource_check_interval" default:"3s"`
	ResourceCheckTimeout    time.Duration     `name:"resource_check_timeout" default:"10m"`
	PodLabelWaitTimeout     time.Duration     `name:"pod_label_wait_timeout" default:"10m"`
	PodDeletionWaitTimeout  time.Duration     `name:"pod_deletion_wait_timeout" default:"10m"`
	PodTerminateGracePeriod time.Duration     `name:"pod_terminate_grace_period" default:"5m"`
	ClusterLabels           map[string]string `name:"cluster_labels" default:"application:spilo"`
	ClusterNameLabel        string            `name:"cluster_name_label" default:"cluster-name"`
	PodRoleLabel            string            `name:"pod_role_label" default:"spilo-role"`
	PodToleration           map[string]string `name:"toleration" default:""`
	DefaultCPURequest       string            `name:"default_cpu_request" default:"100m"`
	DefaultMemoryRequest    string            `name:"default_memory_request" default:"100Mi"`
	DefaultCPULimit         string            `name:"default_cpu_limit" default:"3"`
	DefaultMemoryLimit      string            `name:"default_memory_limit" default:"1Gi"`
	PodEnvironmentConfigMap string            `name:"pod_environment_configmap" default:""`
	NodeReadinessLabel      map[string]string `name:"node_readiness_label" default:""`
	MaxInstances            int32             `name:"max_instances" default:"-1"`
	MinInstances            int32             `name:"min_instances" default:"-1"`
}

// Auth describes authentication specific configuration parameters
type Auth struct {
	SecretNameTemplate            stringTemplate      `name:"secret_name_template" default:"{username}.{cluster}.credentials.{tprkind}.{tprgroup}"`
	PamRoleName                   string              `name:"pam_role_name" default:"zalandos"`
	PamConfiguration              string              `name:"pam_configuration" default:"https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"`
	TeamsAPIUrl                   string              `name:"teams_api_url" default:"https://teams.example.com/api/"`
	OAuthTokenSecretName          spec.NamespacedName `name:"oauth_token_secret_name" default:"postgresql-operator"`
	InfrastructureRolesSecretName spec.NamespacedName `name:"infrastructure_roles_secret_name"`
	SuperUsername                 string              `name:"super_username" default:"postgres"`
	ReplicationUsername           string              `name:"replication_username" default:"standby"`
}

// Scalyr holds the configuration for the Scalyr Agent sidecar for log shipping:
type Scalyr struct {
	ScalyrAPIKey        string `name:"scalyr_api_key" default:""`
	ScalyrImage         string `name:"scalyr_image" default:""`
	ScalyrServerURL     string `name:"scalyr_server_url" default:"https://upload.eu.scalyr.com"`
	ScalyrCPURequest    string `name:"scalyr_cpu_request" default:"100m"`
	ScalyrMemoryRequest string `name:"scalyr_memory_request" default:"50Mi"`
	ScalyrCPULimit      string `name:"scalyr_cpu_limit" default:"1"`
	ScalyrMemoryLimit   string `name:"scalyr_memory_limit" default:"1Gi"`
}

// Config describes operator config
type Config struct {
	CRD
	Resources
	Auth
	Scalyr
	WatchedNamespace          string            `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to'
	EtcdHost                  string            `name:"etcd_host" default:"etcd-client.default.svc.cluster.local:2379"`
	DockerImage               string            `name:"docker_image" default:"registry.opensource.zalan.do/acid/spiloprivate-9.6:1.2-p4"`
	ServiceAccountName        string            `name:"service_account_name" default:"operator"`
	DbHostedZone              string            `name:"db_hosted_zone" default:"db.example.com"`
	EtcdScope                 string            `name:"etcd_scope" default:"service"`
	WALES3Bucket              string            `name:"wal_s3_bucket"`
	KubeIAMRole               string            `name:"kube_iam_role"`
	DebugLogging              bool              `name:"debug_logging" default:"true"`
	EnableDBAccess            bool              `name:"enable_database_access" default:"true"`
	EnableTeamsAPI            bool              `name:"enable_teams_api" default:"true"`
	EnableTeamSuperuser       bool              `name:"enable_team_superuser" default:"false"`
	TeamAdminRole             string            `name:"team_admin_role" default:"admin"`
	EnableMasterLoadBalancer  bool              `name:"enable_master_load_balancer" default:"true"`
	EnableReplicaLoadBalancer bool              `name:"enable_replica_load_balancer" default:"false"`
	MasterDNSNameFormat       stringTemplate    `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"`
	ReplicaDNSNameFormat      stringTemplate    `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"`
	PDBNameFormat             stringTemplate    `name:"pdb_name_format" default:"postgres-{cluster}-pdb"`
	Workers                   uint32            `name:"workers" default:"4"`
	APIPort                   int               `name:"api_port" default:"8080"`
	RingLogLines              int               `name:"ring_log_lines" default:"100"`
	ClusterHistoryEntries     int               `name:"cluster_history_entries" default:"1000"`
	TeamAPIRoleConfiguration  map[string]string `name:"team_api_role_configuration" default:"log_statement:all"`
	PodTerminateGracePeriod   time.Duration     `name:"pod_terminate_grace_period" default:"5m"`
	ProtectedRoles            []string          `name:"protected_role_names" default:"admin"`
}

// MustMarshal marshals the config or panics
func (c Config) MustMarshal() string {
	b, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		panic(err)
	}

	return string(b)
}

// NewFromMap creates Config from the map
func NewFromMap(m map[string]string) *Config {
	cfg := Config{}
	fields, _ := structFields(&cfg)

	for _, structField := range fields {
		key := strings.ToLower(structField.Name)
		value, ok := m[key]
		if !ok && structField.Default != "" {
			value = structField.Default
		}

		if value == "" {
			continue
		}
		err := processField(value, structField.Field)
		if err != nil {
			panic(err)
		}
	}
	if err := validate(&cfg); err != nil {
		panic(err)
	}

	return &cfg
}

// Copy creates a copy of the config
func Copy(c *Config) Config {
	cfg := *c

	cfg.ClusterLabels = make(map[string]string, len(c.ClusterLabels))
	for k, v := range c.ClusterLabels {
		cfg.ClusterLabels[k] = v
	}

	return cfg
}

func validate(cfg *Config) (err error) {
	if cfg.MinInstances > 0 && cfg.MaxInstances > 0 && cfg.MinInstances > cfg.MaxInstances {
		err = fmt.Errorf("minimum number of instances %d is set higher than the maximum number %d",
			cfg.MinInstances, cfg.MaxInstances)
	}
	if cfg.Workers == 0 {
		err = fmt.Errorf("number of workers should be higher than 0")
	}
	return
}
<commit_msg>Disable load balancer for master service by default (it may cost money)<commit_after>package config

import (
	"encoding/json"
	"strings"
	"time"

	"fmt"

	"github.com/zalando-incubator/postgres-operator/pkg/spec"
)

// CRD describes CustomResourceDefinition specific configuration parameters
type CRD struct {
	ReadyWaitInterval time.Duration `name:"ready_wait_interval" default:"4s"`
	ReadyWaitTimeout  time.Duration `name:"ready_wait_timeout" default:"30s"`
	ResyncPeriod      time.Duration `name:"resync_period" default:"5m"`
}

// Resources describes kubernetes resource specific configuration parameters
type Resources struct {
	ResourceCheckInterval   time.Duration     `name:"resource_check_interval" default:"3s"`
	ResourceCheckTimeout    time.Duration     `name:"resource_check_timeout" default:"10m"`
	PodLabelWaitTimeout     time.Duration     `name:"pod_label_wait_timeout" default:"10m"`
	PodDeletionWaitTimeout  time.Duration     `name:"pod_deletion_wait_timeout" default:"10m"`
	PodTerminateGracePeriod time.Duration     `name:"pod_terminate_grace_period" default:"5m"`
	ClusterLabels           map[string]string `name:"cluster_labels" default:"application:spilo"`
	ClusterNameLabel        string            `name:"cluster_name_label" default:"cluster-name"`
	PodRoleLabel            string            `name:"pod_role_label" default:"spilo-role"`
	PodToleration           map[string]string `name:"toleration" default:""`
	DefaultCPURequest       string            `name:"default_cpu_request" default:"100m"`
	DefaultMemoryRequest    string            `name:"default_memory_request" default:"100Mi"`
	DefaultCPULimit         string            `name:"default_cpu_limit" default:"3"`
	DefaultMemoryLimit      string            `name:"default_memory_limit" default:"1Gi"`
	PodEnvironmentConfigMap string            `name:"pod_environment_configmap" default:""`
	NodeReadinessLabel      map[string]string `name:"node_readiness_label" default:""`
	MaxInstances            int32             `name:"max_instances" default:"-1"`
	MinInstances            int32             `name:"min_instances" default:"-1"`
}

// Auth describes authentication specific configuration parameters
type Auth struct {
	SecretNameTemplate            stringTemplate      `name:"secret_name_template" default:"{username}.{cluster}.credentials.{tprkind}.{tprgroup}"`
	PamRoleName                   string              `name:"pam_role_name" default:"zalandos"`
	PamConfiguration              string              `name:"pam_configuration" default:"https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"`
	TeamsAPIUrl                   string              `name:"teams_api_url" default:"https://teams.example.com/api/"`
	OAuthTokenSecretName          spec.NamespacedName `name:"oauth_token_secret_name" default:"postgresql-operator"`
	InfrastructureRolesSecretName spec.NamespacedName `name:"infrastructure_roles_secret_name"`
	SuperUsername                 string              `name:"super_username" default:"postgres"`
	ReplicationUsername           string              `name:"replication_username" default:"standby"`
}

// Scalyr holds the configuration for the Scalyr Agent sidecar for log shipping:
type Scalyr struct {
	ScalyrAPIKey        string `name:"scalyr_api_key" default:""`
	ScalyrImage         string `name:"scalyr_image" default:""`
	ScalyrServerURL     string `name:"scalyr_server_url" default:"https://upload.eu.scalyr.com"`
	ScalyrCPURequest    string `name:"scalyr_cpu_request" default:"100m"`
	ScalyrMemoryRequest string `name:"scalyr_memory_request" default:"50Mi"`
	ScalyrCPULimit      string `name:"scalyr_cpu_limit" default:"1"`
	ScalyrMemoryLimit   string `name:"scalyr_memory_limit" default:"1Gi"`
}

// Config describes operator config
type Config struct {
	CRD
	Resources
	Auth
	Scalyr
	WatchedNamespace          string            `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to'
	EtcdHost                  string            `name:"etcd_host" default:"etcd-client.default.svc.cluster.local:2379"`
	DockerImage               string            `name:"docker_image" default:"registry.opensource.zalan.do/acid/spiloprivate-9.6:1.2-p4"`
	ServiceAccountName        string            `name:"service_account_name" default:"operator"`
	DbHostedZone              string            `name:"db_hosted_zone" default:"db.example.com"`
	EtcdScope                 string            `name:"etcd_scope" default:"service"`
	WALES3Bucket              string            `name:"wal_s3_bucket"`
	KubeIAMRole               string            `name:"kube_iam_role"`
	DebugLogging              bool              `name:"debug_logging" default:"true"`
	EnableDBAccess            bool              `name:"enable_database_access" default:"true"`
	EnableTeamsAPI            bool              `name:"enable_teams_api" default:"true"`
	EnableTeamSuperuser       bool              `name:"enable_team_superuser" default:"false"`
	TeamAdminRole             string            `name:"team_admin_role" default:"admin"`
	EnableMasterLoadBalancer  bool              `name:"enable_master_load_balancer" default:"false"`
	EnableReplicaLoadBalancer bool              `name:"enable_replica_load_balancer" default:"false"`
	MasterDNSNameFormat       stringTemplate    `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"`
	ReplicaDNSNameFormat      stringTemplate    `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"`
	PDBNameFormat             stringTemplate    `name:"pdb_name_format" default:"postgres-{cluster}-pdb"`
	Workers                   uint32            `name:"workers" default:"4"`
	APIPort                   int               `name:"api_port" default:"8080"`
	RingLogLines              int               `name:"ring_log_lines" default:"100"`
	ClusterHistoryEntries     int               `name:"cluster_history_entries" default:"1000"`
	TeamAPIRoleConfiguration  map[string]string `name:"team_api_role_configuration" default:"log_statement:all"`
	PodTerminateGracePeriod   time.Duration     `name:"pod_terminate_grace_period" default:"5m"`
	ProtectedRoles            []string          `name:"protected_role_names" default:"admin"`
}

// MustMarshal marshals the config or panics
func (c Config) MustMarshal() string {
	b, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		panic(err)
	}

	return string(b)
}

// NewFromMap creates Config from the map
func NewFromMap(m map[string]string) *Config {
	cfg := Config{}
	fields, _ := structFields(&cfg)

	for _, structField := range fields {
		key := strings.ToLower(structField.Name)
		value, ok := m[key]
		if !ok && structField.Default != "" {
			value = structField.Default
		}

		if value == "" {
			continue
		}
		err := processField(value, structField.Field)
		if err != nil {
			panic(err)
		}
	}
	if err := validate(&cfg); err != nil {
		panic(err)
	}

	return &cfg
}

// Copy creates a copy of the config
func Copy(c *Config) Config {
	cfg := *c

	cfg.ClusterLabels = make(map[string]string, len(c.ClusterLabels))
	for k, v := range c.ClusterLabels {
		cfg.ClusterLabels[k] = v
	}

	return cfg
}

func validate(cfg *Config) (err error) {
	if cfg.MinInstances > 0 && cfg.MaxInstances > 0 && cfg.MinInstances > cfg.MaxInstances {
		err = fmt.Errorf("minimum number of instances %d is set higher than the maximum number %d",
			cfg.MinInstances, cfg.MaxInstances)
	}
	if cfg.Workers == 0 {
		err = fmt.Errorf("number of workers should be higher than 0")
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"time"
	"encoding/json"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"log"
	"os"
	//"io"
	"fmt"
	"database/sql"
	_ "github.com/lib/pq"
	"gopkg.in/antage/eventsource.v1"
)

var conn *sql.DB

func SetHeaders(w *http.ResponseWriter) {
	(*w).Header().Set("Access-Control-Allow-Origin", "*")
	(*w).Header().Set("Content-Type", "application/json")
}

func GetBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog")
	data := []BlogPost{}
	for rows.Next() {
		post := BlogPost{}
		rows.Scan(&post.Id, &post.Titel, &post.Text, &post.Auteur, &post.Img_url, &post.Ctime, &post.Image)
		data = append(data, post)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog WHERE id = $1 LIMIT 1", ps.ByName("id"))
	data := BlogPost{}
	rows.Next()
	rows.Scan(&data.Id, &data.Titel, &data.Text, &data.Auteur, &data.Img_url, &data.Ctime, &data.Image)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata ORDER BY tijd DESC LIMIT 1")
	spin := SpinData{}
	rows.Next()
	rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
	buf,_ := json.Marshal(spin)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data int
	rows.Next()
	rows.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data string
	rows.Next()
	rows.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata")
	data := []SpinData{}
	for rows.Next() {
		spin := SpinData{}
		rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
		data = append(data, spin)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata")
	data := make([]int, 0)
	var scanInt int
	for rows.Next() {
		rows.Scan(&scanInt)
		data = append(data, scanInt)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata")
	data := make([]string, 0)
	var scanStr string
	for rows.Next() {
		rows.Scan(&scanStr)
		data = append(data, scanStr)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata ORDER BY tijd DESC LIMIT 1")
	servo := ServoData{}
	rows.Next()
	rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
	buf,_ := json.Marshal(servo)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata")
	data := []ServoData{}
	for rows.Next() {
		servo := ServoData{}
		rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
		data = append(data, servo)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func PostBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//r.ParseMultipartForm(32 << 20)
	/*file, handler, err := r.FormFile("uploadfile")
	defer file.Close()
	if err == nil {
		fmt.Fprintf(w, "%v", handler.Header)
		f, err := os.OpenFile("./img/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		defer f.Close()
		io.Copy(f, file)
	}

	err = nil*/

	//_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime, image) VALUES ($1, $2, $3, $4, $5)", r.FormValue("titel"), r.FormValue("text"), r.FormValue("auteur"), time.Now(), "http://idp-api.herokuapp.com/img/"+handler.Filename)
	_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime) VALUES ($1, $2, $3, $4)", r.FormValue("onderwerp"), r.FormValue("bericht"), r.FormValue("naam"), time.Now())
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(201)
	w.Write([]byte("<meta http-equiv=\"refresh\" content=\"5; url=http://knightspider.herokuapp.com/#/blog\">successful"))
}

func PostSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO spindata (tijd, mode, hellingsgraad, snelheid, batterij, balloncount) VALUES ($1, $2, $3, $4, $5, $6)", time.Now(),
		r.FormValue("mode"), r.FormValue("hellingsgraad"), r.FormValue("snelheid"), r.FormValue("batterij"), r.FormValue("ballonCount"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

func PostServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO servodata (servo_id, tijd, voltage, positie, load, temperatuur) VALUES ($1, $2, $3, $4, $5, $6)",
		r.FormValue("servo_id"), time.Now(), r.FormValue("voltage"), r.FormValue("positie"), r.FormValue("load"), r.FormValue("Temperatuur"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

/*func GetDoc(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	http.ServeFile(w,r,"./static/doc.html")
}*/

func Static(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	http.ServeFile(w,r,"./static/"+ps.ByName("file"))
}

func SSESubscribe(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

}

func main() {
	conn,_ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	defer conn.Close()
	router := httprouter.New()
	//router.GET("/", GetDoc)
	router.GET("/blog", GetBlog)
	router.GET("/blog/:id", GetPost)
	router.GET("/spin/latest", GetLatestSpinData)
	router.GET("/spin/latest/batterij", GetLatestSpinBatterij)
	router.GET("/spin/latest/mode", GetLatestSpinMode)
	router.GET("/spin/archive", GetArchivedSpinData)
	router.GET("/spin/archive/batterij", GetArchivedSpinBatterij)
	router.GET("/spin/archive/mode", GetArchivedSpinMode)
	router.GET("/servo/latest", GetLatestServoData)
	router.GET("/servo/archive", GetArchivedServoData)
	router.GET("/subscribe", SSESubscribe)
	router.POST("/blog", PostBlog)
	router.POST("/spin", PostSpinData)
	router.POST("/servo", PostServoData)
	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	fmt.Printf("Starting server at localhost:%s...", port)
	log.Fatal(http.ListenAndServe(":"+port, router))
}<commit_msg>commented unused dep<commit_after>package main

import (
	"time"
	"encoding/json"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"log"
	"os"
	//"io"
	"fmt"
	"database/sql"
	_ "github.com/lib/pq"
	//"gopkg.in/antage/eventsource.v1"
)

var conn *sql.DB

func SetHeaders(w *http.ResponseWriter) {
	(*w).Header().Set("Access-Control-Allow-Origin", "*")
	(*w).Header().Set("Content-Type", "application/json")
}

func GetBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog")
	data := []BlogPost{}
	for rows.Next() {
		post := BlogPost{}
		rows.Scan(&post.Id, &post.Titel, &post.Text, &post.Auteur, &post.Img_url, &post.Ctime, &post.Image)
		data = append(data, post)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog WHERE id = $1 LIMIT 1", ps.ByName("id"))
	data := BlogPost{}
	rows.Next()
	rows.Scan(&data.Id, &data.Titel, &data.Text, &data.Auteur, &data.Img_url, &data.Ctime, &data.Image)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata ORDER BY tijd DESC LIMIT 1")
	spin := SpinData{}
	rows.Next()
	rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
	buf,_ := json.Marshal(spin)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data int
	rows.Next()
	rows.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data string
	rows.Next()
	rows.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata")
	data := []SpinData{}
	for rows.Next() {
		spin := SpinData{}
		rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
		data = append(data, spin)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata")
	data := make([]int, 0)
	var scanInt int
	for rows.Next() {
		rows.Scan(&scanInt)
		data = append(data, scanInt)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata")
	data := make([]string, 0)
	var scanStr string
	for rows.Next() {
		rows.Scan(&scanStr)
		data = append(data, scanStr)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata ORDER BY tijd DESC LIMIT 1")
	servo := ServoData{}
	rows.Next()
	rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
	buf,_ := json.Marshal(servo)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata")
	data := []ServoData{}
	for rows.Next() {
		servo := ServoData{}
		rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
		data = append(data, servo)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func PostBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//r.ParseMultipartForm(32 << 20)
	/*file, handler, err := r.FormFile("uploadfile")
	defer file.Close()
	if err == nil {
		fmt.Fprintf(w, "%v", handler.Header)
		f, err := os.OpenFile("./img/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		defer f.Close()
		io.Copy(f, file)
	}

	err = nil*/

	//_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime, image) VALUES ($1, $2, $3, $4, $5)", r.FormValue("titel"), r.FormValue("text"), r.FormValue("auteur"), time.Now(), "http://idp-api.herokuapp.com/img/"+handler.Filename)
	_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime) VALUES ($1, $2, $3, $4)", r.FormValue("onderwerp"), r.FormValue("bericht"), r.FormValue("naam"), time.Now())
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(201)
	w.Write([]byte("<meta http-equiv=\"refresh\" content=\"5; url=http://knightspider.herokuapp.com/#/blog\">successful"))
}

func PostSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO spindata (tijd, mode, hellingsgraad, snelheid, batterij, balloncount) VALUES ($1, $2, $3, $4, $5, $6)", time.Now(),
		r.FormValue("mode"), r.FormValue("hellingsgraad"), r.FormValue("snelheid"), r.FormValue("batterij"), r.FormValue("ballonCount"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

func PostServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO servodata (servo_id, tijd, voltage, positie, load, temperatuur) VALUES ($1, $2, $3, $4, $5, $6)",
		r.FormValue("servo_id"), time.Now(), r.FormValue("voltage"), r.FormValue("positie"), r.FormValue("load"), r.FormValue("Temperatuur"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

/*func GetDoc(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	http.ServeFile(w,r,"./static/doc.html")
}*/

func Static(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	http.ServeFile(w,r,"./static/"+ps.ByName("file"))
}

func SSESubscribe(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

}

func main() {
	conn,_ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	defer conn.Close()
	router := httprouter.New()
	//router.GET("/", GetDoc)
	router.GET("/blog", GetBlog)
	router.GET("/blog/:id", GetPost)
	router.GET("/spin/latest", GetLatestSpinData)
	router.GET("/spin/latest/batterij", GetLatestSpinBatterij)
	router.GET("/spin/latest/mode", GetLatestSpinMode)
	router.GET("/spin/archive", GetArchivedSpinData)
	router.GET("/spin/archive/batterij", GetArchivedSpinBatterij)
	router.GET("/spin/archive/mode", GetArchivedSpinMode)
	router.GET("/servo/latest", GetLatestServoData)
	router.GET("/servo/archive", GetArchivedServoData)
	router.GET("/subscribe", SSESubscribe)
	router.POST("/blog", PostBlog)
	router.POST("/spin", PostSpinData)
	router.POST("/servo", PostServoData)
	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	fmt.Printf("Starting server at localhost:%s...", port)
	log.Fatal(http.ListenAndServe(":"+port, router))
}<|endoftext|>


<commit_before>package portutil

import (
	"net"
	"strconv"
)

const (
	tcp = "tcp"
	udp = "udp"
)

// Verifies if a port is available on TCP
func VerifyTCP(port int) (verifiedPort int, err error) {
	ln, err := newListenerTCP(port)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	return port, nil
}

// Verifies if a port is available on UDP
func VerifyUDP(port int) (verifiedPort int, err error) {
	ln, err := newListenerUDP(port)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	return port, nil
}

// Verifies if a port is available on "udp" or "tcp"
func Verify(netProto string, port int) (verifiedPort int, err error) {
	switch netProto {
	case udp:
		_, err = VerifyUDP(port)
		if err != nil {
			return 0, err
		}
	case tcp:
		_, err = VerifyTCP(port)
		if err != nil {
			return 0, err
		}
	}

	return port, nil
}

// Wrapper function for VerifyTCP to easily accept address string
func VerifyHostPort(netProto string, addr string) (verifiedAddr string, err error) {
	port, err := GetPortFromAddr(addr)
	if err != nil {
		return "", err
	}

	_, err = Verify(netProto, port)
	if err != nil {
		return "", err
	}

	return addr, nil
}

// Get a unique port TCP
func GetUniqueTCP() (port int, err error) {
	ln, err := newListenerTCP(0)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	port, err = GetPortFromAddr(ln.Addr().String())
	if err != nil {
		return 0, err
	}

	return port, nil
}

// Get a unique port UDP
func GetUniqueUDP() (port int, err error) {
	ln, err := newListenerUDP(0)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	port, err = GetPortFromAddr(ln.LocalAddr().String())
	if err != nil {
		return 0, err
	}

	return port, nil
}

// Get a unique port on "udp" or "tcp"
func GetUnique(netProto string) (port int, err error) {
	switch netProto {
	case udp:
		port, err = GetUniqueUDP()
		if err != nil {
			return 0, err
		}
	case tcp:
		port, err = GetUniqueTCP()
		if err != nil {
			return 0, err
		}
	}

	return port, nil
}

// Helper function to quickly get the port from an addr string
func GetPortFromAddr(addr string) (port int, err error) {
	_, portStr, err := net.SplitHostPort(addr)
	if err != nil {
		return 0, err
	}

	port, err = strconv.Atoi(portStr)
	if err != nil {
		return 0, err
	}

	return port, nil
}

// Wrapper function for net.JoinHostPort to easily
// pass port as an int instead of a string
func JoinHostPort(host string, port int) string {
	return net.JoinHostPort(host, strconv.Itoa(port))
}

// Helper function to create a new UDP Listener
func newListenerUDP(port int) (*net.UDPConn, error) {
	addr := JoinHostPort("127.0.0.1", port)
	udpAddr, err := net.ResolveUDPAddr(udp, addr)
	if err != nil {
		return nil, err
	}

	ln, err := net.ListenUDP(udp, udpAddr)
	if err != nil {
		return nil, err
	}

	return ln, nil
}

// Helper function to create new UDP Listener
func newListenerTCP(port int) (net.Listener, error) {
	addr := JoinHostPort("127.0.0.1", port)
	ln, err := net.Listen(tcp, addr)
	if err != nil {
		return nil, err
	}

	return ln, nil
}
<commit_msg>adding ReplacePortInAddr and updating comments<commit_after>package portutil

import (
	"net"
	"strconv"
)

const (
	tcp = "tcp"
	udp = "udp"
)

// VerifyTCP verifies if a port is available on TCP
func VerifyTCP(port int) (verifiedPort int, err error) {
	ln, err := newListenerTCP(port)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	return port, nil
}

// VerifyUDP verifies if a port is available on UDP
func VerifyUDP(port int) (verifiedPort int, err error) {
	ln, err := newListenerUDP(port)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	return port, nil
}

// Verify verifies if a port is available on "udp" or "tcp"
func Verify(netProto string, port int) (verifiedPort int, err error) {
	switch netProto {
	case udp:
		_, err = VerifyUDP(port)
		if err != nil {
			return 0, err
		}
	case tcp:
		_, err = VerifyTCP(port)
		if err != nil {
			return 0, err
		}
	}

	return port, nil
}

// VerifyHostPort is a wrapper function for VerifyTCP to easily accept address string
func VerifyHostPort(netProto string, addr string) (verifiedAddr string, err error) {
	port, err := GetPortFromAddr(addr)
	if err != nil {
		return "", err
	}

	_, err = Verify(netProto, port)
	if err != nil {
		return "", err
	}

	return addr, nil
}

// GetUniqueTCP gets a unique port TCP
func GetUniqueTCP() (port int, err error) {
	ln, err := newListenerTCP(0)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	port, err = GetPortFromAddr(ln.Addr().String())
	if err != nil {
		return 0, err
	}

	return port, nil
}

// GetUniqueUDP gets a unique port UDP
func GetUniqueUDP() (port int, err error) {
	ln, err := newListenerUDP(0)
	if err != nil {
		return 0, err
	}
	defer ln.Close()

	port, err = GetPortFromAddr(ln.LocalAddr().String())
	if err != nil {
		return 0, err
	}

	return port, nil
}

// GetUnique gets a unique port on "udp" or "tcp"
func GetUnique(netProto string) (port int, err error) {
	switch netProto {
	case udp:
		port, err = GetUniqueUDP()
		if err != nil {
			return 0, err
		}
	case tcp:
		port, err = GetUniqueTCP()
		if err != nil {
			return 0, err
		}
	}

	return port, nil
}

// GetPortFromAddr is a helper function to quickly get the port from an addr string
func GetPortFromAddr(addr string) (port int, err error) {
	_, portStr, err := net.SplitHostPort(addr)
	if err != nil {
		return 0, err
	}

	port, err = strconv.Atoi(portStr)
	if err != nil {
		return 0, err
	}

	return port, nil
}

// JoinHostPort wrapper function for net.JoinHostPort to easily
// pass port as an int instead of a string
func JoinHostPort(host string, port int) string {
	return net.JoinHostPort(host, strconv.Itoa(port))
}

// ReplacePortInAddr takes an address string and replaces the port
func ReplacePortInAddr(addr, newPort string) (string, error) {
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		return "", err
	}

	return net.JoinHostPort(host, newPort), nil
}

// Helper function to create a new UDP Listener
func newListenerUDP(port int) (*net.UDPConn, error) {
	addr := JoinHostPort("127.0.0.1", port)
	udpAddr, err := net.ResolveUDPAddr(udp, addr)
	if err != nil {
		return nil, err
	}

	ln, err := net.ListenUDP(udp, udpAddr)
	if err != nil {
		return nil, err
	}

	return ln, nil
}

// Helper function to create new UDP Listener
func newListenerTCP(port int) (net.Listener, error) {
	addr := JoinHostPort("127.0.0.1", port)
	ln, err := net.Listen(tcp, addr)
	if err != nil {
		return nil, err
	}

	return ln, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strconv"
	"encoding/json"
	"database/sql"
	_ "github.com/lib/pq"
)

var workingDir string = path.Join(os.TempDir(), "apollo-audio")
var clipDir string = path.Join(workingDir, "clips")
var AAC string = "aac"
var M4A string = "m4a"
var OGG string = "ogg"

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

func makeDir(dir string) {
	dirExists, err := exists(dir)
	check(err)
	if !dirExists {
		err := os.Mkdir(dir, 0777)
		check(err)
	}
}

func downloadFromS3AndSave(url string, filename string) string {
	clipPath := path.Join(clipDir, filename)
	if _, err := os.Stat(clipPath); err == nil {
		fmt.Println("file exists; skipping")
		return clipPath
	}
	fmt.Println(clipPath)
	fmt.Println("debug")
	out, err := os.Create(clipPath)
	check(err)
	defer out.Close()
	resp, err := http.Get(url)
	check(err)
	defer resp.Body.Close()
	_, err = io.Copy(out, resp.Body)
	check(err)
	return clipPath
}

type flushWriter struct {
	f http.Flusher
	w io.Writer
}

func (fw *flushWriter) Write(p []byte) (n int, err error) {
	n, err = fw.w.Write(p)
	if fw.f != nil {
		fw.f.Flush()
	}
	return
}

/* container for the request variables */
type RequestVars struct {
	mission int
	channels []int
	format string
	start int
	duration int
}

/* local paths to audio files for all channels belonging to particular time slice */
type TimeSlice struct {
	start int
	end int
	location []string
}

type DatabaseVars struct {
	DB_HOST string `json:"DB_HOST"`
	DB_PORT int `json:"DB_PORT"`
	DB_USER string `json:"DB_USER"`
	DB_PASSWORD string `json:"DB_PASSWORD"`
	DB_NAME string `json:"DB_NAME"`
}

func parseParameters(r *http.Request) RequestVars {
	r.ParseForm()

	var rv RequestVars

	tempMission, err := strconv.Atoi(r.Form["mission"][0])
	check(err)
	rv.mission = tempMission

	var tempChannels []int
	for n := range r.Form["channel"] {
		ch, err := strconv.Atoi(r.Form["channel"][n])
		check(err)
		tempChannels = append(tempChannels, ch)
	}
	rv.channels = tempChannels

	tempFormat := r.Form["format"][0]
	rv.format = tempFormat

	tempStart, err := strconv.Atoi(r.Form["t"][0])
	check(err)
	rv.start = tempStart

	tempDuration, err := strconv.Atoi(r.Form["len"][0])
	check(err)
	rv.duration = tempDuration

	return rv
}

func getLocations(rv RequestVars) []TimeSlice {

	var slices []TimeSlice

	dbjson, err := ioutil.ReadFile("./config.json")
	check(err)

	var dbvars DatabaseVars
	err = json.Unmarshal(dbjson, &dbvars)
	check(err)

	dbcreds := dbvars
	dbinfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", dbcreds.DB_HOST, dbcreds.DB_PORT, dbcreds.DB_USER, dbcreds.DB_PASSWORD, dbcreds.DB_NAME)
	db, err := sql.Open("postgres", dbinfo)
	check(err)
	defer db.Close()

	stmt, err := db.Prepare("CREATE TABLE chunks_a AS SELECT * FROM channel_chunks WHERE met_end > $1")
	check(err)
	_, err = stmt.Exec(rv.start)
	check(err)

	stmt, err = db.Prepare("CREATE TABLE chunks_b AS SELECT * FROM chunks_a WHERE met_start < $1")
	check(err)
	reqEnd := rv.start + rv.duration
	_, err = stmt.Exec(reqEnd)
	check(err)

	_, err = db.Query("DROP TABLE chunks_a")
	check(err)

	rows, err := db.Query("SELECT DISTINCT met_start, met_end FROM chunks_b ORDER BY met_start")

	for rows.Next() {
		var metstart int
		var metend int
		var loc []string
		err = rows.Scan(&metstart, &metend)
		slice := TimeSlice{start: metstart, end: metend, location: loc}
		slices = append(slices, slice)
	}

	for ch := range rv.channels {
		rows, err := db.Query("SELECT url, met_start, met_end from chunks_b cb WHERE cb.channel = $1", rv.channels[ch])
		check(err)

		for rows.Next() {
			var url string
			var startTime int
			var endTime int
			err = rows.Scan(&url, &startTime, &endTime)
			check(err)

			filename := fmt.Sprintf("mission%dchannel%d%d%d", rv.mission, rv.channels[ch], rv.start, rv.duration)
			loc := downloadFromS3AndSave(url, filename)

			for ts := range slices {
				if (startTime == slices[ts].start && endTime == slices[ts].end) {
					slices[ts].location = append(slices[ts].location, loc)
				}
			}
		}
	}

	_, err = db.Query("DROP TABLE chunks_b;")
	check(err)
	return slices
}

func streamHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "audio/mpeg")

	/* PARRRAMETERS */
	rv := parseParameters(r)

	/* DEEBEE */
	timeslices := getLocations(rv)

	sox, err := exec.LookPath("sox")
	check(err)
	fmt.Println("using sox " + sox)
	ffmpeg, err := exec.LookPath("ffmpeg")
	check(err)
	fmt.Println("using ffmpeg " + ffmpeg)

	for s := range timeslices {

		chunkFiles := timeslices[s].location

		soxArgs := []string{"-t", "wav", "-m"}
		soxArgs = append(soxArgs, chunkFiles...)
		soxArgs = append(soxArgs, "-p")
		soxCommand := exec.Command(sox, soxArgs...)

		// convert the thing
		var ffmpegArgs []string
		if rv.format == AAC || rv.format == M4A {
			ffmpegArgs = []string{"-i", "-", "-c:a", "libfdk_aac", "-b:a", "256k", "-f", M4A, "pipe:"}
			// works, but gotta compile ffmpeg on server with special options
		} else if rv.format == OGG {
			ffmpegArgs = []string{"-i", "-", "-c:a", "libvorbis", "-qscale:a", "6", "-f", OGG, "pipe:"}
		} else {
			fmt.Println("unsupported output format requested. break some rools.")
			ffmpegArgs = []string{"-i", "-", "-f", "mp3", "-ab", "256k", "pipe:"}
		}
		ffmpegCommand := exec.Command(ffmpeg, ffmpegArgs...)

		fw := flushWriter{w: w}
		if f, ok := w.(http.Flusher); ok {
			fw.f = f
		}

		ffmpegCommand.Stdin, _ = soxCommand.StdoutPipe()
		ffmpegCommand.Stdout = &fw
		ffmpegCommand.Stderr = os.Stdout

		ffmpegCommand.Start()
		soxCommand.Run()
		ffmpegCommand.Wait()

	}

	fmt.Println("done")

}

func main() {
	makeDir(workingDir)
	makeDir(clipDir)
	http.HandleFunc("/stream", streamHandler)
	ServerPort := "5000" // default port
	if len(os.Getenv("PORT")) > 0 {
		ServerPort = os.Getenv("PORT")
	}
	fmt.Println("Starting server on " + ServerPort)
	http.ListenAndServe(":"+ServerPort, nil)
}
<commit_msg>db query success<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strconv"
	"encoding/json"
	"database/sql"
	_ "github.com/lib/pq"
)

var workingDir string = path.Join(os.TempDir(), "apollo-audio")
var clipDir string = path.Join(workingDir, "clips")
var AAC string = "aac"
var M4A string = "m4a"
var OGG string = "ogg"

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

func makeDir(dir string) {
	dirExists, err := exists(dir)
	check(err)
	if !dirExists {
		err := os.Mkdir(dir, 0777)
		check(err)
	}
}

func downloadFromS3AndSave(url string, filename string) string {
	clipPath := path.Join(clipDir, filename)
	if _, err := os.Stat(clipPath); err == nil {
		fmt.Println("file exists; skipping")
		return clipPath
	}
	fmt.Println(clipPath)
	fmt.Println("debug")
	out, err := os.Create(clipPath)
	check(err)
	defer out.Close()
	resp, err := http.Get(url)
	check(err)
	defer resp.Body.Close()
	_, err = io.Copy(out, resp.Body)
	check(err)
	return clipPath
}

type flushWriter struct {
	f http.Flusher
	w io.Writer
}

func (fw *flushWriter) Write(p []byte) (n int, err error) {
	n, err = fw.w.Write(p)
	if fw.f != nil {
		fw.f.Flush()
	}
	return
}

/* container for the request variables */
type RequestVars struct {
	mission int
	channels []int
	format string
	start int
	duration int
}

/* local paths to audio files for all channels belonging to particular time slice */
type TimeSlice struct {
	start int
	end int
	location []string
}

type DatabaseVars struct {
	DB_HOST string `json:"DB_HOST"`
	DB_PORT int `json:"DB_PORT"`
	DB_USER string `json:"DB_USER"`
	DB_PASSWORD string `json:"DB_PASSWORD"`
	DB_NAME string `json:"DB_NAME"`
}

func parseParameters(r *http.Request) RequestVars {
	r.ParseForm()

	var rv RequestVars

	tempMission, err := strconv.Atoi(r.Form["mission"][0])
	check(err)
	rv.mission = tempMission

	var tempChannels []int
	for n := range r.Form["channel"] {
		ch, err := strconv.Atoi(r.Form["channel"][n])
		check(err)
		tempChannels = append(tempChannels, ch)
	}
	rv.channels = tempChannels

	tempFormat := r.Form["format"][0]
	rv.format = tempFormat

	tempStart, err := strconv.Atoi(r.Form["t"][0])
	check(err)
	rv.start = tempStart

	tempDuration, err := strconv.Atoi(r.Form["len"][0])
	check(err)
	rv.duration = tempDuration

	return rv
}

func getLocations(rv RequestVars) []TimeSlice {

	var slices []TimeSlice

	dbjson, err := ioutil.ReadFile("./config.json")
	check(err)

	var dbvars DatabaseVars
	err = json.Unmarshal(dbjson, &dbvars)
	check(err)

	dbcreds := dbvars
	dbinfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", dbcreds.DB_HOST, dbcreds.DB_PORT, dbcreds.DB_USER, dbcreds.DB_PASSWORD, dbcreds.DB_NAME)
	db, err := sql.Open("postgres", dbinfo)
	check(err)
	defer db.Close()

	stmt, err := db.Prepare("CREATE TABLE chunks_a AS SELECT * FROM channel_chunks WHERE met_end > $1")
	check(err)
	_, err = stmt.Exec(rv.start)
	check(err)

	stmt, err = db.Prepare("CREATE TABLE chunks_b AS SELECT * FROM chunks_a WHERE met_start < $1")
	check(err)
	reqEnd := rv.start + rv.duration
	_, err = stmt.Exec(reqEnd)
	check(err)

	_, err = db.Query("DROP TABLE chunks_a")
	check(err)

	rows, err := db.Query("SELECT DISTINCT met_start, met_end FROM chunks_b ORDER BY met_start")

	for rows.Next() {
		var metstart int
		var metend int
		var loc []string
		err = rows.Scan(&metstart, &metend)
		slice := TimeSlice{start: metstart, end: metend, location: loc}
		slices = append(slices, slice)
	}

	for ch := range rv.channels {
		rows, err := db.Query("SELECT url, met_start, met_end from chunks_b cb WHERE cb.channel = $1", rv.channels[ch])
		check(err)

		for rows.Next() {
			var url string
			var startTime int
			var endTime int
			err = rows.Scan(&url, &startTime, &endTime)
			fmt.Println(url)
			check(err)

			filename := fmt.Sprintf("mission%dchannel%d%d%d.wav", rv.mission, rv.channels[ch], rv.start, rv.duration)
			loc := downloadFromS3AndSave(url, filename)

			for ts := range slices {
				if (startTime == slices[ts].start && endTime == slices[ts].end) {
					slices[ts].location = append(slices[ts].location, loc)
				}
			}
		}
	}

	_, err = db.Query("DROP TABLE chunks_b;")
	check(err)
	return slices
}

func streamHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "audio/mpeg")

	/* PARRRAMETERS */
	rv := parseParameters(r)

	/* DEEBEE */
	timeslices := getLocations(rv)

	sox, err := exec.LookPath("sox")
	check(err)
	fmt.Println("using sox " + sox)
	ffmpeg, err := exec.LookPath("ffmpeg")
	check(err)
	fmt.Println("using ffmpeg " + ffmpeg)

	for s := range timeslices {

		chunkFiles := timeslices[s].location

		soxArgs := []string{"-t", "wav", "-m"}
		soxArgs = append(soxArgs, chunkFiles...)
		soxArgs = append(soxArgs, "-p")
		soxCommand := exec.Command(sox, soxArgs...)

		// convert the thing
		var ffmpegArgs []string
		if rv.format == AAC || rv.format == M4A {
			ffmpegArgs = []string{"-i", "-", "-c:a", "libfdk_aac", "-b:a", "256k", "-f", M4A, "pipe:"}
			// works, but gotta compile ffmpeg on server with special options
		} else if rv.format == OGG {
			ffmpegArgs = []string{"-i", "-", "-c:a", "libvorbis", "-qscale:a", "6", "-f", OGG, "pipe:"}
		} else {
			fmt.Println("unsupported output format requested. break some rools.")
			ffmpegArgs = []string{"-i", "-", "-f", "mp3", "-ab", "256k", "pipe:"}
		}
		ffmpegCommand := exec.Command(ffmpeg, ffmpegArgs...)

		fw := flushWriter{w: w}
		if f, ok := w.(http.Flusher); ok {
			fw.f = f
		}

		ffmpegCommand.Stdin, _ = soxCommand.StdoutPipe()
		ffmpegCommand.Stdout = &fw
		ffmpegCommand.Stderr = os.Stdout

		ffmpegCommand.Start()
		soxCommand.Run()
		ffmpegCommand.Wait()

	}

	fmt.Println("done")

}

func main() {
	makeDir(workingDir)
	makeDir(clipDir)
	http.HandleFunc("/stream", streamHandler)
	ServerPort := "5000" // default port
	if len(os.Getenv("PORT")) > 0 {
		ServerPort = os.Getenv("PORT")
	}
	fmt.Println("Starting server on " + ServerPort)
	http.ListenAndServe(":"+ServerPort, nil)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import(`bytes`)

var tree [1024]Position
var node int

type Flags struct {
        enpassant     int       // En-passant square caused by previous move.
        irreversible  bool      // Is this position reversible?
}

type Position struct {
        game      *Game
        flags     Flags         // Flags set by last move leading to this position.
        pieces    [64]Piece     // Array of 64 squares with pieces on them.
        board     [3]Bitmask    // [0] white pieces only, [1] black pieces, and [2] all pieces.
        outposts  [14]Bitmask   // Bitmasks of each piece on the board, ex. white pawns, black king, etc.
        count     [16]int       // counts of each piece on the board, ex. white pawns: 6, etc.
        color     int           // Side to make next move.
        stage     int           // Game stage (256 in the initial position).
        hash      uint64        // Polyglot hash value.
        castles   uint8         // Castle rights mask.
}

func NewPosition(game *Game, pieces [64]Piece, color int, flags Flags) *Position {
        tree[node] = Position{ game: game, pieces: pieces, color: color }
        p := &tree[node]

        p.castles = castleKingside[White] | castleQueenside[White] |
                    castleKingside[Black] | castleQueenside[Black]

        if p.pieces[E1] != King(White) || p.pieces[H1] != Rook(White) {
                p.castles &= ^castleKingside[White]
        }
        if p.pieces[E1] != King(White) || p.pieces[A1] != Rook(White) {
                p.castles &= ^castleQueenside[White]
        }

        if p.pieces[E8] != King(Black) || p.pieces[H8] != Rook(Black) {
                p.castles &= ^castleKingside[Black]
        }
        if p.pieces[E8] != King(Black) || p.pieces[A8] != Rook(Black) {
                p.castles &= ^castleQueenside[Black]
        }

        return p.setupPieces().computeStage()
}

func (p *Position) setupPieces() *Position {
        for square, piece := range p.pieces {
                if piece != 0 {
                        p.outposts[piece].set(square)
                        p.board[piece.color()].set(square)
                        p.count[piece]++
                }
        }
        p.board[2] = p.board[White] | p.board[Black]
        return p
}

func (p *Position) computeStage() *Position {
        p.hash  = p.polyglot()
        p.stage = 2 * (p.count[Pawn(White)]   + p.count[Pawn(Black)])   +
                  6 * (p.count[Knight(White)] + p.count[Knight(Black)]) +
                 12 * (p.count[Bishop(White)] + p.count[Bishop(Black)]) +
                 16 * (p.count[Rook(White)]   + p.count[Rook(Black)])   +
                 44 * (p.count[Queen(White)]  + p.count[Queen(Black)])
        return p
}

func (p *Position) movePiece(from, to int) *Position {
        piece, color := p.pieces[from], p.pieces[from].color()

        p.pieces[from], p.pieces[to] = 0, piece
        p.outposts[piece] ^= Bit(from) | Bit(to)
        p.board[color] ^= Bit(from) | Bit(to)

        return p
}

func (p *Position) promotePawn(from, to int, promo Piece) *Position {
        piece, color := p.pieces[from], p.pieces[from].color()

        p.pieces[from], p.pieces[to] = 0, promo
        p.outposts[piece] ^= Bit(from)
        p.outposts[promo] ^= Bit(to)
        p.board[color] ^= Bit(from) | Bit(to)
        p.count[piece]--
        p.count[promo]++

        return p
}

func (p *Position) capturePiece(from, to int) *Position {
        capture, enemy := p.pieces[to], p.pieces[to].color()

        p.outposts[capture] ^= Bit(to)
        p.board[enemy] ^= Bit(to)
        p.count[capture]--

        return p
}

func (p *Position) captureEnpassant(from, to int) *Position {
        color := p.pieces[from].color()
        enemy := color^1
        capture := Pawn(enemy)
        enpassant := to - eight[color]

        p.pieces[enpassant] = 0
        p.outposts[capture] ^= Bit(enpassant)
        p.board[enemy] ^= Bit(enpassant)
        p.count[capture]--

        return p
}

func (p *Position) MakeMove(move Move) *Position {
        color := move.color()
        flags := Flags{}

        from, to, piece, capture := move.split()
        //
        // Copy over the contents of previous tree node to the current one.
        //
        node++
        tree[node] = tree[node - 1] // Faster that tree[node] = *p ?!

        hash := tree[node].hash ^ hashCastle[tree[node].castles]
        if tree[node].flags.enpassant != 0 {
                hash ^= hashEnpassant[Col(tree[node].flags.enpassant)]
        }
        //
        // Castle rights for current node are based on the castle rights from
        // the previous node.
        //
        tree[node].castles &= castleRights[from] & castleRights[to]

        if capture != 0 {
                flags.irreversible = true
                if to != 0 && to == tree[node].flags.enpassant {
                        tree[node].captureEnpassant(from, to)
                } else {
                        tree[node].capturePiece(from, to)
                }
        }

        if promo := move.promo(); promo == 0 {
                tree[node].movePiece(from, to)
                if move.isCastle() {
                        flags.irreversible = true
                        switch to {
                        case G1:
                                tree[node].movePiece(H1, F1)
                        case C1:
                                tree[node].movePiece(A1, D1)
                        case G8:
                                tree[node].movePiece(H8, F8)
                        case C8:
                                tree[node].movePiece(A8, D8)
                        }
                } else if piece.isPawn() {
                        flags.irreversible = true
                        if move.isEnpassant() {
                                flags.enpassant = from + eight[color] // Save the en-passant square.
                        }
                }
        } else {
                flags.irreversible = true
                tree[node].promotePawn(from, to, promo)
        }

	tree[node].color = color^1
	tree[node].flags = flags
	tree[node].board[2] = tree[node].board[White] | tree[node].board[Black]

	if tree[node].isInCheck(color) {
		node--
		return nil
	}
	return tree[node].computeStage()

}

func (p *Position) TakeBack(move Move) *Position {
        node--
        return &tree[node]
}

func (p *Position) isInCheck(color int) bool {
        return p.isAttacked(p.outposts[King(color)].first(), color^1)
}

func (p *Position) isRepetition() bool {
        if p.flags.irreversible {
                return false
        }

        for reps, prevNode := 1, node - 1; prevNode >= 0; prevNode-- {
                if tree[prevNode].flags.irreversible {
                        return false
                }
                if tree[prevNode].color == p.color && tree[prevNode].hash == p.hash {
                        reps++
                        if reps == 3 {
                                return true
                        }
                }
        }

        return false
}

func (p *Position) saveBest(ply int, move Move) {
        p.game.bestLine[ply][ply] = move
        p.game.bestLength[ply] = ply + 1
        for i := ply + 1; i < p.game.bestLength[ply + 1]; i++ {
                p.game.bestLine[ply][i] = p.game.bestLine[ply + 1][i]
                p.game.bestLength[ply]++
        }
}

func (p *Position) canCastle(color int) (kingside, queenside bool) {
        attacks := p.attacks(color^1)
        kingside = p.castles & castleKingside[color] != 0 &&
                   (gapKing[color] & p.board[2] == 0) &&
                   (castleKing[color] & attacks == 0)

        queenside = p.castles & castleQueenside[color] != 0 &&
                    (gapQueen[color] & p.board[2] == 0) &&
                    (castleQueen[color] & attacks == 0)
        return
}

// Compute position's polyglot hash.
func (p *Position) polyglot() (key uint64) {
        board := p.board[2]
        for board != 0 {
                square := board.pop() // Inline polyhash() is at lest 10% faster.
                key ^= polyglotRandom[64 * p.pieces[square].polyglot() + square]
        }

	key ^= hashCastle[p.castles]

	if p.flags.enpassant != 0 {
                key ^= hashEnpassant[Col(p.flags.enpassant)]
	}
	if p.color == White {
                key ^= polyglotRandomWhite
	}

	return
}

func (p *Position) polyhash (square int) uint64 {
       return polyglotRandom[64 * p.pieces[square].polyglot() + square]
}

func (p *Position) String() string {
	buffer := bytes.NewBufferString("  a b c d e f g h")
        if !p.isInCheck(p.color) {
                buffer.WriteString("\n")
        } else {
                buffer.WriteString("  Check to " + C(p.color) + "\n")
        }
	for row := 7;  row >= 0;  row-- {
		buffer.WriteByte('1' + byte(row))
		for col := 0;  col <= 7; col++ {
			square := Square(row, col)
			buffer.WriteByte(' ')
			if piece := p.pieces[square]; piece != 0 {
				buffer.WriteString(piece.String())
			} else {
				buffer.WriteString("\u22C5")
			}
		}
		buffer.WriteByte('\n')
	}
	return buffer.String()
}
<commit_msg>Incremental hash calculation!<commit_after>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import(`bytes`)

var tree [1024]Position
var node int

type Flags struct {
        enpassant     int       // En-passant square caused by previous move.
        irreversible  bool      // Is this position reversible?
}

type Position struct {
        game      *Game
        flags     Flags         // Flags set by last move leading to this position.
        pieces    [64]Piece     // Array of 64 squares with pieces on them.
        board     [3]Bitmask    // [0] white pieces only, [1] black pieces, and [2] all pieces.
        outposts  [14]Bitmask   // Bitmasks of each piece on the board, ex. white pawns, black king, etc.
        count     [16]int       // counts of each piece on the board, ex. white pawns: 6, etc.
        color     int           // Side to make next move.
        stage     int           // Game stage (256 in the initial position).
        hash      uint64        // Polyglot hash value.
        castles   uint8         // Castle rights mask.
}

func NewPosition(game *Game, pieces [64]Piece, color int, flags Flags) *Position {
        tree[node] = Position{ game: game, pieces: pieces, color: color }
        p := &tree[node]

        p.castles = castleKingside[White] | castleQueenside[White] |
                    castleKingside[Black] | castleQueenside[Black]

        if p.pieces[E1] != King(White) || p.pieces[H1] != Rook(White) {
                p.castles &= ^castleKingside[White]
        }
        if p.pieces[E1] != King(White) || p.pieces[A1] != Rook(White) {
                p.castles &= ^castleQueenside[White]
        }

        if p.pieces[E8] != King(Black) || p.pieces[H8] != Rook(Black) {
                p.castles &= ^castleKingside[Black]
        }
        if p.pieces[E8] != King(Black) || p.pieces[A8] != Rook(Black) {
                p.castles &= ^castleQueenside[Black]
        }

        return p.setupPieces().computeStage()
}

func (p *Position) setupPieces() *Position {
        for square, piece := range p.pieces {
                if piece != 0 {
                        p.outposts[piece].set(square)
                        p.board[piece.color()].set(square)
                        p.count[piece]++
                }
        }
        p.hash = p.polyglot()
        p.board[2] = p.board[White] | p.board[Black]
        return p
}

func (p *Position) computeStage() *Position {
        p.stage = 2 * (p.count[Pawn(White)]   + p.count[Pawn(Black)])   +
                  6 * (p.count[Knight(White)] + p.count[Knight(Black)]) +
                 12 * (p.count[Bishop(White)] + p.count[Bishop(Black)]) +
                 16 * (p.count[Rook(White)]   + p.count[Rook(Black)])   +
                 44 * (p.count[Queen(White)]  + p.count[Queen(Black)])
        return p
}

func (p *Position) movePiece(from, to int) *Position {
        piece, color := p.pieces[from], p.pieces[from].color()

        p.pieces[from], p.pieces[to] = 0, piece
        p.outposts[piece] ^= Bit(from) | Bit(to)
        p.board[color] ^= Bit(from) | Bit(to)

        return p
}

func (p *Position) promotePawn(from, to int, promo Piece) *Position {
        piece, color := p.pieces[from], p.pieces[from].color()

        p.pieces[from], p.pieces[to] = 0, promo
        p.outposts[piece] ^= Bit(from)
        p.outposts[promo] ^= Bit(to)
        p.board[color] ^= Bit(from) | Bit(to)
        p.count[piece]--
        p.count[promo]++

        return p
}

func (p *Position) capturePiece(from, to int) *Position {
        capture, enemy := p.pieces[to], p.pieces[to].color()

        p.outposts[capture] ^= Bit(to)
        p.board[enemy] ^= Bit(to)
        p.count[capture]--

        return p
}

func (p *Position) captureEnpassant(from, to int) *Position {
        color := p.pieces[from].color()
        enemy := color^1
        capture := Pawn(enemy)
        enpassant := to - eight[color]

        p.pieces[enpassant] = 0
        p.outposts[capture] ^= Bit(enpassant)
        p.board[enemy] ^= Bit(enpassant)
        p.count[capture]--

        return p
}

func (p *Position) MakeMove(move Move) *Position {
        color := move.color()
        flags := Flags{}

        from, to, piece, capture := move.split()
        //
        // Copy over the contents of previous tree node to the current one.
        //
        node++
        tree[node] = tree[node - 1] // Faster that tree[node] = *p ?!

        hash := tree[node].hash ^ hashCastle[tree[node].castles]
        if tree[node].flags.enpassant != 0 {
                hash ^= hashEnpassant[Col(tree[node].flags.enpassant)]
        }
        //
        // Castle rights for current node are based on the castle rights from
        // the previous node.
        //
        tree[node].castles &= castleRights[from] & castleRights[to]
        hash ^= hashCastle[tree[node].castles]

        if capture != 0 {
                flags.irreversible = true
                if to != 0 && to == tree[node].flags.enpassant {
                        hash ^= polyglotRandom[64 * Pawn(color^1).polyglot() + to - eight[color]]
                        tree[node].captureEnpassant(from, to)
                } else {
                        hash ^= polyglotRandom[64 * p.pieces[to].polyglot() + to]
                        tree[node].capturePiece(from, to)
                }
        }

        if promo := move.promo(); promo == 0 {
                poly := 64 * p.pieces[from].polyglot()
                hash ^= polyglotRandom[poly + from] ^ polyglotRandom[poly + to]
                tree[node].movePiece(from, to)
                if move.isCastle() {
                        flags.irreversible = true
                        switch to {
                        case G1:
                                poly = 64 * Rook(White).polyglot()
                                hash ^= polyglotRandom[poly + H1] ^ polyglotRandom[poly + F1]
                                tree[node].movePiece(H1, F1)
                        case C1:
                                poly = 64 * Rook(White).polyglot()
                                hash ^= polyglotRandom[poly + A1] ^ polyglotRandom[poly + D1]
                                tree[node].movePiece(A1, D1)
                        case G8:
                                poly = 64 * Rook(Black).polyglot()
                                hash ^= polyglotRandom[poly + H8] ^ polyglotRandom[poly + F8]
                                tree[node].movePiece(H8, F8)
                        case C8:
                                poly = 64 * Rook(Black).polyglot()
                                hash ^= polyglotRandom[poly + A8] ^ polyglotRandom[poly + D8]
                                tree[node].movePiece(A8, D8)
                        }
                } else if piece.isPawn() {
                        flags.irreversible = true
                        if move.isEnpassant() {
                                flags.enpassant = from + eight[color] // Save the en-passant square.
                                hash ^= hashEnpassant[Col(flags.enpassant)]
                        }
                }
        } else {
                flags.irreversible = true
                hash ^= polyglotRandom[64 * Pawn(color).polyglot() + from]
                hash ^= polyglotRandom[64 * promo.polyglot() + to]
                tree[node].promotePawn(from, to, promo)
        }

	if color == White {
                hash ^= polyglotRandomWhite
	}

	tree[node].color = color^1
	tree[node].flags = flags
	tree[node].hash = hash
	tree[node].board[2] = tree[node].board[White] | tree[node].board[Black]

	if tree[node].isInCheck(color) {
		node--
		return nil
	}
	return tree[node].computeStage()

}

func (p *Position) TakeBack(move Move) *Position {
        node--
        return &tree[node]
}

func (p *Position) isInCheck(color int) bool {
        return p.isAttacked(p.outposts[King(color)].first(), color^1)
}

func (p *Position) isRepetition() bool {
        if p.flags.irreversible {
                return false
        }

        for reps, prevNode := 1, node - 1; prevNode >= 0; prevNode-- {
                if tree[prevNode].flags.irreversible {
                        return false
                }
                if tree[prevNode].color == p.color && tree[prevNode].hash == p.hash {
                        reps++
                        if reps == 3 {
                                return true
                        }
                }
        }

        return false
}

func (p *Position) saveBest(ply int, move Move) {
        p.game.bestLine[ply][ply] = move
        p.game.bestLength[ply] = ply + 1
        for i := ply + 1; i < p.game.bestLength[ply + 1]; i++ {
                p.game.bestLine[ply][i] = p.game.bestLine[ply + 1][i]
                p.game.bestLength[ply]++
        }
}

func (p *Position) canCastle(color int) (kingside, queenside bool) {
        attacks := p.attacks(color^1)
        kingside = p.castles & castleKingside[color] != 0 &&
                   (gapKing[color] & p.board[2] == 0) &&
                   (castleKing[color] & attacks == 0)

        queenside = p.castles & castleQueenside[color] != 0 &&
                    (gapQueen[color] & p.board[2] == 0) &&
                    (castleQueen[color] & attacks == 0)
        return
}

// Compute position's polyglot hash.
func (p *Position) polyglot() (key uint64) {
        board := p.board[2]
        for board != 0 {
                square := board.pop() // Inline polyhash() is at lest 10% faster.
                key ^= polyglotRandom[64 * p.pieces[square].polyglot() + square]
        }

	key ^= hashCastle[p.castles]

	if p.flags.enpassant != 0 {
                key ^= hashEnpassant[Col(p.flags.enpassant)]
	}
	if p.color == White {
                key ^= polyglotRandomWhite
	}

	return
}

func (p *Position) polyhash (square int) uint64 {
       return polyglotRandom[64 * p.pieces[square].polyglot() + square]
}

func (p *Position) String() string {
	buffer := bytes.NewBufferString("  a b c d e f g h")
        if !p.isInCheck(p.color) {
                buffer.WriteString("\n")
        } else {
                buffer.WriteString("  Check to " + C(p.color) + "\n")
        }
	for row := 7;  row >= 0;  row-- {
		buffer.WriteByte('1' + byte(row))
		for col := 0;  col <= 7; col++ {
			square := Square(row, col)
			buffer.WriteByte(' ')
			if piece := p.pieces[square]; piece != 0 {
				buffer.WriteString(piece.String())
			} else {
				buffer.WriteString("\u22C5")
			}
		}
		buffer.WriteByte('\n')
	}
	return buffer.String()
}
<|endoftext|>