<commit_before>package vm

import (
	"fmt"
	"github.com/goby-lang/goby/vm/classes"
	"github.com/goby-lang/goby/vm/errors"
	"sync"
)

// ChannelObject represents Goby's "channel", which equips the Golang' channel and works with `thread`.
// `thread` is actually a "goroutine".
// A channel object can relay any kind of objects and guarantees thread-safe communications.
// You should always use channel objects for safe communications between threads.
// `Channel#new` is available.
//
// Note that channels are not like files and you don't need to explicitly close them (e.g.: exiting a loop).
// See https://tour.golang.org/concurrency/4
//
// ```ruby
// def f(from)
//   i = 0
//   while i < 3 do
//     puts(from + ": " + i.to_s)
//     i += 1
//   end
// end
//
// f("direct")
//
// c = Channel.new    # spawning a channel object
//
// thread do
//   puts(c.receive)
//   f("thread")
// end
//
// thread do
//   puts("going")
//   c.deliver(10)
// end
//
// sleep(2) # This is to prevent main program finished before goroutine.
// ```
//
// Note that the possibility of race conditions still exists. Handle them with care.
//
// ```ruby
// c = Channel.new
//
// i = 0
// thread do
//   i += 1
//   c.deliver(i)     # sends `i` to channel `c`
// end
//
// # If we put a bare `i += 1` here, then it will execute along with other thread,
// # which will cause a race condition.
// # The following "receive" is needed to block the main process until thread is finished
// c.receive
// i += 1
//
// c.close           # Redundant: just for explanation and you don't need to call this here
// ```
type ChannelObject struct {
	*baseObj
	Chan         chan int
	ChannelState int
}

// Channel's state.
// To Goby language contributors: Golang's channels should be carefully handled because:
// - You cannot write to closed channels, or got a panic.
// - You cannot close closed channels, or got a panic.
// - You cannot write to nil channels, or causes a deadlock.
// - You cannot read nil channels, or causes a deadlock.
// Ref: https://beatsync.net/main/log20150325.html
const (
	OPEN = iota
	CLOSED
)

// Class methods --------------------------------------------------------
func builtinChannelClassMethods() []*BuiltinMethodObject {
	return []*BuiltinMethodObject{
		{
			// Creates an instance of `Channel` class, taking no arguments.
			//
			// ```ruby
			// c = Channel.new
			// c.class         #=> Channel
			// ```
			//
			// @return [Channel]
			Name: "new",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					c := &ChannelObject{baseObj: &baseObj{class: t.vm.topLevelClass(classes.ChannelClass)}, Chan: make(chan int, OPEN)}
					return c
				}
			},
		},
	}
}

// Instance methods -----------------------------------------------------
func builtinChannelInstanceMethods() []*BuiltinMethodObject {
	return []*BuiltinMethodObject{
		{
			// Just to close and the channel to declare no more objects will be sent.
			// Channel is not like files, and you don't need to call `close` explicitly unless
			// you definitely need to notify that no more objects will be sent,
			// Well, you can call `#close` against the same channel twice or more, which is redundant.
			// (Go's channel cannot do that)
			// See https://tour.golang.org/concurrency/4
			//
			// ```ruby
			// c = Channel.new
			//
			// 1001.times do |i|
			// 	 thread do
			//     c.deliver(i)
			//	 end
			// end
			//
			// r = 0
			// 1001.times do
			//   r = r + c.receive
			// end
			//
			// c.close           # close the channel
			//
			// puts(r)
			// ```
			//
			// If you call `close` twice against the same channel, an error is returned.
			//
			// It takes no argument.
			//
			// @return [Null]
			Name: "close",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					if len(args) != 0 {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentFormat, 0, len(args))
					}
					c := receiver.(*ChannelObject)

					if c.ChannelState == CLOSED {
						return t.vm.InitErrorObject(errors.ChannelCloseError, sourceLine, errors.ChannelIsClosed)
					}
					c.ChannelState = CLOSED

					close(receiver.(*ChannelObject).Chan)
					receiver = nil
					return NULL
				}
			},
		},
		{
			// Sends an object to the receiver (channel), then returns the object.
			// Note that the method suspends the process until the object is actually received.
			// Thus if you call `deliver` outside thread, the main process would suspend.
			// Note that you don't need to send dummy object just to resume; use `close` instead.
			//
			// ```ruby
			// c = Channel.new
			//
			// i = 0
			// thread do
			//   i += 1
			//   c.deliver(i)   # sends `i` to channel `c`
			// end
			//
			// c.receive        # receives `i`
			// ```
			//
			// If you call `deliver` against the closed channel, an error is returned.
			//
			// It takes 1 argument.
			//
			// @param object [Object]
			// @return [Object]
			Name: "deliver",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					if len(args) != 1 {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentFormat, 1, len(args))
					}
					c := receiver.(*ChannelObject)

					if c.ChannelState == CLOSED {
						return t.vm.InitErrorObject(errors.ChannelCloseError, sourceLine, errors.ChannelIsClosed)
					}

					id := t.vm.channelObjectMap.storeObj(args[0])
					c.Chan <- id

					return args[0]
				}
			},
		},
		{
			// Receives objects from other threads' `deliver` method, then returns it.
			// The method works as if the channel would receive objects perpetually from outside.
			// Note that the method suspends the process until it actually receives something via `deliver`.
			// Thus if you call `receive` outside thread, the main process would suspend.
			// This also means you can resume a code by using the `receive` method.
			//
			// ```ruby
			// c = Channel.new
			//
			// thread do
			//   puts(c.receive)    # prints the object received from other threads.
			//   f("thread")
			// end
			// ```
			//
			// If you call `receive` against the closed channel, an error is returned.
			//
			// It takes no arguments.
			//
			// @return [Object]
			Name: "receive",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					if len(args) != 0 {
						if len(args) != 0 {
							return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentFormat, 0, len(args))
						}
					}
					c := receiver.(*ChannelObject)

					if c.ChannelState == CLOSED {
						return t.vm.InitErrorObject(errors.ChannelCloseError, sourceLine, errors.ChannelIsClosed)
					}

					num := <-c.Chan

					return t.vm.channelObjectMap.retrieveObj(num)
				}
			},
		},
	}
}

// Internal functions ===================================================

// Functions for initialization -----------------------------------------

func (vm *VM) initChannelClass() *RClass {
	class := vm.initializeClass(classes.ChannelClass, false)
	class.setBuiltinMethods(builtinChannelClassMethods(), true)
	class.setBuiltinMethods(builtinChannelInstanceMethods(), false)
	return class
}

// Polymorphic helper functions -----------------------------------------

// Value returns the object
func (co *ChannelObject) Value() interface{} {
	return co.Chan
}

// toString returns the object's name as the string format
func (co *ChannelObject) toString() string {
	return fmt.Sprintf("<Channel: %p>", co.Chan)
}

// toJSON just delegates to toString
func (co *ChannelObject) toJSON(t *Thread) string {
	return co.toString()
}

// copy returns the duplicate of the Array object
func (co *ChannelObject) copy() Object {
	newC := &ChannelObject{baseObj: &baseObj{class: co.class}, Chan: make(chan int)}
	return newC
}

// objectMap ==========================================================

type objectMap struct {
	store *sync.Map
}

// Polymorphic helper functions -----------------------------------------

// storeObj stores objects into the container map
// and update containerCount at the same time
func (m *objectMap) storeObj(obj Object) int {
	m.store.Store(obj.id(), obj)

	return obj.id()
}

// retrieveObj returns the objects with the number specified
func (m *objectMap) retrieveObj(num int) Object {
	obj, _ := m.store.Load(num)
	return obj.(Object)
}
<commit_msg>Change constants to be adhesive to Go's convention<commit_after>package vm

import (
	"fmt"
	"github.com/goby-lang/goby/vm/classes"
	"github.com/goby-lang/goby/vm/errors"
	"sync"
)

// ChannelObject represents Goby's "channel", which equips the Golang' channel and works with `thread`.
// `thread` is actually a "goroutine".
// A channel object can relay any kind of objects and guarantees thread-safe communications.
// You should always use channel objects for safe communications between threads.
// `Channel#new` is available.
//
// Note that channels are not like files and you don't need to explicitly close them (e.g.: exiting a loop).
// See https://tour.golang.org/concurrency/4
//
// ```ruby
// def f(from)
//   i = 0
//   while i < 3 do
//     puts(from + ": " + i.to_s)
//     i += 1
//   end
// end
//
// f("direct")
//
// c = Channel.new    # spawning a channel object
//
// thread do
//   puts(c.receive)
//   f("thread")
// end
//
// thread do
//   puts("going")
//   c.deliver(10)
// end
//
// sleep(2) # This is to prevent main program finished before goroutine.
// ```
//
// Note that the possibility of race conditions still exists. Handle them with care.
//
// ```ruby
// c = Channel.new
//
// i = 0
// thread do
//   i += 1
//   c.deliver(i)     # sends `i` to channel `c`
// end
//
// # If we put a bare `i += 1` here, then it will execute along with other thread,
// # which will cause a race condition.
// # The following "receive" is needed to block the main process until thread is finished
// c.receive
// i += 1
//
// c.close           # Redundant: just for explanation and you don't need to call this here
// ```
type ChannelObject struct {
	*baseObj
	Chan         chan int
	ChannelState int
}

// Channel's state.
// To Goby language contributors: Golang's channels should be carefully handled because:
// - You cannot write to closed channels, or got a panic.
// - You cannot close closed channels, or got a panic.
// - You cannot write to nil channels, or causes a deadlock.
// - You cannot read nil channels, or causes a deadlock.
// Ref: https://beatsync.net/main/log20150325.html
const (
	chOpen = iota
	chClosed
)

// Class methods --------------------------------------------------------
func builtinChannelClassMethods() []*BuiltinMethodObject {
	return []*BuiltinMethodObject{
		{
			// Creates an instance of `Channel` class, taking no arguments.
			//
			// ```ruby
			// c = Channel.new
			// c.class         #=> Channel
			// ```
			//
			// @return [Channel]
			Name: "new",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					c := &ChannelObject{baseObj: &baseObj{class: t.vm.topLevelClass(classes.ChannelClass)}, Chan: make(chan int, chOpen)}
					return c
				}
			},
		},
	}
}

// Instance methods -----------------------------------------------------
func builtinChannelInstanceMethods() []*BuiltinMethodObject {
	return []*BuiltinMethodObject{
		{
			// Just to close and the channel to declare no more objects will be sent.
			// Channel is not like files, and you don't need to call `close` explicitly unless
			// you definitely need to notify that no more objects will be sent,
			// Well, you can call `#close` against the same channel twice or more, which is redundant.
			// (Go's channel cannot do that)
			// See https://tour.golang.org/concurrency/4
			//
			// ```ruby
			// c = Channel.new
			//
			// 1001.times do |i|
			// 	 thread do
			//     c.deliver(i)
			//	 end
			// end
			//
			// r = 0
			// 1001.times do
			//   r = r + c.receive
			// end
			//
			// c.close           # close the channel
			//
			// puts(r)
			// ```
			//
			// If you call `close` twice against the same channel, an error is returned.
			//
			// It takes no argument.
			//
			// @return [Null]
			Name: "close",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					if len(args) != 0 {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentFormat, 0, len(args))
					}
					c := receiver.(*ChannelObject)

					if c.ChannelState == chClosed {
						return t.vm.InitErrorObject(errors.ChannelCloseError, sourceLine, errors.ChannelIsClosed)
					}
					c.ChannelState = chClosed

					close(receiver.(*ChannelObject).Chan)
					receiver = nil
					return NULL
				}
			},
		},
		{
			// Sends an object to the receiver (channel), then returns the object.
			// Note that the method suspends the process until the object is actually received.
			// Thus if you call `deliver` outside thread, the main process would suspend.
			// Note that you don't need to send dummy object just to resume; use `close` instead.
			//
			// ```ruby
			// c = Channel.new
			//
			// i = 0
			// thread do
			//   i += 1
			//   c.deliver(i)   # sends `i` to channel `c`
			// end
			//
			// c.receive        # receives `i`
			// ```
			//
			// If you call `deliver` against the closed channel, an error is returned.
			//
			// It takes 1 argument.
			//
			// @param object [Object]
			// @return [Object]
			Name: "deliver",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					if len(args) != 1 {
						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentFormat, 1, len(args))
					}
					c := receiver.(*ChannelObject)

					if c.ChannelState == chClosed {
						return t.vm.InitErrorObject(errors.ChannelCloseError, sourceLine, errors.ChannelIsClosed)
					}

					id := t.vm.channelObjectMap.storeObj(args[0])
					c.Chan <- id

					return args[0]
				}
			},
		},
		{
			// Receives objects from other threads' `deliver` method, then returns it.
			// The method works as if the channel would receive objects perpetually from outside.
			// Note that the method suspends the process until it actually receives something via `deliver`.
			// Thus if you call `receive` outside thread, the main process would suspend.
			// This also means you can resume a code by using the `receive` method.
			//
			// ```ruby
			// c = Channel.new
			//
			// thread do
			//   puts(c.receive)    # prints the object received from other threads.
			//   f("thread")
			// end
			// ```
			//
			// If you call `receive` against the closed channel, an error is returned.
			//
			// It takes no arguments.
			//
			// @return [Object]
			Name: "receive",
			Fn: func(receiver Object, sourceLine int) builtinMethodBody {
				return func(t *Thread, args []Object, blockFrame *normalCallFrame) Object {
					if len(args) != 0 {
						if len(args) != 0 {
							return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentFormat, 0, len(args))
						}
					}
					c := receiver.(*ChannelObject)

					if c.ChannelState == chClosed {
						return t.vm.InitErrorObject(errors.ChannelCloseError, sourceLine, errors.ChannelIsClosed)
					}

					num := <-c.Chan

					return t.vm.channelObjectMap.retrieveObj(num)
				}
			},
		},
	}
}

