<commit_before>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 1
	appPatch uint = 1

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "beta"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<commit_msg>Bump for v0.1.2<commit_after>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 1
	appPatch uint = 2

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "beta"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<|endoftext|>


<commit_before>package main

const VERSION = "0.11.0"
<commit_msg>:+1: Bump up the version to 0.11.1<commit_after>package main

const VERSION = "0.11.1"
<|endoftext|>


<commit_before>//
// Copyright © 2016 Guy M. Allard
//
// 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 stompngo

/*
	Provide package version information.  A nod to the concept of semver.

	Example:
		fmt.Println("current stompngo version", stompngo.Version())

*/

import (
	"fmt"
)

var (
	pref  = "v"          // Prefix
	major = "1"          // Major
	minor = "0"          // Minor
	patch = "2.plvl.016" // Patch
)

func Version() string {
	return fmt.Sprintf("%s%s.%s.%s", pref, major, minor, patch)
}
<commit_msg>Version 1.0.3<commit_after>//
// Copyright © 2016 Guy M. Allard
//
// 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 stompngo

/*
	Provide package version information.  A nod to the concept of semver.

	Example:
		fmt.Println("current stompngo version", stompngo.Version())

*/

import (
	"fmt"
)

var (
	pref = "v" // Prefix

	major = "1" // Major

	minor = "0" // Minor

	patch = "3" // Patch

	//patch = "3.plvl.001" // Patch
)

func Version() string {
	return fmt.Sprintf("%s%s.%s.%s", pref, major, minor, patch)
}
<|endoftext|>


<commit_before>package main

// Version is the current version of the chaosmonkey tool. A ".dev" suffix
// denotes that the version is currently being developed.
const Version = "v0.3.0"
<commit_msg>Start work on v0.4.0<commit_after>package main

// Version is the current version of the chaosmonkey tool. A ".dev" suffix
// denotes that the version is currently being developed.
const Version = "v0.4.0.dev"
<|endoftext|>


<commit_before>package redditgo

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

func Get(subreddit string, pageno string) ([]Item, error) {
	url := fmt.Sprintf("http://www.reddit.com/r/%s.json#page=%s", subreddit, pageno)
	r, err := http.Get(url)
	if err != nil {
		return nil, err
	}

	defer r.Body.Close()
	if r.StatusCode != http.StatusOK {
		return nil, errors.New(r.Status)
	}

	resp := new(Response)
	err = json.NewDecoder(r.Body).Decode(resp)
	if err != nil {
		return nil, err
	}

	items := make([]Item, len(resp.Data.Children))
	for i, child := range resp.Data.Children {
		items[i] = child.Data
	}
	//    after := resp.Data.After
	//    fmt.Printf("%s\n", after)
	return items, nil
}
<commit_msg>Changed function name<commit_after>package redditgo

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

func Decode(subreddit string) ([]Item, error) {
	url := fmt.Sprintf("http://www.reddit.com/r/%s.json", subreddit)
	r, err := http.Get(url)
	if err != nil {
		return nil, err
	}

	defer r.Body.Close()
	if r.StatusCode != http.StatusOK {
		return nil, errors.New(r.Status)
	}

	resp := new(Response)
	err = json.NewDecoder(r.Body).Decode(resp)
	if err != nil {
		return nil, err
	}

	items := make([]Item, len(resp.Data.Children))
	for i, child := range resp.Data.Children {
		items[i] = child.Data
	}
	//    after := resp.Data.After
	//    fmt.Printf("%s\n", after)
	return items, nil
}
<|endoftext|>


<commit_before>package hob

import (
	"testing"

	"github.com/bmizerany/assert"
	"github.com/mrb/hob"
)

func TestNewLWWESet(t *testing.T) {
	_, err := hob.NewLWWESet("nah")
	assert.T(t, err == hob.ErrInvalidBias)
}

func setupLWWESet(t *testing.T) (lwwset *hob.LWWESet) {
	lwwset, err := hob.NewLWWESet("a")
	assert.T(t, lwwset != nil)
	assert.T(t, err == nil)
	return
}

func setupLWWESetWithData(t *testing.T) (lwwset *hob.LWWESet) {
	lwwset = setupLWWESet(t)

	err := lwwset.Add("Key1")
	assert.T(t, err == nil)

	err = lwwset.Remove("Key1")
	assert.T(t, err == nil)
	err = lwwset.Add("Key2")
	assert.T(t, err == nil)

	return
}

/*
- Bias: "a" / "r"
* e added, not removed - true / true
* e added, removed, removed > added - false / false
* e added, removed, removed = added - true / false
* e added, removed, added again - true / true
*/
func TestLWWESetBias(t *testing.T) {
	lwwset := setupLWWESetWithData(t)

	is_member, err := lwwset.Test("Key2")
	assert.T(t, err == nil)
	assert.T(t, is_member == true)

	is_member, err = lwwset.Test("NOOOOOOO")
	assert.T(t, err == nil)
	assert.T(t, is_member == false)

	err = lwwset.Remove("Key1")
	assert.T(t, err == nil)
	assert.T(t, is_member == false)
}

func TestLWWJson(t *testing.T) {
	lwwset := setupLWWESetWithData(t)

	json, err := lwwset.JSON()

	assert.T(t, err == nil)
	assert.T(t, json != nil)

	//data, err := hob.ParseJson(json)
	//assert.T(t, err == nil)
	//assert.T(t, data != nil)
	//assert.T(t, data.(LWWESet).Type == "lww-e-set")
	//assert.T(t, data.(*hob.LWWESet).JSONData != nil)
	//assert.T(t, len(data.(*hob.LWWESet).JSONData) == 2)
}

func TestLWWMerge(t *testing.T) {
	lwwset := setupLWWESetWithData(t)
	olwwset := setupLWWESetWithData(t)

	err := olwwset.Remove("Key2")
	assert.T(t, err == nil)

	merged, err := lwwset.Merge(olwwset)
	assert.T(t, err == nil)

	assert.T(t, merged.Data["Key2"] != nil)
	assert.T(t, merged.Data["Key2"].Add != "")
	assert.T(t, merged.Data["Key2"].Remove != "")
	assert.T(t, merged.Data["Key2"].Remove == olwwset.Data["Key2"].Remove)
	assert.T(t, merged.Data["Key2"].Add == olwwset.Data["Key2"].Add)
}
<commit_msg>LWW-e-set semantics fully tested<commit_after>package hob

import (
	"testing"

	"github.com/bmizerany/assert"
	"github.com/mrb/hob"
)

func TestNewLWWESet(t *testing.T) {
	_, err := hob.NewLWWESet("nah")
	assert.T(t, err == hob.ErrInvalidBias)
}

func setupLWWESet(t *testing.T) (lwwset *hob.LWWESet) {
	lwwset, err := hob.NewLWWESet("a")
	assert.T(t, lwwset != nil)
	assert.T(t, err == nil)
	return
}

func setupLWWESetWithData(t *testing.T) (lwwset *hob.LWWESet) {
	lwwset = setupLWWESet(t)

	err := lwwset.Add("Key1")
	assert.T(t, err == nil)

	err = lwwset.Remove("Key1")
	assert.T(t, err == nil)

	err = lwwset.Add("Key2")
	assert.T(t, err == nil)

	return
}

/*
- Bias: "a" / "r"
*/
func TestLWWESetBias(t *testing.T) {
	lwwset := setupLWWESetWithData(t)
	assert.T(t, lwwset.Bias == "a")

	rlwwset := setupLWWESetWithData(t)
	rlwwset.Bias = "r"
	assert.T(t, rlwwset.Bias == "r")

	// e added, not removed - true / true
	is_member, err := lwwset.Test("Key2")
	assert.T(t, err == nil)
	assert.T(t, is_member == true)

	is_member, err = rlwwset.Test("Key2")
	assert.T(t, err == nil)
	assert.T(t, is_member == true)

	// e added, removed, removed > added - false / false
	is_member, err = lwwset.Test("Key1")
	assert.T(t, err == nil)
	assert.T(t, is_member == false)

	is_member, err = rlwwset.Test("Key1")
	assert.T(t, err == nil)
	assert.T(t, is_member == false)

	// e added, removed, added -- added = removed - true / false
	err = lwwset.Add("Key1")
	assert.T(t, err == nil)
	lwwset.Data["Key1"].Add = lwwset.Data["Key1"].Remove
	assert.T(t, lwwset.Data["Key1"].Add == lwwset.Data["Key1"].Remove)

	is_member, err = lwwset.Test("Key1")
	assert.T(t, err == nil)
	assert.T(t, is_member == true)

	err = rlwwset.Add("Key1")
	assert.T(t, err == nil)
	rlwwset.Data["Key1"].Add = rlwwset.Data["Key1"].Remove
	assert.T(t, rlwwset.Data["Key1"].Add == rlwwset.Data["Key1"].Remove)

	is_member, err = rlwwset.Test("Key1")
	assert.T(t, err == nil)
	assert.T(t, is_member == false)

	// e added, removed, added again - true / true
	err = lwwset.Add("Key1")
	assert.T(t, err == nil)

	is_member, err = lwwset.Test("Key1")
	assert.T(t, err == nil)
	assert.T(t, is_member == true)

	err = rlwwset.Add("Key1")
	assert.T(t, err == nil)

	is_member, err = rlwwset.Test("Key1")
	assert.T(t, err == nil)
	assert.T(t, is_member == true)
}

func TestLWWJson(t *testing.T) {
	lwwset := setupLWWESetWithData(t)

	json, err := lwwset.JSON()

	assert.T(t, err == nil)
	assert.T(t, json != nil)

	//data, err := hob.ParseJson(json)
	//assert.T(t, err == nil)
	//assert.T(t, data != nil)
	//assert.T(t, data.(LWWESet).Type == "lww-e-set")
	//assert.T(t, data.(*hob.LWWESet).JSONData != nil)
	//assert.T(t, len(data.(*hob.LWWESet).JSONData) == 2)
}