// Internal functions ===================================================

// Functions for initialization -----------------------------------------

func (vm *VM) initChannelClass() *RClass {
	class := vm.initializeClass(classes.ChannelClass, false)
	class.setBuiltinMethods(builtinChannelClassMethods(), true)
	class.setBuiltinMethods(builtinChannelInstanceMethods(), false)
	return class
}

// Polymorphic helper functions -----------------------------------------

// Value returns the object
func (co *ChannelObject) Value() interface{} {
	return co.Chan
}

// toString returns the object's name as the string format
func (co *ChannelObject) toString() string {
	return fmt.Sprintf("<Channel: %p>", co.Chan)
}

// toJSON just delegates to toString
func (co *ChannelObject) toJSON(t *Thread) string {
	return co.toString()
}

// copy returns the duplicate of the Array object
func (co *ChannelObject) copy() Object {
	newC := &ChannelObject{baseObj: &baseObj{class: co.class}, Chan: make(chan int)}
	return newC
}

// objectMap ==========================================================

type objectMap struct {
	store *sync.Map
}

// Polymorphic helper functions -----------------------------------------

// storeObj stores objects into the container map
// and update containerCount at the same time
func (m *objectMap) storeObj(obj Object) int {
	m.store.Store(obj.id(), obj)

	return obj.id()
}