func TestLWWMerge(t *testing.T) {
	lwwset := setupLWWESetWithData(t)
	olwwset := setupLWWESetWithData(t)

	err := olwwset.Remove("Key2")
	assert.T(t, err == nil)

	merged, err := lwwset.Merge(olwwset)
	assert.T(t, err == nil)

	assert.T(t, merged.Data["Key2"] != nil)
	assert.T(t, merged.Data["Key2"].Add != "")
	assert.T(t, merged.Data["Key2"].Remove != "")
	assert.T(t, merged.Data["Key2"].Remove == olwwset.Data["Key2"].Remove)
	assert.T(t, merged.Data["Key2"].Add == olwwset.Data["Key2"].Add)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"gopkg.in/lxc/go-lxc.v2"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

var containersCmd = Command{
	name: "containers",
	get:  containersGet,
	post: containersPost,
}

var containerCmd = Command{
	name:   "containers/{name}",
	get:    containerGet,
	put:    containerPut,
	delete: containerDelete,
	post:   containerPost,
}

var containerStateCmd = Command{
	name: "containers/{name}/state",
	get:  containerState,
	put:  containerStatePut,
}

var containerFileCmd = Command{
	name: "containers/{name}/files",
	get:  containerFileHandler,
	post: containerFileHandler,
}

var containerSnapshotsCmd = Command{
	name: "containers/{name}/snapshots",
	get:  containerSnapshotsGet,
	post: containerSnapshotsPost,
}

var containerSnapshotCmd = Command{
	name:   "containers/{name}/snapshots/{snapshotName}",
	get:    snapshotHandler,
	post:   snapshotHandler,
	delete: snapshotHandler,
}

var containerExecCmd = Command{
	name: "containers/{name}/exec",
	post: containerExecPost,
}

type containerAutostartList []container

func (slice containerAutostartList) Len() int {
	return len(slice)
}

func (slice containerAutostartList) Less(i, j int) bool {
	iOrder := slice[i].ExpandedConfig()["boot.autostart.priority"]
	jOrder := slice[j].ExpandedConfig()["boot.autostart.priority"]

	if iOrder != jOrder {
		iOrderInt, _ := strconv.Atoi(iOrder)
		jOrderInt, _ := strconv.Atoi(jOrder)
		return iOrderInt > jOrderInt
	}

	return slice[i].Name() < slice[j].Name()
}

func (slice containerAutostartList) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func containersRestart(d *Daemon) error {
	// Get all the containers
	result, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return err
	}

	containers := []container{}

	for _, name := range result {
		c, err := containerLoadByName(d, name)
		if err != nil {
			return err
		}

		containers = append(containers, c)
	}

	sort.Sort(containerAutostartList(containers))

	// Restart the containers
	for _, c := range containers {
		config := c.ExpandedConfig()
		lastState := config["volatile.last_state.power"]

		autoStart := config["boot.autostart"]
		autoStartDelay := config["boot.autostart.delay"]

		if shared.IsTrue(autoStart) || (autoStart == "" && lastState == "RUNNING") {
			if c.IsRunning() {
				continue
			}

			c.Start(false)

			autoStartDelayInt, err := strconv.Atoi(autoStartDelay)
			if err == nil {
				time.Sleep(time.Duration(autoStartDelayInt) * time.Second)
			}
		}
	}

	// Reset the recorded state (to ensure it's up to date)
	_, err = dbExec(d.db, "DELETE FROM containers_config WHERE key='volatile.last_state.power'")
	if err != nil {
		return err
	}

	for _, c := range containers {
		err = c.ConfigKeySet("volatile.last_state.power", c.State())
		if err != nil {
			return err
		}
	}

	return nil
}

func containersShutdown(d *Daemon) error {
	var wg sync.WaitGroup

	// Get all the containers
	results, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return err
	}

	// Reset all container states
	_, err = dbExec(d.db, "DELETE FROM containers_config WHERE key='volatile.last_state.power'")
	if err != nil {
		return err
	}

	for _, r := range results {
		// Load the container
		c, err := containerLoadByName(d, r)
		if err != nil {
			return err
		}

		// Record the current state
		err = c.ConfigKeySet("volatile.last_state.power", c.State())
		if err != nil {
			return err
		}

		// Stop the container
		if c.IsRunning() {
			wg.Add(1)
			go func() {
				c.Shutdown(time.Second * 30)
				c.Stop(false)
				wg.Done()
			}()
		}
	}
	wg.Wait()

	return nil
}

func containerDeleteSnapshots(d *Daemon, cname string) error {
	shared.LogDebug("containerDeleteSnapshots",
		log.Ctx{"container": cname})

	results, err := dbContainerGetSnapshots(d.db, cname)
	if err != nil {
		return err
	}

	for _, sname := range results {
		sc, err := containerLoadByName(d, sname)
		if err != nil {
			shared.LogError(
				"containerDeleteSnapshots: Failed to load the snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname})

			continue
		}

		if err := sc.Delete(); err != nil {
			shared.LogError(
				"containerDeleteSnapshots: Failed to delete a snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname, "err": err})
		}
	}

	return nil
}

/*
 * This is called by lxd when called as "lxd forkstart <container>"
 * 'forkstart' is used instead of just 'start' in the hopes that people
 * do not accidentally type 'lxd start' instead of 'lxc start'
 */
func startContainer(args []string) error {
	if len(args) != 4 {
		return fmt.Errorf("Bad arguments: %q", args)
	}

	name := args[1]
	lxcpath := args[2]
	configPath := args[3]

	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		return fmt.Errorf("Error initializing container for start: %q", err)
	}

	err = c.LoadConfigFile(configPath)
	if err != nil {
		return fmt.Errorf("Error opening startup config file: %q", err)
	}

	/* due to https://github.com/golang/go/issues/13155 and the
	 * CollectOutput call we make for the forkstart process, we need to
	 * close our stdin/stdout/stderr here. Collecting some of the logs is
	 * better than collecting no logs, though.
	 */
	os.Stdin.Close()
	os.Stderr.Close()
	os.Stdout.Close()

	// Redirect stdout and stderr to a log file
	logPath := shared.LogPath(name, "forkstart.log")
	if shared.PathExists(logPath) {
		os.Remove(logPath)
	}

	logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err == nil {
		syscall.Dup3(int(logFile.Fd()), 1, 0)
		syscall.Dup3(int(logFile.Fd()), 2, 0)
	}

	return c.Start()
}

/*
 * This is called by lxd when called as "lxd forkexec <container>"
 */
func execContainer(args []string) (int, error) {
	if len(args) < 6 {
		return -1, fmt.Errorf("Bad arguments: %q", args)
	}

	name := args[1]
	lxcpath := args[2]
	configPath := args[3]

	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		return -1, fmt.Errorf("Error initializing container for start: %q", err)
	}

	err = c.LoadConfigFile(configPath)
	if err != nil {
		return -1, fmt.Errorf("Error opening startup config file: %q", err)
	}

	syscall.Dup3(int(os.Stdin.Fd()), 200, 0)
	syscall.Dup3(int(os.Stdout.Fd()), 201, 0)
	syscall.Dup3(int(os.Stderr.Fd()), 202, 0)

	syscall.Close(int(os.Stdin.Fd()))
	syscall.Close(int(os.Stdout.Fd()))
	syscall.Close(int(os.Stderr.Fd()))

	opts := lxc.DefaultAttachOptions
	opts.ClearEnv = true
	opts.StdinFd = 200
	opts.StdoutFd = 201
	opts.StderrFd = 202

	logPath := shared.LogPath(name, "forkexec.log")
	if shared.PathExists(logPath) {
		os.Remove(logPath)
	}

	logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err == nil {
		syscall.Dup3(int(logFile.Fd()), 1, 0)
		syscall.Dup3(int(logFile.Fd()), 2, 0)
	}

	env := []string{}
	cmd := []string{}

	section := ""
	for _, arg := range args[5:len(args)] {
		// The "cmd" section must come last as it may contain a --
		if arg == "--" && section != "cmd" {
			section = ""
			continue
		}

		if section == "" {
			section = arg
			continue
		}

		if section == "env" {
			fields := strings.SplitN(arg, "=", 2)
			if len(fields) == 2 && fields[0] == "HOME" {
				opts.Cwd = fields[1]
			}
			env = append(env, arg)
		} else if section == "cmd" {
			cmd = append(cmd, arg)
		} else {
			return -1, fmt.Errorf("Invalid exec section: %s", section)
		}
	}

	opts.Env = env

	status, err := c.RunCommandStatus(cmd, opts)
	if err != nil {
		return -1, fmt.Errorf("Failed running command: %q", err)
	}

	return status >> 8, nil
}
<commit_msg>Fix container state recording<commit_after>package main

import (
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"gopkg.in/lxc/go-lxc.v2"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

var containersCmd = Command{
	name: "containers",
	get:  containersGet,
	post: containersPost,
}

var containerCmd = Command{
	name:   "containers/{name}",
	get:    containerGet,
	put:    containerPut,
	delete: containerDelete,
	post:   containerPost,
}

var containerStateCmd = Command{
	name: "containers/{name}/state",
	get:  containerState,
	put:  containerStatePut,
}

var containerFileCmd = Command{
	name: "containers/{name}/files",
	get:  containerFileHandler,
	post: containerFileHandler,
}

var containerSnapshotsCmd = Command{
	name: "containers/{name}/snapshots",
	get:  containerSnapshotsGet,
	post: containerSnapshotsPost,
}

var containerSnapshotCmd = Command{
	name:   "containers/{name}/snapshots/{snapshotName}",
	get:    snapshotHandler,
	post:   snapshotHandler,
	delete: snapshotHandler,
}

var containerExecCmd = Command{
	name: "containers/{name}/exec",
	post: containerExecPost,
}

type containerAutostartList []container

func (slice containerAutostartList) Len() int {
	return len(slice)
}

func (slice containerAutostartList) Less(i, j int) bool {
	iOrder := slice[i].ExpandedConfig()["boot.autostart.priority"]
	jOrder := slice[j].ExpandedConfig()["boot.autostart.priority"]

	if iOrder != jOrder {
		iOrderInt, _ := strconv.Atoi(iOrder)
		jOrderInt, _ := strconv.Atoi(jOrder)
		return iOrderInt > jOrderInt
	}

	return slice[i].Name() < slice[j].Name()
}

func (slice containerAutostartList) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func containersRestart(d *Daemon) error {
	// Get all the containers
	result, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return err
	}

	containers := []container{}

	for _, name := range result {
		c, err := containerLoadByName(d, name)
		if err != nil {
			return err
		}

		containers = append(containers, c)
	}

	sort.Sort(containerAutostartList(containers))

	// Restart the containers
	for _, c := range containers {
		config := c.ExpandedConfig()
		lastState := config["volatile.last_state.power"]

		autoStart := config["boot.autostart"]
		autoStartDelay := config["boot.autostart.delay"]

		if shared.IsTrue(autoStart) || (autoStart == "" && lastState == "RUNNING") {
			if c.IsRunning() {
				continue
			}

			c.Start(false)

			autoStartDelayInt, err := strconv.Atoi(autoStartDelay)
			if err == nil {
				time.Sleep(time.Duration(autoStartDelayInt) * time.Second)
			}
		}
	}

	// Reset the recorded state (to ensure it's up to date)
	_, err = dbExec(d.db, "DELETE FROM containers_config WHERE key='volatile.last_state.power'")
	if err != nil {
		return err
	}

	for _, c := range containers {
		err = c.ConfigKeySet("volatile.last_state.power", c.State())
		if err != nil {
			return err
		}
	}

	return nil
}

func containersShutdown(d *Daemon) error {
	var wg sync.WaitGroup

	// Get all the containers
	results, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return err
	}

	// Reset all container states
	_, err = dbExec(d.db, "DELETE FROM containers_config WHERE key='volatile.last_state.power'")
	if err != nil {
		return err
	}

	for _, r := range results {
		// Load the container
		c, err := containerLoadByName(d, r)
		if err != nil {
			return err
		}

		// Record the current state
		lastState := c.State()

		// Stop the container
		if c.IsRunning() {
			wg.Add(1)
			go func() {
				c.Shutdown(time.Second * 30)
				c.Stop(false)
				c.ConfigKeySet("volatile.last_state.power", lastState)

				wg.Done()
			}()
		} else {
			c.ConfigKeySet("volatile.last_state.power", lastState)
		}
	}
	wg.Wait()

	return nil
}