// retrieveObj returns the objects with the number specified
func (m *objectMap) retrieveObj(num int) Object {
	obj, _ := m.store.Load(num)
	return obj.(Object)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package model

import (
	"fmt"
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
	"k8s.io/kops/util/pkg/distributions"
)

// SysctlBuilder set up our sysctls
type SysctlBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &SysctlBuilder{}

// Build is responsible for configuring sysctl settings
func (b *SysctlBuilder) Build(c *fi.ModelBuilderContext) error {
	var sysctls []string

	// Common settings
	{
		sysctls = append(sysctls,
			"# Kubernetes Settings",
			"")

		// A higher vm.max_map_count is great for elasticsearch, mongo, or other mmap users
		// See https://github.com/kubernetes/kops/issues/1340
		sysctls = append(sysctls, "vm.max_map_count = 262144",
			"")

		// See https://github.com/kubernetes/kubernetes/pull/38001
		sysctls = append(sysctls,
			"kernel.softlockup_panic = 1",
			"kernel.softlockup_all_cpu_backtrace = 1",
			"")

		// See https://github.com/kubernetes/kops/issues/6342
		portRange := b.Cluster.Spec.KubeAPIServer.ServiceNodePortRange
		if portRange == "" {
			portRange = "30000-32767" // Default kube-apiserver ServiceNodePortRange
		}
		sysctls = append(sysctls, "net.ipv4.ip_local_reserved_ports = "+portRange,
			"")

		// See https://github.com/kubernetes/kube-deploy/issues/261
		// and https://github.com/kubernetes/kops/issues/10206
		sysctls = append(sysctls,
			"# Increase the number of connections",
			"net.core.somaxconn = 32768",
			"",

			"# Maximum Socket Receive Buffer",
			"net.core.rmem_max = 16777216",
			"",

			"# Maximum Socket Send Buffer",
			"net.core.wmem_max = 16777216",
			"",

			"# Increase the maximum total buffer-space allocatable",
			"net.ipv4.tcp_wmem = 4096 87380 16777216",
			"net.ipv4.tcp_rmem = 4096 87380 16777216",
			"",

			"# Increase the number of outstanding syn requests allowed",
			"net.ipv4.tcp_max_syn_backlog = 8096",
			"",

			"# For persistent HTTP connections",
			"net.ipv4.tcp_slow_start_after_idle = 0",
			"",

			"# Allow to reuse TIME_WAIT sockets for new connections",
			"# when it is safe from protocol viewpoint",
			"net.ipv4.tcp_tw_reuse = 1",
			"",

			// We can't change the local_port_range without changing the NodePort range
			//"# Allowed local port range",
			//"net.ipv4.ip_local_port_range = 10240 65535",
			//"",

			"# Max number of packets that can be queued on interface input",
			"# If kernel is receiving packets faster than can be processed",
			"# this queue increases",
			"net.core.netdev_max_backlog = 16384",
			"",

			"# Increase size of file handles and inode cache",
			"fs.file-max = 2097152",
			"",

			"# Max number of inotify instances and watches for a user",
			"# Since dockerd runs as a single user, the default instances value of 128 per user is too low",
			"# e.g. uses of inotify: nginx ingress controller, kubectl logs -f",
			"fs.inotify.max_user_instances = 8192",
			"fs.inotify.max_user_watches = 524288",

			"# Additional sysctl flags that kubelet expects",
			"vm.overcommit_memory = 1",
			"kernel.panic = 10",
			"kernel.panic_on_oops = 1",
			"",
		)
	}

	// Running Flannel on CentOS7 / rhel7 needs custom settings
	if b.Cluster.Spec.Networking.Flannel != nil {
		proxyMode := b.Cluster.Spec.KubeProxy.ProxyMode
		if proxyMode == "" {
			proxyMode = "iptables"
		}

		if proxyMode == "iptables" && (b.Distribution == distributions.DistributionCentos7 || b.Distribution == distributions.DistributionRhel7) {
			sysctls = append(sysctls,
				"# Flannel settings on CentOS 7",
				"# Issue https://github.com/coreos/flannel/issues/902",
				"net.bridge.bridge-nf-call-ip6tables=1",
				"net.bridge.bridge-nf-call-iptables=1",
				"")
		}
	}

	if b.Cluster.Spec.CloudProvider == string(kops.CloudProviderAWS) {
		sysctls = append(sysctls,
			"# AWS settings",
			"",
			"# Issue #23395",
			"net.ipv4.neigh.default.gc_thresh1=0",
			"")
	}

	if b.Cluster.Spec.IsIPv6Only() {
		sysctls = append(sysctls,
			"# Enable IPv6 forwarding for network plugins that don't do it themselves",
			"net.ipv6.conf.all.forwarding=1",
			"")
	} else {
		sysctls = append(sysctls,
			"# Prevent docker from changing iptables: https://github.com/kubernetes/kubernetes/issues/40182",
			"net.ipv4.ip_forward=1",
			"")
	}

	if params := b.NodeupConfig.SysctlParameters; len(params) > 0 {
		sysctls = append(sysctls,
			"# Custom sysctl parameters from instance group spec",
			"")
		for _, param := range params {
			if !strings.ContainsRune(param, '=') {
				return fmt.Errorf("Invalid SysctlParameter: expected %q to contain '='", param)
			}
			sysctls = append(sysctls, param)
		}
	}

	if params := b.Cluster.Spec.SysctlParameters; len(params) > 0 {
		sysctls = append(sysctls,
			"# Custom sysctl parameters from cluster spec",
			"")
		for _, param := range params {
			if !strings.ContainsRune(param, '=') {
				return fmt.Errorf("Invalid SysctlParameter: expected %q to contain '='", param)
			}
			sysctls = append(sysctls, param)
		}
	}

	c.AddTask(&nodetasks.File{
		Path:            "/etc/sysctl.d/99-k8s-general.conf",
		Contents:        fi.NewStringResource(strings.Join(sysctls, "\n")),
		Type:            nodetasks.FileType_File,
		OnChangeExecute: [][]string{{"sysctl", "--system"}},
	})

	return nil
}
<commit_msg>Enable Router Advertisements for Debian 11<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package model

import (
	"fmt"
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
	"k8s.io/kops/util/pkg/distributions"
)

// SysctlBuilder set up our sysctls
type SysctlBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &SysctlBuilder{}

// Build is responsible for configuring sysctl settings
func (b *SysctlBuilder) Build(c *fi.ModelBuilderContext) error {
	var sysctls []string

	// Common settings
	{
		sysctls = append(sysctls,
			"# Kubernetes Settings",
			"")

		// A higher vm.max_map_count is great for elasticsearch, mongo, or other mmap users
		// See https://github.com/kubernetes/kops/issues/1340
		sysctls = append(sysctls, "vm.max_map_count = 262144",
			"")

		// See https://github.com/kubernetes/kubernetes/pull/38001
		sysctls = append(sysctls,
			"kernel.softlockup_panic = 1",
			"kernel.softlockup_all_cpu_backtrace = 1",
			"")

		// See https://github.com/kubernetes/kops/issues/6342
		portRange := b.Cluster.Spec.KubeAPIServer.ServiceNodePortRange
		if portRange == "" {
			portRange = "30000-32767" // Default kube-apiserver ServiceNodePortRange
		}
		sysctls = append(sysctls, "net.ipv4.ip_local_reserved_ports = "+portRange,
			"")

		// See https://github.com/kubernetes/kube-deploy/issues/261
		// and https://github.com/kubernetes/kops/issues/10206
		sysctls = append(sysctls,
			"# Increase the number of connections",
			"net.core.somaxconn = 32768",
			"",

			"# Maximum Socket Receive Buffer",
			"net.core.rmem_max = 16777216",
			"",

			"# Maximum Socket Send Buffer",
			"net.core.wmem_max = 16777216",
			"",

			"# Increase the maximum total buffer-space allocatable",
			"net.ipv4.tcp_wmem = 4096 87380 16777216",
			"net.ipv4.tcp_rmem = 4096 87380 16777216",
			"",

			"# Increase the number of outstanding syn requests allowed",
			"net.ipv4.tcp_max_syn_backlog = 8096",
			"",

			"# For persistent HTTP connections",
			"net.ipv4.tcp_slow_start_after_idle = 0",
			"",

			"# Allow to reuse TIME_WAIT sockets for new connections",
			"# when it is safe from protocol viewpoint",
			"net.ipv4.tcp_tw_reuse = 1",
			"",

			// We can't change the local_port_range without changing the NodePort range
			//"# Allowed local port range",
			//"net.ipv4.ip_local_port_range = 10240 65535",
			//"",

			"# Max number of packets that can be queued on interface input",
			"# If kernel is receiving packets faster than can be processed",
			"# this queue increases",
			"net.core.netdev_max_backlog = 16384",
			"",

			"# Increase size of file handles and inode cache",
			"fs.file-max = 2097152",
			"",

			"# Max number of inotify instances and watches for a user",
			"# Since dockerd runs as a single user, the default instances value of 128 per user is too low",
			"# e.g. uses of inotify: nginx ingress controller, kubectl logs -f",
			"fs.inotify.max_user_instances = 8192",
			"fs.inotify.max_user_watches = 524288",

			"# Additional sysctl flags that kubelet expects",
			"vm.overcommit_memory = 1",
			"kernel.panic = 10",
			"kernel.panic_on_oops = 1",
			"",
		)
	}

	// Running Flannel on CentOS7 / rhel7 needs custom settings
	if b.Cluster.Spec.Networking.Flannel != nil {
		proxyMode := b.Cluster.Spec.KubeProxy.ProxyMode
		if proxyMode == "" {
			proxyMode = "iptables"
		}

		if proxyMode == "iptables" && (b.Distribution == distributions.DistributionCentos7 || b.Distribution == distributions.DistributionRhel7) {
			sysctls = append(sysctls,
				"# Flannel settings on CentOS 7",
				"# Issue https://github.com/coreos/flannel/issues/902",
				"net.bridge.bridge-nf-call-ip6tables=1",
				"net.bridge.bridge-nf-call-iptables=1",
				"")
		}
	}

	if b.Cluster.Spec.CloudProvider == string(kops.CloudProviderAWS) {
		sysctls = append(sysctls,
			"# AWS settings",
			"",
			"# Issue #23395",
			"net.ipv4.neigh.default.gc_thresh1=0",
			"")
	}

	if b.Cluster.Spec.IsIPv6Only() {
		if b.Distribution == distributions.DistributionDebian11 {
			sysctls = append(sysctls,
				"# Enable Router Advertisements to get the default IPv6 route",
				"net.ipv6.conf.ens5.accept_ra=2")
		}
		sysctls = append(sysctls,
			"# Enable IPv6 forwarding for network plugins that don't do it themselves",
			"net.ipv6.conf.all.forwarding=1",
			"")
	} else {
		sysctls = append(sysctls,
			"# Prevent docker from changing iptables: https://github.com/kubernetes/kubernetes/issues/40182",
			"net.ipv4.ip_forward=1",
			"")
	}

	if params := b.NodeupConfig.SysctlParameters; len(params) > 0 {
		sysctls = append(sysctls,
			"# Custom sysctl parameters from instance group spec",
			"")
		for _, param := range params {
			if !strings.ContainsRune(param, '=') {
				return fmt.Errorf("Invalid SysctlParameter: expected %q to contain '='", param)
			}
			sysctls = append(sysctls, param)
		}
	}

	if params := b.Cluster.Spec.SysctlParameters; len(params) > 0 {
		sysctls = append(sysctls,
			"# Custom sysctl parameters from cluster spec",
			"")
		for _, param := range params {
			if !strings.ContainsRune(param, '=') {
				return fmt.Errorf("Invalid SysctlParameter: expected %q to contain '='", param)
			}
			sysctls = append(sysctls, param)
		}
	}

	c.AddTask(&nodetasks.File{
		Path:            "/etc/sysctl.d/99-k8s-general.conf",
		Contents:        fi.NewStringResource(strings.Join(sysctls, "\n")),
		Type:            nodetasks.FileType_File,
		OnChangeExecute: [][]string{{"sysctl", "--system"}},
	})

	return nil
}
<|endoftext|>


<commit_before>package pages

import (
	"encoding/json"
	"fmt"
	"github.com/elcuervo/geoip"
	mw "github.com/elcuervo/minimalweather/minimalweather"
	"html/template"
	"log"
	"math"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
)

type Homepage struct {
	w  http.ResponseWriter
	r  *http.Request
	cw *CityWeather
}

func (h *Homepage) getCoords() mw.Coordinates {
	var coords mw.Coordinates
	location_cookie, err := h.r.Cookie("mw-location")

	if err == nil {
		log.Println("From Cookie cache")
		parts := strings.Split(location_cookie.Value, "|")
		lat, _ := strconv.ParseFloat(parts[0], 64)
		lng, _ := strconv.ParseFloat(parts[1], 64)
		coords = mw.Coordinates{lat, lng}
	} else {
		log.Println("From geolocation")
		geo := h.geolocate()
		coords = mw.Coordinates{geo.Location.Latitude, geo.Location.Longitude}
	}

	return coords
}

func (h *Homepage) ipFromRemote() string {
	index := strings.LastIndex(h.r.RemoteAddr, ":")
	if index == -1 {
		return h.r.RemoteAddr
	}
	return h.r.RemoteAddr[:index]
}

func (h *Homepage) ipAddress() string {
	development := os.Getenv("DEVELOPMENT")
	if development != "" {
		return "186.52.170.66"
	}

	hdr := h.r.Header
	hdrRealIp := hdr.Get("X-Real-Ip")
	hdrForwardedFor := hdr.Get("X-Forwarded-For")

	if hdrRealIp == "" && hdrForwardedFor == "" {
		return h.ipFromRemote()
	}

	if hdrForwardedFor != "" {
		// X-Forwarded-For is potentially a list of addresses separated with ","
		parts := strings.Split(hdrForwardedFor, ",")
		for i, p := range parts {
			parts[i] = strings.TrimSpace(p)
		}
		// TODO: should return first non-local address
		return parts[0]
	}
	return hdrRealIp
}

func (h *Homepage) geolocate() geoip.Geolocation {
	var user_addr string

	user_addr = h.ipAddress()
	log.Println(user_addr)

	return <-mw.GetLocation(user_addr)
}

func (h *Homepage) handleUnit() {
	unit_cookie, err := h.r.Cookie("mw-unit")
	if err == nil {
		h.cw.Unit = unit_cookie.Value
	} else {
		h.cw.Unit = "C"
	}

	// Based on @chadot knowladge < 17 is minimun to confort temperature
	if h.cw.Weather.Temperature < 17 {
		h.cw.Cold = true
	} else {
		h.cw.Cold = false
	}

	if h.cw.Unit == "F" {
		h.cw.Weather.Temperature = ((h.cw.Weather.Temperature * 9) / 5) + 32
	}

	h.cw.Celsius = h.cw.Unit == "C"
}

func (h *Homepage) saveCityCache(city mw.City) {
	cookie := &http.Cookie{
		Name:  "mw-location",
		Value: fmt.Sprintf("%f|%f", city.Coords.Lat, city.Coords.Lng),
		Path:  "/",
	}

	http.SetCookie(h.w, cookie)

	city_cookie := &http.Cookie{
		Name:  "mw-city",
		Value: fmt.Sprintf("%s", url.QueryEscape(city.Name)),
		Path:  "/",
	}

	http.SetCookie(h.w, city_cookie)
}

func (h *Homepage) Render() {
	coords := h.getCoords()
	city := <-mw.FindByCoords(coords)
	weather := <-mw.GetWeather(city.Coords)

	h.cw = &CityWeather{City: city, Weather: weather}

	h.handleUnit()
	h.saveCityCache(city)

	t, _ := template.ParseFiles("./website/index.html")
	out, err := json.Marshal(h.cw)
	h.cw.JSON = string(out)
	h.cw.Weather.Temperature = math.Floor(h.cw.Weather.Temperature)
	err = t.Execute(h.w, h.cw)

	if err != nil {
		http.Error(h.w, err.Error(), http.StatusInternalServerError)
	}
}

func NewHomepage(w http.ResponseWriter, req *http.Request) *Homepage {
	home := new(Homepage)
	home.w = w
	home.r = req

	return home
}
<commit_msg>Use F when in US as default unit<commit_after>package pages

import (
	"encoding/json"
	"fmt"
	"github.com/elcuervo/geoip"
	mw "github.com/elcuervo/minimalweather/minimalweather"
	"html/template"
	"log"
	"math"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
)

type Homepage struct {
	w  http.ResponseWriter
	r  *http.Request
	cw *CityWeather
}

func (h *Homepage) getCoords() mw.Coordinates {
	var coords mw.Coordinates
	location_cookie, err := h.r.Cookie("mw-location")

	if err == nil {
		log.Println("From Cookie cache")
		parts := strings.Split(location_cookie.Value, "|")
		lat, _ := strconv.ParseFloat(parts[0], 64)
		lng, _ := strconv.ParseFloat(parts[1], 64)
		coords = mw.Coordinates{lat, lng}
	} else {
		log.Println("From geolocation")
		geo := h.geolocate()
		coords = mw.Coordinates{geo.Location.Latitude, geo.Location.Longitude}
	}

	return coords
}

func (h *Homepage) ipFromRemote() string {
	index := strings.LastIndex(h.r.RemoteAddr, ":")
	if index == -1 {
		return h.r.RemoteAddr
	}
	return h.r.RemoteAddr[:index]
}

func (h *Homepage) ipAddress() string {
	development := os.Getenv("DEVELOPMENT")
	if development != "" {
		return "186.52.170.66"
	}

	hdr := h.r.Header
	hdrRealIp := hdr.Get("X-Real-Ip")
	hdrForwardedFor := hdr.Get("X-Forwarded-For")

	if hdrRealIp == "" && hdrForwardedFor == "" {
		return h.ipFromRemote()
	}

	if hdrForwardedFor != "" {
		// X-Forwarded-For is potentially a list of addresses separated with ","
		parts := strings.Split(hdrForwardedFor, ",")
		for i, p := range parts {
			parts[i] = strings.TrimSpace(p)
		}
		// TODO: should return first non-local address
		return parts[0]
	}
	return hdrRealIp
}

func (h *Homepage) geolocate() geoip.Geolocation {
	var user_addr string

	user_addr = h.ipAddress()
	log.Println(user_addr)

	return <-mw.GetLocation(user_addr)
}

func (h *Homepage) handleUnit() {
	unit_cookie, err := h.r.Cookie("mw-unit")
	if err == nil {
		h.cw.Unit = unit_cookie.Value
	} else {
                if h.cw.City.Country == "US" {
                        h.cw.Unit = "F"
                } else {
                        h.cw.Unit = "C"
                }
	}

	// Based on @chadot knowladge < 17 is minimun to confort temperature
	if h.cw.Weather.Temperature < 17 {
		h.cw.Cold = true
	} else {
		h.cw.Cold = false
	}

	if h.cw.Unit == "F" {
		h.cw.Weather.Temperature = ((h.cw.Weather.Temperature * 9) / 5) + 32
	}

	h.cw.Celsius = h.cw.Unit == "C"
}

func (h *Homepage) saveCityCache(city mw.City) {
	cookie := &http.Cookie{
		Name:  "mw-location",
		Value: fmt.Sprintf("%f|%f", city.Coords.Lat, city.Coords.Lng),
		Path:  "/",
	}

	http.SetCookie(h.w, cookie)

	city_cookie := &http.Cookie{
		Name:  "mw-city",
		Value: fmt.Sprintf("%s", url.QueryEscape(city.Name)),
		Path:  "/",
	}

	http.SetCookie(h.w, city_cookie)
}

func (h *Homepage) Render() {
	coords := h.getCoords()
	city := <-mw.FindByCoords(coords)
	weather := <-mw.GetWeather(city.Coords)

	h.cw = &CityWeather{City: city, Weather: weather}

	h.handleUnit()
	h.saveCityCache(city)

	t, _ := template.ParseFiles("./website/index.html")
	out, err := json.Marshal(h.cw)
	h.cw.JSON = string(out)
	h.cw.Weather.Temperature = math.Floor(h.cw.Weather.Temperature)
	err = t.Execute(h.w, h.cw)

	if err != nil {
		http.Error(h.w, err.Error(), http.StatusInternalServerError)
	}
}

func NewHomepage(w http.ResponseWriter, req *http.Request) *Homepage {
	home := new(Homepage)
	home.w = w
	home.r = req

	return home
}
<|endoftext|>


<commit_before>package protocol

type DeleteTopicsRequest struct {
	APIVersion int16

	Topics  []string
	Timeout int32
}

func (c *DeleteTopicsRequest) Encode(e PacketEncoder) (err error) {
	if err = e.PutStringArray(c.Topics); err != nil {
		return err
	}
	e.PutInt32(c.Timeout)
	return nil
}

func (c *DeleteTopicsRequest) Decode(d PacketDecoder, version int16) (err error) {
	c.APIVersion = version
	c.Topics, err = d.StringArray()
	if err != nil {
		return err
	}
	c.Timeout, err = d.Int32()
	return err
}

func (c *DeleteTopicsRequest) Key() int16 {
	return DeleteTopicsKey
}

func (r *DeleteTopicsRequest) Version() int16 {
	return r.APIVersion
}
<commit_msg>protocol/delete topic request: turn timeout into a time.Duration<commit_after>package protocol

import "time"

type DeleteTopicsRequest struct {
	APIVersion int16

	Topics  []string
	Timeout time.Duration
}

func (r *DeleteTopicsRequest) Encode(e PacketEncoder) (err error) {
	if err = e.PutStringArray(r.Topics); err != nil {
		return err
	}
	e.PutInt32(int32(r.Timeout / time.Millisecond))
	return nil
}

func (r *DeleteTopicsRequest) Decode(d PacketDecoder, version int16) (err error) {
	r.APIVersion = version
	r.Topics, err = d.StringArray()
	if err != nil {
		return err
	}
	timeout, err := d.Int32()
	if err != nil {
		return err
	}
	r.Timeout = time.Duration(timeout) * time.Millisecond
	return err
}

func (r *DeleteTopicsRequest) Key() int16 {
	return DeleteTopicsKey
}

func (r *DeleteTopicsRequest) Version() int16 {
	return r.APIVersion
}
<|endoftext|>


<commit_before>package protocol

import (
	"fmt"
	"gdcl/fsm"
	"os"
	"time"
)

const (
	IDLE = iota
	LINK_REQUEST
	DATA_PHASE
	DISCONNECTING
)

const (
	LR byte = 1
	LD byte = 2
	LT byte = 4
	LA byte = 5
)

type PacketType struct {
	packetType byte
}

type OutstandingPacket struct {
	data               []byte
	sendSequenceNumber byte
}

type AckInfo struct {
	credit                byte
	receiveSequenceNumber byte
	lastAckSequenceNumber byte
}

type MNPConnectionLayer struct {
	state                      int
	stateTable                 map[int][]fsm.State
	maxInfoLength              uint16
	lastAckSequenceNumber      byte
	FromDockLink               chan []byte
	ToDockLink                 chan []byte
	FromPacketLayer            chan Packet
	ToPacketLayer              chan []byte
	writeQueue                 chan []byte
	ackChannel                 chan AckInfo
	outstandingPackets         []OutstandingPacket
	sendCreditStateVariable    byte
	receiveCreditStateVariable byte
	sendStateVariable          byte
	receiveStateVariable       byte
}

var connectionLayer MNPConnectionLayer

func (packetType PacketType) Matches(input interface{}) bool {
	return input.(*Packet).packetType == packetType.packetType
}

func sendLinkRequestResponse(state int, input interface{}, output interface{}, data interface{}) {
	layer := data.(*MNPConnectionLayer)
	packet := input.(*Packet)
	framingMode := packet.data[11]
	maxOutstanding := packet.data[14]
	dataPhaseOpt := packet.data[21]
	buf := []byte{23, LR, 2,
		1, 6, 1, 0, 0, 0, 0, 255,
		2, 1, framingMode,
		3, 1, maxOutstanding,
		4, 2, byte(layer.maxInfoLength & 0xff), byte(layer.maxInfoLength >> 8),
		8, 1, dataPhaseOpt}
	layer.outstandingPackets = make([]OutstandingPacket, 0, maxOutstanding)
	layer.ToPacketLayer <- buf
}

func handleLinkAcknowledgement(state int, input interface{}, output interface{}, data interface{}) {
	layer := data.(*MNPConnectionLayer)
	packet := input.(*Packet)
	receiveStateVariable := packet.data[0]
	adjustedCredit := int(packet.data[1]) - len(layer.outstandingPackets)
	if adjustedCredit > 0 && adjustedCredit <= 8 {
		layer.receiveCreditStateVariable = byte(adjustedCredit)
	} else {
		layer.receiveCreditStateVariable = 0
	}
	layer.ackChannel <- AckInfo{layer.receiveCreditStateVariable, receiveStateVariable, layer.lastAckSequenceNumber}
	layer.lastAckSequenceNumber = receiveStateVariable
}

func handleLinkTransfer(state int, input interface{}, output interface{}, data interface{}) {
	layer := data.(*MNPConnectionLayer)
	packet := input.(*Packet)
	layer.receiveStateVariable = packet.data[0]
	packet.data = packet.data[1:]
	layer.sendLinkAcknowledgement(layer.receiveStateVariable, 8)
	layer.ToDockLink <- packet.data
}

func closeConnection(state int, input interface{}, output interface{}, data interface{}) {
	fmt.Println("Disconnected")
	os.Exit(0)
}

func (layer *MNPConnectionLayer) sendLinkAcknowledgement(receiveSequenceNumber byte, credit byte) {
	buf := []byte{3, LA, receiveSequenceNumber, credit}
	layer.ToPacketLayer <- buf
}

func (layer *MNPConnectionLayer) sendLinkTransfer(data []byte) {
	layer.sendStateVariable++
	buf := make([]byte, len(data)+3)
	buf[0] = 2
	buf[1] = LT
	buf[2] = layer.sendStateVariable
	copy(buf[3:], data)
	layer.writeQueue <- buf
}

func (layer *MNPConnectionLayer) clearAcknowledgedPackets(ack AckInfo) {
	n := len(layer.outstandingPackets) - 1
	for n >= 0 && layer.outstandingPackets[n].sendSequenceNumber != ack.receiveSequenceNumber {
		n--
	}
	layer.outstandingPackets = layer.outstandingPackets[n+1:]
	if ack.receiveSequenceNumber == ack.lastAckSequenceNumber {
		for i := 0; i < int(layer.receiveCreditStateVariable) && i < len(layer.outstandingPackets); i++ {
			layer.ToPacketLayer <- layer.outstandingPackets[i].data
		}
	}
}

func (layer *MNPConnectionLayer) transition(packet *Packet) {
	layer.state = fsm.Transition(layer.stateTable, layer.state, packet, nil, layer)
}

func (layer *MNPConnectionLayer) reader() {
	go func() {
		for {
			packet := <-layer.FromPacketLayer
			layer.transition(&packet)
		}
	}()
}

func (layer *MNPConnectionLayer) writer() {
	go func() {
		for {
			buf := <-layer.FromDockLink
			for len(buf) > 0 {
				n := len(buf)
				if n > int(layer.maxInfoLength) {
					n = int(layer.maxInfoLength)
				}
				layer.sendLinkTransfer(buf[:n])
				buf = buf[n:]
			}
		}
	}()
}

func (layer *MNPConnectionLayer) writeQueueHandler() {
	go func() {
		for {
			if layer.receiveCreditStateVariable > 0 {
				select {
				case buf := <-layer.writeQueue:
					layer.outstandingPackets = append(layer.outstandingPackets, OutstandingPacket{buf, buf[2]})
					layer.ToPacketLayer <- buf
					layer.receiveCreditStateVariable--
				case ack := <-layer.ackChannel:
					layer.clearAcknowledgedPackets(ack)
				}
			} else {
				ack := <-layer.ackChannel
				layer.clearAcknowledgedPackets(ack)
			}
		}
	}()
}

func (layer *MNPConnectionLayer) keepAlive() {
	go func() {
		for {
			time.Sleep(3 * time.Second)
			if layer.state == DATA_PHASE {
				layer.sendLinkAcknowledgement(layer.receiveStateVariable, 8)
			}
		}
	}()
}

func MNPConnectionLayerNew(fromPacketLayer chan Packet, toPacketLayer chan []byte) *MNPConnectionLayer {
	connectionLayer.receiveCreditStateVariable = 8
	connectionLayer.FromPacketLayer = fromPacketLayer
	connectionLayer.ToPacketLayer = toPacketLayer
	connectionLayer.FromDockLink = make(chan []byte)
	connectionLayer.ToDockLink = make(chan []byte)
	connectionLayer.writeQueue = make(chan []byte)
	connectionLayer.ackChannel = make(chan AckInfo)
	connectionLayer.stateTable = map[int][]fsm.State{
		IDLE: {{Input: PacketType{LR}, NewState: LINK_REQUEST, Action: sendLinkRequestResponse}},
		LINK_REQUEST: {
			{Input: PacketType{LR}, NewState: LINK_REQUEST},
			{Input: PacketType{LA}, NewState: DATA_PHASE},
			{Input: PacketType{LD}, NewState: IDLE},
			{Input: PacketType{LT}, NewState: IDLE},
		},
		DATA_PHASE: {
			{Input: PacketType{LR}, NewState: IDLE},
			{Input: PacketType{LA}, NewState: DATA_PHASE, Action: handleLinkAcknowledgement},
			{Input: PacketType{LD}, NewState: IDLE, Action: closeConnection},
			{Input: PacketType{LT}, NewState: DATA_PHASE, Action: handleLinkTransfer},
		},
	}
	connectionLayer.writeQueueHandler()
	connectionLayer.reader()
	connectionLayer.writer()
	connectionLayer.keepAlive()
	return &connectionLayer
}
<commit_msg>Fix possible zero length info config<commit_after>package protocol

import (
	"fmt"
	"gdcl/fsm"
	"os"
	"time"
)

const (
	IDLE = iota
	LINK_REQUEST
	DATA_PHASE
	DISCONNECTING
)

const (
	LR byte = 1
	LD byte = 2
	LT byte = 4
	LA byte = 5
)

type PacketType struct {
	packetType byte
}

type OutstandingPacket struct {
	data               []byte
	sendSequenceNumber byte
}

type AckInfo struct {
	credit                byte
	receiveSequenceNumber byte
	lastAckSequenceNumber byte
}

type MNPConnectionLayer struct {
	state                      int
	stateTable                 map[int][]fsm.State
	maxInfoLength              uint16
	lastAckSequenceNumber      byte
	FromDockLink               chan []byte
	ToDockLink                 chan []byte
	FromPacketLayer            chan Packet
	ToPacketLayer              chan []byte
	writeQueue                 chan []byte
	ackChannel                 chan AckInfo
	outstandingPackets         []OutstandingPacket
	sendCreditStateVariable    byte
	receiveCreditStateVariable byte
	sendStateVariable          byte
	receiveStateVariable       byte
}

var connectionLayer MNPConnectionLayer

func (packetType PacketType) Matches(input interface{}) bool {
	return input.(*Packet).packetType == packetType.packetType
}

func sendLinkRequestResponse(state int, input interface{}, output interface{}, data interface{}) {
	layer := data.(*MNPConnectionLayer)
	packet := input.(*Packet)
	framingMode := packet.data[11]
	maxOutstanding := packet.data[14]
	dataPhaseOpt := packet.data[21]
	buf := []byte{23, LR, 2,
		1, 6, 1, 0, 0, 0, 0, 255,
		2, 1, framingMode,
		3, 1, maxOutstanding,
		4, 2, 64, 0,
		8, 1, dataPhaseOpt}
	layer.outstandingPackets = make([]OutstandingPacket, 0, maxOutstanding)
	layer.ToPacketLayer <- buf
}

func handleLinkAcknowledgement(state int, input interface{}, output interface{}, data interface{}) {
	layer := data.(*MNPConnectionLayer)
	packet := input.(*Packet)
	receiveStateVariable := packet.data[0]
	adjustedCredit := int(packet.data[1]) - len(layer.outstandingPackets)
	if adjustedCredit > 0 && adjustedCredit <= 8 {
		layer.receiveCreditStateVariable = byte(adjustedCredit)
	} else {
		layer.receiveCreditStateVariable = 0
	}
	layer.ackChannel <- AckInfo{layer.receiveCreditStateVariable, receiveStateVariable, layer.lastAckSequenceNumber}
	layer.lastAckSequenceNumber = receiveStateVariable
}

func handleLinkTransfer(state int, input interface{}, output interface{}, data interface{}) {
	layer := data.(*MNPConnectionLayer)
	packet := input.(*Packet)
	layer.receiveStateVariable = packet.data[0]
	packet.data = packet.data[1:]
	layer.sendLinkAcknowledgement(layer.receiveStateVariable, 8)
	layer.ToDockLink <- packet.data
}

func closeConnection(state int, input interface{}, output interface{}, data interface{}) {
	fmt.Println("Disconnected")
	os.Exit(0)
}

func (layer *MNPConnectionLayer) sendLinkAcknowledgement(receiveSequenceNumber byte, credit byte) {
	buf := []byte{3, LA, receiveSequenceNumber, credit}
	layer.ToPacketLayer <- buf
}

func (layer *MNPConnectionLayer) sendLinkTransfer(data []byte) {
	layer.sendStateVariable++
	buf := make([]byte, len(data)+3)
	buf[0] = 2
	buf[1] = LT
	buf[2] = layer.sendStateVariable
	copy(buf[3:], data)
	layer.writeQueue <- buf
}

func (layer *MNPConnectionLayer) clearAcknowledgedPackets(ack AckInfo) {
	n := len(layer.outstandingPackets) - 1
	for n >= 0 && layer.outstandingPackets[n].sendSequenceNumber != ack.receiveSequenceNumber {
		n--
	}
	layer.outstandingPackets = layer.outstandingPackets[n+1:]
	if ack.receiveSequenceNumber == ack.lastAckSequenceNumber {
		for i := 0; i < int(layer.receiveCreditStateVariable) && i < len(layer.outstandingPackets); i++ {
			layer.ToPacketLayer <- layer.outstandingPackets[i].data
		}
	}
}

func (layer *MNPConnectionLayer) transition(packet *Packet) {
	layer.state = fsm.Transition(layer.stateTable, layer.state, packet, nil, layer)
}

func (layer *MNPConnectionLayer) reader() {
	go func() {
		for {
			packet := <-layer.FromPacketLayer
			layer.transition(&packet)
		}
	}()
}

func (layer *MNPConnectionLayer) writer() {
	go func() {
		for {
			buf := <-layer.FromDockLink
			for len(buf) > 0 {
				n := len(buf)
				if n > int(layer.maxInfoLength) {
					n = int(layer.maxInfoLength)
				}
				layer.sendLinkTransfer(buf[:n])
				buf = buf[n:]
			}
		}
	}()
}

func (layer *MNPConnectionLayer) writeQueueHandler() {
	go func() {
		for {
			if layer.receiveCreditStateVariable > 0 {
				select {
				case buf := <-layer.writeQueue:
					layer.outstandingPackets = append(layer.outstandingPackets, OutstandingPacket{buf, buf[2]})
					layer.ToPacketLayer <- buf
					layer.receiveCreditStateVariable--
				case ack := <-layer.ackChannel:
					layer.clearAcknowledgedPackets(ack)
				}
			} else {
				ack := <-layer.ackChannel
				layer.clearAcknowledgedPackets(ack)
			}
		}
	}()
}

func (layer *MNPConnectionLayer) keepAlive() {
	go func() {
		for {
			time.Sleep(3 * time.Second)
			if layer.state == DATA_PHASE {
				layer.sendLinkAcknowledgement(layer.receiveStateVariable, 8)
			}
		}
	}()
}

func MNPConnectionLayerNew(fromPacketLayer chan Packet, toPacketLayer chan []byte) *MNPConnectionLayer {
	connectionLayer.receiveCreditStateVariable = 8
	connectionLayer.FromPacketLayer = fromPacketLayer
	connectionLayer.ToPacketLayer = toPacketLayer
	connectionLayer.FromDockLink = make(chan []byte)
	connectionLayer.ToDockLink = make(chan []byte)
	connectionLayer.writeQueue = make(chan []byte)
	connectionLayer.ackChannel = make(chan AckInfo)
	connectionLayer.stateTable = map[int][]fsm.State{
		IDLE: {{Input: PacketType{LR}, NewState: LINK_REQUEST, Action: sendLinkRequestResponse}},
		LINK_REQUEST: {
			{Input: PacketType{LR}, NewState: LINK_REQUEST},
			{Input: PacketType{LA}, NewState: DATA_PHASE},
			{Input: PacketType{LD}, NewState: IDLE},
			{Input: PacketType{LT}, NewState: IDLE},
		},
		DATA_PHASE: {
			{Input: PacketType{LR}, NewState: IDLE},
			{Input: PacketType{LA}, NewState: DATA_PHASE, Action: handleLinkAcknowledgement},
			{Input: PacketType{LD}, NewState: IDLE, Action: closeConnection},
			{Input: PacketType{LT}, NewState: DATA_PHASE, Action: handleLinkTransfer},
		},
	}
	connectionLayer.writeQueueHandler()
	connectionLayer.reader()
	connectionLayer.writer()
	connectionLayer.keepAlive()
	return &connectionLayer
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	// If message.new_chat_members
	if true {
		// member.name = message.new_chat_members
		member := "<username>"
		fmt.Printf("Вечер в хату, %s!\n", member)
	}
}
<commit_msg>Removed old helloworld code<commit_after><|endoftext|>


<commit_before>package gcache

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"golang.org/x/oauth2"
	"google.golang.org/api/drive/v3"
	"google.golang.org/api/googleapi"
)

var (
	oauth2TokenSource oauth2.TokenSource // The token is valid for 30 minutes.
)

// GetGDriveService returns the API service of Google Drive.
func GetGDriveService(
	r *http.Request,
) (
	*drive.Service,
	error,
) {
	n := 1
retry:
	service, err := drive.New(createGDriveClient(r))
	if err == nil {
		return service, nil
	}
	_, n, err = Triable(n, err)
	if err != nil {
		return nil, err
	}
	goto retry
}

func getGDriveFile(
	r *http.Request,
	name string,
	field googleapi.Field,
) (
	*drive.File,
	*drive.Service,
	error,
) {
	if field == "" {
		field = MinimumField
	}

	var refreshToken bool
	n := 1
refresh:
	service, err := GetGDriveService(r)
	if err != nil {
		return nil, nil, err
	}

retry:
	<-tokenBucketGDriveAPI
	fileList, err := service.Files.List().PageSize(1).Spaces("drive").Q(fmt.Sprintf("name='%s'", name)).Fields(field).Do()

	if err != nil {
		refreshToken, n, err = Triable(n, err)
		if err != nil {
			return nil, nil, err
		}
		if refreshToken {
			goto refresh
		}
		goto retry
	}

	if len(fileList.Files) <= 0 {
		return nil, nil, &DriveFileDoesNotExistError{}
	}
	return fileList.Files[0], service, nil
}