func containerDeleteSnapshots(d *Daemon, cname string) error {
	shared.LogDebug("containerDeleteSnapshots",
		log.Ctx{"container": cname})

	results, err := dbContainerGetSnapshots(d.db, cname)
	if err != nil {
		return err
	}

	for _, sname := range results {
		sc, err := containerLoadByName(d, sname)
		if err != nil {
			shared.LogError(
				"containerDeleteSnapshots: Failed to load the snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname})

			continue
		}

		if err := sc.Delete(); err != nil {
			shared.LogError(
				"containerDeleteSnapshots: Failed to delete a snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname, "err": err})
		}
	}

	return nil
}

/*
 * This is called by lxd when called as "lxd forkstart <container>"
 * 'forkstart' is used instead of just 'start' in the hopes that people
 * do not accidentally type 'lxd start' instead of 'lxc start'
 */
func startContainer(args []string) error {
	if len(args) != 4 {
		return fmt.Errorf("Bad arguments: %q", args)
	}

	name := args[1]
	lxcpath := args[2]
	configPath := args[3]

	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		return fmt.Errorf("Error initializing container for start: %q", err)
	}

	err = c.LoadConfigFile(configPath)
	if err != nil {
		return fmt.Errorf("Error opening startup config file: %q", err)
	}

	/* due to https://github.com/golang/go/issues/13155 and the
	 * CollectOutput call we make for the forkstart process, we need to
	 * close our stdin/stdout/stderr here. Collecting some of the logs is
	 * better than collecting no logs, though.
	 */
	os.Stdin.Close()
	os.Stderr.Close()
	os.Stdout.Close()

	// Redirect stdout and stderr to a log file
	logPath := shared.LogPath(name, "forkstart.log")
	if shared.PathExists(logPath) {
		os.Remove(logPath)
	}

	logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err == nil {
		syscall.Dup3(int(logFile.Fd()), 1, 0)
		syscall.Dup3(int(logFile.Fd()), 2, 0)
	}

	return c.Start()
}

/*
 * This is called by lxd when called as "lxd forkexec <container>"
 */
func execContainer(args []string) (int, error) {
	if len(args) < 6 {
		return -1, fmt.Errorf("Bad arguments: %q", args)
	}

	name := args[1]
	lxcpath := args[2]
	configPath := args[3]

	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		return -1, fmt.Errorf("Error initializing container for start: %q", err)
	}

	err = c.LoadConfigFile(configPath)
	if err != nil {
		return -1, fmt.Errorf("Error opening startup config file: %q", err)
	}

	syscall.Dup3(int(os.Stdin.Fd()), 200, 0)
	syscall.Dup3(int(os.Stdout.Fd()), 201, 0)
	syscall.Dup3(int(os.Stderr.Fd()), 202, 0)

	syscall.Close(int(os.Stdin.Fd()))
	syscall.Close(int(os.Stdout.Fd()))
	syscall.Close(int(os.Stderr.Fd()))

	opts := lxc.DefaultAttachOptions
	opts.ClearEnv = true
	opts.StdinFd = 200
	opts.StdoutFd = 201
	opts.StderrFd = 202

	logPath := shared.LogPath(name, "forkexec.log")
	if shared.PathExists(logPath) {
		os.Remove(logPath)
	}

	logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err == nil {
		syscall.Dup3(int(logFile.Fd()), 1, 0)
		syscall.Dup3(int(logFile.Fd()), 2, 0)
	}

	env := []string{}
	cmd := []string{}

	section := ""
	for _, arg := range args[5:len(args)] {
		// The "cmd" section must come last as it may contain a --
		if arg == "--" && section != "cmd" {
			section = ""
			continue
		}

		if section == "" {
			section = arg
			continue
		}

		if section == "env" {
			fields := strings.SplitN(arg, "=", 2)
			if len(fields) == 2 && fields[0] == "HOME" {
				opts.Cwd = fields[1]
			}
			env = append(env, arg)
		} else if section == "cmd" {
			cmd = append(cmd, arg)
		} else {
			return -1, fmt.Errorf("Invalid exec section: %s", section)
		}
	}

	opts.Env = env

	status, err := c.RunCommandStatus(cmd, opts)
	if err != nil {
		return -1, fmt.Errorf("Failed running command: %q", err)
	}

	return status >> 8, nil
}
<|endoftext|>


<commit_before>package main

import (
	//"github.com/macross-contrib/statio"
	"github.com/insionng/macross"
	"github.com/insionng/macross/logger"
	"github.com/insionng/macross/pongor"
	"github.com/insionng/macross/static"
	"github.com/macross-contrib/vuejsto/handlers"
)

func main() {

	m := macross.New()
	m.Use(logger.Logger())
	m.Use(static.Static("public"))
	//m.Use(statio.Serve("/", statio.LocalFile("public", false)))
	m.SetRenderer(pongor.Renderor())

	m.File("/favicon.ico", "public/favicon.ico")
	m.Get("/", handlers.GetMain)
	m.Get("/tasks", handlers.GetTasks)
	m.Post("/task", handlers.PostTask).Put(handlers.PutTask)
	m.Delete("/task/<id>", handlers.DeleteTask)
	//m.Static("/", "public")

	m.Run(":7000")
}
<commit_msg>fixed listen<commit_after>package main

import (
	//"github.com/macross-contrib/statio"
	"github.com/insionng/macross"
	"github.com/insionng/macross/logger"
	"github.com/insionng/macross/pongor"
	"github.com/insionng/macross/static"
	"github.com/macross-contrib/vuejsto/handlers"
)

func main() {

	m := macross.New()
	m.Use(logger.Logger())
	m.Use(static.Static("public"))
	//m.Use(statio.Serve("/", statio.LocalFile("public", false)))
	m.SetRenderer(pongor.Renderor())

	m.File("/favicon.ico", "public/favicon.ico")
	m.Get("/", handlers.GetMain)
	m.Get("/tasks", handlers.GetTasks)
	m.Post("/task", handlers.PostTask).Put(handlers.PutTask)
	m.Delete("/task/<id>", handlers.DeleteTask)
	//m.Static("/", "public")

	m.Listen(":7000")
}
<|endoftext|>


<commit_before>package d3d9

// PSVersion creates a pixel shader version token.
func PSVersion(major, minor int) uint32 {
	return uint32(0xFFFF0000 | ((major) << 8) | (minor))
}

// VSVersion creates a vertex shader version token.
func VSVersion(major, minor int) uint32 {
	return uint32(0xFFFE0000 | ((major) << 8) | (minor))
}

// TSWorldMatrix maps indices in the range 0 through 255 to the corresponding
// transform states.
func TSWorldMatrix(index int) TRANSFORMSTATETYPE {
	return TRANSFORMSTATETYPE(index + 256)
}

// FVFTexCoordSize1 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize1(CoordIndex uint) uint32 {
	return uint32(int(FVF_TEXTUREFORMAT1) << (CoordIndex*2 + 16))
}

// FVFTexCoordSize2 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize2(CoordIndex uint) uint32 {
	return FVF_TEXTUREFORMAT2
}

// FVFTexCoordSize3 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize3(CoordIndex uint) uint32 {
	return FVF_TEXTUREFORMAT3 << (CoordIndex*2 + 16)
}

// FVFTexCoordSize4 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize4(CoordIndex uint) uint32 {
	return FVF_TEXTUREFORMAT4 << (CoordIndex*2 + 16)
}
<commit_msg>Fixed compile error on 32 bit machines due to constant overflow.<commit_after>package d3d9

// PSVersion creates a pixel shader version token.
func PSVersion(major, minor uint) uint32 {
	return uint32(0xFFFF0000 | ((major) << 8) | (minor))
}

// VSVersion creates a vertex shader version token.
func VSVersion(major, minor uint) uint32 {
	return uint32(0xFFFE0000 | ((major) << 8) | (minor))
}

// TSWorldMatrix maps indices in the range 0 through 255 to the corresponding
// transform states.
func TSWorldMatrix(index int) TRANSFORMSTATETYPE {
	return TRANSFORMSTATETYPE(index + 256)
}

// FVFTexCoordSize1 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize1(CoordIndex uint) uint32 {
	return uint32(int(FVF_TEXTUREFORMAT1) << (CoordIndex*2 + 16))
}

// FVFTexCoordSize2 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize2(CoordIndex uint) uint32 {
	return FVF_TEXTUREFORMAT2
}

// FVFTexCoordSize3 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize3(CoordIndex uint) uint32 {
	return FVF_TEXTUREFORMAT3 << (CoordIndex*2 + 16)
}

// FVFTexCoordSize4 constructs bit patterns that are used to identify texture
// coordinate formats within a FVF description. The results of these macros can
// be combined within a FVF description by using the OR operator.
func FVFTexCoordSize4(CoordIndex uint) uint32 {
	return FVF_TEXTUREFORMAT4 << (CoordIndex*2 + 16)
}
<|endoftext|>


<commit_before>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
Package wal provides an implementation of a write ahead log that is used by
etcd.

A WAL is created at a particular directory and is made up of a number of
segmented WAL files. Inside of each file the raft state and entries are appended
to it with the Save method:

	metadata := []byte{}
	w, err := wal.Create("/var/lib/etcd", metadata)
	...
	err := w.Save(s, ents)

After saving an raft snapshot to disk, SaveSnapshot method should be called to
record it. So WAL can match with the saved snapshot when restarting.

	err := w.SaveSnapshot(walpb.Snapshot{Index: 10, Term: 2})

When a user has finished using a WAL it must be closed:

	w.Close()

Each WAL file is a stream of WAL records. A WAL record is a length field and a wal record
protobuf. The record protobuf contains a CRC, a type, and a data payload. The length field is a
64-bit packed structure holding the length of the remaining logical record data in its lower
56 bits and its physical padding in the first three bits of the most significant byte. Each
record is 8-byte aligned so that the length field is never torn. The CRC contains the CRC32
value of all record protobufs preceding the current record.

WAL files are placed inside of the directory in the following format:
$seq-$index.wal

The first WAL file to be created will be 0000000000000000-0000000000000000.wal
indicating an initial sequence of 0 and an initial raft index of 0. The first
entry written to WAL MUST have raft index 0.

WAL will cut its current tail wal file if its size exceeds 64MB. This will increment an internal
sequence number and cause a new file to be created. If the last raft index saved
was 0x20 and this is the first time cut has been called on this WAL then the sequence will
increment from 0x0 to 0x1. The new file will be: 0000000000000001-0000000000000021.wal.
If a second cut issues 0x10 entries with incremental index later then the file will be called:
0000000000000002-0000000000000031.wal.

At a later time a WAL can be opened at a particular snapshot. If there is no
snapshot, an empty snapshot should be passed in.

	w, err := wal.Open("/var/lib/etcd", walpb.Snapshot{Index: 10, Term: 2})
	...

The snapshot must have been written to the WAL.

Additional items cannot be Saved to this WAL until all of the items from the given
snapshot to the end of the WAL are read first:

	metadata, state, ents, err := w.ReadAll()

This will give you the metadata, the last raft.State and the slice of
raft.Entry items in the log.

*/
package wal
<commit_msg>wal: document grammar correction<commit_after>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
Package wal provides an implementation of a write ahead log that is used by
etcd.

A WAL is created at a particular directory and is made up of a number of
segmented WAL files. Inside of each file the raft state and entries are appended
to it with the Save method:

	metadata := []byte{}
	w, err := wal.Create("/var/lib/etcd", metadata)
	...
	err := w.Save(s, ents)

After saving a raft snapshot to disk, SaveSnapshot method should be called to
record it. So WAL can match with the saved snapshot when restarting.

	err := w.SaveSnapshot(walpb.Snapshot{Index: 10, Term: 2})

When a user has finished using a WAL it must be closed:

	w.Close()

Each WAL file is a stream of WAL records. A WAL record is a length field and a wal record
protobuf. The record protobuf contains a CRC, a type, and a data payload. The length field is a
64-bit packed structure holding the length of the remaining logical record data in its lower
56 bits and its physical padding in the first three bits of the most significant byte. Each
record is 8-byte aligned so that the length field is never torn. The CRC contains the CRC32
value of all record protobufs preceding the current record.

WAL files are placed inside of the directory in the following format:
$seq-$index.wal

The first WAL file to be created will be 0000000000000000-0000000000000000.wal
indicating an initial sequence of 0 and an initial raft index of 0. The first
entry written to WAL MUST have raft index 0.