// GetGDriveFile returns a file on Google Drive.
func GetGDriveFile(
	r *http.Request,
	name string,
	field googleapi.Field,
) (
	*drive.File,
	error,
) {
	if field == "" {
		field = defaultField
	}

	file, _, err := getGDriveFile(r, name, field)
	if err != nil {
		return nil, err
	}

	return file, nil
}

// GetGDriveFileContent returns a file with content on Google Drive.
func GetGDriveFileContent(
	r *http.Request,
	name string,
	field googleapi.Field,
) (
	*drive.File,
	[]byte, // payload
	error,
) {
	if field == "" {
		field = defaultField
	}

	file, service, err := getGDriveFile(r, name, field)
	if err != nil {
		return nil, nil, err
	}
	fileID := file.Id

	var payload []byte

	var refreshToken bool
	n := 1
retry:
	httpResponse, err := service.Files.Export(fileID, mimeTxt).Download()
	if IsFileNotExportableError(err) {
		<-tokenBucketGDriveAPI
		err = service.Files.Delete(fileID).Do()
		if err != nil {
			// pass
		}
		return nil, nil, &DriveFileDoesNotExistError{}
	}
	if err != nil {
		refreshToken, n, err = Triable(n, err)
		if err != nil {
			return nil, nil, err
		}
		if refreshToken {
			service, err = GetGDriveService(r)
			if err != nil {
				return nil, nil, err
			}
		}
		goto retry
	}

	defer httpResponse.Body.Close()
	payload, err = ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		return nil, nil, err
	}
	return file, payload, err
}

// Triable returns whether it can retry or not.
func Triable(
	retries int,
	err error,
) (
	bool, //refreshToken
	int, //retries
	error,
) {
	if err == nil {
		return false, retries, nil
	}
	if retries < 1 {
		retries = 1
	}
	if IsInvalidSecurityTicket(err) {
		oauth2TokenSource = nil
		return true, retries, nil
	}
	if IsServerError(err) {
		retries, err = sleeping(retries)
		if err != nil {
			return false, retries, err
		}
		return false, retries, nil
	}
	return false, retries, err
}

func sleeping(
	n int,
) (
	int,
	error,
) {
	if n > 16 {
		return 0, errors.New("Sleeping Timeout")
	}
	time.Sleep(time.Duration(n)*time.Second + time.Duration(random.Intn(1000))*time.Millisecond)
	return n * 2, nil
}
<commit_msg>refactor<commit_after>package gcache

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"golang.org/x/oauth2"
	"google.golang.org/api/drive/v3"
	"google.golang.org/api/googleapi"
)

var (
	oauth2TokenSource oauth2.TokenSource // The token is valid for 30 minutes.
)

// GetGDriveService returns the API service of Google Drive.
func GetGDriveService(
	r *http.Request,
) (
	*drive.Service,
	error,
) {
	n := 1
retry:
	service, err := drive.New(createGDriveClient(r))
	if err == nil {
		return service, nil
	}
	_, n, err = Triable(n, err)
	if err != nil {
		return nil, err
	}
	goto retry
}

func getGDriveFile(
	r *http.Request,
	name string,
	field googleapi.Field,
) (
	*drive.File,
	*drive.Service,
	error,
) {
	if field == "" {
		field = MinimumField
	}

	var refreshToken bool
	n := 1
refresh:
	service, err := GetGDriveService(r)
	if err != nil {
		return nil, nil, err
	}

retry:
	<-tokenBucketGDriveAPI
	fileList, err := service.Files.List().PageSize(1).Spaces("drive").Q(fmt.Sprintf("name='%s'", name)).Fields(field).Do()

	if err != nil {
		refreshToken, n, err = Triable(n, err)
		if err != nil {
			return nil, nil, err
		}
		if refreshToken {
			goto refresh
		}
		goto retry
	}

	if len(fileList.Files) <= 0 {
		return nil, nil, &DriveFileDoesNotExistError{}
	}
	return fileList.Files[0], service, nil
}

// GetGDriveFile returns a file on Google Drive.
func GetGDriveFile(
	r *http.Request,
	name string,
	field googleapi.Field,
) (
	*drive.File,
	error,
) {
	if field == "" {
		field = defaultField
	}

	file, _, err := getGDriveFile(r, name, field)
	if err != nil {
		return nil, err
	}

	return file, nil
}

// GetGDriveFileContent returns a file with content on Google Drive.
func GetGDriveFileContent(
	r *http.Request,
	name string,
	field googleapi.Field,
) (
	*drive.File,
	[]byte, // payload
	error,
) {
	if field == "" {
		field = defaultField
	}

	file, service, err := getGDriveFile(r, name, field)
	if err != nil {
		return nil, nil, err
	}
	fileID := file.Id

	var payload []byte

	var refreshToken bool
	n := 1
retry:
	httpResponse, err := service.Files.Export(fileID, mimeTxt).Download()
	if IsFileNotExportableError(err) {
		<-tokenBucketGDriveAPI
		err = service.Files.Delete(fileID).Do()
		if err != nil {
			// pass
		}
		return nil, nil, &DriveFileDoesNotExistError{}
	}
	if err != nil {
		refreshToken, n, err = Triable(n, err)
		if err != nil {
			return nil, nil, err
		}
		if refreshToken {
			service, err = GetGDriveService(r)
			if err != nil {
				return nil, nil, err
			}
		}
		goto retry
	}

	defer httpResponse.Body.Close()
	payload, err = ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		return nil, nil, err
	}
	return file, payload, err
}

// Triable returns whether it can retry or not.
func Triable(
	retries int,
	err error,
) (
	bool, //refreshToken
	int, //retries
	error,
) {
	if err == nil {
		return false, retries, nil
	}
	if retries < 1 {
		retries = 1
	}
	switch {
	case IsInvalidSecurityTicket(err):
		oauth2TokenSource = nil
		return true, retries, nil
	case IsServerError(err):
		retries, err = sleeping(retries)
		if err != nil {
			return false, retries, err
		}
		return false, retries, nil
	}
	return false, retries, err
}

func sleeping(
	n int,
) (
	int,
	error,
) {
	if n > 16 {
		return 0, errors.New("Sleeping Timeout")
	}
	time.Sleep(time.Duration(n)*time.Second + time.Duration(random.Intn(1000))*time.Millisecond)
	return n * 2, nil
}
<|endoftext|>


<commit_before>package rest_json

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

	"github.com/Everlane/evan/config"
	"github.com/Everlane/evan/context"
)

type CreateDeploymentRequest struct {
	Application string `json:"application"`
	Environment string `json:"environment"`
	Ref         string `json:"ref"`
}

func (cdr *CreateDeploymentRequest) newDeployment(app *config.Application) (*context.Deployment, error) {
	return context.NewDeployment(app.Wrapper(), cdr.Environment, cdr.Ref)
}

type CreateDeploymentHandler struct {
	Applications *config.Applications
}

func (handler *CreateDeploymentHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	var deploymentRequest CreateDeploymentRequest
	err := handler.readRequestInto(req, &deploymentRequest)
	if err != nil {
		respondWithError(res, err, http.StatusInternalServerError)
		return
	}

	app := handler.Applications.FindApplicationByName(deploymentRequest.Application)
	if app == nil {
		err = fmt.Errorf("Application not found: '%v'", deploymentRequest.Application)
		respondWithError(res, err, http.StatusNotFound)
		return
	}

	deployment, err := deploymentRequest.newDeployment(app)
	if err != nil {
		respondWithError(res, err, http.StatusNotFound)
		return
	}

	err = deployment.SetStoreAndSave(handler.Applications.Store)
	if err != nil {
		respondWithError(res, err, http.StatusInternalServerError)
		return
	}

	err = deployment.CheckPreconditions()
	if err != nil {
		respondWithError(res, err, http.StatusPreconditionFailed)
		return
	}

	// Start the party!
	go deployment.RunPhases()

	message := fmt.Sprintf(
		"Deploying %v to %v for %v",
		deploymentRequest.Ref,
		deploymentRequest.Environment,
		deploymentRequest.Application,
	)
	respondWithOk(res, message)
}

func (handler *CreateDeploymentHandler) readRequestInto(req *http.Request, val interface{}) error {
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return err
	}

	return json.Unmarshal(body, val)
}
<commit_msg>Add optional pre-deployment hook in REST API handler<commit_after>package rest_json

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

	"github.com/Everlane/evan/common"
	"github.com/Everlane/evan/config"
	"github.com/Everlane/evan/context"
)

type CreateDeploymentRequest struct {
	Application string `json:"application"`
	Environment string `json:"environment"`
	Ref         string `json:"ref"`
}

func (cdr *CreateDeploymentRequest) newDeployment(app *config.Application) (*context.Deployment, error) {
	return context.NewDeployment(app.Wrapper(), cdr.Environment, cdr.Ref)
}

type CreateDeploymentHandler struct {
	Applications *config.Applications
	PreDeployment func(*http.Request, common.Deployment) error
}

func (handler *CreateDeploymentHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	var deploymentRequest CreateDeploymentRequest
	err := handler.readRequestInto(req, &deploymentRequest)
	if err != nil {
		respondWithError(res, err, http.StatusInternalServerError)
		return
	}

	app := handler.Applications.FindApplicationByName(deploymentRequest.Application)
	if app == nil {
		err = fmt.Errorf("Application not found: '%v'", deploymentRequest.Application)
		respondWithError(res, err, http.StatusNotFound)
		return
	}

	deployment, err := deploymentRequest.newDeployment(app)
	if err != nil {
		respondWithError(res, err, http.StatusNotFound)
		return
	}

	err = deployment.SetStoreAndSave(handler.Applications.Store)
	if err != nil {
		respondWithError(res, err, http.StatusInternalServerError)
		return
	}

	if handler.PreDeployment != nil {
		err = handler.PreDeployment(req, deployment)
		if err != nil {
			respondWithError(res, err, http.StatusInternalServerError)
			return
		}
	}

	err = deployment.CheckPreconditions()
	if err != nil {
		respondWithError(res, err, http.StatusPreconditionFailed)
		return
	}

	// Start the party!
	go deployment.RunPhases()

	message := fmt.Sprintf(
		"Deploying %v to %v for %v",
		deploymentRequest.Ref,
		deploymentRequest.Environment,
		deploymentRequest.Application,
	)
	respondWithOk(res, message)
}

func (handler *CreateDeploymentHandler) readRequestInto(req *http.Request, val interface{}) error {
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return err
	}

	return json.Unmarshal(body, val)
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 render

import (
	"bytes"
	"fmt"
	"html"
	"io"
	"path"
	"sort"
	"strconv"
	"strings"

	"github.com/googlecodelabs/tools/claat/types"
)

// MD renders nodes as markdown for the target env.
func MD(ctx Context, nodes ...types.Node) (string, error) {
	var buf bytes.Buffer
	if err := WriteMD(&buf, ctx.Env, ctx.Format, nodes...); err != nil {
		return "", err
	}
	return buf.String(), nil
}

// WriteMD does the same as MD but outputs rendered markup to w.
func WriteMD(w io.Writer, env string, fmt string, nodes ...types.Node) error {
	mw := mdWriter{w: w, env: env, format: fmt, Prefix: []byte("")}
	return mw.write(nodes...)
}

type mdWriter struct {
	w                  io.Writer // output writer
	env                string    // target environment
	format             string    // target template
	err                error     // error during any writeXxx methods
	lineStart          bool
	isWritingTableCell bool   // used to override lineStart for correct cell formatting
	isWritingList      bool   // used for override newblock when needed
	Prefix             []byte // prefix for e.g. blockquote content
}

func (mw *mdWriter) writeBytes(b []byte) {
	if mw.err != nil {
		return
	}
	if mw.lineStart {
		_, mw.err = mw.w.Write(mw.Prefix)
	}
	mw.lineStart = len(b) > 0 && b[len(b)-1] == '\n'
	_, mw.err = mw.w.Write(b)
}

func (mw *mdWriter) writeString(s string) {
	mw.writeBytes([]byte(s))
}

func (mw *mdWriter) writeEscape(s string) {
	s = html.EscapeString(s)
	mw.writeString(ReplaceDoubleCurlyBracketsWithEntity(s))
}

func (mw *mdWriter) space() {
	if !mw.lineStart {
		mw.writeString(" ")
	}
}

func (mw *mdWriter) newBlock() {
	if !mw.lineStart {
		mw.writeString("\n")
	}
	mw.writeString("\n")
}

func (mw *mdWriter) matchEnv(v []string) bool {
	if len(v) == 0 || mw.env == "" {
		return true
	}
	i := sort.SearchStrings(v, mw.env)
	return i < len(v) && v[i] == mw.env
}

func (mw *mdWriter) write(nodes ...types.Node) error {
	for _, n := range nodes {
		if !mw.matchEnv(n.Env()) {
			continue
		}
		switch n := n.(type) {
		case *types.TextNode:
			mw.text(n)
		case *types.ImageNode:
			mw.image(n)
		case *types.URLNode:
			mw.url(n)
		case *types.ButtonNode:
			mw.write(n.Content.Nodes...)
		case *types.CodeNode:
			mw.code(n)
		case *types.ListNode:
			mw.list(n)
		case *types.ImportNode:
			if len(n.Content.Nodes) == 0 {
				break
			}
			mw.write(n.Content.Nodes...)
		case *types.ItemsListNode:
			mw.itemsList(n)
		case *types.GridNode:
			mw.table(n)
		case *types.InfoboxNode:
			mw.infobox(n)
		case *types.SurveyNode:
			mw.survey(n)
		case *types.HeaderNode:
			mw.header(n)
		case *types.YouTubeNode:
			mw.youtube(n)
		}
		if mw.err != nil {
			return mw.err
		}
	}
	return nil
}

func (mw *mdWriter) text(n *types.TextNode) {
	tr := strings.TrimLeft(n.Value, " \t\n\r\f\v")
	left := n.Value[0:(len(n.Value) - len(tr))]
	t := strings.TrimRight(tr, " \t\n\r\f\v")
	right := tr[len(t):len(tr)]

	mw.writeString(left)

	if n.Bold {
		mw.writeString("**")
	}
	if n.Italic {
		mw.writeString("*")
	}
	if n.Code {
		mw.writeString("`")
	}

	t = strings.Replace(t, "<", "<", -1)
	t = strings.Replace(t, ">", ">", -1)

	mw.writeString(t)

	if n.Code {
		mw.writeString("`")
	}
	if n.Italic {
		mw.writeString("*")
	}
	if n.Bold {
		mw.writeString("**")
	}

	mw.writeString(right)
}

func (mw *mdWriter) image(n *types.ImageNode) {
	mw.space()
	mw.writeString("<img ")
	mw.writeString(fmt.Sprintf("src=%q ", n.Src))

	if n.Alt != "" {
		mw.writeString(fmt.Sprintf("alt=%q ", n.Alt))
	} else {
		mw.writeString(fmt.Sprintf("alt=%q ", path.Base(n.Src)))
	}

	if n.Title != "" {
		mw.writeString(fmt.Sprintf("title=%q ", n.Title))
	}

	// If available append width to the src string of the image.
	if n.Width > 0 {
		mw.writeString(fmt.Sprintf(" width=\"%.2f\" ", n.Width))
	}

	mw.writeString("/>")
}

func (mw *mdWriter) url(n *types.URLNode) {
	mw.space()
	if n.URL != "" {
		// Look-ahead for button syntax.
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			mw.writeString("<button>")
		}
		mw.writeString("[")
	}
	mw.write(n.Content.Nodes...)
	if n.URL != "" {
		mw.writeString("](")
		mw.writeString(n.URL)
		mw.writeString(")")
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			// Look-ahead for button syntax.
			mw.writeString("</button>")
		}
	}
}

func (mw *mdWriter) code(n *types.CodeNode) {
	if n.Empty() {
		return
	}
	mw.newBlock()
	defer mw.writeString("\n")
	mw.writeString("```")
	if n.Term {
		mw.writeString("console")
	} else {
		mw.writeString(n.Lang)
	}
	mw.writeString("\n")
	mw.writeString(n.Value)
	if !mw.lineStart {
		mw.writeString("\n")
	}
	mw.writeString("```")
}

func (mw *mdWriter) list(n *types.ListNode) {
	if n.Block() == true {
		mw.newBlock()
	}
	mw.write(n.Nodes...)
	if !mw.lineStart && !mw.isWritingTableCell {
		mw.writeString("\n")
	}
}

func (mw *mdWriter) itemsList(n *types.ItemsListNode) {
	mw.isWritingList = true
	if n.Block() == true {
		mw.newBlock()
	}
	for i, item := range n.Items {
		s := "* "
		if n.Type() == types.NodeItemsList && n.Start > 0 {
			s = strconv.Itoa(i+n.Start) + ". "
		}
		mw.writeString(s)
		mw.write(item.Nodes...)
		if !mw.lineStart {
			mw.writeString("\n")
		}
	}
	mw.isWritingList = false
}

func (mw *mdWriter) infobox(n *types.InfoboxNode) {
	// InfoBoxes are comprised of a ListNode with the contents of the InfoBox.
	// Writing the ListNode directly results in extra newlines in the md output
	// which breaks the formatting. So instead, write the ListNode's children
	// directly and don't write the ListNode itself.
	mw.newBlock()
	k := "aside positive"
	if n.Kind == types.InfoboxNegative {
		k = "aside negative"
	}
	mw.Prefix = []byte("> ")
	mw.writeString(k)
	mw.writeString("\n")

	for _, cn := range n.Content.Nodes {
		mw.write(cn)
	}

	mw.Prefix = []byte("")
}

func (mw *mdWriter) survey(n *types.SurveyNode) {
	mw.newBlock()
	mw.writeString("<form>")
	mw.writeString("\n")
	for _, g := range n.Groups {
		mw.writeString("<name>")
		mw.writeEscape(g.Name)
		mw.writeString("</name>")
		mw.writeString("\n")
		for _, o := range g.Options {
			mw.writeString("<input value=\"")
			mw.writeEscape(o)
			mw.writeString("\">")
			mw.writeString("\n")
		}
	}
	mw.writeString("</form>")
}

func (mw *mdWriter) header(n *types.HeaderNode) {
	mw.newBlock()
	mw.writeString(strings.Repeat("#", n.Level+1))
	mw.writeString(" ")
	mw.write(n.Content.Nodes...)
	if !mw.lineStart {
		mw.writeString("\n")
	}
}

func (mw *mdWriter) youtube(n *types.YouTubeNode) {
	if !mw.isWritingList {
		mw.newBlock()
	}
	mw.writeString(fmt.Sprintf(`<video id="%s"></video>`, n.VideoID))
}

func (mw *mdWriter) table(n *types.GridNode) {
	// If table content is empty, don't output the table.
	if n.Empty() {
		return
	}

	mw.writeString("\n")
	maxcols := maxColsInTable(n)
	for rowIndex, row := range n.Rows {
		mw.writeString("|")
		for _, cell := range row {
			mw.isWritingTableCell = true
			mw.writeString(" ")

			// Check cell content for newlines and replace with inline HTML if newlines are present.
			var nw bytes.Buffer
			WriteMD(&nw, mw.env, mw.format, cell.Content.Nodes...)
			if bytes.ContainsRune(nw.Bytes(), '\n') {
				for _, cn := range cell.Content.Nodes {
					cn.MutateBlock(false) // don't treat content as a new block
					var nw2 bytes.Buffer
					WriteHTML(&nw2, mw.env, mw.format, cn)
					mw.writeBytes(bytes.Replace(nw2.Bytes(), []byte("\n"), []byte(""), -1))
				}
			} else {
				mw.writeBytes(nw.Bytes())
			}

			mw.writeString(" |")
		}
		if rowIndex == 0 && len(row) < maxcols {
			for i := 0; i < maxcols-len(row); i++ {
				mw.writeString(" |")
			}
		}
		mw.writeString("\n")

		// Write header bottom border
		if rowIndex == 0 {
			mw.writeString("|")
			for i := 0; i < maxcols; i++ {
				mw.writeString(" --- |")
			}
			mw.writeString("\n")
		}

		mw.isWritingTableCell = false
	}
}

func maxColsInTable(n *types.GridNode) int {
	m := 0
	for _, row := range n.Rows {
		if len(row) > m {
			m = len(row)
		}
	}
	return m
}
<commit_msg>Escapes parens in URLs (#513)<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 render

import (
	"bytes"
	"fmt"
	"html"
	"io"
	"path"
	"sort"
	"strconv"
	"strings"

	"github.com/googlecodelabs/tools/claat/types"
)

// MD renders nodes as markdown for the target env.
func MD(ctx Context, nodes ...types.Node) (string, error) {
	var buf bytes.Buffer
	if err := WriteMD(&buf, ctx.Env, ctx.Format, nodes...); err != nil {
		return "", err
	}
	return buf.String(), nil
}

// WriteMD does the same as MD but outputs rendered markup to w.
func WriteMD(w io.Writer, env string, fmt string, nodes ...types.Node) error {
	mw := mdWriter{w: w, env: env, format: fmt, Prefix: []byte("")}
	return mw.write(nodes...)
}

type mdWriter struct {
	w                  io.Writer // output writer
	env                string    // target environment
	format             string    // target template
	err                error     // error during any writeXxx methods
	lineStart          bool
	isWritingTableCell bool   // used to override lineStart for correct cell formatting
	isWritingList      bool   // used for override newblock when needed
	Prefix             []byte // prefix for e.g. blockquote content
}

func (mw *mdWriter) writeBytes(b []byte) {
	if mw.err != nil {
		return
	}
	if mw.lineStart {
		_, mw.err = mw.w.Write(mw.Prefix)
	}
	mw.lineStart = len(b) > 0 && b[len(b)-1] == '\n'
	_, mw.err = mw.w.Write(b)
}

func (mw *mdWriter) writeString(s string) {
	mw.writeBytes([]byte(s))
}

func (mw *mdWriter) writeEscape(s string) {
	s = html.EscapeString(s)
	mw.writeString(ReplaceDoubleCurlyBracketsWithEntity(s))
}

func (mw *mdWriter) space() {
	if !mw.lineStart {
		mw.writeString(" ")
	}
}

func (mw *mdWriter) newBlock() {
	if !mw.lineStart {
		mw.writeString("\n")
	}
	mw.writeString("\n")
}

func (mw *mdWriter) matchEnv(v []string) bool {
	if len(v) == 0 || mw.env == "" {
		return true
	}
	i := sort.SearchStrings(v, mw.env)
	return i < len(v) && v[i] == mw.env
}

func (mw *mdWriter) write(nodes ...types.Node) error {
	for _, n := range nodes {
		if !mw.matchEnv(n.Env()) {
			continue
		}
		switch n := n.(type) {
		case *types.TextNode:
			mw.text(n)
		case *types.ImageNode:
			mw.image(n)
		case *types.URLNode:
			mw.url(n)
		case *types.ButtonNode:
			mw.write(n.Content.Nodes...)
		case *types.CodeNode:
			mw.code(n)
		case *types.ListNode:
			mw.list(n)
		case *types.ImportNode:
			if len(n.Content.Nodes) == 0 {
				break
			}
			mw.write(n.Content.Nodes...)
		case *types.ItemsListNode:
			mw.itemsList(n)
		case *types.GridNode:
			mw.table(n)
		case *types.InfoboxNode:
			mw.infobox(n)
		case *types.SurveyNode:
			mw.survey(n)
		case *types.HeaderNode:
			mw.header(n)
		case *types.YouTubeNode:
			mw.youtube(n)
		}
		if mw.err != nil {
			return mw.err
		}
	}
	return nil
}

func (mw *mdWriter) text(n *types.TextNode) {
	tr := strings.TrimLeft(n.Value, " \t\n\r\f\v")
	left := n.Value[0:(len(n.Value) - len(tr))]
	t := strings.TrimRight(tr, " \t\n\r\f\v")
	right := tr[len(t):len(tr)]

	mw.writeString(left)

	if n.Bold {
		mw.writeString("**")
	}
	if n.Italic {
		mw.writeString("*")
	}
	if n.Code {
		mw.writeString("`")
	}

	t = strings.Replace(t, "<", "<", -1)
	t = strings.Replace(t, ">", ">", -1)

	mw.writeString(t)

	if n.Code {
		mw.writeString("`")
	}
	if n.Italic {
		mw.writeString("*")
	}
	if n.Bold {
		mw.writeString("**")
	}

	mw.writeString(right)
}

func (mw *mdWriter) image(n *types.ImageNode) {
	mw.space()
	mw.writeString("<img ")
	mw.writeString(fmt.Sprintf("src=%q ", n.Src))

	if n.Alt != "" {
		mw.writeString(fmt.Sprintf("alt=%q ", n.Alt))
	} else {
		mw.writeString(fmt.Sprintf("alt=%q ", path.Base(n.Src)))
	}

	if n.Title != "" {
		mw.writeString(fmt.Sprintf("title=%q ", n.Title))
	}

	// If available append width to the src string of the image.
	if n.Width > 0 {
		mw.writeString(fmt.Sprintf(" width=\"%.2f\" ", n.Width))
	}

	mw.writeString("/>")
}

func (mw *mdWriter) url(n *types.URLNode) {
	mw.space()
	if n.URL != "" {
		// Look-ahead for button syntax.
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			mw.writeString("<button>")
		}
		mw.writeString("[")
	}
	mw.write(n.Content.Nodes...)
	if n.URL != "" {
		// escape parentheses
		strings.Replace(n.URL, "(", "%28", -1)
		strings.Replace(n.URL, ")", "%29", -1)
		mw.writeString("](")
		mw.writeString(n.URL)
		mw.writeString(")")
		if _, ok := n.Content.Nodes[0].(*types.ButtonNode); ok {
			// Look-ahead for button syntax.
			mw.writeString("</button>")
		}
	}
}