WAL will cut its current tail wal file if its size exceeds 64MB. This will increment an internal
sequence number and cause a new file to be created. If the last raft index saved
was 0x20 and this is the first time cut has been called on this WAL then the sequence will
increment from 0x0 to 0x1. The new file will be: 0000000000000001-0000000000000021.wal.
If a second cut issues 0x10 entries with incremental index later then the file will be called:
0000000000000002-0000000000000031.wal.

At a later time a WAL can be opened at a particular snapshot. If there is no
snapshot, an empty snapshot should be passed in.

	w, err := wal.Open("/var/lib/etcd", walpb.Snapshot{Index: 10, Term: 2})
	...

The snapshot must have been written to the WAL.

Additional items cannot be Saved to this WAL until all of the items from the given
snapshot to the end of the WAL are read first:

	metadata, state, ents, err := w.ReadAll()

This will give you the metadata, the last raft.State and the slice of
raft.Entry items in the log.

*/
package wal
<|endoftext|>


<commit_before>package watcher

import (
	"errors"
	"os"
	"path/filepath"
	"time"
)

var (
	// ErrNothingAdded is an error that occurs when a Watcher's Start() method is
	// called and no files or folders have been added to the Watcher's watchlist.
	ErrNothingAdded = errors.New("error: no files added to the watchlist")

	// ErrWatchedFileDeleted is an error that occurs when a file or folder that was
	// being watched has been deleted.
	ErrWatchedFileDeleted = errors.New("error: watched file or folder deleted")
)

// An Event is a type that is used to describe what type
// of event has occured during the watching process.
type Event int

const (
	EventFileAdded Event = 1 << iota
	EventFileDeleted
	EventFileModified
)

// String returns a small string depending on what
// type of event it is.
func (e Event) String() string {
	switch e {
	case EventFileAdded:
		return "FILE/FOLDER ADDED"
	case EventFileDeleted:
		return "FILE/FOLDER DELETED"
	case EventFileModified:
		return "FILE/FOLDER MODIFIED"
	default:
		return "UNRECOGNIZED EVENT"
	}
}

// A Watcher describes a file watcher.
type Watcher struct {
	Names []string
	Files []File
	Event chan Event
	Error chan error
}

// A Watcher describes a file/folder being watched.
type File struct {
	Dir string
	os.FileInfo
}

// New returns a new initialized *Watcher.
func New() *Watcher {
	return &Watcher{
		Names: []string{},
		Files: []File{},
		Event: make(chan Event),
		Error: make(chan error),
	}
}

// Add adds either a single file or recursed directory to
// the Watcher's file list.
func (w *Watcher) Add(name string) error {
	// Add the name from w's Names list.
	w.Names = append(w.Names, name)

	// Make sure name exists.
	fInfo, err := os.Stat(name)
	if err != nil {
		return err
	}

	// If watching a single file, add it and return.
	if !fInfo.IsDir() {
		w.Files = append(w.Files, File{Dir: filepath.Dir(fInfo.Name()), FileInfo: fInfo})
		return nil
	}

	// Add all of the os.FileInfo's to w from dir recursively.
	fInfoList, err := ListFiles(name)
	if err != nil {
		return err
	}
	w.Files = append(w.Files, fInfoList...)
	return nil
}

// Remove removes either a single file or recursed directory from
// the Watcher's file list.
func (w *Watcher) Remove(name string) error {
	// Remove the name from w's Names list.
	for i := range w.Names {
		if w.Names[i] == name {
			w.Names = append(w.Names[:i], w.Names[i+1:]...)
		}
	}

	// Make sure name exists.
	fInfo, err := os.Stat(name)
	if err != nil {
		return err
	}

	// If name is a single file, remove it and return.
	if !fInfo.IsDir() {
		for i := range w.Files {
			if w.Files[i].FileInfo == fInfo &&
				w.Files[i].Dir == filepath.Dir(fInfo.Name()) {
				w.Files = append(w.Files[:i], w.Files[i+1:]...)
			}
		}
		return nil
	}

	// Retrieve a list of all of the os.FileInfo's to delete from w.Files.
	fileList, err := ListFiles(name)
	if err != nil {
		return err
	}

	// TODO: Make more precise remove method. Make os.FileInfo's mapped to dir?
	//
	// Remove the appropriate os.FileInfo's from w's os.FileInfo list.
	for _, file := range fileList {
		for i, wFile := range w.Files {
			if wFile.Dir == file.Dir &&
				wFile.Name() == file.Name() {
				w.Files = append(w.Files[:i], w.Files[i+1:]...)
			}
		}
	}
	return nil
}

// Start starts the watching process and checks for changes every `pollInterval`
// amount of milliseconds. If pollInterval is 0, the default is 100ms.
func (w *Watcher) Start(pollInterval int) error {
	if pollInterval == 0 {
		pollInterval = 100
	}

	if len(w.Names) < 1 {
		return ErrNothingAdded
	}

	for {
		var fileList []File
		for _, name := range w.Names {
			// Retrieve the list of os.FileInfo's from w.Name.
			list, err := ListFiles(name)
			if err != nil {
				if os.IsNotExist(err) {
					w.Error <- ErrWatchedFileDeleted
				} else {
					w.Error <- err
				}
			}
			fileList = append(fileList, list...)
		}

		if len(fileList) > len(w.Files) {
			// Check for new files.
			w.Event <- EventFileAdded
			w.Files = fileList
		} else if len(fileList) < len(w.Files) {
			// Check for deleted files.
			w.Event <- EventFileDeleted
			w.Files = fileList
		}

		// Check for modified files.
		for i, file := range w.Files {
			if fileList[i].ModTime() != file.ModTime() {
				w.Event <- EventFileModified
				w.Files = fileList
				break
			}
		}

		// Sleep for a little bit.
		time.Sleep(time.Millisecond * time.Duration(pollInterval))
	}

	return nil
}

// ListFiles returns a slice of all os.FileInfo's recursively
// contained in a directory. If name is a single file, it returns
// an os.FileInfo slice with a single os.FileInfo.
func ListFiles(name string) ([]File, error) {
	var currentDir string

	fileList := []File{}

	if err := filepath.Walk(name, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			currentDir = info.Name()
		}

		if err != nil {
			return err
		}

		fileList = append(fileList, File{Dir: currentDir, FileInfo: info})
		return nil
	}); err != nil {
		return nil, err
	}

	return fileList, nil
}
<commit_msg>watcher can now tell file name's from events<commit_after>package watcher

import (
	"errors"
	"os"
	"path/filepath"
	"time"
)

var (
	// ErrNothingAdded is an error that occurs when a Watcher's Start() method is
	// called and no files or folders have been added to the Watcher's watchlist.
	ErrNothingAdded = errors.New("error: no files added to the watchlist")

	// ErrWatchedFileDeleted is an error that occurs when a file or folder that was
	// being watched has been deleted.
	ErrWatchedFileDeleted = errors.New("error: watched file or folder deleted")
)

// An EventType is a type that is used to describe what type
// of event has occured during the watching process.
type EventType int

const (
	EventFileAdded EventType = 1 << iota
	EventFileDeleted
	EventFileModified
)

// String returns a small string depending on what
// type of event it is.
func (e EventType) String() string {
	switch e {
	case EventFileAdded:
		return "FILE/FOLDER ADDED"
	case EventFileDeleted:
		return "FILE/FOLDER DELETED"
	case EventFileModified:
		return "FILE/FOLDER MODIFIED"
	default:
		return "UNRECOGNIZED EVENT"
	}
}

type Event struct {
	EventType
	File
}

// A Watcher describes a file watcher.
type Watcher struct {
	Names []string
	Files []File
	Event chan Event
	Error chan error
}

// A Watcher describes a file/folder being watched.
type File struct {
	Dir string
	os.FileInfo
}

// New returns a new initialized *Watcher.
func New() *Watcher {
	return &Watcher{
		Names: []string{},
		Files: []File{},
		Event: make(chan Event),
		Error: make(chan error),
	}
}

// Add adds either a single file or recursed directory to
// the Watcher's file list.
func (w *Watcher) Add(name string) error {
	// Add the name from w's Names list.
	w.Names = append(w.Names, name)

	// Make sure name exists.
	fInfo, err := os.Stat(name)
	if err != nil {
		return err
	}

	// If watching a single file, add it and return.
	if !fInfo.IsDir() {
		w.Files = append(w.Files, File{Dir: filepath.Dir(fInfo.Name()), FileInfo: fInfo})
		return nil
	}

	// Add all of the os.FileInfo's to w from dir recursively.
	fInfoList, err := ListFiles(name)
	if err != nil {
		return err
	}
	w.Files = append(w.Files, fInfoList...)
	return nil
}

// Remove removes either a single file or recursed directory from
// the Watcher's file list.
func (w *Watcher) Remove(name string) error {
	// Remove the name from w's Names list.
	for i := range w.Names {
		if w.Names[i] == name {
			w.Names = append(w.Names[:i], w.Names[i+1:]...)
		}
	}

	// Make sure name exists.
	fInfo, err := os.Stat(name)
	if err != nil {
		return err
	}

	// If name is a single file, remove it and return.
	if !fInfo.IsDir() {
		for i := range w.Files {
			if w.Files[i].FileInfo == fInfo &&
				w.Files[i].Dir == filepath.Dir(fInfo.Name()) {
				w.Files = append(w.Files[:i], w.Files[i+1:]...)
			}
		}
		return nil
	}

	// Retrieve a list of all of the os.FileInfo's to delete from w.Files.
	fileList, err := ListFiles(name)
	if err != nil {
		return err
	}

	// Remove the appropriate os.FileInfo's from w's os.FileInfo list.
	for _, file := range fileList {
		for i, wFile := range w.Files {
			if wFile.Dir == file.Dir &&
				wFile.Name() == file.Name() {
				w.Files = append(w.Files[:i], w.Files[i+1:]...)
			}
		}
	}
	return nil
}

// Start starts the watching process and checks for changes every `pollInterval`
// amount of milliseconds. If pollInterval is 0, the default is 100ms.
func (w *Watcher) Start(pollInterval int) error {
	if pollInterval == 0 {
		pollInterval = 100
	}

	if len(w.Names) < 1 {
		return ErrNothingAdded
	}

	for {
		var fileList []File
		for _, name := range w.Names {
			// Retrieve the list of os.FileInfo's from w.Name.
			list, err := ListFiles(name)
			if err != nil {
				if os.IsNotExist(err) {
					w.Error <- ErrWatchedFileDeleted
				} else {
					w.Error <- err
				}
			}
			fileList = append(fileList, list...)
		}

		if len(fileList) > len(w.Files) {
			// Check for new files.
			w.Event <- Event{
				EventType: EventFileAdded,
				File:      w.Files[len(w.Files)],
			}
			w.Files = fileList
		} else if len(fileList) < len(w.Files) {
			// Check for deleted files.
			//
			// Find the missing file.
			var missingFile File
			for i, file := range w.Files {
				// Shouldn't happen with one list shorter than the other.
				if len(fileList) == i {
					break
				}
				// Check if the file is missing.
				if fileList[i] != file {
					missingFile = file
				}
			}
			w.Event <- Event{
				EventType: EventFileAdded,
				File:      missingFile,
			}
			w.Files = fileList
		}

		// Check for modified files.
		for i, file := range w.Files {
			if fileList[i].ModTime() != file.ModTime() {
				w.Event <- Event{
					EventType: EventFileModified,
					File:      file,
				}
				w.Files = fileList
				break
			}
		}

		// Sleep for a little bit.
		time.Sleep(time.Millisecond * time.Duration(pollInterval))
	}

	return nil
}

// ListFiles returns a slice of all os.FileInfo's recursively
// contained in a directory. If name is a single file, it returns
// an os.FileInfo slice with a single os.FileInfo.
func ListFiles(name string) ([]File, error) {
	var currentDir string

	fileList := []File{}

	if err := filepath.Walk(name, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			currentDir = info.Name()
		}

		if err != nil {
			return err
		}

		fileList = append(fileList, File{Dir: currentDir, FileInfo: info})
		return nil
	}); err != nil {
		return nil, err
	}

	return fileList, nil
}
<|endoftext|>


<commit_before>package wav

import (
	"io"

	"encoding/binary"

	"github.com/200sc/klangsynthese/audio"
)

// def wav format
var format = audio.Format{
	SampleRate: 44100,
	Bits:       16,
	Channels:   2,
}

type Controller struct{}

func NewController() *Controller {
	return &Controller{}
}

func (mc *Controller) Wave(b []byte) (audio.Audio, error) {
	return audio.EncodeBytes(
		audio.Encoding{
			Data:   b,
			Format: mc.Format(),
		})
}

func (mc *Controller) Load(r io.ReadCloser) (audio.Audio, error) {
	wav, err := ReadWavData(r)
	if err != nil {
		return nil, err
	}
	format := mc.Format()
	format.SampleRate = wav.SampleRate
	format.Channels = wav.NumChannels
	// This might also be WavData.ByteRate / 8, or BitsPerSample
	format.Bits = wav.BlockAlign * 8 / wav.NumChannels
	return audio.EncodeBytes(
		audio.Encoding{
			Data:   wav.Data,
			Format: format,
		})
}

func (mc *Controller) Save(r io.ReadWriter, a audio.Audio) error {
	return nil
}

func (mc *Controller) Format() audio.Format {
	return format
}

type WavData struct {
	bChunkID  [4]byte // B
	ChunkSize uint32  // L
	bFormat   [4]byte // B

	bSubchunk1ID  [4]byte // B
	Subchunk1Size uint32  // L
	AudioFormat   uint16  // L
	NumChannels   uint16  // L
	SampleRate    uint32  // L
	ByteRate      uint32  // L
	BlockAlign    uint16  // L
	BitsPerSample uint16  // L

	bSubchunk2ID  [4]byte // B
	Subchunk2Size uint32  // L
	Data          []byte  // L
}

func ReadWavData(r io.Reader) (WavData, error) {
	wav := WavData{}

	binary.Read(r, binary.BigEndian, &wav.bChunkID)
	binary.Read(r, binary.LittleEndian, &wav.ChunkSize)
	binary.Read(r, binary.BigEndian, &wav.bFormat)

	binary.Read(r, binary.BigEndian, &wav.bSubchunk1ID)
	binary.Read(r, binary.LittleEndian, &wav.Subchunk1Size)
	binary.Read(r, binary.LittleEndian, &wav.AudioFormat)
	binary.Read(r, binary.LittleEndian, &wav.NumChannels)
	binary.Read(r, binary.LittleEndian, &wav.SampleRate)
	binary.Read(r, binary.LittleEndian, &wav.ByteRate)
	binary.Read(r, binary.LittleEndian, &wav.BlockAlign)
	binary.Read(r, binary.LittleEndian, &wav.BitsPerSample)

	binary.Read(r, binary.BigEndian, &wav.bSubchunk2ID)
	binary.Read(r, binary.LittleEndian, &wav.Subchunk2Size)

	wav.Data = make([]byte, wav.Subchunk2Size)
	binary.Read(r, binary.LittleEndian, &wav.Data)

	return wav, nil
}
<commit_msg>Wav tweaks<commit_after>package wav

import (
	"io"

	"encoding/binary"

	"github.com/200sc/klangsynthese/audio"
)

// def wav format
var format = audio.Format{
	SampleRate: 44100,
	Bits:       16,
	Channels:   2,
}

type Controller struct{}

func NewController() *Controller {
	return &Controller{}
}

func (mc *Controller) Wave(b []byte) (audio.Audio, error) {
	return audio.EncodeBytes(
		audio.Encoding{
			Data:   b,
			Format: mc.Format(),
		})
}

func (mc *Controller) Load(r io.ReadCloser) (audio.Audio, error) {
	wav, err := ReadWavData(r)
	if err != nil {
		return nil, err
	}
	format := mc.Format()
	format.SampleRate = wav.SampleRate
	format.Channels = wav.NumChannels
	format.Bits = wav.BitsPerSample
	return audio.EncodeBytes(
		audio.Encoding{
			Data:   wav.Data,
			Format: format,
		})
}

func (mc *Controller) Save(r io.ReadWriter, a audio.Audio) error {
	return nil
}

func (mc *Controller) Format() audio.Format {
	return format
}

// The following is a "fork" of verdverm's go-wav library

type WavData struct {
	bChunkID  [4]byte // B
	ChunkSize uint32  // L
	bFormat   [4]byte // B

	bSubchunk1ID  [4]byte // B
	Subchunk1Size uint32  // L
	AudioFormat   uint16  // L
	NumChannels   uint16  // L
	SampleRate    uint32  // L
	ByteRate      uint32  // L
	BlockAlign    uint16  // L
	BitsPerSample uint16  // L

	bSubchunk2ID  [4]byte // B
	Subchunk2Size uint32  // L
	Data          []byte  // L
}

func ReadWavData(r io.Reader) (WavData, error) {
	wav := WavData{}

	binary.Read(r, binary.BigEndian, &wav.bChunkID)
	binary.Read(r, binary.LittleEndian, &wav.ChunkSize)
	binary.Read(r, binary.BigEndian, &wav.bFormat)

	binary.Read(r, binary.BigEndian, &wav.bSubchunk1ID)
	binary.Read(r, binary.LittleEndian, &wav.Subchunk1Size)
	binary.Read(r, binary.LittleEndian, &wav.AudioFormat)
	binary.Read(r, binary.LittleEndian, &wav.NumChannels)
	binary.Read(r, binary.LittleEndian, &wav.SampleRate)
	binary.Read(r, binary.LittleEndian, &wav.ByteRate)
	binary.Read(r, binary.LittleEndian, &wav.BlockAlign)
	binary.Read(r, binary.LittleEndian, &wav.BitsPerSample)

	binary.Read(r, binary.BigEndian, &wav.bSubchunk2ID)
	binary.Read(r, binary.LittleEndian, &wav.Subchunk2Size)

	wav.Data = make([]byte, wav.Subchunk2Size)
	binary.Read(r, binary.LittleEndian, &wav.Data)

	return wav, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/ava-labs/avalanchego/chains"
	"github.com/ava-labs/avalanchego/database/manager"
	"github.com/ava-labs/avalanchego/node"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/utils/storage"
)

type migrationManager struct {
	nodeManager *nodeManager
	rootConfig  node.Config
	log         logging.Logger
}

func newMigrationManager(nodeManager *nodeManager, rootConfig node.Config, log logging.Logger) *migrationManager {
	return &migrationManager{
		nodeManager: nodeManager,
		rootConfig:  rootConfig,
		log:         log,
	}
}

// Runs migration if required. See runMigration().
func (m *migrationManager) migrate() error {
	shouldMigrate, err := m.shouldMigrate()
	if err != nil {
		return err
	}
	if !shouldMigrate {
		return nil
	}
	err = m.verifyDiskStorage()
	if err != nil {
		return err
	}
	return m.runMigration()
}

func (m *migrationManager) verifyDiskStorage() error {
	storagePath := m.rootConfig.DBPath
	avail, err := storage.OsDiskStat(storagePath)
	if err != nil {
		return err
	}
	used, err := storage.DirSize(storagePath)
	if err != nil {
		return err
	}
	twox := used + used
	saftyBuf := (twox * 15) / 100
	required := used + saftyBuf // free space must be equal to used plus 30% overhead
	if avail < required {
		return fmt.Errorf("available space %d Megabyes is less then required space %d Megabytes for migration",
			avail/1024/1024, required/1024/1024)
	}
	if avail < constants.TwoHundredGigabytes {
		m.log.Warn("at least 200GB of free disk space is recommended")
	}
	return nil
}

// Returns true if the database should be migrated from the previous database version.
// Should migrate if the previous database version exists and
// if the latest database version has not finished bootstrapping.
func (m *migrationManager) shouldMigrate() (bool, error) {
	if !m.rootConfig.DBEnabled {
		return false, nil
	}
	dbManager, err := manager.New(m.rootConfig.DBPath, logging.NoLog{}, node.DatabaseVersion, true)
	if err != nil {
		return false, fmt.Errorf("couldn't create db manager at %s: %w", m.rootConfig.DBPath, err)
	}
	defer func() {
		if err := dbManager.Close(); err != nil {
			m.log.Error("error closing db manager: %s", err)
		}
	}()

	currentDBBootstrapped, err := dbManager.Current().Database.Has(chains.BootstrappedKey)
	if err != nil {
		return false, fmt.Errorf("couldn't get if database version %s is bootstrapped: %w", node.DatabaseVersion, err)
	}
	if currentDBBootstrapped {
		return false, nil
	}
	_, exists := dbManager.Previous()
	return exists, nil
}

// Run two nodes simultaneously: one is a version before the database upgrade and the other after.
// The latter will bootstrap from the former.
// When the new node version is done bootstrapping, both nodes are stopped.
// Returns nil if the new node version successfully bootstrapped.
// Some configuration flags are modified before being passed into the 2 nodes.
func (m *migrationManager) runMigration() error {
	m.log.Info("starting database migration")
	m.nodeManager.lock.Lock()
	if m.nodeManager.hasShutdown {
		m.nodeManager.lock.Unlock()
		return nil
	}

	preDBUpgradeNode, err := m.nodeManager.preDBUpgradeNode()
	if err != nil {
		m.nodeManager.lock.Unlock()
		return fmt.Errorf("couldn't create pre-upgrade node during migration: %w", err)
	}
	m.log.Info("starting pre-database upgrade node")
	preDBUpgradeNodeExitCodeChan := preDBUpgradeNode.start()
	defer func() {
		if err := m.nodeManager.Stop(preDBUpgradeNode.path); err != nil {
			m.log.Error("%s", fmt.Errorf("error while stopping node at %s: %s", preDBUpgradeNode.path, err))
		}
	}()

	m.log.Info("starting latest node version")
	latestVersion, err := m.nodeManager.latestVersionNodeFetchOnly(m.rootConfig)
	if err != nil {
		m.nodeManager.lock.Unlock()
		return fmt.Errorf("couldn't create latest version during migration: %w", err)
	}
	latestVersionExitCodeChan := latestVersion.start()
	defer func() {
		if err := m.nodeManager.Stop(latestVersion.path); err != nil {
			m.log.Error("error while stopping latest version node: %s", err)
		}
	}()
	m.nodeManager.lock.Unlock()

	// Wait until one of the nodes finishes.
	// If the bootstrapping node finishes with an exit code other than
	// the one indicating it is done bootstrapping, error.
	select {
	case exitCode := <-preDBUpgradeNodeExitCodeChan:
		// If this node ended because the node manager shut down,
		// don't return an error
		m.nodeManager.lock.Lock()
		hasShutdown := m.nodeManager.hasShutdown
		m.nodeManager.lock.Unlock()
		if hasShutdown {
			return nil
		}
		return fmt.Errorf("previous version node stopped with exit code %d", exitCode)
	case exitCode := <-latestVersionExitCodeChan:
		if exitCode != constants.ExitCodeDoneMigrating {
			return fmt.Errorf("latest version died with exit code %d", exitCode)
		}

		return nil
	}
}
<commit_msg>more straightforward saftybuf calc<commit_after>package main