func (mw *mdWriter) code(n *types.CodeNode) {
	if n.Empty() {
		return
	}
	mw.newBlock()
	defer mw.writeString("\n")
	mw.writeString("```")
	if n.Term {
		mw.writeString("console")
	} else {
		mw.writeString(n.Lang)
	}
	mw.writeString("\n")
	mw.writeString(n.Value)
	if !mw.lineStart {
		mw.writeString("\n")
	}
	mw.writeString("```")
}

func (mw *mdWriter) list(n *types.ListNode) {
	if n.Block() == true {
		mw.newBlock()
	}
	mw.write(n.Nodes...)
	if !mw.lineStart && !mw.isWritingTableCell {
		mw.writeString("\n")
	}
}

func (mw *mdWriter) itemsList(n *types.ItemsListNode) {
	mw.isWritingList = true
	if n.Block() == true {
		mw.newBlock()
	}
	for i, item := range n.Items {
		s := "* "
		if n.Type() == types.NodeItemsList && n.Start > 0 {
			s = strconv.Itoa(i+n.Start) + ". "
		}
		mw.writeString(s)
		mw.write(item.Nodes...)
		if !mw.lineStart {
			mw.writeString("\n")
		}
	}
	mw.isWritingList = false
}

func (mw *mdWriter) infobox(n *types.InfoboxNode) {
	// InfoBoxes are comprised of a ListNode with the contents of the InfoBox.
	// Writing the ListNode directly results in extra newlines in the md output
	// which breaks the formatting. So instead, write the ListNode's children
	// directly and don't write the ListNode itself.
	mw.newBlock()
	k := "aside positive"
	if n.Kind == types.InfoboxNegative {
		k = "aside negative"
	}
	mw.Prefix = []byte("> ")
	mw.writeString(k)
	mw.writeString("\n")

	for _, cn := range n.Content.Nodes {
		mw.write(cn)
	}

	mw.Prefix = []byte("")
}

func (mw *mdWriter) survey(n *types.SurveyNode) {
	mw.newBlock()
	mw.writeString("<form>")
	mw.writeString("\n")
	for _, g := range n.Groups {
		mw.writeString("<name>")
		mw.writeEscape(g.Name)
		mw.writeString("</name>")
		mw.writeString("\n")
		for _, o := range g.Options {
			mw.writeString("<input value=\"")
			mw.writeEscape(o)
			mw.writeString("\">")
			mw.writeString("\n")
		}
	}
	mw.writeString("</form>")
}

func (mw *mdWriter) header(n *types.HeaderNode) {
	mw.newBlock()
	mw.writeString(strings.Repeat("#", n.Level+1))
	mw.writeString(" ")
	mw.write(n.Content.Nodes...)
	if !mw.lineStart {
		mw.writeString("\n")
	}
}

func (mw *mdWriter) youtube(n *types.YouTubeNode) {
	if !mw.isWritingList {
		mw.newBlock()
	}
	mw.writeString(fmt.Sprintf(`<video id="%s"></video>`, n.VideoID))
}

func (mw *mdWriter) table(n *types.GridNode) {
	// If table content is empty, don't output the table.
	if n.Empty() {
		return
	}

	mw.writeString("\n")
	maxcols := maxColsInTable(n)
	for rowIndex, row := range n.Rows {
		mw.writeString("|")
		for _, cell := range row {
			mw.isWritingTableCell = true
			mw.writeString(" ")

			// Check cell content for newlines and replace with inline HTML if newlines are present.
			var nw bytes.Buffer
			WriteMD(&nw, mw.env, mw.format, cell.Content.Nodes...)
			if bytes.ContainsRune(nw.Bytes(), '\n') {
				for _, cn := range cell.Content.Nodes {
					cn.MutateBlock(false) // don't treat content as a new block
					var nw2 bytes.Buffer
					WriteHTML(&nw2, mw.env, mw.format, cn)
					mw.writeBytes(bytes.Replace(nw2.Bytes(), []byte("\n"), []byte(""), -1))
				}
			} else {
				mw.writeBytes(nw.Bytes())
			}

			mw.writeString(" |")
		}
		if rowIndex == 0 && len(row) < maxcols {
			for i := 0; i < maxcols-len(row); i++ {
				mw.writeString(" |")
			}
		}
		mw.writeString("\n")

		// Write header bottom border
		if rowIndex == 0 {
			mw.writeString("|")
			for i := 0; i < maxcols; i++ {
				mw.writeString(" --- |")
			}
			mw.writeString("\n")
		}

		mw.isWritingTableCell = false
	}
}

func maxColsInTable(n *types.GridNode) int {
	m := 0
	for _, row := range n.Rows {
		if len(row) > m {
			m = len(row)
		}
	}
	return m
}
<|endoftext|>


<commit_before>package run

import (
	"fmt"
	"os"
	"sync"

	"github.com/raviqqe/tisp/src/lib/compile"
	"github.com/raviqqe/tisp/src/lib/core"
)

const maxConcurrentOutputs = 256

var sem = make(chan bool, maxConcurrentOutputs)

// Run runs outputs.
func Run(os []compile.Output) {
	// TODO: Ensure results are OutputTypes.

	wg := sync.WaitGroup{}

	for _, v := range os {
		wg.Add(1)

		if v.Expanded() {
			go func() {
				evalOutputList(v.Value())
				wg.Done()
			}()
		} else {
			sem <- true
			go runOutput(v.Value(), &wg)
		}
	}

	wg.Wait()
}

func evalOutputList(t *core.Thunk) {
	wg := sync.WaitGroup{}

	for {
		v := core.PApp(core.Equal, t, core.EmptyList).Eval()

		if b, ok := v.(core.BoolType); !ok {
			failOnError(core.NotBoolError(v).Eval().(core.ErrorType))
		} else if b {
			break
		}

		wg.Add(1)
		sem <- true
		go runOutput(core.PApp(core.First, t), &wg)

		t = core.PApp(core.Rest, t)
	}

	wg.Wait()
}

func runOutput(t *core.Thunk, wg *sync.WaitGroup) {
	if err, ok := t.EvalOutput().(core.ErrorType); ok {
		failOnError(err)
	}

	<-sem
	wg.Done()
}

func failOnError(err core.ErrorType) {
	fmt.Fprint(os.Stderr, err.Lines())
	os.Exit(1)
}
<commit_msg>Remove todo which has been done<commit_after>package run

import (
	"fmt"
	"os"
	"sync"

	"github.com/raviqqe/tisp/src/lib/compile"
	"github.com/raviqqe/tisp/src/lib/core"
)

const maxConcurrentOutputs = 256

var sem = make(chan bool, maxConcurrentOutputs)

// Run runs outputs.
func Run(os []compile.Output) {
	wg := sync.WaitGroup{}

	for _, v := range os {
		wg.Add(1)

		if v.Expanded() {
			go func() {
				evalOutputList(v.Value())
				wg.Done()
			}()
		} else {
			sem <- true
			go runOutput(v.Value(), &wg)
		}
	}

	wg.Wait()
}

func evalOutputList(t *core.Thunk) {
	wg := sync.WaitGroup{}

	for {
		v := core.PApp(core.Equal, t, core.EmptyList).Eval()

		if b, ok := v.(core.BoolType); !ok {
			failOnError(core.NotBoolError(v).Eval().(core.ErrorType))
		} else if b {
			break
		}

		wg.Add(1)
		sem <- true
		go runOutput(core.PApp(core.First, t), &wg)

		t = core.PApp(core.Rest, t)
	}

	wg.Wait()
}

func runOutput(t *core.Thunk, wg *sync.WaitGroup) {
	if err, ok := t.EvalOutput().(core.ErrorType); ok {
		failOnError(err)
	}

	<-sem
	wg.Done()
}

func failOnError(err core.ErrorType) {
	fmt.Fprint(os.Stderr, err.Lines())
	os.Exit(1)
}
<|endoftext|>


<commit_before>// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gredis_test

import (
	"fmt"
	"github.com/gogf/gf/container/gvar"
	"github.com/gogf/gf/frame/g"
)

func Example_autoMarshalUnmarshalMap() {
	var (
		err    error
		result *gvar.Var
		key    = "user"
		data   = g.Map{
			"id":   10000,
			"name": "john",
		}
	)
	_, err = g.Redis().Do("SET", key, data)
	if err != nil {
		panic(err)
	}
	result, err = g.Redis().DoVar("GET", key)
	if err != nil {
		panic(err)
	}
	fmt.Println(result.Map())
}

func Example_autoMarshalUnmarshalStruct() {
	type User struct {
		Id   int
		Name string
	}
	var (
		err    error
		result *gvar.Var
		key    = "user"
		user   = &User{
			Id:   10000,
			Name: "john",
		}
	)

	_, err = g.Redis().Do("SET", key, user)
	if err != nil {
		panic(err)
	}
	result, err = g.Redis().DoVar("GET", key)
	if err != nil {
		panic(err)
	}

	var user2 *User
	if err = result.Struct(&user2); err != nil {
		panic(err)
	}
	fmt.Println(user2.Id, user2.Name)
}
<commit_msg>add more example for package gredis<commit_after>// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gredis_test

import (
	"fmt"
	"github.com/gogf/gf/container/gvar"
	"github.com/gogf/gf/frame/g"
)

func Example_autoMarshalUnmarshalMap() {
	var (
		err    error
		result *gvar.Var
		key    = "user"
		data   = g.Map{
			"id":   10000,
			"name": "john",
		}
	)
	_, err = g.Redis().Do("SET", key, data)
	if err != nil {
		panic(err)
	}
	result, err = g.Redis().DoVar("GET", key)
	if err != nil {
		panic(err)
	}
	fmt.Println(result.Map())
}

func Example_autoMarshalUnmarshalStruct() {
	type User struct {
		Id   int
		Name string
	}
	var (
		err    error
		result *gvar.Var
		key    = "user"
		user   = &User{
			Id:   10000,
			Name: "john",
		}
	)

	_, err = g.Redis().Do("SET", key, user)
	if err != nil {
		panic(err)
	}
	result, err = g.Redis().DoVar("GET", key)
	if err != nil {
		panic(err)
	}

	var user2 *User
	if err = result.Struct(&user2); err != nil {
		panic(err)
	}
	fmt.Println(user2.Id, user2.Name)
}

func Example_hashSet() {
	var (
		err    error
		result *gvar.Var
		key    = "user"
	)
	_, err = g.Redis().Do("HSET", key, "id", 10000)
	if err != nil {
		panic(err)
	}
	_, err = g.Redis().Do("HSET", key, "name", "john")
	if err != nil {
		panic(err)
	}
	result, err = g.Redis().DoVar("HGETALL", key)
	if err != nil {
		panic(err)
	}
	fmt.Println(result.Map())

	// May Output:
	// map[id:10000 name:john]
}
<|endoftext|>


<commit_before>package consultant

import (
	"reflect"
	"sync"
	"time"

	"github.com/hashicorp/consul/api"
)

type WatchPlanType string

const (
	// retryInterval is the base retry value
	retryInterval = 5 * time.Second

	// set an upper limit to how long we are prepared to wait for a response from a watched endpoint.
	maxBackOffTime = 180 * time.Second

	WatchPlanTypeService     WatchPlanType = "service"
	WatchPlanTypeServiceList WatchPlanType = "service-list"
	WatchPlanTypeKey         WatchPlanType = "key"
	WatchPlanTypeKeyList     WatchPlanType = "key-list"
	WatchPlanTypeEvent       WatchPlanType = "event"
)

// WatchAction is used to watch for a diff
type WatchAction func(*WatchPlan) (uint64, interface{}, error)

// WatchHandler is used to handle new data
type WatchHandler func(uint64, interface{})

// WatchPlan is the parsed version of a watch specification. A watch provides
// the details of a query, which generates a view into the Consul data store.
// This view is watched for changes and a handler is invoked to take any
// appropriate actions.
// Simplified version based on hashicorp/consul/watch
type WatchPlan struct {
	Type WatchPlanType

	Action  WatchAction
	Handler WatchHandler

	StopOnError bool

	lastIndex  uint64
	lastResult interface{}

	stop     bool
	stopCh   chan struct{}
	stopLock sync.RWMutex
}

// create the watch plan
func NewWatchPlan() *WatchPlan {
	return &WatchPlan{
		stopCh: make(chan struct{}, 1),
	}
}

// Stop stops a running watchplan
func (p *WatchPlan) Stop() error {
	p.stopLock.Lock()
	defer p.stopLock.Unlock()

	var code WatchPlanErrorCode

	if p.stop {
		code = WatchPlanErrorAlreadyStopped
	} else {
		p.stop = true
		p.stopCh <- struct{}{}
		close(p.stopCh)
	}

	return getWatchPlanError(code)
}

// NewServiceWatchPlan builds a WatchPlan for a specific service
func NewServiceWatchPlan(c *api.Client, name, tag string, passingOnly bool, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeService
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		nodes, meta, err := c.Health().Service(name, tag, passingOnly, options)
		if err != nil {
			return 0, nil, err
		}
		return meta.LastIndex, nodes, err
	}

	return wp, nil
}

// NewServiceListPlan builds a watch plan to list of available services
func NewServiceListPlan(c *api.Client, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeServiceList
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		services, meta, err := c.Catalog().Services(options)
		if err != nil {
			return 0, nil, err
		}
		return meta.LastIndex, services, err
	}
	return wp, nil
}

// NewKeyPlan builds a WatchPlan for a particular key
func NewKeyPlan(c *api.Client, key string, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeKey
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		kv, qm, err := c.KV().Get(key, options)
		if err != nil {
			return 0, nil, err
		}
		if nil == kv {
			return 0, nil, getWatchPlanError(WatchPlanErrorKeyNotFound)
		}

		return qm.LastIndex, kv, err
	}

	return wp, nil
}

// NewKeyListPlan builds a WatchPlan for a particular key prefix
func NewKeyListPlan(c *api.Client, prefix string, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeKeyList
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		kvps, qm, err := c.KV().List(prefix, options)
		if err != nil {
			return 0, nil, err
		}
		return qm.LastIndex, kvps, err
	}
	return wp, nil
}

// NewEventPlan builds a WatchPlan for events optionally filtering my name if specified
func NewEventPlan(c *api.Client, name string, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeEvent
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		eventClient := c.Event()
		events, qm, err := eventClient.List(name, options)
		if err != nil {
			return 0, nil, err
		}

		// Prune to only the new events
		for i := 0; i < len(events); i++ {
			if eventClient.IDToIndex(events[i].ID) == p.lastIndex {
				events = events[i+1:]
				break
			}
		}
		return qm.LastIndex, events, err
	}
	return wp, nil
}

// RunWatchPlan is used to run a watch plan - the instance should have a valid client.
// The WatchPlan's Handler() is triggered when change is detected on the watched endpoint.
func RunWatchPlan(wp *WatchPlan) error {
	var err error
	var index uint64
	var result interface{}

	// check if plan has been stopped or is stopping
	wp.stopLock.RLock()
	if wp.stop {
		wp.stopLock.RUnlock()
		return getWatchPlanError(WatchPlanErrorAlreadyStopped)
	}
	wp.stopLock.RUnlock()

	// Loop until we are canceled
	failures := 0
OUTER:

	for {
		select {
		case <-wp.stopCh:
			return err
		default:
			// Invoke the handler
			index, result, err = wp.Action(wp)

			// Check if we should terminate since the function
			// could have blocked for a while
			wp.stopLock.RLock()
			if wp.stop {
				wp.stopLock.RUnlock()
				return err
			}
			wp.stopLock.RUnlock()

			// Handle an error in the watch function
			if err != nil {
				if wp.StopOnError {
					wp.Stop()
					continue OUTER
				}

				// Perform an quadratic backoff
				failures++
				retry := retryInterval * time.Duration(failures*failures)
				if retry > maxBackOffTime {
					retry = maxBackOffTime
				}
				log.Printf("[watchplan] Watch (type: %s) errored: %v, retry in %v",
					wp.Type, err, retry)

				select {
				case <-time.After(retry):
					wp.stopLock.RLock()
					if wp.stop {
						wp.stopLock.RUnlock()
						return err
					}
					wp.stopLock.RUnlock()
					continue OUTER
				}
			}

			// Clear the failures
			failures = 0

			// If the index is unchanged do nothing
			if index == wp.lastIndex {
				continue
			}

			// Update the index, look for change
			oldIndex := wp.lastIndex
			wp.lastIndex = index

			// discard the first change (from an unknown state)
			if oldIndex == 0 {
				continue
			}

			// make damn sure we have a change
			if reflect.DeepEqual(wp.lastResult, result) {
				continue
			}

			// Handle the updated result
			wp.lastResult = result
			if wp.Handler != nil {
				wp.Handler(index, result)
			}
		}
	}
}
<commit_msg>strange npe...<commit_after>package consultant

import (
	"reflect"
	"sync"
	"time"

	"github.com/hashicorp/consul/api"
)

type WatchPlanType string

const (
	// retryInterval is the base retry value
	retryInterval = 5 * time.Second

	// set an upper limit to how long we are prepared to wait for a response from a watched endpoint.
	maxBackOffTime = 180 * time.Second

	WatchPlanTypeService     WatchPlanType = "service"
	WatchPlanTypeServiceList WatchPlanType = "service-list"
	WatchPlanTypeKey         WatchPlanType = "key"
	WatchPlanTypeKeyList     WatchPlanType = "key-list"
	WatchPlanTypeEvent       WatchPlanType = "event"
)

// WatchAction is used to watch for a diff
type WatchAction func(*WatchPlan) (uint64, interface{}, error)

// WatchHandler is used to handle new data
type WatchHandler func(uint64, interface{})

// WatchPlan is the parsed version of a watch specification. A watch provides
// the details of a query, which generates a view into the Consul data store.
// This view is watched for changes and a handler is invoked to take any
// appropriate actions.
// Simplified version based on hashicorp/consul/watch
type WatchPlan struct {
	Type WatchPlanType

	Action  WatchAction
	Handler WatchHandler

	StopOnError bool

	lastIndex  uint64
	lastResult interface{}

	stop     bool
	stopCh   chan struct{}
	stopLock sync.RWMutex
}

// create the watch plan
func NewWatchPlan() *WatchPlan {
	return &WatchPlan{
		stopCh:   make(chan struct{}, 1),
		stopLock: sync.RWMutex{},
	}
}

// Stop stops a running watchplan
func (p *WatchPlan) Stop() error {
	p.stopLock.Lock()
	defer p.stopLock.Unlock()

	var code WatchPlanErrorCode

	if p.stop {
		code = WatchPlanErrorAlreadyStopped
	} else {
		p.stop = true
		p.stopCh <- struct{}{}
		close(p.stopCh)
	}

	return getWatchPlanError(code)
}

// NewServiceWatchPlan builds a WatchPlan for a specific service
func NewServiceWatchPlan(c *api.Client, name, tag string, passingOnly bool, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeService
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		nodes, meta, err := c.Health().Service(name, tag, passingOnly, options)
		if err != nil {
			return 0, nil, err
		}
		return meta.LastIndex, nodes, err
	}

	return wp, nil
}

// NewServiceListPlan builds a watch plan to list of available services
func NewServiceListPlan(c *api.Client, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeServiceList
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		services, meta, err := c.Catalog().Services(options)
		if err != nil {
			return 0, nil, err
		}
		return meta.LastIndex, services, err
	}
	return wp, nil
}

// NewKeyPlan builds a WatchPlan for a particular key
func NewKeyPlan(c *api.Client, key string, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeKey
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		kv, qm, err := c.KV().Get(key, options)
		if err != nil {
			return 0, nil, err
		}
		if nil == kv {
			return 0, nil, getWatchPlanError(WatchPlanErrorKeyNotFound)
		}

		return qm.LastIndex, kv, err
	}

	return wp, nil
}

// NewKeyListPlan builds a WatchPlan for a particular key prefix
func NewKeyListPlan(c *api.Client, prefix string, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeKeyList
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		kvps, qm, err := c.KV().List(prefix, options)
		if err != nil {
			return 0, nil, err
		}
		return qm.LastIndex, kvps, err
	}
	return wp, nil
}

// NewEventPlan builds a WatchPlan for events optionally filtering my name if specified
func NewEventPlan(c *api.Client, name string, queryOptions api.QueryOptions, handler WatchHandler) (*WatchPlan, error) {
	wp := NewWatchPlan()
	wp.Type = WatchPlanTypeEvent
	wp.Handler = handler

	options := &queryOptions

	wp.Action = func(p *WatchPlan) (uint64, interface{}, error) {
		options.WaitIndex = p.lastIndex
		eventClient := c.Event()
		events, qm, err := eventClient.List(name, options)
		if err != nil {
			return 0, nil, err
		}

		// Prune to only the new events
		for i := 0; i < len(events); i++ {
			if eventClient.IDToIndex(events[i].ID) == p.lastIndex {
				events = events[i+1:]
				break
			}
		}
		return qm.LastIndex, events, err
	}
	return wp, nil
}

// RunWatchPlan is used to run a watch plan - the instance should have a valid client.
// The WatchPlan's Handler() is triggered when change is detected on the watched endpoint.
func RunWatchPlan(wp *WatchPlan) error {
	var err error
	var index uint64
	var result interface{}

	// check if plan has been stopped or is stopping
	wp.stopLock.RLock()
	if wp.stop {
		wp.stopLock.RUnlock()
		return getWatchPlanError(WatchPlanErrorAlreadyStopped)
	}
	wp.stopLock.RUnlock()

	// Loop until we are canceled
	failures := 0
OUTER:

	for {
		select {
		case <-wp.stopCh:
			return err
		default:
			// Invoke the handler
			index, result, err = wp.Action(wp)

			// Check if we should terminate since the function
			// could have blocked for a while
			wp.stopLock.RLock()
			if wp.stop {
				wp.stopLock.RUnlock()
				return err
			}
			wp.stopLock.RUnlock()

			// Handle an error in the watch function
			if err != nil {
				if wp.StopOnError {
					wp.Stop()
					continue OUTER
				}

				// Perform an quadratic backoff
				failures++
				retry := retryInterval * time.Duration(failures*failures)
				if retry > maxBackOffTime {
					retry = maxBackOffTime
				}
				log.Printf("[watchplan] Watch (type: %s) errored: %v, retry in %v",
					wp.Type, err, retry)

				select {
				case <-time.After(retry):
					wp.stopLock.RLock()
					if wp.stop {
						wp.stopLock.RUnlock()
						return err
					}
					wp.stopLock.RUnlock()
					continue OUTER
				}
			}

			// Clear the failures
			failures = 0

			// If the index is unchanged do nothing
			if index == wp.lastIndex {
				continue
			}

			// Update the index, look for change
			oldIndex := wp.lastIndex
			wp.lastIndex = index

			// discard the first change (from an unknown state)
			if oldIndex == 0 {
				continue
			}

			// make damn sure we have a change
			if reflect.DeepEqual(wp.lastResult, result) {
				continue
			}

			// Handle the updated result
			wp.lastResult = result
			if wp.Handler != nil {
				wp.Handler(index, result)
			}
		}
	}
}
<|endoftext|>