import (
	"fmt"

	"github.com/ava-labs/avalanchego/chains"
	"github.com/ava-labs/avalanchego/database/manager"
	"github.com/ava-labs/avalanchego/node"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/utils/storage"
)

type migrationManager struct {
	nodeManager *nodeManager
	rootConfig  node.Config
	log         logging.Logger
}

func newMigrationManager(nodeManager *nodeManager, rootConfig node.Config, log logging.Logger) *migrationManager {
	return &migrationManager{
		nodeManager: nodeManager,
		rootConfig:  rootConfig,
		log:         log,
	}
}

// Runs migration if required. See runMigration().
func (m *migrationManager) migrate() error {
	shouldMigrate, err := m.shouldMigrate()
	if err != nil {
		return err
	}
	if !shouldMigrate {
		return nil
	}
	err = m.verifyDiskStorage()
	if err != nil {
		return err
	}
	return m.runMigration()
}

func (m *migrationManager) verifyDiskStorage() error {
	storagePath := m.rootConfig.DBPath
	avail, err := storage.OsDiskStat(storagePath)
	if err != nil {
		return err
	}
	used, err := storage.DirSize(storagePath)
	if err != nil {
		return err
	}
	saftyBuf := (used * 30) / 100
	required := used + saftyBuf // free space must be equal to used plus 30% overhead
	if avail < required {
		return fmt.Errorf("available space %d Megabyes is less then required space %d Megabytes for migration",
			avail/1024/1024, required/1024/1024)
	}
	if avail < constants.TwoHundredGigabytes {
		m.log.Warn("at least 200GB of free disk space is recommended")
	}
	return nil
}

// Returns true if the database should be migrated from the previous database version.
// Should migrate if the previous database version exists and
// if the latest database version has not finished bootstrapping.
func (m *migrationManager) shouldMigrate() (bool, error) {
	if !m.rootConfig.DBEnabled {
		return false, nil
	}
	dbManager, err := manager.New(m.rootConfig.DBPath, logging.NoLog{}, node.DatabaseVersion, true)
	if err != nil {
		return false, fmt.Errorf("couldn't create db manager at %s: %w", m.rootConfig.DBPath, err)
	}
	defer func() {
		if err := dbManager.Close(); err != nil {
			m.log.Error("error closing db manager: %s", err)
		}
	}()

	currentDBBootstrapped, err := dbManager.Current().Database.Has(chains.BootstrappedKey)
	if err != nil {
		return false, fmt.Errorf("couldn't get if database version %s is bootstrapped: %w", node.DatabaseVersion, err)
	}
	if currentDBBootstrapped {
		return false, nil
	}
	_, exists := dbManager.Previous()
	return exists, nil
}

// Run two nodes simultaneously: one is a version before the database upgrade and the other after.
// The latter will bootstrap from the former.
// When the new node version is done bootstrapping, both nodes are stopped.
// Returns nil if the new node version successfully bootstrapped.
// Some configuration flags are modified before being passed into the 2 nodes.
func (m *migrationManager) runMigration() error {
	m.log.Info("starting database migration")
	m.nodeManager.lock.Lock()
	if m.nodeManager.hasShutdown {
		m.nodeManager.lock.Unlock()
		return nil
	}

	preDBUpgradeNode, err := m.nodeManager.preDBUpgradeNode()
	if err != nil {
		m.nodeManager.lock.Unlock()
		return fmt.Errorf("couldn't create pre-upgrade node during migration: %w", err)
	}
	m.log.Info("starting pre-database upgrade node")
	preDBUpgradeNodeExitCodeChan := preDBUpgradeNode.start()
	defer func() {
		if err := m.nodeManager.Stop(preDBUpgradeNode.path); err != nil {
			m.log.Error("%s", fmt.Errorf("error while stopping node at %s: %s", preDBUpgradeNode.path, err))
		}
	}()

	m.log.Info("starting latest node version")
	latestVersion, err := m.nodeManager.latestVersionNodeFetchOnly(m.rootConfig)
	if err != nil {
		m.nodeManager.lock.Unlock()
		return fmt.Errorf("couldn't create latest version during migration: %w", err)
	}
	latestVersionExitCodeChan := latestVersion.start()
	defer func() {
		if err := m.nodeManager.Stop(latestVersion.path); err != nil {
			m.log.Error("error while stopping latest version node: %s", err)
		}
	}()
	m.nodeManager.lock.Unlock()

	// Wait until one of the nodes finishes.
	// If the bootstrapping node finishes with an exit code other than
	// the one indicating it is done bootstrapping, error.
	select {
	case exitCode := <-preDBUpgradeNodeExitCodeChan:
		// If this node ended because the node manager shut down,
		// don't return an error
		m.nodeManager.lock.Lock()
		hasShutdown := m.nodeManager.hasShutdown
		m.nodeManager.lock.Unlock()
		if hasShutdown {
			return nil
		}
		return fmt.Errorf("previous version node stopped with exit code %d", exitCode)
	case exitCode := <-latestVersionExitCodeChan:
		if exitCode != constants.ExitCodeDoneMigrating {
			return fmt.Errorf("latest version died with exit code %d", exitCode)
		}

		return nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/tidwall/gjson"

	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
)

func main(int, int) {
	weatherMoscow := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(2122265)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
	weatherOymyakon := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22oymyakon%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"

	res, err := http.Get(weatherMoscow)

	if err != nil {
		panic(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println(err)
	}
	fahr := gjson.GetBytes(body, "query.results.channel.item.condition.temp")

	res, err = http.Get(weatherOymyakon)

	if err != nil {
		panic(err)
	}

	body, err = ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println(err)
	}

	defer res.Body.Close()

	fahrOy := gjson.GetBytes(body, "query.results.channel.item.condition.temp")

	return int(fahr.Int()), int(fahrOy.Int())
}
<commit_msg>fixed function name<commit_after>package main

import (
	"github.com/tidwall/gjson"

	"io/ioutil"
	"log"
	"net/http"
)

func getWeather(int, int) {
	weatherMoscow := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(2122265)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
	weatherOymyakon := "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22oymyakon%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"

	res, err := http.Get(weatherMoscow)

	if err != nil {
		panic(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println(err)
	}
	fahr := gjson.GetBytes(body, "query.results.channel.item.condition.temp")

	res, err = http.Get(weatherOymyakon)

	if err != nil {
		panic(err)
	}

	body, err = ioutil.ReadAll(res.Body)
	if err != nil {
		log.Println(err)
	}

	defer res.Body.Close()

	fahrOy := gjson.GetBytes(body, "query.results.channel.item.condition.temp")

	return int(fahr.Int()), int(fahrOy.Int())
}
<|endoftext|>


<commit_before>/*
Package web provides a fast and flexible middleware stack and mux.

This package attempts to solve three problems that net/http does not. First, it
allows you to specify flexible patterns, including routes with named parameters
and regular expressions. Second, it allows you to write reconfigurable
middleware stacks. And finally, it allows you to attach additional context to
requests, in a manner that can be manipulated by both compliant middleware and
handlers.

A usage example:

	m := web.New()

Use your favorite HTTP verbs and the interfaces you know and love from net/http:

	var legacyFooHttpHandler http.Handler // From elsewhere
	m.Get("/foo", legacyFooHttpHandler)
	m.Post("/bar", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello world!"))
	})

Bind parameters using either named captures or regular expressions:

	m.Get("/hello/:name", func(c web.C, w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"])
	})
	pattern := regexp.MustCompile(`^/ip/(?P<ip>(?:\d{1,3}\.){3}\d{1,3})$`)
	m.Get(pattern, func(c web.C, w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Info for IP address %s:", c.URLParams["ip"])
	})

Middleware are functions that wrap http.Handlers, just like you'd use with raw
net/http. Middleware functions can optionally take a context parameter, which
will be threaded throughout the middleware stack and to the final handler, even
if not all of the intervening middleware or handlers support contexts.
Middleware are encouraged to use the Env parameter to pass request-scoped data
to other middleware and to the final handler:

	func LoggerMiddleware(h http.Handler) http.Handler {
		handler := func(w http.ResponseWriter, r *http.Request) {
			log.Println("Before request")
			h.ServeHTTP(w, r)
			log.Println("After request")
		}
		return http.HandlerFunc(handler)
	}
	func AuthMiddleware(c *web.C, h http.Handler) http.Handler {
		handler := func(w http.ResponseWriter, r *http.Request) {
			if cookie, err := r.Cookie("user"); err == nil {
				c.Env["user"] = cookie.Value
			}
			h.ServeHTTP(w, r)
		}
		return http.HandlerFunc(handler)
	}

	// This makes the AuthMiddleware above a little cleaner
	m.Use(middleware.EnvInit)
	m.Use(AuthMiddleware)
	m.Use(LoggerMiddleware)
	m.Get("/baz", func(c web.C, w http.ResponseWriter, r *http.Request) {
		if user, ok := c.Env["user"].(string); ok {
			w.Write([]byte("Hello " + user))
		} else {
			w.Write([]byte("Hello Stranger!"))
		}
	})
*/
package web

import (
	"net/http"
)

/*
C is a request-local context object which is threaded through all compliant
middleware layers and given to the final request handler.
*/
type C struct {
	// URLParams is a map of variables extracted from the URL (typically
	// from the path portion) during routing. See the documentation for the
	// URL Pattern you are using (or the documentation for PatternType for
	// the case of standard pattern types) for more information about how
	// variables are extracted and named.
	URLParams map[string]string
	// Env is a free-form environment for storing request-local data. Keys
	// may be arbitrary types that support equality, however package-private
	// types with type-safe accessors provide a convenient way for packages
	// to mediate access to their request-local data.
	Env map[interface{}]interface{}
}

// Handler is similar to net/http's http.Handler, but also accepts a Goji
// context object.
type Handler interface {
	ServeHTTPC(C, http.ResponseWriter, *http.Request)
}

// HandlerFunc is similar to net/http's http.HandlerFunc, but supports a context
// object. Implements both http.Handler and Handler.
type HandlerFunc func(C, http.ResponseWriter, *http.Request)

// ServeHTTP implements http.Handler, allowing HandlerFunc's to be used with
// net/http and other compliant routers. When used in this way, the underlying
// function will be passed an empty context.
func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h(C{}, w, r)
}

// ServeHTTPC implements Handler.
func (h HandlerFunc) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
	h(c, w, r)
}

/*
PatternType is the type denoting Patterns and types that Goji internally
converts to Pattern (via the ParsePattern function). In order to provide an
expressive API, this type is an alias for interface{} (that is named for the
purposes of documentation), however only the following concrete types are
accepted:
	- types that implement Pattern
	- string, which is interpreted as a Sinatra-like URL pattern. In
	  particular, the following syntax is recognized:
		- a path segment starting with with a colon will match any
		  string placed at that position. e.g., "/:name" will match
		  "/carl", binding "name" to "carl".
		- a pattern ending with "/*" will match any route with that
		  prefix. For instance, the pattern "/u/:name/*" will match
		  "/u/carl/" and "/u/carl/projects/123", but not "/u/carl"
		  (because there is no trailing slash). In addition to any names
		  bound in the pattern, the special key "*" is bound to the
		  unmatched tail of the match, but including the leading "/". So
		  for the two matching examples above, "*" would be bound to "/"
		  and "/projects/123" respectively.
	  Unlike http.ServeMux's patterns, string patterns support neither the
	  "rooted subtree" behavior nor Host-specific routes. Users who require
	  either of these features are encouraged to compose package http's mux
	  with the mux provided by this package.
	- regexp.Regexp, which is assumed to be a Perl-style regular expression
	  that is anchored on the left (i.e., the beginning of the string). If
	  your regular expression is not anchored on the left, a
	  hopefully-identical left-anchored regular expression will be created
	  and used instead.

	  Capturing groups will be converted into bound URL parameters in
	  URLParams. If the capturing group is named, that name will be used;
	  otherwise the special identifiers "$1", "$2", etc. will be used.
*/
type PatternType interface{}

/*
HandlerType is the type of Handlers and types that Goji internally converts to
Handler. In order to provide an expressive API, this type is an alias for
interface{} (that is named for the purposes of documentation), however only the
following concrete types are accepted:
	- types that implement http.Handler
	- types that implement Handler
	- func(w http.ResponseWriter, r *http.Request)
	- func(c web.C, w http.ResponseWriter, r *http.Request)
*/
type HandlerType interface{}

/*
MiddlewareType is the type of Goji middleware. In order to provide an expressive
API, this type is an alias for interface{} (that is named for the purposes of
documentation), however only the following concrete types are accepted:
	- func(http.Handler) http.Handler
	- func(c *web.C, http.Handler) http.Handler
*/
type MiddlewareType interface{}
<commit_msg>Wording<commit_after>/*
Package web provides a fast and flexible middleware stack and mux.

This package attempts to solve three problems that net/http does not. First, it
allows you to specify flexible patterns, including routes with named parameters
and regular expressions. Second, it allows you to write reconfigurable
middleware stacks. And finally, it allows you to attach additional context to
requests, in a manner that can be manipulated by both compliant middleware and
handlers.

A usage example:

	m := web.New()

Use your favorite HTTP verbs and the interfaces you know and love from net/http:

	var existingHTTPHandler http.Handler // From elsewhere
	m.Get("/foo", existingHTTPHandler)
	m.Post("/bar", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello world!"))
	})

Bind parameters using either named captures or regular expressions:

	m.Get("/hello/:name", func(c web.C, w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"])
	})
	pattern := regexp.MustCompile(`^/ip/(?P<ip>(?:\d{1,3}\.){3}\d{1,3})$`)
	m.Get(pattern, func(c web.C, w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Info for IP address %s:", c.URLParams["ip"])
	})

Middleware are functions that wrap http.Handlers, just like you'd use with raw
net/http. Middleware functions can optionally take a context parameter, which
will be threaded throughout the middleware stack and to the final handler, even
if not all of the intervening middleware or handlers support contexts.
Middleware are encouraged to use the Env parameter to pass request-scoped data
to other middleware and to the final handler:

	func LoggerMiddleware(h http.Handler) http.Handler {
		handler := func(w http.ResponseWriter, r *http.Request) {
			log.Println("Before request")
			h.ServeHTTP(w, r)
			log.Println("After request")
		}
		return http.HandlerFunc(handler)
	}
	func AuthMiddleware(c *web.C, h http.Handler) http.Handler {
		handler := func(w http.ResponseWriter, r *http.Request) {
			if cookie, err := r.Cookie("user"); err == nil {
				c.Env["user"] = cookie.Value
			}
			h.ServeHTTP(w, r)
		}
		return http.HandlerFunc(handler)
	}

	// This makes the AuthMiddleware above a little cleaner
	m.Use(middleware.EnvInit)
	m.Use(AuthMiddleware)
	m.Use(LoggerMiddleware)
	m.Get("/baz", func(c web.C, w http.ResponseWriter, r *http.Request) {
		if user, ok := c.Env["user"].(string); ok {
			w.Write([]byte("Hello " + user))
		} else {
			w.Write([]byte("Hello Stranger!"))
		}
	})
*/
package web

import (
	"net/http"
)

/*
C is a request-local context object which is threaded through all compliant
middleware layers and given to the final request handler.
*/
type C struct {
	// URLParams is a map of variables extracted from the URL (typically
	// from the path portion) during routing. See the documentation for the
	// URL Pattern you are using (or the documentation for PatternType for
	// the case of standard pattern types) for more information about how
	// variables are extracted and named.
	URLParams map[string]string
	// Env is a free-form environment for storing request-local data. Keys
	// may be arbitrary types that support equality, however package-private
	// types with type-safe accessors provide a convenient way for packages
	// to mediate access to their request-local data.
	Env map[interface{}]interface{}
}

// Handler is similar to net/http's http.Handler, but also accepts a Goji
// context object.
type Handler interface {
	ServeHTTPC(C, http.ResponseWriter, *http.Request)
}

// HandlerFunc is similar to net/http's http.HandlerFunc, but supports a context
// object. Implements both http.Handler and Handler.
type HandlerFunc func(C, http.ResponseWriter, *http.Request)

// ServeHTTP implements http.Handler, allowing HandlerFunc's to be used with
// net/http and other compliant routers. When used in this way, the underlying
// function will be passed an empty context.
func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h(C{}, w, r)
}

// ServeHTTPC implements Handler.
func (h HandlerFunc) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
	h(c, w, r)
}

/*
PatternType is the type denoting Patterns and types that Goji internally
converts to Pattern (via the ParsePattern function). In order to provide an
expressive API, this type is an alias for interface{} (that is named for the
purposes of documentation), however only the following concrete types are
accepted:
	- types that implement Pattern
	- string, which is interpreted as a Sinatra-like URL pattern. In
	  particular, the following syntax is recognized:
		- a path segment starting with with a colon will match any
		  string placed at that position. e.g., "/:name" will match
		  "/carl", binding "name" to "carl".
		- a pattern ending with "/*" will match any route with that
		  prefix. For instance, the pattern "/u/:name/*" will match
		  "/u/carl/" and "/u/carl/projects/123", but not "/u/carl"
		  (because there is no trailing slash). In addition to any names
		  bound in the pattern, the special key "*" is bound to the
		  unmatched tail of the match, but including the leading "/". So
		  for the two matching examples above, "*" would be bound to "/"
		  and "/projects/123" respectively.
	  Unlike http.ServeMux's patterns, string patterns support neither the
	  "rooted subtree" behavior nor Host-specific routes. Users who require
	  either of these features are encouraged to compose package http's mux
	  with the mux provided by this package.
	- regexp.Regexp, which is assumed to be a Perl-style regular expression
	  that is anchored on the left (i.e., the beginning of the string). If
	  your regular expression is not anchored on the left, a
	  hopefully-identical left-anchored regular expression will be created
	  and used instead.

	  Capturing groups will be converted into bound URL parameters in
	  URLParams. If the capturing group is named, that name will be used;
	  otherwise the special identifiers "$1", "$2", etc. will be used.
*/
type PatternType interface{}

/*
HandlerType is the type of Handlers and types that Goji internally converts to
Handler. In order to provide an expressive API, this type is an alias for
interface{} (that is named for the purposes of documentation), however only the
following concrete types are accepted:
	- types that implement http.Handler
	- types that implement Handler
	- func(w http.ResponseWriter, r *http.Request)
	- func(c web.C, w http.ResponseWriter, r *http.Request)
*/
type HandlerType interface{}

/*
MiddlewareType is the type of Goji middleware. In order to provide an expressive
API, this type is an alias for interface{} (that is named for the purposes of
documentation), however only the following concrete types are accepted:
	- func(http.Handler) http.Handler
	- func(c *web.C, http.Handler) http.Handler
*/
type MiddlewareType interface{}
<|endoftext|>


<commit_before>//Copyright 2015 TF2Stadium. All rights reserved.
//Use of this source code is governed by the MIT
//that can be found in the LICENSE file.

//Package wsevent implements thread-safe event-driven communication similar to socket.IO,
//on the top of Gorilla's WebSocket implementation.
package wsevent

import (
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	ws "github.com/gorilla/websocket"
)

//Client
type Client struct {
	//Session ID
	id string

	conn     *ws.Conn
	connLock *sync.RWMutex
	request  *http.Request
}

//Server
type Server struct {
	//maps room string to a list of clients in it
	rooms     map[string]([]*Client)
	roomsLock *sync.RWMutex

	//maps client IDs to the list of rooms the corresponding client has joined
	joinedRooms     map[string][]string
	joinedRoomsLock *sync.RWMutex

	//The extractor function reads the byte array and the message type
	//and returns the event represented by the message.
	Extractor func(string) string
	//Called when the websocket connection closes. The disconnected client's
	//session ID is sent as an argument
	OnDisconnect func(string)
	//Called when no event handler for a specific event exists
	DefaultHandler func(*Server, *Client, []byte) []byte

	handlers     map[string]func(*Server, *Client, []byte) []byte
	handlersLock *sync.RWMutex

	newClient chan *Client
}

func genID(r *http.Request) string {
	hash := fmt.Sprintf("%s%d", r.RemoteAddr, time.Now().UnixNano())
	return fmt.Sprintf("%x", sha1.Sum([]byte(hash)))
}

//Returns the client's unique session ID
func (c *Client) Id() string {
	return c.id
}

// Returns the first http request when established connection.
func (c *Client) Request() *http.Request {
	return c.request
}

func (s *Server) NewClient(upgrader ws.Upgrader, w http.ResponseWriter, r *http.Request) (*Client, error) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		return nil, err
	}

	client := &Client{
		id:       genID(r),
		conn:     conn,
		connLock: new(sync.RWMutex),
		request:  r,
	}
	s.newClient <- client

	return client, nil
}

func (c *Client) Close() error {
	c.connLock.Lock()
	defer c.connLock.Unlock()
	return c.conn.Close()
}

//A thread-safe variant of WriteMessage
func (c *Client) Emit(data string) error {
	c.connLock.Lock()
	defer c.connLock.Unlock()
	return c.conn.WriteMessage(ws.TextMessage, []byte(data))
}

//A thread-safe variant of EmitJSON
func (c *Client) EmitJSON(v interface{}) error {
	c.connLock.Lock()
	defer c.connLock.Unlock()

	js := struct {
		Id   int         `json:"id"`
		Data interface{} `json:"data"`
	}{-1, v}

	return c.conn.WriteJSON(js)
}

//Return a new server object
func NewServer() *Server {
	s := &Server{
		rooms:     make(map[string]([]*Client)),
		roomsLock: new(sync.RWMutex),

		//Maps socket ID -> list of rooms the client is in
		joinedRooms:     make(map[string][]string),
		joinedRoomsLock: new(sync.RWMutex),

		handlers:     make(map[string](func(*Server, *Client, []byte) []byte)),
		handlersLock: new(sync.RWMutex),

		newClient: make(chan *Client),
	}

	go s.listener()
	return s
}

//Add a client c to room r
func (s *Server) AddClient(c *Client, r string) {
	s.joinedRoomsLock.RLock()
	for _, room := range s.joinedRooms[c.id] {
		if r == room {
			//log.Printf("%s already in room %s", c.id, r)
			s.joinedRoomsLock.RUnlock()
			return
		}
	}
	s.joinedRoomsLock.RUnlock()

	s.roomsLock.Lock()
	defer s.roomsLock.Unlock()
	s.rooms[r] = append(s.rooms[r], c)

	s.joinedRoomsLock.Lock()
	defer s.joinedRoomsLock.Unlock()
	s.joinedRooms[c.id] = append(s.joinedRooms[c.id], r)
	//log.Printf("Added %s to room %s", c.id, r)
}

//Remove client c from room r
func (s *Server) RemoveClient(id, r string) {
	index := -1
	s.roomsLock.Lock()

	for i, client := range s.rooms[r] {
		if id == client.id {
			index = i
			break
		}
	}
	if index == -1 {
		//log.Printf("Client %s not found in room %s", id, r)
		s.roomsLock.Unlock()
		return
	}

	s.rooms[r] = append(s.rooms[r][:index], s.rooms[r][index+1:]...)
	s.roomsLock.Unlock()

	index = -1

	s.joinedRoomsLock.Lock()
	defer s.joinedRoomsLock.Unlock()

	for i, room := range s.joinedRooms[id] {
		if room == r {
			index = i
		}
	}
	if index == -1 {
		return
	}

	s.joinedRooms[id] = append(s.joinedRooms[id][:index], s.joinedRooms[id][index+1:]...)
}

//Send all clients in room room data with type messageType
func (s *Server) Broadcast(room string, data string) {
	for _, client := range s.rooms[room] {
		//log.Printf("sending to %s in room %s\n", client.id, room)
		go func(c *Client) {
			c.Emit(data)
		}(client)
	}
}

func (s *Server) BroadcastJSON(room string, v interface{}) {
	for _, client := range s.rooms[room] {
		//log.Printf("sending to %s %s\n", client.id, room)
		go func(c *Client) {
			c.EmitJSON(v)
		}(client)
	}
}

func (c *Client) cleanup(s *Server) {
	c.conn.Close()

	s.roomsLock.Lock()
	for _, room := range s.joinedRooms[c.id] {
		//log.Println(room)
		index := -1

		for i, client := range s.rooms[room] {
			if client.id == c.id {
				index = i
			}
		}
		if index == -1 {
			s.roomsLock.Unlock()
			return
		}

		s.rooms[room] = append(s.rooms[room][:index], s.rooms[room][index+1:]...)
	}
	s.roomsLock.Unlock()

	s.joinedRoomsLock.Lock()
	delete(s.joinedRooms, c.id)
	s.joinedRoomsLock.Unlock()

	if s.OnDisconnect != nil {
		s.OnDisconnect(c.id)
	}
}

//Returns an array of rooms the client c has been added to
func (s *Server) RoomsJoined(id string) []string {
	var rooms []string
	s.joinedRoomsLock.RLock()
	defer s.joinedRoomsLock.RUnlock()

	copy(rooms, s.joinedRooms[id])

	return rooms
}

func (c *Client) listener(s *Server) {
	for {
		mtype, data, err := c.conn.ReadMessage()
		if err != nil {
			c.cleanup(s)
			return
		}

		var js struct {
			Id   string
			Data json.RawMessage
		}
		err = json.Unmarshal(data, &js)

		if err != nil || mtype != ws.TextMessage {
			log.Println(err)
			continue
		}

		callName := s.Extractor(string(js.Data))

		s.handlersLock.RLock()
		f, ok := s.handlers[callName]
		s.handlersLock.RUnlock()

		if !ok {
			if s.DefaultHandler != nil {
				f = s.DefaultHandler
				goto call
			}
			continue
		}
	call:
		go func() {
			rtrn := f(s, c, js.Data)
			reply := struct {
				Id   string `json:"id"`
				Data string `json:"data,string"`
			}{js.Id, string(rtrn)}

			bytes, _ := json.Marshal(reply)
			c.Emit(string(bytes))
		}()
	}
}

func (s *Server) listener() {
	for {
		c := <-s.newClient
		go c.listener(s)
	}
}

//Registers a callback for the event string. The callback must take 2 arguments,
//The client from which the message was received and the string message itself.
func (s *Server) On(event string, f func(*Server, *Client, []byte) []byte) {
	s.handlersLock.Lock()
	s.handlers[event] = f
	s.handlersLock.Unlock()
}
<commit_msg>genID(): use crypto/rand<commit_after>//Copyright 2015 TF2Stadium. All rights reserved.
//Use of this source code is governed by the MIT
//that can be found in the LICENSE file.

//Package wsevent implements thread-safe event-driven communication similar to socket.IO,
//on the top of Gorilla's WebSocket implementation.
package wsevent

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"log"
	"net/http"
	"sync"

	ws "github.com/gorilla/websocket"
)

//Client
type Client struct {
	//Session ID
	id string

	conn     *ws.Conn
	connLock *sync.RWMutex
	request  *http.Request
}

//Server
type Server struct {
	//maps room string to a list of clients in it
	rooms     map[string]([]*Client)
	roomsLock *sync.RWMutex

	//maps client IDs to the list of rooms the corresponding client has joined
	joinedRooms     map[string][]string
	joinedRoomsLock *sync.RWMutex

	//The extractor function reads the byte array and the message type
	//and returns the event represented by the message.
	Extractor func(string) string
	//Called when the websocket connection closes. The disconnected client's
	//session ID is sent as an argument
	OnDisconnect func(string)
	//Called when no event handler for a specific event exists
	DefaultHandler func(*Server, *Client, []byte) []byte

	handlers     map[string]func(*Server, *Client, []byte) []byte
	handlersLock *sync.RWMutex

	newClient chan *Client
}

func genID() string {
	bytes := make([]byte, 32)
	rand.Read(bytes)

	return base64.URLEncoding.EncodeToString(bytes)
}

//Returns the client's unique session ID
func (c *Client) Id() string {
	return c.id
}

// Returns the first http request when established connection.
func (c *Client) Request() *http.Request {
	return c.request
}

func (s *Server) NewClientWithID(upgrader ws.Upgrader, w http.ResponseWriter, r *http.Request, id string) (*Client, error) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		return nil, err
	}

	client := &Client{
		id:       id,
		conn:     conn,
		connLock: new(sync.RWMutex),
		request:  r,
	}
	s.newClient <- client

	return client, nil
}

func (s *Server) NewClient(upgrader ws.Upgrader, w http.ResponseWriter, r *http.Request) (*Client, error) {
	return s.NewClientWithID(upgrader, w, r, genID())
}

func (c *Client) Close() error {
	c.connLock.Lock()
	defer c.connLock.Unlock()
	return c.conn.Close()
}

//A thread-safe variant of WriteMessage
func (c *Client) Emit(data string) error {
	c.connLock.Lock()
	defer c.connLock.Unlock()
	return c.conn.WriteMessage(ws.TextMessage, []byte(data))
}

//A thread-safe variant of EmitJSON
func (c *Client) EmitJSON(v interface{}) error {
	c.connLock.Lock()
	defer c.connLock.Unlock()

	js := struct {
		Id   int         `json:"id"`
		Data interface{} `json:"data"`
	}{-1, v}

	return c.conn.WriteJSON(js)
}

//Return a new server object
func NewServer() *Server {
	s := &Server{
		rooms:     make(map[string]([]*Client)),
		roomsLock: new(sync.RWMutex),

		//Maps socket ID -> list of rooms the client is in
		joinedRooms:     make(map[string][]string),
		joinedRoomsLock: new(sync.RWMutex),

		handlers:     make(map[string](func(*Server, *Client, []byte) []byte)),
		handlersLock: new(sync.RWMutex),

		newClient: make(chan *Client),
	}

	go s.listener()
	return s
}

//Add a client c to room r
func (s *Server) AddClient(c *Client, r string) {
	s.joinedRoomsLock.RLock()
	for _, room := range s.joinedRooms[c.id] {
		if r == room {
			//log.Printf("%s already in room %s", c.id, r)
			s.joinedRoomsLock.RUnlock()
			return
		}
	}
	s.joinedRoomsLock.RUnlock()

	s.roomsLock.Lock()
	defer s.roomsLock.Unlock()
	s.rooms[r] = append(s.rooms[r], c)

	s.joinedRoomsLock.Lock()
	defer s.joinedRoomsLock.Unlock()
	s.joinedRooms[c.id] = append(s.joinedRooms[c.id], r)
	//log.Printf("Added %s to room %s", c.id, r)
}

//Remove client c from room r
func (s *Server) RemoveClient(id, r string) {
	index := -1
	s.roomsLock.Lock()

	for i, client := range s.rooms[r] {
		if id == client.id {
			index = i
			break
		}
	}
	if index == -1 {
		//log.Printf("Client %s not found in room %s", id, r)
		s.roomsLock.Unlock()
		return
	}

	s.rooms[r] = append(s.rooms[r][:index], s.rooms[r][index+1:]...)
	s.roomsLock.Unlock()

	index = -1

	s.joinedRoomsLock.Lock()
	defer s.joinedRoomsLock.Unlock()

	for i, room := range s.joinedRooms[id] {
		if room == r {
			index = i
		}
	}
	if index == -1 {
		return
	}

	s.joinedRooms[id] = append(s.joinedRooms[id][:index], s.joinedRooms[id][index+1:]...)
}

//Send all clients in room room data with type messageType
func (s *Server) Broadcast(room string, data string) {
	for _, client := range s.rooms[room] {
		//log.Printf("sending to %s in room %s\n", client.id, room)
		go func(c *Client) {
			c.Emit(data)
		}(client)
	}
}

func (s *Server) BroadcastJSON(room string, v interface{}) {
	for _, client := range s.rooms[room] {
		//log.Printf("sending to %s %s\n", client.id, room)
		go func(c *Client) {
			c.EmitJSON(v)
		}(client)
	}
}

func (c *Client) cleanup(s *Server) {
	c.conn.Close()

	s.roomsLock.Lock()
	for _, room := range s.joinedRooms[c.id] {
		//log.Println(room)
		index := -1

		for i, client := range s.rooms[room] {
			if client.id == c.id {
				index = i
			}
		}
		if index == -1 {
			s.roomsLock.Unlock()
			return
		}

		s.rooms[room] = append(s.rooms[room][:index], s.rooms[room][index+1:]...)
	}
	s.roomsLock.Unlock()

	s.joinedRoomsLock.Lock()
	delete(s.joinedRooms, c.id)
	s.joinedRoomsLock.Unlock()

	if s.OnDisconnect != nil {
		s.OnDisconnect(c.id)
	}
}

//Returns an array of rooms the client c has been added to
func (s *Server) RoomsJoined(id string) []string {
	rooms := make([]string, len(s.joinedRooms[id]))
	s.joinedRoomsLock.RLock()
	defer s.joinedRoomsLock.RUnlock()

	copy(rooms, s.joinedRooms[id])

	return rooms
}

func (c *Client) listener(s *Server) {
	for {
		mtype, data, err := c.conn.ReadMessage()
		if err != nil {
			c.cleanup(s)
			return
		}

		var js struct {
			Id   string
			Data json.RawMessage
		}
		err = json.Unmarshal(data, &js)

		if err != nil || mtype != ws.TextMessage {
			log.Println(err)
			continue
		}

		callName := s.Extractor(string(js.Data))

		s.handlersLock.RLock()
		f, ok := s.handlers[callName]
		s.handlersLock.RUnlock()

		if !ok {
			if s.DefaultHandler != nil {
				f = s.DefaultHandler
				goto call
			}
			continue
		}
	call:
		go func() {
			rtrn := f(s, c, js.Data)
			reply := struct {
				Id   string `json:"id"`
				Data string `json:"data,string"`
			}{js.Id, string(rtrn)}

			bytes, _ := json.Marshal(reply)
			c.Emit(string(bytes))
		}()
	}
}

func (s *Server) listener() {
	for {
		c := <-s.newClient
		go c.listener(s)
	}
}

//Registers a callback for the event string. The callback must take 2 arguments,
//The client from which the message was received and the string message itself.
func (s *Server) On(event string, f func(*Server, *Client, []byte) []byte) {
	s.handlersLock.Lock()
	s.handlers[event] = f
	s.handlersLock.Unlock()
}
<|endoftext|>