<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"net"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/uber-go/zap"
)

// HTTPServer like, http.Server but improved management of listening and serving
// Allows you to listen on port 0, query for real OS port and then serve requests
type HTTPServer struct {
	*http.Server
	Logger zap.Logger

	listeningSocket net.Listener
	closing         bool

	RealPort int32
	RealAddr string
}

// JustListen will only listen on port and query real addr
func (server *HTTPServer) JustListen() (net.Listener, error) {
	addr := server.Addr
	if addr == "" {
		addr = ":http"
	}

	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return nil, err
	}
	server.listeningSocket = ln

	realAddr := ln.Addr().(*net.TCPAddr)
	server.RealPort = int32(realAddr.Port)
	server.RealAddr = realAddr.IP.String() + ":" +
		strconv.Itoa(int(server.RealPort))

	return ln, nil
}

// JustServe will serve all incoming requests
func (server *HTTPServer) JustServe(waitGroup *sync.WaitGroup) {
	ln := server.listeningSocket.(*net.TCPListener)

	err := server.Serve(tcpKeepAliveListener{ln})
	if err != nil && !server.closing {
		server.Logger.Error("Error http serving",
			zap.String("error", err.Error()),
		)
	}

	waitGroup.Done()
}

// Close the listening socket
func (server *HTTPServer) Close() {
	server.closing = true
	err := server.listeningSocket.Close()
	if err != nil {
		server.Logger.Error("Error closing listening socket",
			zap.String("error", err.Error()),
		)
	}
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	_ = tc.SetKeepAlive(true)
	_ = tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<commit_msg>runtime/http_server: fix nil pointer in HttpServer.Close()<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"net"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/uber-go/zap"
)

// HTTPServer like, http.Server but improved management of listening and serving
// Allows you to listen on port 0, query for real OS port and then serve requests
type HTTPServer struct {
	*http.Server
	Logger zap.Logger

	listeningSocket net.Listener
	closing         bool

	RealPort int32
	RealAddr string
}

// JustListen will only listen on port and query real addr
func (server *HTTPServer) JustListen() (net.Listener, error) {
	addr := server.Addr
	if addr == "" {
		addr = ":http"
	}

	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return nil, err
	}
	server.listeningSocket = ln

	realAddr := ln.Addr().(*net.TCPAddr)
	server.RealPort = int32(realAddr.Port)
	server.RealAddr = realAddr.IP.String() + ":" +
		strconv.Itoa(int(server.RealPort))

	return ln, nil
}

// JustServe will serve all incoming requests
func (server *HTTPServer) JustServe(waitGroup *sync.WaitGroup) {
	ln := server.listeningSocket.(*net.TCPListener)

	err := server.Serve(tcpKeepAliveListener{ln})
	if err != nil && !server.closing {
		server.Logger.Error("Error http serving",
			zap.String("error", err.Error()),
		)
	}

	waitGroup.Done()
}

// Close the listening socket
func (server *HTTPServer) Close() {
	server.closing = true
	if server.listeningSocket == nil {
		return
	}

	err := server.listeningSocket.Close()
	if err != nil {
		server.Logger.Error("Error closing listening socket",
			zap.String("error", err.Error()),
		)
	}
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	_ = tc.SetKeepAlive(true)
	_ = tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<|endoftext|>


<commit_before>// (c) 2021 Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package config

import (
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/spf13/viper"
)

// BuildViper returns the viper environment from parsing config file from
// default search paths and any parsed command line flags
func BuildViper(fs *flag.FlagSet, args []string) (*viper.Viper, error) {
	pfs, err := buildPFlagSet(fs)
	if err != nil {
		return nil, err
	}
	if err := pfs.Parse(args); err != nil {
		return nil, err
	}

	v := viper.New()
	if err := v.BindPFlags(pfs); err != nil {
		return nil, err
	}
	if v.IsSet(ConfigFileKey) {
		v.SetConfigFile(os.ExpandEnv(v.GetString(ConfigFileKey)))
		if err := v.ReadInConfig(); err != nil {
			return nil, err
		}
	}

	// Config deprecations must be after v.ReadInConfig
	deprecateConfigs(v, fs.Output())
	return v, nil
}

func deprecateConfigs(v *viper.Viper, output io.Writer) {
	for key, message := range deprecatedKeys {
		if v.InConfig(key) {
			fmt.Fprintf(output, "Config %s has been deprecated, %s\n", key, message)
		}
	}
}
<commit_msg>Configuration via env vars in avalanchego (#678)<commit_after>// (c) 2021 Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package config

import (
	"flag"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/spf13/viper"
)

// BuildViper returns the viper environment from parsing config file from
// default search paths and any parsed command line flags
func BuildViper(fs *flag.FlagSet, args []string) (*viper.Viper, error) {
	pfs, err := buildPFlagSet(fs)
	if err != nil {
		return nil, err
	}
	if err := pfs.Parse(args); err != nil {
		return nil, err
	}

	v := viper.New()
	v.AutomaticEnv()
	v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
	v.SetEnvPrefix("avago")
	if err := v.BindPFlags(pfs); err != nil {
		return nil, err
	}
	if v.IsSet(ConfigFileKey) {
		v.SetConfigFile(os.ExpandEnv(v.GetString(ConfigFileKey)))
		if err := v.ReadInConfig(); err != nil {
			return nil, err
		}
	}

	// Config deprecations must be after v.ReadInConfig
	deprecateConfigs(v, fs.Output())
	return v, nil
}

func deprecateConfigs(v *viper.Viper, output io.Writer) {
	for key, message := range deprecatedKeys {
		if v.InConfig(key) {
			fmt.Fprintf(output, "Config %s has been deprecated, %s\n", key, message)
		}
	}
}
<|endoftext|>


<commit_before>package veneur

import (
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/kelseyhightower/envconfig"

	"gopkg.in/yaml.v2"
)

const defaultBufferSizeBytes = 1048576 * 2 // 2 MB

// ReadProxyConfig unmarshals the proxy config file and slurps in its data.
func ReadProxyConfig(path string) (c ProxyConfig, err error) {
	f, err := os.Open(path)
	if err != nil {
		return c, err
	}
	defer f.Close()

	bts, err := ioutil.ReadAll(f)
	if err != nil {
		return
	}
	err = yaml.Unmarshal(bts, &c)
	if err != nil {
		return
	}

	err = envconfig.Process("veneur", &c)
	if err != nil {
		log.Fatal(err.Error())
	}

	return c, nil
}

// ReadConfig unmarshals the config file and slurps in it's data.
func ReadConfig(path string) (c Config, err error) {
	f, err := os.Open(path)
	if err != nil {
		return c, err
	}
	defer f.Close()
	return readConfig(f)
}

func readConfig(r io.Reader) (c Config, err error) {
	// Unfortunately the YAML package does not
	// support reader inputs
	// TODO(aditya) convert this when the
	// upstream PR lands
	bts, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}
	err = yaml.Unmarshal(bts, &c)
	if err != nil {
		return
	}

	err = envconfig.Process("veneur", &c)
	if err != nil {
		log.Fatal(err.Error())
	}

	if c.Hostname == "" && !c.OmitEmptyHostname {
		c.Hostname, _ = os.Hostname()
	}

	if c.ReadBufferSizeBytes == 0 {
		c.ReadBufferSizeBytes = defaultBufferSizeBytes
	}

	if c.Key != "" {
		log.Warn("The config key `key` is deprecated and replaced with `datadog_api_key` and will be removed in 2.0!")
		// If they set the DatadogAPIKey, favor it. Otherwise, replace it.
		if c.DatadogAPIKey == "" {
			c.DatadogAPIKey = c.Key
		}
	}

	if c.APIHostname != "" {
		log.Warn("The config key `api_hostname` is deprecated and replaced with `datadog_api_hostname` and will be removed in 2.0!")
		if c.DatadogAPIHostname == "" {
			c.DatadogAPIHostname = c.APIHostname
		}
	}

	if c.TraceAPIAddress != "" {
		log.Warn("The config key `trace_api_address` is deprecated and replaced with `datadog_trace_api_hostname` and will be removed in 2.0!")
		if c.DatadogTraceAPIAddress == "" {
			c.DatadogTraceAPIAddress = c.TraceAPIAddress
		}
	}

	if c.TraceAddress != "" {
		log.Warn("The config key `trace_address` is deprecated and replaced with `ssf_address` and will be removed in 2.0!")
		if c.SsfAddress == "" {
			c.SsfAddress = c.TraceAddress
		}
	}

	return c, nil
}

// ParseInterval handles parsing the flush interval as a time.Duration
func (c Config) ParseInterval() (time.Duration, error) {
	return time.ParseDuration(c.Interval)
}
<commit_msg>Return errors on failed envconfig.<commit_after>package veneur

import (
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/kelseyhightower/envconfig"

	"gopkg.in/yaml.v2"
)

const defaultBufferSizeBytes = 1048576 * 2 // 2 MB

// ReadProxyConfig unmarshals the proxy config file and slurps in its data.
func ReadProxyConfig(path string) (c ProxyConfig, err error) {
	f, err := os.Open(path)
	if err != nil {
		return c, err
	}
	defer f.Close()

	bts, err := ioutil.ReadAll(f)
	if err != nil {
		return
	}
	err = yaml.Unmarshal(bts, &c)
	if err != nil {
		return
	}

	err = envconfig.Process("veneur", &c)
	if err != nil {
		return c, err
	}

	return c, nil
}

// ReadConfig unmarshals the config file and slurps in it's data.
func ReadConfig(path string) (c Config, err error) {
	f, err := os.Open(path)
	if err != nil {
		return c, err
	}
	defer f.Close()
	return readConfig(f)
}

func readConfig(r io.Reader) (c Config, err error) {
	// Unfortunately the YAML package does not
	// support reader inputs
	// TODO(aditya) convert this when the
	// upstream PR lands
	bts, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}
	err = yaml.Unmarshal(bts, &c)
	if err != nil {
		return
	}

	err = envconfig.Process("veneur", &c)
	if err != nil {
		return c, err
	}

	if c.Hostname == "" && !c.OmitEmptyHostname {
		c.Hostname, _ = os.Hostname()
	}

	if c.ReadBufferSizeBytes == 0 {
		c.ReadBufferSizeBytes = defaultBufferSizeBytes
	}

	if c.Key != "" {
		log.Warn("The config key `key` is deprecated and replaced with `datadog_api_key` and will be removed in 2.0!")
		// If they set the DatadogAPIKey, favor it. Otherwise, replace it.
		if c.DatadogAPIKey == "" {
			c.DatadogAPIKey = c.Key
		}
	}

	if c.APIHostname != "" {
		log.Warn("The config key `api_hostname` is deprecated and replaced with `datadog_api_hostname` and will be removed in 2.0!")
		if c.DatadogAPIHostname == "" {
			c.DatadogAPIHostname = c.APIHostname
		}
	}

	if c.TraceAPIAddress != "" {
		log.Warn("The config key `trace_api_address` is deprecated and replaced with `datadog_trace_api_hostname` and will be removed in 2.0!")
		if c.DatadogTraceAPIAddress == "" {
			c.DatadogTraceAPIAddress = c.TraceAPIAddress
		}
	}

	if c.TraceAddress != "" {
		log.Warn("The config key `trace_address` is deprecated and replaced with `ssf_address` and will be removed in 2.0!")
		if c.SsfAddress == "" {
			c.SsfAddress = c.TraceAddress
		}
	}

	return c, nil
}

// ParseInterval handles parsing the flush interval as a time.Duration
func (c Config) ParseInterval() (time.Duration, error) {
	return time.ParseDuration(c.Interval)
}
<|endoftext|>


<commit_before>/*

*/
package mandrake

import (
	"log"
	//"golang.org/x/exp/inotify"
	"github.com/hosom/gomandrake/config"
	"github.com/hosom/gomandrake/inputs"
	//"github.com/hosom/gomandrake/plugin"
)

type Mandrake struct {
	AnalysisPipeline	chan string
	Input				string
}

func NewMandrake(c config.Config) (*Mandrake, error) {
	return &Mandrake{make(chan string), c.Input}, nil
}

func (m *Mandrake) ListenAndServe() {

	i := inputs.INotify{"/tmp/", m.AnalysisPipeline}
	i.Monitor()
	//plugin.CreateListenerAndServe(m.AnalysisPipeline, m.Input)
}

func (m *Mandrake) DispatchAnalysis() {
	for fpath := range m.AnalysisPipeline {
		log.Printf("%s", fpath)
	}
}<commit_msg>updates<commit_after>/*

*/
package mandrake

import (
	"log"
	//"golang.org/x/exp/inotify"
	"github.com/hosom/gomandrake/config"
	"github.com/hosom/gomandrake/inputs"
	//"github.com/hosom/gomandrake/plugin"
)

type Mandrake struct {
	AnalysisPipeline	chan string
	Input				string
}

func NewMandrake(c config.Config) (*Mandrake, error) {
	return &Mandrake{make(chan string), c.Input}, nil
}

func (m *Mandrake) ListenAndServe() {
	go m.DispatchAnalysis()
	i := inputs.INotify{"/tmp/", m.AnalysisPipeline}
	i.Monitor()
	//plugin.CreateListenerAndServe(m.AnalysisPipeline, m.Input)
}

func (m *Mandrake) DispatchAnalysis() {
	for fpath := range m.AnalysisPipeline {
		log.Printf("%s", fpath)
	}
}<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"

	"github.com/eirka/eirka-libs/audit"
	e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/perms"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"

	"github.com/eirka/eirka-admin/models"
)

// DeleteImageTagController will delete an image tag
func DeleteImageTagController(c *gin.Context) {

	// Get parameters from validate middleware
	params := c.MustGet("params").([]uint)

	// get userdata from session middleware
	userdata := c.MustGet("userdata").(user.User)

	// Initialize model struct
	m := &models.DeleteImageTagModel{
		Image: params[0],
		Tag:   params[1],
	}

	// Check the record id and get further info
	err := m.Status()
	if err == e.ErrNotFound {
		c.JSON(e.ErrorMessage(e.ErrNotFound))
		c.Error(err)
		return
	} else if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// check if the user is authorized to perform this functions
	if !userdata.IsAuthorized(m.Ib) {
		c.JSON(e.ErrorMessage(e.ErrForbidden))
		c.Error(e.ErrForbidden)
		return
	}

	// Delete data
	err = m.Delete()
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Initialize cache handle
	cache := redis.RedisCache

	// Delete redis stuff
	tags_key := fmt.Sprintf("%s:%d", "tags", m.Ib)
	tag_key := fmt.Sprintf("%s:%d:%d", "tag", m.Ib, m.Tag)
	image_key := fmt.Sprintf("%s:%d", "image", m.Ib)

	err = cache.Delete(tags_key, tag_key, image_key)
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// response message
	c.JSON(http.StatusOK, gin.H{"success_message": audit.AuditDeleteImageTag})

	// audit log
	audit := audit.Audit{
		User:   userdata.Id,
		Ib:     m.Ib,
		Ip:     c.ClientIP(),
		Action: audit.AuditDeleteImageTag,
		Info:   fmt.Sprintf("%d/%s", m.Image, m.Name),
	}

	err = audit.Submit()
	if err != nil {
		c.Error(err)
	}

	return

}
<commit_msg>new user lib<commit_after>package controllers

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"

	"github.com/eirka/eirka-libs/audit"
	e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"

	"github.com/eirka/eirka-admin/models"
)

// DeleteImageTagController will delete an image tag
func DeleteImageTagController(c *gin.Context) {

	// Get parameters from validate middleware
	params := c.MustGet("params").([]uint)

	// get userdata from session middleware
	userdata := c.MustGet("userdata").(user.User)

	// Initialize model struct
	m := &models.DeleteImageTagModel{
		Image: params[0],
		Tag:   params[1],
	}

	// Check the record id and get further info
	err := m.Status()
	if err == e.ErrNotFound {
		c.JSON(e.ErrorMessage(e.ErrNotFound))
		c.Error(err)
		return
	} else if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// check if the user is authorized to perform this functions
	if !userdata.IsAuthorized(m.Ib) {
		c.JSON(e.ErrorMessage(e.ErrForbidden))
		c.Error(e.ErrForbidden)
		return
	}

	// Delete data
	err = m.Delete()
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Initialize cache handle
	cache := redis.RedisCache

	// Delete redis stuff
	tags_key := fmt.Sprintf("%s:%d", "tags", m.Ib)
	tag_key := fmt.Sprintf("%s:%d:%d", "tag", m.Ib, m.Tag)
	image_key := fmt.Sprintf("%s:%d", "image", m.Ib)

	err = cache.Delete(tags_key, tag_key, image_key)
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// response message
	c.JSON(http.StatusOK, gin.H{"success_message": audit.AuditDeleteImageTag})

	// audit log
	audit := audit.Audit{
		User:   userdata.Id,
		Ib:     m.Ib,
		Ip:     c.ClientIP(),
		Action: audit.AuditDeleteImageTag,
		Info:   fmt.Sprintf("%d/%s", m.Image, m.Name),
	}

	err = audit.Submit()
	if err != nil {
		c.Error(err)
	}

	return

}
<|endoftext|>


<commit_before>package main

import "context"

func main() {

	ctx, cancel := context.WithCancel(context.Background())
	defer func() {
		println("defer")
		cancel()
	}()

	v := value{
		ctx:    ctx,
		cancel: cancel,
	}

	for n := range gen(ctx) {
		v.n = n

		println(n)

		abort(v)

		select {
		case <-ctx.Done():
			println("main done")
			return
		default:
		}
	}

	println("end")
}

func gen(ctx context.Context) <-chan int {

	ch := make(chan int)

	go inc(ctx, ch)

	return ch
}

func inc(ctx context.Context, ch chan int) {

	var n int

	for {
		select {
		case <-ctx.Done():
			println("inc done")
			return
		case ch <- n:
			n++
		}
	}
}

type value struct {
	n      int
	ctx    context.Context
	cancel context.CancelFunc
}

const abortNumber = 5

func abort(v value) {

	if v.n == abortNumber {
		println("abort", abortNumber)
		v.cancel()
	}

}
<commit_msg>remove context<commit_after><|endoftext|>


<commit_before>package app

import (
	"testing"

	"github.com/murlokswarm/uid"
)

func TestContext(t *testing.T) {
	ctx := &ZeroContext{
		id: uid.Context(),
	}

	RegisterContext(ctx)
	defer UnregisterContext(ctx)

	compo := &Hello{}

	ctx.Mount(compo)

	// Normal case.
	ctxBis, err := Context(compo)
	if err != nil {
		t.Fatal(err)
	}

	if ctx != ctxBis {
		t.Error("ctx and ctx bis should be equals")
	}

	// Closed context.
	ctx.Close()

	if _, err = Context(compo); err == nil {
		t.Error("err should not be nil")
	}

	// Component not mounted.
	compo = &Hello{}

	if _, err = Context(compo); err == nil {
		t.Error("err should not be nil")
	}
}

func TestRegisterContext(t *testing.T) {
	ctx := &ZeroContext{
		id: uid.Context(),
	}

	RegisterContext(ctx)
	defer UnregisterContext(ctx)

	ctxBis, registered := contexts[ctx.ID()]
	if !registered {
		t.Fatal("ctx should be registered")
	}

	if ctxBis != ctx {
		t.Error("ctxBis and ctx should be equal")
	}
}

func TestRegisterContextNoID(t *testing.T) {
	defer func() { recover() }()

	ctx := &ZeroContext{}
	RegisterContext(ctx)
	t.Error("should panic")
}

func TestRegisterContextAlreadyRegistered(t *testing.T) {
	defer func() { recover() }()

	ctx := NewZeroContext("context test")
	RegisterContext(ctx)
	RegisterContext(ctx)
	t.Error("should panic")
}

func TestZeroContext(t *testing.T) {
	ctx := NewZeroContext("context test")
	defer UnregisterContext(ctx)

	t.Log(ctx.ID())
	ctx.Resize(42, 42)
	ctx.Move(42, 42)
	ctx.SetIcon("test.png")

	hello := &Hello{}
	ctx.Mount(hello)
}
<commit_msg>cox tests<commit_after>package app

import (
	"testing"

	"github.com/murlokswarm/uid"
)

func TestContext(t *testing.T) {
	ctx := &ZeroContext{
		id: uid.Context(),
	}

	RegisterContext(ctx)
	defer UnregisterContext(ctx)

	compo := &Hello{}

	ctx.Mount(compo)

	// Normal case.
	ctxBis, err := Context(compo)
	if err != nil {
		t.Fatal(err)
	}

	if ctx != ctxBis {
		t.Error("ctx and ctx bis should be equals")
	}

	// Closed context.
	ctx.Close()

	if _, err = Context(compo); err == nil {
		t.Error("err should not be nil")
	}

	// Component not mounted.
	compo = &Hello{}

	if _, err = Context(compo); err == nil {
		t.Error("err should not be nil")
	}
}

func TestRegisterContext(t *testing.T) {
	ctx := &ZeroContext{
		id: uid.Context(),
	}

	RegisterContext(ctx)
	defer UnregisterContext(ctx)

	ctxBis, registered := contexts[ctx.ID()]
	if !registered {
		t.Fatal("ctx should be registered")
	}

	if ctxBis != ctx {
		t.Error("ctxBis and ctx should be equal")
	}
}

func TestRegisterContextNoID(t *testing.T) {
	defer func() { recover() }()

	ctx := &ZeroContext{}
	RegisterContext(ctx)
	t.Error("should panic")
}

func TestRegisterContextAlreadyRegistered(t *testing.T) {
	defer func() { recover() }()

	ctx := NewZeroContext("context test")
	RegisterContext(ctx)
	RegisterContext(ctx)
	t.Error("should panic")
}

func TestZeroContext(t *testing.T) {
	ctx := NewZeroContext("context test")
	defer UnregisterContext(ctx)

	t.Log(ctx.ID())
	ctx.Resize(42, 42)
	ctx.Move(42, 42)
	ctx.SetIcon("test.png")
	ctx.Size()
	ctx.Position()

	hello := &Hello{}
	ctx.Mount(hello)
}
<|endoftext|>


<commit_before>/*
TODO:
 - Torus
 - Disc
 - Texture offset
 - Beers law (again)
 - Skybox
 - BSPTree
 - Trimesh
 - CSG
 - Caustics
 - Distance estimators
 - Fractals
*/
package main

import (
	"flag"
	"fmt"
	"image"
	// "image/color"
	"image/jpeg"
	"image/png"
	"io"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/Bredgren/gotracer"
)

const (
	sceneDir  = "scene"
	renderDir = "renderedscene"
	usageStr  = "Usage: raytracer scenefile"
)

var (
	// rayCounts [][]map[int]int
	imgW int
	imgH int
)

var (
	sceneFile   = ""
	noImg       = false
	gridSize    = 50
	format      = "jpg"
	jpegQuality = 95
	countRays   = false
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s\n", usageStr)
		flag.PrintDefaults()
	}
	flag.BoolVar(&noImg, "NoImg", noImg, "Don't create an image if present.")
	flag.IntVar(&gridSize, "gridSize", gridSize, "Size of simultaneous trace grids.")
	flag.StringVar(&format, "format", format, "Image format [jpg | png].")
	flag.IntVar(&jpegQuality, "jpegQuality", jpegQuality, "JPEG quality.")
	flag.BoolVar(&countRays, "CountRays", countRays, "Make images showing ray counts.")
	flag.Parse()

	if flag.NArg() < 1 {
		panic(usageStr)
	}

	if format != "jpg" && format != "png" {
		panic("Unknown format " + format)
	}

	sceneFile = flag.Arg(0)

	runtime.GOMAXPROCS(runtime.NumCPU())
}

type grid struct {
	scene                  *raytracer.Scene
	xMin, yMin, xMax, yMax int // Min inclusive, Max exclusive
	img                    *image.NRGBA
	ch                     chan float64 // signal done
}

func traceGrid(g grid) {
	for y := g.yMin; y < g.yMax; y++ {
		for x := g.xMin; x < g.xMax; x++ {
			g.img.SetNRGBA(x, y, g.scene.TracePixel(x, y))
		}
	}
	g.ch <- 1
}

func main() {
	sceneFilePath := sceneDir + "/" + sceneFile
	scene := raytracer.Parse(sceneFilePath)

	imgW = scene.Camera.ImageWidth
	imgH = scene.Camera.ImageHeight
	// rayCounts = make([][]map[int]int, imgW)
	// for x := 0; x < imgW; x++ {
	// 	rayCounts[x] = make([]map[int]int, imgH)
	// 	for y := 0; y < imgH; y++ {
	// 		rayCounts[x][y] = make(map[int]int)
	// 	}
	// }
	bounds := image.Rect(0, 0, imgW, imgH)
	img := image.NewNRGBA(bounds)

	gridChan := make(chan float64, 100)
	gridCount := 0.0

	log.Println("Begin tracing")
	begin := time.Now()
	for y := bounds.Min.Y; y < bounds.Max.Y; y += gridSize {
		for x := bounds.Min.X; x < bounds.Max.X; x += gridSize {
			xMax := x + gridSize
			if xMax > imgW {
				xMax = imgW
			}
			yMax := y + gridSize
			if yMax > imgH {
				yMax = imgH
			}
			go traceGrid(grid{scene, x, y, xMax, yMax, img, gridChan})
			gridCount++
		}
	}
	for g := 0.0; g < gridCount; g += <-gridChan {
		log.Printf("%.2f%%", g/gridCount*100)
	}
	end := time.Now()
	log.Printf("Done tracing, took %v", end.Sub(begin))

	if noImg {
		return
	}

	files, err := ioutil.ReadDir(renderDir)
	if err != nil {
		log.Fatal(err)
	}
	count := 0
	for _, file := range files {
		name := file.Name()
		if strings.HasPrefix(name, "render") && len(name) > 10 &&
			!strings.Contains(name, "Rays") && !strings.Contains(name, "scene") {
			number, err := strconv.Atoi(name[6 : len(name)-4])
			if err != nil {
				log.Fatal(err)
			}
			if number > count {
				count = number
			}
		}
	}

	baseFileName := fmt.Sprintf("%s/render%d", renderDir, count+1)

	outFile := fmt.Sprintf("%s.%s", baseFileName, format)

	file, err := os.Create(outFile)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	if format == "jpg" {
		jpeg.Encode(file, img, &jpeg.Options{jpegQuality})
	} else if format == "png" {
		png.Encode(file, img)
	}
	log.Printf("Saved %s", outFile)

	copyFileContents(sceneFilePath, baseFileName+"scene.json")

	// saveRayCounts(baseFileName)
}

func copyFileContents(src, dst string) (err error) {
	in, err := os.Open(src)
	if err != nil {
		return
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return
	}
	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return
	}
	err = out.Sync()
	log.Printf("Saved %s", dst)
	return
}

// func saveRayCounts(baseFileName string) {
// 	imgs := new([raytracer.NumRayTypes]*image.NRGBA)
// 	bounds := image.Rect(0, 0, imgW, imgH)
// 	for i := 0; i < len(imgs); i++ {
// 		imgs[i] = image.NewNRGBA(bounds)
// 	}

// 	maxCount := new([raytracer.NumRayTypes]int)
// 	for x := 0; x < len(rayCounts); x++ {
// 		for y := 0; y < len(rayCounts[x]); y++ {
// 			for rayType := 0; rayType < raytracer.NumRayTypes; rayType++ {
// 				if maxCount[rayType] < rayCounts[x][y][rayType] {
// 					maxCount[rayType] = rayCounts[x][y][rayType]
// 				}
// 			}
// 		}
// 	}

// 	for x := 0; x < len(rayCounts); x++ {
// 		for y := 0; y < len(rayCounts[x]); y++ {
// 			for rayType := 0; rayType < raytracer.NumRayTypes; rayType++ {
// 				ratio := float64(rayCounts[x][y][rayType]) / float64(maxCount[rayType])
// 				shade := uint8(ratio * 255)
// 				color := color.NRGBA{shade, shade, shade, 255}
// 				imgs[rayType].SetNRGBA(x, y, color)
// 			}
// 		}
// 	}

// 	fileName := fmt.Sprintf("%sPrimaryRays.png", baseFileName)
// 	saveRayFile(fileName, imgs[raytracer.PrimaryRay])
// 	fileName = fmt.Sprintf("%sShadowRays.png", baseFileName)
// 	saveRayFile(fileName, imgs[raytracer.ShadowRay])
// }

// func saveRayFile(fileName string, img *image.NRGBA) {
//  	file, err := os.Create(fileName)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	defer file.Close()
// 	png.Encode(file, img)
// 	log.Printf("Saved %s", fileName)
// }
<commit_msg>Start rewritting raytracer main: cmdline options and decode optioons<commit_after>/*
The raytracer application takes a scene as a json file and produces a rendered version of that scene as
a png or jpeg image. See lib.Options for details on all the options.
*/
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"

	"github.com/Bredgren/gotracer/lib"
)

const (
	usageStr = `Usage: raytracer [OPTIONS]
Reads a json-formatted scene description from stdin and writes the image to stdout.
`
)

var (
	imgFormats = [...]string{"jpg", "jpeg", "png"}
)

// cmdline options
var (
	inFile      = ""
	outFile     = ""
	gridSize    = 50
	format      = "jpg"
	jpegQuality = 95
	verbose     = false
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s\n", usageStr)
		flag.PrintDefaults()
	}
	flag.StringVar(&inFile, "in", inFile, "Read scene from this json file instead of stdin")
	flag.StringVar(&outFile, "out", outFile, "Save image here instead of sending to stdout. If the format option is unspecified then it will attempt to determine the format from the file name")
	flag.IntVar(&gridSize, "gridSize", gridSize, "The image is divided into a grid an each section rendered in parallel. This is the size in pixels of each square")
	flag.StringVar(&format, "format", format, fmt.Sprintf("Image format, one of %s", imgFormats))
	flag.IntVar(&jpegQuality, "jpegQuality", jpegQuality, "JPEG quality")
	flag.BoolVar(&verbose, "v", verbose, "Print progress reports")
}

// type grid struct {
// 	scene                  *raytracer.Scene
// 	xMin, yMin, xMax, yMax int // Min inclusive, Max exclusive
// 	img                    *image.NRGBA
// 	ch                     chan float64 // signal done
// }

// func traceGrid(g grid) {
// 	for y := g.yMin; y < g.yMax; y++ {
// 		for x := g.xMin; x < g.xMax; x++ {
// 			g.img.SetNRGBA(x, y, g.scene.TracePixel(x, y))
// 		}
// 	}
// 	g.ch <- 1
// }

func main() {
	flag.Parse()

	// Verify requested format
	imgFormat := ""
	for _, f := range imgFormats {
		if format == f {
			imgFormat = format
			break
		}
	}
	if imgFormat == "" {
		fmt.Fprintf(os.Stderr, "Invalid image format '%s'\n", format)
		flag.Usage()
		return
	}

	// Choose stdin or user-specified file
	var inReader io.Reader = os.Stdin
	if inFile != "" {
		file, e := os.Open(inFile)
		if e != nil {
			log.Fatalf("opening file to read: %s\n", e)
		}
		defer file.Close()
		inReader = io.Reader(file)
	}

	// Read and decode options
	var options lib.Options
	jsonOpts, e := ioutil.ReadAll(inReader)
	if e != nil {
		log.Fatalf("reading file: %s\n", e)
	}
	e = json.Unmarshal(jsonOpts, &options)
	if e != nil {
		log.Fatalf("decoding json: %s\n", e)
	}
	fmt.Println(options)

	// Choose stdout or user-specified file
	var outWriter io.Writer = os.Stdout
	if outFile != "" {
		var e error
		outWriter, e = os.Create(outFile)
		if e != nil {
			log.Fatalf("creating file to write: %s\n", e)
		}
	}
	_ = outWriter

	// 	sceneFilePath := sceneDir + "/" + sceneFile
	// 	scene := raytracer.Parse(sceneFilePath)

	// 	imgW = scene.Camera.ImageWidth
	// 	imgH = scene.Camera.ImageHeight
	// 	// rayCounts = make([][]map[int]int, imgW)
	// 	// for x := 0; x < imgW; x++ {
	// 	// 	rayCounts[x] = make([]map[int]int, imgH)
	// 	// 	for y := 0; y < imgH; y++ {
	// 	// 		rayCounts[x][y] = make(map[int]int)
	// 	// 	}
	// 	// }
	// 	bounds := image.Rect(0, 0, imgW, imgH)
	// 	img := image.NewNRGBA(bounds)

	// 	gridChan := make(chan float64, 100)
	// 	gridCount := 0.0

	// 	log.Println("Begin tracing")
	// 	begin := time.Now()
	// 	for y := bounds.Min.Y; y < bounds.Max.Y; y += gridSize {
	// 		for x := bounds.Min.X; x < bounds.Max.X; x += gridSize {
	// 			xMax := x + gridSize
	// 			if xMax > imgW {
	// 				xMax = imgW
	// 			}
	// 			yMax := y + gridSize
	// 			if yMax > imgH {
	// 				yMax = imgH
	// 			}
	// 			go traceGrid(grid{scene, x, y, xMax, yMax, img, gridChan})
	// 			gridCount++
	// 		}
	// 	}
	// 	for g := 0.0; g < gridCount; g += <-gridChan {
	// 		log.Printf("%.2f%%", g/gridCount*100)
	// 	}
	// 	end := time.Now()
	// 	log.Printf("Done tracing, took %v", end.Sub(begin))

	// 	if noImg {
	// 		return
	// 	}

	// 	files, err := ioutil.ReadDir(renderDir)
	// 	if err != nil {
	// 		log.Fatal(err)
	// 	}
	// 	count := 0
	// 	for _, file := range files {
	// 		name := file.Name()
	// 		if strings.HasPrefix(name, "render") && len(name) > 10 &&
	// 			!strings.Contains(name, "Rays") && !strings.Contains(name, "scene") {
	// 			number, err := strconv.Atoi(name[6 : len(name)-4])
	// 			if err != nil {
	// 				log.Fatal(err)
	// 			}
	// 			if number > count {
	// 				count = number
	// 			}
	// 		}
	// 	}

	// 	baseFileName := fmt.Sprintf("%s/render%d", renderDir, count+1)

	// 	outFile := fmt.Sprintf("%s.%s", baseFileName, format)

	// 	file, err := os.Create(outFile)
	// 	if err != nil {
	// 		log.Fatal(err)
	// 	}
	// 	defer file.Close()

	// 	if format == "jpg" {
	// 		jpeg.Encode(file, img, &jpeg.Options{jpegQuality})
	// 	} else if format == "png" {
	// 		png.Encode(file, img)
	// 	}
	// 	log.Printf("Saved %s", outFile)

	// 	copyFileContents(sceneFilePath, baseFileName+"scene.json")

	// 	// saveRayCounts(baseFileName)
	// }

	// func copyFileContents(src, dst string) (err error) {
	// 	in, err := os.Open(src)
	// 	if err != nil {
	// 		return
	// 	}
	// 	defer in.Close()
	// 	out, err := os.Create(dst)
	// 	if err != nil {
	// 		return
	// 	}
	// 	defer func() {
	// 		cerr := out.Close()
	// 		if err == nil {
	// 			err = cerr
	// 		}
	// 	}()
	// 	if _, err = io.Copy(out, in); err != nil {
	// 		return
	// 	}
	// 	err = out.Sync()
	// 	log.Printf("Saved %s", dst)
	// 	return
}
<|endoftext|>


<commit_before>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"testing"

	driver "github.com/arangodb/go-driver"
)

// TestServerMode creates a database and checks the various server modes.
func TestServerMode(t *testing.T) {
	c := createClientFromEnv(t, true)
	ctx := context.Background()

	// Create simple collection
	db := ensureDatabase(ctx, c, "_system", nil, t)
	colName := "server_mode_test1"
	col := ensureCollection(ctx, db, colName, nil, t)

	// Initial server mode must be default
	if mode, err := c.ServerMode(ctx); err != nil {
		t.Fatalf("ServerMode failed: %s", describe(err))
	} else if mode != driver.ServerModeDefault {
		t.Errorf("ServerMode returned '%s', but expected '%s'", mode, driver.ServerModeDefault)
	}

	// Change server mode to readonly.
	if err := c.SetServerMode(ctx, driver.ServerModeReadOnly); err != nil {
		t.Fatalf("SetServerMode failed: %s", describe(err))
	}

	// Try to drop collection now (it must fail)
	if err := col.Remove(ctx); !driver.IsForbidden(err) {
		t.Fatalf("Collection remove should have return ForbiddenError, got error %s", describe(err))
	}

	// Check server mode, must be readonly
	if mode, err := c.ServerMode(ctx); err != nil {
		t.Fatalf("ServerMode failed: %s", describe(err))
	} else if mode != driver.ServerModeReadOnly {
		t.Errorf("ServerMode returned '%s', but expected '%s'", mode, driver.ServerModeReadOnly)
	}

	// Change server mode back to default.
	if err := c.SetServerMode(ctx, driver.ServerModeDefault); err != nil {
		t.Fatalf("SetServerMode failed: %s", describe(err))
	}

	// Try to drop collection now (it must succeed)
	if err := col.Remove(ctx); err != nil {
		t.Fatalf("Collection remove failed: %s", describe(err))
	}
}
<commit_msg>Skip test of pre-3.3 versions<commit_after>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"testing"

	driver "github.com/arangodb/go-driver"
)

// TestServerMode creates a database and checks the various server modes.
func TestServerMode(t *testing.T) {
	c := createClientFromEnv(t, true)
	ctx := context.Background()

	version, err := c.Version(nil)
	if err != nil {
		t.Fatalf("Version failed: %s", describe(err))
	}
	isv33p := version.Version.CompareTo("3.3") >= 0
	if !isv33p {
		t.Skip("This test requires version 3.3")
	} else {
		// Create simple collection
		db := ensureDatabase(ctx, c, "_system", nil, t)
		colName := "server_mode_test1"
		col := ensureCollection(ctx, db, colName, nil, t)

		// Initial server mode must be default
		if mode, err := c.ServerMode(ctx); err != nil {
			t.Fatalf("ServerMode failed: %s", describe(err))
		} else if mode != driver.ServerModeDefault {
			t.Errorf("ServerMode returned '%s', but expected '%s'", mode, driver.ServerModeDefault)
		}

		// Change server mode to readonly.
		if err := c.SetServerMode(ctx, driver.ServerModeReadOnly); err != nil {
			t.Fatalf("SetServerMode failed: %s", describe(err))
		}

		// Try to drop collection now (it must fail)
		if err := col.Remove(ctx); !driver.IsForbidden(err) {
			t.Fatalf("Collection remove should have return ForbiddenError, got error %s", describe(err))
		}

		// Check server mode, must be readonly
		if mode, err := c.ServerMode(ctx); err != nil {
			t.Fatalf("ServerMode failed: %s", describe(err))
		} else if mode != driver.ServerModeReadOnly {
			t.Errorf("ServerMode returned '%s', but expected '%s'", mode, driver.ServerModeReadOnly)
		}

		// Change server mode back to default.
		if err := c.SetServerMode(ctx, driver.ServerModeDefault); err != nil {
			t.Fatalf("SetServerMode failed: %s", describe(err))
		}

		// Try to drop collection now (it must succeed)
		if err := col.Remove(ctx); err != nil {
			t.Fatalf("Collection remove failed: %s", describe(err))
		}
	}
}
<|endoftext|>


<commit_before>package apns

import (
	"errors"
	"log"
	"math"
	"math/rand"
	"net"
	"strings"
	"sync"
	"time"

	"code.google.com/p/go.net/context"
)

const (
	gatewayName = "gateway.push.apple.com"
	gatewayPort = "2195"

	gatewaySandboxName = "gateway.sandbox.push.apple.com"
	gatewaySandboxPort = "2195"
)

type gatewayIPs []string

var (
	mu               sync.Mutex // Protect acces to `gatewayIP` or to `gatewaySandboxIP`
	gatewayIP        gatewayIPs // Cache of the IPs of the production APNs
	gatewaySandboxIP gatewayIPs // Cache of the IPs of the sandbox APNs
)

// ips is useed to balance senders connection between all the gateway IPs
type ips struct {
	mu    sync.Mutex      // Protect acces to `ipMap`
	ipMap map[string]int8 // Save the usage of each IP available
}

// Gateway keeps all the informations needed to communicate with the APNs
type Gateway struct {
	gateway   string                         // The gateway name could be either `gatewayName`, `gatewaySandboxName` or a custom host:port
	gips      ips                            // save the balance of used IPs for the `gateway`
	responses chan *PushNotificationResponse // Channel of errors, directly from senders
	onError   OnErrorCallback                // Error callback to execute client code on error
	senders   []*Sender                      // Array of potential senders
}

// OnErrorCallback functions are called to let the library client react when an error occured
type OnErrorCallback func(*PushNotificationResponse)

func init() {
	// Initialize at startup the rand seed
	rand.Seed(time.Now().UTC().UnixNano())
}

// NewGateway creates a new gateway interface to the Apple APNs production servers
func NewGateway(ctx context.Context, certificateFile, keyFile string) (*Gateway, error) {

	gw := gatewayName + ":" + gatewayPort
	return NewCustomGateway(ctx, gw, certificateFile, keyFile)
}

// NewSandboxGateway creates a new gateway interface to the Apple APNs sandbox servers
func NewSandboxGateway(ctx context.Context, certificateFile, keyFile string) (*Gateway, error) {

	gw := gatewaySandboxName + ":" + gatewaySandboxPort
	return NewCustomGateway(ctx, gw, certificateFile, keyFile)
}

// NewCustomGateway create a client interface to a custom APNs server
// `gateway` format must be "hostname:port"
func NewCustomGateway(ctx context.Context, gateway, certificateFile, keyFile string) (*Gateway, error) {

	g := &Gateway{gateway: gateway}
	return g.newGateway(ctx, certificateFile, keyFile)
}

// Send uses one of the gateway sender to send the push notification
func (g *Gateway) Send(pn *PushNotification) {

	min := 0
	max := len(g.senders)
	n := rand.Intn(max-min) + min
	g.senders[n].Send(pn)
}

// Errors gives feedback to the library client on which push notifications got errors
// The library client has to provide a callback via this method to get error informations.
func (g *Gateway) Errors(onError OnErrorCallback) {

	g.onError = onError
}

// newGateway does all the gateway initialisation once the gateway name is known
func (g *Gateway) newGateway(ctx context.Context, certificateFile, keyFile string) (*Gateway, error) {

	gips, err := lookupGateway(g.gateway)
	if nil != err {
		return nil, err
	}
	ipMap := map[string]int8{}
	for _, ip := range gips {
		ipMap[ip] = 0
	}
	g.gips = ips{ipMap: ipMap}
	g.responses = make(chan *PushNotificationResponse)
	g.senders = []*Sender{}
	// TODO GSE: Enable the possibilty to choose the number of senders
	err = g.newSender(ctx, certificateFile, keyFile)
	if err != nil {
		return nil, err
	}
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case pnr := <-g.responses:
				if g.onError != nil {
					go g.onError(pnr)
				}
			}
		}
	}()
	return g, nil
}

// newSender creates a sender and attach it to the gateway
func (g *Gateway) newSender(ctx context.Context, certificateFile, keyFile string) error {

	ip := g.balanceGatewayIps()
	s, err := NewSender(ctx, g.gateway, ip, certificateFile, keyFile)
	if err != nil {
		return err
	}
	s.pnrec = g.responses
	g.senders = append(g.senders, s)
	return nil
}

// balanceGatewayIps chooses the best ip for the gateway
func (g *Gateway) balanceGatewayIps() string {

	// TODO(GSE): Should probably get feedbacks from the clients to minus one an IP when it is freed by a sender
	minNbUsage := int8(math.MaxInt8) // Initialize it at the max value possible to track the best choice available
	bestip := ""
	g.gips.mu.Lock()
	defer g.gips.mu.Unlock()
	for ip, usage := range g.gips.ipMap {
		if usage < minNbUsage {
			minNbUsage = usage
			bestip = ip
		}
	}
	if bestip != "" {
		g.gips.ipMap[bestip] = g.gips.ipMap[bestip] + 1
	}
	return bestip
}

// lookupGateway gets the gateway IPs from the gateway name without the colon and the port
// Useful to load balance over the different APNS servers behind the gateway name
func lookupGateway(gateway string) (gatewayIPs, error) {

	gatewayParts := strings.Split(gateway, ":")
	if len(gatewayParts) == 2 {
		gateway = gatewayParts[0]
	}
	ips, err := net.LookupIP(gateway)
	if err != nil {
		return nil, err
	}
	mu.Lock()
	defer mu.Unlock()
	if gateway == gatewayName {
		gatewayIP = make(gatewayIPs, len(ips))
		for i := 0; i < len(ips); i++ {
			ip := ips[i]
			gatewayIP[i] = ip.String()
		}
		return gatewayIP, nil
	}
	if gateway == gatewaySandboxName {
		gatewaySandboxIP = make(gatewayIPs, len(ips))
		for i := 0; i < len(ips); i++ {
			ip := ips[i]
			gatewaySandboxIP[i] = ip.String()
		}
		return gatewaySandboxIP, nil
	}
	return nil, errors.New("lookupGateway reach an invalid state")
}

// cachedLookupGateway gets the cached IPs from the gateway name without the colon and the port
// If there is no cache retrieves the IPs
func cachedLookupGateway(gateway string) (gatewayIPs, error) {

	if gateway == gatewayName && len(gatewayIP) > 0 {
		return gatewayIP, nil
	}
	if gateway == gatewaySandboxName && len(gatewaySandboxIP) > 0 {
		return gatewaySandboxIP, nil
	}
	return lookupGateway(gateway)
}

// pickGatewayIP picks an IP of the gateway
func pickGatewayIP(gateway string) (string, error) {

	ips, err := cachedLookupGateway(gateway)
	if err != nil {
		return "", err
	}
	// TODO(GSE): Make the pick better
	// IPs picks should be balanced between all the IPs available for the gateway
	//
	min := 0
	max := len(ips)
	n := rand.Intn(max-min) + min
	return ips[n], nil
}
<commit_msg>Fix: unused import<commit_after>package apns

import (
	"errors"
	"math"
	"math/rand"
	"net"
	"strings"
	"sync"
	"time"

	"code.google.com/p/go.net/context"
)

const (
	gatewayName = "gateway.push.apple.com"
	gatewayPort = "2195"

	gatewaySandboxName = "gateway.sandbox.push.apple.com"
	gatewaySandboxPort = "2195"
)

type gatewayIPs []string

var (
	mu               sync.Mutex // Protect acces to `gatewayIP` or to `gatewaySandboxIP`
	gatewayIP        gatewayIPs // Cache of the IPs of the production APNs
	gatewaySandboxIP gatewayIPs // Cache of the IPs of the sandbox APNs
)

// ips is useed to balance senders connection between all the gateway IPs
type ips struct {
	mu    sync.Mutex      // Protect acces to `ipMap`
	ipMap map[string]int8 // Save the usage of each IP available
}

// Gateway keeps all the informations needed to communicate with the APNs
type Gateway struct {
	gateway   string                         // The gateway name could be either `gatewayName`, `gatewaySandboxName` or a custom host:port
	gips      ips                            // save the balance of used IPs for the `gateway`
	responses chan *PushNotificationResponse // Channel of errors, directly from senders
	onError   OnErrorCallback                // Error callback to execute client code on error
	senders   []*Sender                      // Array of potential senders
}

// OnErrorCallback functions are called to let the library client react when an error occured
type OnErrorCallback func(*PushNotificationResponse)

func init() {
	// Initialize at startup the rand seed
	rand.Seed(time.Now().UTC().UnixNano())
}

// NewGateway creates a new gateway interface to the Apple APNs production servers
func NewGateway(ctx context.Context, certificateFile, keyFile string) (*Gateway, error) {

	gw := gatewayName + ":" + gatewayPort
	return NewCustomGateway(ctx, gw, certificateFile, keyFile)
}

// NewSandboxGateway creates a new gateway interface to the Apple APNs sandbox servers
func NewSandboxGateway(ctx context.Context, certificateFile, keyFile string) (*Gateway, error) {

	gw := gatewaySandboxName + ":" + gatewaySandboxPort
	return NewCustomGateway(ctx, gw, certificateFile, keyFile)
}

// NewCustomGateway create a client interface to a custom APNs server
// `gateway` format must be "hostname:port"
func NewCustomGateway(ctx context.Context, gateway, certificateFile, keyFile string) (*Gateway, error) {

	g := &Gateway{gateway: gateway}
	return g.newGateway(ctx, certificateFile, keyFile)
}

// Send uses one of the gateway sender to send the push notification
func (g *Gateway) Send(pn *PushNotification) {

	min := 0
	max := len(g.senders)
	n := rand.Intn(max-min) + min
	g.senders[n].Send(pn)
}

// Errors gives feedback to the library client on which push notifications got errors
// The library client has to provide a callback via this method to get error informations.
func (g *Gateway) Errors(onError OnErrorCallback) {

	g.onError = onError
}

// newGateway does all the gateway initialisation once the gateway name is known
func (g *Gateway) newGateway(ctx context.Context, certificateFile, keyFile string) (*Gateway, error) {

	gips, err := lookupGateway(g.gateway)
	if nil != err {
		return nil, err
	}
	ipMap := map[string]int8{}
	for _, ip := range gips {
		ipMap[ip] = 0
	}
	g.gips = ips{ipMap: ipMap}
	g.responses = make(chan *PushNotificationResponse)
	g.senders = []*Sender{}
	// TODO GSE: Enable the possibilty to choose the number of senders
	err = g.newSender(ctx, certificateFile, keyFile)
	if err != nil {
		return nil, err
	}
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case pnr := <-g.responses:
				if g.onError != nil {
					go g.onError(pnr)
				}
			}
		}
	}()
	return g, nil
}

// newSender creates a sender and attach it to the gateway
func (g *Gateway) newSender(ctx context.Context, certificateFile, keyFile string) error {

	ip := g.balanceGatewayIps()
	s, err := NewSender(ctx, g.gateway, ip, certificateFile, keyFile)
	if err != nil {
		return err
	}
	s.pnrec = g.responses
	g.senders = append(g.senders, s)
	return nil
}

// balanceGatewayIps chooses the best ip for the gateway
func (g *Gateway) balanceGatewayIps() string {

	// TODO(GSE): Should probably get feedbacks from the clients to minus one an IP when it is freed by a sender
	minNbUsage := int8(math.MaxInt8) // Initialize it at the max value possible to track the best choice available
	bestip := ""
	g.gips.mu.Lock()
	defer g.gips.mu.Unlock()
	for ip, usage := range g.gips.ipMap {
		if usage < minNbUsage {
			minNbUsage = usage
			bestip = ip
		}
	}
	if bestip != "" {
		g.gips.ipMap[bestip] = g.gips.ipMap[bestip] + 1
	}
	return bestip
}

// lookupGateway gets the gateway IPs from the gateway name without the colon and the port
// Useful to load balance over the different APNS servers behind the gateway name
func lookupGateway(gateway string) (gatewayIPs, error) {

	gatewayParts := strings.Split(gateway, ":")
	if len(gatewayParts) == 2 {
		gateway = gatewayParts[0]
	}
	ips, err := net.LookupIP(gateway)
	if err != nil {
		return nil, err
	}
	mu.Lock()
	defer mu.Unlock()
	if gateway == gatewayName {
		gatewayIP = make(gatewayIPs, len(ips))
		for i := 0; i < len(ips); i++ {
			ip := ips[i]
			gatewayIP[i] = ip.String()
		}
		return gatewayIP, nil
	}
	if gateway == gatewaySandboxName {
		gatewaySandboxIP = make(gatewayIPs, len(ips))
		for i := 0; i < len(ips); i++ {
			ip := ips[i]
			gatewaySandboxIP[i] = ip.String()
		}
		return gatewaySandboxIP, nil
	}
	return nil, errors.New("lookupGateway reach an invalid state")
}

// cachedLookupGateway gets the cached IPs from the gateway name without the colon and the port
// If there is no cache retrieves the IPs
func cachedLookupGateway(gateway string) (gatewayIPs, error) {

	if gateway == gatewayName && len(gatewayIP) > 0 {
		return gatewayIP, nil
	}
	if gateway == gatewaySandboxName && len(gatewaySandboxIP) > 0 {
		return gatewaySandboxIP, nil
	}
	return lookupGateway(gateway)
}

// pickGatewayIP picks an IP of the gateway
func pickGatewayIP(gateway string) (string, error) {

	ips, err := cachedLookupGateway(gateway)
	if err != nil {
		return "", err
	}
	// TODO(GSE): Make the pick better
	// IPs picks should be balanced between all the IPs available for the gateway
	//
	min := 0
	max := len(ips)
	n := rand.Intn(max-min) + min
	return ips[n], nil
}
<|endoftext|>


<commit_before>package sandbox

import (
	"fmt"
	"net"

	"github.com/docker/libnetwork/types"
	"github.com/vishvananda/netlink"
)

func (n *networkNamespace) Gateway() net.IP {
	n.Lock()
	defer n.Unlock()

	return n.gw
}

func (n *networkNamespace) GatewayIPv6() net.IP {
	n.Lock()
	defer n.Unlock()

	return n.gwv6
}

func (n *networkNamespace) StaticRoutes() []*types.StaticRoute {
	n.Lock()
	defer n.Unlock()

	routes := make([]*types.StaticRoute, len(n.staticRoutes))
	for i, route := range n.staticRoutes {
		r := route.GetCopy()
		routes[i] = r
	}

	return routes
}

func (n *networkNamespace) setGateway(gw net.IP) {
	n.Lock()
	n.gw = gw
	n.Unlock()
}

func (n *networkNamespace) setGatewayIPv6(gwv6 net.IP) {
	n.Lock()
	n.gwv6 = gwv6
	n.Unlock()
}

func (n *networkNamespace) SetGateway(gw net.IP) error {
	// Silently return if the gateway is empty
	if len(gw) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gw, true)
	if err == nil {
		n.setGateway(gw)
	}

	return err
}

func (n *networkNamespace) UnsetGateway() error {
	gw := n.Gateway()

	// Silently return if the gateway is empty
	if len(gw) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gw, false)
	if err == nil {
		n.setGateway(net.IP{})
	}

	return err
}

func programGateway(path string, gw net.IP, isAdd bool) error {
	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
		gwRoutes, err := netlink.RouteGet(gw)
		if err != nil {
			return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
		}

		if isAdd {
			return netlink.RouteAdd(&netlink.Route{
				Scope:     netlink.SCOPE_UNIVERSE,
				LinkIndex: gwRoutes[0].LinkIndex,
				Gw:        gw,
			})
		}

		return netlink.RouteDel(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: gwRoutes[0].LinkIndex,
			Gw:        gw,
		})
	})
}

// Program a route in to the namespace routing table.
func programRoute(path string, dest *net.IPNet, nh net.IP) error {
	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
		gwRoutes, err := netlink.RouteGet(nh)
		if err != nil {
			return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
		}

		return netlink.RouteAdd(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: gwRoutes[0].LinkIndex,
			Gw:        gwRoutes[0].Gw,
			Dst:       dest,
		})
	})
}

// Delete a route from the namespace routing table.
func removeRoute(path string, dest *net.IPNet, nh net.IP) error {
	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
		gwRoutes, err := netlink.RouteGet(nh)
		if err != nil {
			return fmt.Errorf("route for the next hop could not be found: %v", err)
		}

		return netlink.RouteDel(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: gwRoutes[0].LinkIndex,
			Gw:        gwRoutes[0].Gw,
			Dst:       dest,
		})
	})
}

func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error {
	// Silently return if the gateway is empty
	if len(gwv6) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gwv6, true)
	if err == nil {
		n.SetGatewayIPv6(gwv6)
	}

	return err
}

func (n *networkNamespace) UnsetGatewayIPv6() error {
	gwv6 := n.GatewayIPv6()

	// Silently return if the gateway is empty
	if len(gwv6) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gwv6, false)
	if err == nil {
		n.Lock()
		n.gwv6 = net.IP{}
		n.Unlock()
	}

	return err
}

func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
	err := programRoute(n.nsPath(), r.Destination, r.NextHop)
	if err == nil {
		n.Lock()
		n.staticRoutes = append(n.staticRoutes, r)
		n.Unlock()
	}
	return err
}

func (n *networkNamespace) RemoveStaticRoute(r *types.StaticRoute) error {
	n.Lock()

	err := removeRoute(n.nsPath(), r.Destination, r.NextHop)
	if err == nil {
		n.Lock()
		lastIndex := len(n.staticRoutes) - 1
		for i, v := range n.staticRoutes {
			if v == r {
				// Overwrite the route we're removing with the last element
				n.staticRoutes[i] = n.staticRoutes[lastIndex]
				// Shorten the slice to trim the extra element
				n.staticRoutes = n.staticRoutes[:lastIndex]
				break
			}
		}
		n.Unlock()
	}
	return err
}
<commit_msg>fix for #14633, use original nexthop ip value instead of obtained via RouteGet<commit_after>package sandbox

import (
	"fmt"
	"net"

	"github.com/docker/libnetwork/types"
	"github.com/vishvananda/netlink"
)

func (n *networkNamespace) Gateway() net.IP {
	n.Lock()
	defer n.Unlock()

	return n.gw
}

func (n *networkNamespace) GatewayIPv6() net.IP {
	n.Lock()
	defer n.Unlock()

	return n.gwv6
}

func (n *networkNamespace) StaticRoutes() []*types.StaticRoute {
	n.Lock()
	defer n.Unlock()

	routes := make([]*types.StaticRoute, len(n.staticRoutes))
	for i, route := range n.staticRoutes {
		r := route.GetCopy()
		routes[i] = r
	}

	return routes
}

func (n *networkNamespace) setGateway(gw net.IP) {
	n.Lock()
	n.gw = gw
	n.Unlock()
}

func (n *networkNamespace) setGatewayIPv6(gwv6 net.IP) {
	n.Lock()
	n.gwv6 = gwv6
	n.Unlock()
}

func (n *networkNamespace) SetGateway(gw net.IP) error {
	// Silently return if the gateway is empty
	if len(gw) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gw, true)
	if err == nil {
		n.setGateway(gw)
	}

	return err
}

func (n *networkNamespace) UnsetGateway() error {
	gw := n.Gateway()

	// Silently return if the gateway is empty
	if len(gw) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gw, false)
	if err == nil {
		n.setGateway(net.IP{})
	}

	return err
}

func programGateway(path string, gw net.IP, isAdd bool) error {
	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
		gwRoutes, err := netlink.RouteGet(gw)
		if err != nil {
			return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
		}

		if isAdd {
			return netlink.RouteAdd(&netlink.Route{
				Scope:     netlink.SCOPE_UNIVERSE,
				LinkIndex: gwRoutes[0].LinkIndex,
				Gw:        gw,
			})
		}

		return netlink.RouteDel(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: gwRoutes[0].LinkIndex,
			Gw:        gw,
		})
	})
}

// Program a route in to the namespace routing table.
func programRoute(path string, dest *net.IPNet, nh net.IP) error {
	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
		gwRoutes, err := netlink.RouteGet(nh)
		if err != nil {
			return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
		}

		return netlink.RouteAdd(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: gwRoutes[0].LinkIndex,
			Gw:        nh,
			Dst:       dest,
		})
	})
}

// Delete a route from the namespace routing table.
func removeRoute(path string, dest *net.IPNet, nh net.IP) error {
	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
		gwRoutes, err := netlink.RouteGet(nh)
		if err != nil {
			return fmt.Errorf("route for the next hop could not be found: %v", err)
		}

		return netlink.RouteDel(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: gwRoutes[0].LinkIndex,
			Gw:        nh,
			Dst:       dest,
		})
	})
}

func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error {
	// Silently return if the gateway is empty
	if len(gwv6) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gwv6, true)
	if err == nil {
		n.SetGatewayIPv6(gwv6)
	}

	return err
}

func (n *networkNamespace) UnsetGatewayIPv6() error {
	gwv6 := n.GatewayIPv6()

	// Silently return if the gateway is empty
	if len(gwv6) == 0 {
		return nil
	}

	err := programGateway(n.nsPath(), gwv6, false)
	if err == nil {
		n.Lock()
		n.gwv6 = net.IP{}
		n.Unlock()
	}

	return err
}

func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
	err := programRoute(n.nsPath(), r.Destination, r.NextHop)
	if err == nil {
		n.Lock()
		n.staticRoutes = append(n.staticRoutes, r)
		n.Unlock()
	}
	return err
}

func (n *networkNamespace) RemoveStaticRoute(r *types.StaticRoute) error {
	n.Lock()

	err := removeRoute(n.nsPath(), r.Destination, r.NextHop)
	if err == nil {
		n.Lock()
		lastIndex := len(n.staticRoutes) - 1
		for i, v := range n.staticRoutes {
			if v == r {
				// Overwrite the route we're removing with the last element
				n.staticRoutes[i] = n.staticRoutes[lastIndex]
				// Shorten the slice to trim the extra element
				n.staticRoutes = n.staticRoutes[:lastIndex]
				break
			}
		}
		n.Unlock()
	}
	return err
}
<|endoftext|>


<commit_before>// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package core

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"strings"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/params"
)

// WriteGenesisBlock writes the genesis block to the database as block number 0
func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) {
	contents, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	var genesis struct {
		Nonce      string
		Timestamp  string
		ParentHash string
		ExtraData  string
		GasLimit   string
		Difficulty string
		Mixhash    string
		Coinbase   string
		Alloc      map[string]struct {
			Code    string
			Storage map[string]string
			Balance string
		}
	}

	if err := json.Unmarshal(contents, &genesis); err != nil {
		return nil, err
	}

	statedb := state.New(common.Hash{}, chainDb)
	for addr, account := range genesis.Alloc {
		address := common.HexToAddress(addr)
		statedb.AddBalance(address, common.String2Big(account.Balance))
		statedb.SetCode(address, common.Hex2Bytes(account.Code))
		for key, value := range account.Storage {
			statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
		}
	}
	statedb.SyncObjects()

	difficulty := common.String2Big(genesis.Difficulty)
	block := types.NewBlock(&types.Header{
		Nonce:      types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()),
		Time:       common.String2Big(genesis.Timestamp),
		ParentHash: common.HexToHash(genesis.ParentHash),
		Extra:      common.FromHex(genesis.ExtraData),
		GasLimit:   common.String2Big(genesis.GasLimit),
		Difficulty: difficulty,
		MixDigest:  common.HexToHash(genesis.Mixhash),
		Coinbase:   common.HexToAddress(genesis.Coinbase),
		Root:       statedb.Root(),
	}, nil, nil, nil)

	if block := GetBlock(chainDb, block.Hash()); block != nil {
		glog.V(logger.Info).Infoln("Genesis block already in chain. Writing canonical number")
		err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
		if err != nil {
			return nil, err
		}
		return block, nil
	}
	statedb.Sync()

	if err := WriteTd(chainDb, block.Hash(), difficulty); err != nil {
		return nil, err
	}
	if err := WriteBlock(chainDb, block); err != nil {
		return nil, err
	}
	if err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()); err != nil {
		return nil, err
	}
	if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil {
		return nil, err
	}
	return block, nil
}

// GenesisBlockForTesting creates a block in which addr has the given wei balance.
// The state trie of the block is written to db.
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
	statedb := state.New(common.Hash{}, db)
	obj := statedb.GetOrNewStateObject(addr)
	obj.SetBalance(balance)
	statedb.SyncObjects()
	statedb.Sync()
	block := types.NewBlock(&types.Header{
		Difficulty: params.GenesisDifficulty,
		GasLimit:   params.GenesisGasLimit,
		Root:       statedb.Root(),
	}, nil, nil, nil)
	return block
}

type GenesisAccount struct {
	Address common.Address
	Balance *big.Int
}

func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) *types.Block {
	accountJson := "{"
	for i, account := range accounts {
		if i != 0 {
			accountJson += ","
		}
		accountJson += fmt.Sprintf(`"0x%x":{"balance":"0x%x"}`, account.Address, account.Balance.Bytes())
	}
	accountJson += "}"

	testGenesis := fmt.Sprintf(`{
	"nonce":"0x%x",
	"gasLimit":"0x%x",
	"difficulty":"0x%x",
	"alloc": %s
}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), accountJson)
	block, _ := WriteGenesisBlock(db, strings.NewReader(testGenesis))
	return block
}

func WriteTestNetGenesisBlock(chainDb ethdb.Database, nonce uint64) (*types.Block, error) {
	testGenesis := fmt.Sprintf(`{
	"nonce":"0x%x",
	"gasLimit":"0x%x",
	"difficulty":"0x%x",
	"alloc": {
		"0000000000000000000000000000000000000001": {"balance": "1"},
		"0000000000000000000000000000000000000002": {"balance": "1"},
		"0000000000000000000000000000000000000003": {"balance": "1"},
		"0000000000000000000000000000000000000004": {"balance": "1"},
		"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
	}
}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
	return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis))
}
<commit_msg>core: fix #1848, block receipts db entry for the genesis too<commit_after>// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package core

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"strings"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/params"
)

// WriteGenesisBlock writes the genesis block to the database as block number 0
func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) {
	contents, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	var genesis struct {
		Nonce      string
		Timestamp  string
		ParentHash string
		ExtraData  string
		GasLimit   string
		Difficulty string
		Mixhash    string
		Coinbase   string
		Alloc      map[string]struct {
			Code    string
			Storage map[string]string
			Balance string
		}
	}

	if err := json.Unmarshal(contents, &genesis); err != nil {
		return nil, err
	}

	statedb := state.New(common.Hash{}, chainDb)
	for addr, account := range genesis.Alloc {
		address := common.HexToAddress(addr)
		statedb.AddBalance(address, common.String2Big(account.Balance))
		statedb.SetCode(address, common.Hex2Bytes(account.Code))
		for key, value := range account.Storage {
			statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
		}
	}
	statedb.SyncObjects()

	difficulty := common.String2Big(genesis.Difficulty)
	block := types.NewBlock(&types.Header{
		Nonce:      types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()),
		Time:       common.String2Big(genesis.Timestamp),
		ParentHash: common.HexToHash(genesis.ParentHash),
		Extra:      common.FromHex(genesis.ExtraData),
		GasLimit:   common.String2Big(genesis.GasLimit),
		Difficulty: difficulty,
		MixDigest:  common.HexToHash(genesis.Mixhash),
		Coinbase:   common.HexToAddress(genesis.Coinbase),
		Root:       statedb.Root(),
	}, nil, nil, nil)

	if block := GetBlock(chainDb, block.Hash()); block != nil {
		glog.V(logger.Info).Infoln("Genesis block already in chain. Writing canonical number")
		err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
		if err != nil {
			return nil, err
		}
		return block, nil
	}
	statedb.Sync()

	if err := WriteTd(chainDb, block.Hash(), difficulty); err != nil {
		return nil, err
	}
	if err := WriteBlock(chainDb, block); err != nil {
		return nil, err
	}
	if err := PutBlockReceipts(chainDb, block, nil); err != nil {
		return nil, err
	}
	if err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()); err != nil {
		return nil, err
	}
	if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil {
		return nil, err
	}
	return block, nil
}

// GenesisBlockForTesting creates a block in which addr has the given wei balance.
// The state trie of the block is written to db.
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
	statedb := state.New(common.Hash{}, db)
	obj := statedb.GetOrNewStateObject(addr)
	obj.SetBalance(balance)
	statedb.SyncObjects()
	statedb.Sync()
	block := types.NewBlock(&types.Header{
		Difficulty: params.GenesisDifficulty,
		GasLimit:   params.GenesisGasLimit,
		Root:       statedb.Root(),
	}, nil, nil, nil)
	return block
}

type GenesisAccount struct {
	Address common.Address
	Balance *big.Int
}

func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) *types.Block {
	accountJson := "{"
	for i, account := range accounts {
		if i != 0 {
			accountJson += ","
		}
		accountJson += fmt.Sprintf(`"0x%x":{"balance":"0x%x"}`, account.Address, account.Balance.Bytes())
	}
	accountJson += "}"

	testGenesis := fmt.Sprintf(`{
	"nonce":"0x%x",
	"gasLimit":"0x%x",
	"difficulty":"0x%x",
	"alloc": %s
}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), accountJson)
	block, _ := WriteGenesisBlock(db, strings.NewReader(testGenesis))
	return block
}

func WriteTestNetGenesisBlock(chainDb ethdb.Database, nonce uint64) (*types.Block, error) {
	testGenesis := fmt.Sprintf(`{
	"nonce":"0x%x",
	"gasLimit":"0x%x",
	"difficulty":"0x%x",
	"alloc": {
		"0000000000000000000000000000000000000001": {"balance": "1"},
		"0000000000000000000000000000000000000002": {"balance": "1"},
		"0000000000000000000000000000000000000003": {"balance": "1"},
		"0000000000000000000000000000000000000004": {"balance": "1"},
		"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
		"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
	}
}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
	return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis))
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Andrew Goulas
// Licensed under the MIT license.

package main

import (
	"sync"

	"github.com/structinf/Go-MCC/gomcc"
)

func (plugin *CorePlugin) initPhysics(level *gomcc.Level) {
	level.RegisterSimulator(&WaterSimulator{Level: level})
	level.RegisterSimulator(&LavaSimulator{Level: level})
	level.RegisterSimulator(&SandSimulator{Level: level})
}

type blockUpdate struct {
	index, ticks int
}

type BlockUpdateQueue struct {
	lock    sync.Mutex
	updates []blockUpdate
}

func (queue *BlockUpdateQueue) Add(index int, delay int) {
	queue.lock.Lock()
	queue.updates = append(queue.updates, blockUpdate{index, delay})
	queue.lock.Unlock()
}

func (queue *BlockUpdateQueue) Tick() (updates []int) {
	i := 0
	queue.lock.Lock()
	for _, update := range queue.updates {
		update.ticks--
		if update.ticks == 0 {
			updates = append(updates, update.index)
		} else {
			queue.updates[i] = update
			i++
		}
	}
	queue.updates = queue.updates[:i]
	queue.lock.Unlock()
	return
}

type WaterSimulator struct {
	Level *gomcc.Level
	queue BlockUpdateQueue
}

func (simulator *WaterSimulator) Update(block, old byte, index int) {
	if block == gomcc.BlockActiveWater || (block == gomcc.BlockWater && block == old) {
		simulator.queue.Add(index, 5)
	} else if block != old {
		if block == gomcc.BlockSponge {
			simulator.placeSponge(index)
		} else if old == gomcc.BlockSponge {
			simulator.breakSponge(index)
		}
	}
}

func (simulator *WaterSimulator) Tick() {
	level := simulator.Level
	for _, index := range simulator.queue.Tick() {
		block := level.Blocks[index]
		if block != gomcc.BlockActiveWater && block != gomcc.BlockWater {
			return
		}

		x, y, z := level.Position(index)
		if x < level.Width-1 {
			simulator.spread(x+1, y, z)
		}
		if x > 0 {
			simulator.spread(x-1, y, z)
		}
		if z < level.Length-1 {
			simulator.spread(x, y, z+1)
		}
		if z > 0 {
			simulator.spread(x, y, z-1)
		}
		if y > 0 {
			simulator.spread(x, y-1, z)
		}
	}
}

func (simulator *WaterSimulator) spread(x, y, z int) {
	level := simulator.Level
	switch level.GetBlock(x, y, z) {
	case gomcc.BlockAir:
		for yy := max(y-2, 0); yy <= min(y+2, level.Height-1); yy++ {
			for zz := max(z-2, 0); zz <= min(z+2, level.Length-1); zz++ {
				for xx := max(x-2, 0); xx <= min(x+2, level.Width-1); xx++ {
					if level.GetBlock(xx, yy, zz) == gomcc.BlockSponge {
						return
					}
				}
			}
		}

		level.SetBlock(x, y, z, gomcc.BlockActiveWater)

	case gomcc.BlockActiveLava, gomcc.BlockLava:
		level.SetBlock(x, y, z, gomcc.BlockStone)
	}
}

func (simulator *WaterSimulator) placeSponge(index int) {
	level := simulator.Level
	x, y, z := level.Position(index)
	for yy := max(y-2, 0); yy <= min(y+2, level.Height-1); yy++ {
		for zz := max(z-2, 0); zz <= min(z+2, level.Length-1); zz++ {
			for xx := max(x-2, 0); xx <= min(x+2, level.Width-1); xx++ {
				switch level.GetBlock(xx, yy, zz) {
				case gomcc.BlockActiveWater, gomcc.BlockWater:
					level.SetBlock(xx, yy, zz, gomcc.BlockAir)
				}
			}
		}
	}
}

func (simulator *WaterSimulator) breakSponge(index int) {
	level := simulator.Level
	x, y, z := level.Position(index)
	for yy := max(y-3, 0); yy <= min(y+3, level.Height-1); yy++ {
		for zz := max(z-3, 0); zz <= min(z+3, level.Length-1); zz++ {
			for xx := max(x-3, 0); xx <= min(x+3, level.Width-1); xx++ {
				if abs(xx-x) == 3 || abs(yy-y) == 3 || abs(zz-z) == 3 {
					switch level.GetBlock(xx, yy, zz) {
					case gomcc.BlockActiveWater, gomcc.BlockWater:
						level.UpdateBlock(xx, yy, zz)
					}
				}
			}
		}
	}
}

type LavaSimulator struct {
	Level *gomcc.Level
	queue BlockUpdateQueue
}

func (simulator *LavaSimulator) Update(block, old byte, index int) {
	if block == gomcc.BlockActiveLava || (block == gomcc.BlockLava && block == old) {
		simulator.queue.Add(index, 30)
	}
}

func (simulator *LavaSimulator) Tick() {
	level := simulator.Level
	for _, index := range simulator.queue.Tick() {
		block := level.Blocks[index]
		if block != gomcc.BlockActiveLava && block != gomcc.BlockLava {
			return
		}

		x, y, z := level.Position(index)
		if x < level.Width-1 {
			simulator.spread(x+1, y, z)
		}
		if x > 0 {
			simulator.spread(x-1, y, z)
		}
		if z < level.Length-1 {
			simulator.spread(x, y, z+1)
		}
		if z > 0 {
			simulator.spread(x, y, z-1)
		}
		if y > 0 {
			simulator.spread(x, y-1, z)
		}
	}
}

func (simulator *LavaSimulator) spread(x, y, z int) {
	level := simulator.Level
	switch level.GetBlock(x, y, z) {
	case gomcc.BlockAir:
		level.SetBlock(x, y, z, gomcc.BlockActiveLava)

	case gomcc.BlockActiveWater, gomcc.BlockWater:
		level.SetBlock(x, y, z, gomcc.BlockStone)
	}
}

type SandSimulator struct {
	Level *gomcc.Level
}

func (simulator *SandSimulator) Update(block, old byte, index int) {
	if block != gomcc.BlockSand && block != gomcc.BlockGravel {
		return
	}

	level := simulator.Level
	x, y0, z := level.Position(index)
	y1 := y0
	for y1 >= 0 && simulator.check(x, y1-1, z) {
		y1--
	}

	if y0 != y1 {
		level.SetBlock(x, y0, z, gomcc.BlockAir)
		level.SetBlock(x, y1, z, block)
	}
}

func (simulator *SandSimulator) Tick() {}

func (simulator *SandSimulator) check(x, y, z int) bool {
	switch simulator.Level.GetBlock(x, y, z) {
	case gomcc.BlockAir, gomcc.BlockActiveWater, gomcc.BlockWater,
		gomcc.BlockActiveLava, gomcc.BlockLava:
		return true
	default:
		return false
	}
}
<commit_msg>Edge water<commit_after>// Copyright (c) 2017-2019 Andrew Goulas
// Licensed under the MIT license.

package main

import (
	"sync"

	"github.com/structinf/Go-MCC/gomcc"
)

func (plugin *CorePlugin) initPhysics(level *gomcc.Level) {
	level.RegisterSimulator(&WaterSimulator{Level: level})
	level.RegisterSimulator(&LavaSimulator{Level: level})
	level.RegisterSimulator(&SandSimulator{Level: level})
}

type blockUpdate struct {
	index, ticks int
}

type BlockUpdateQueue struct {
	lock    sync.Mutex
	updates []blockUpdate
}

func (queue *BlockUpdateQueue) Add(index int, delay int) {
	queue.lock.Lock()
	queue.updates = append(queue.updates, blockUpdate{index, delay})
	queue.lock.Unlock()
}

func (queue *BlockUpdateQueue) Tick() (updates []int) {
	i := 0
	queue.lock.Lock()
	for _, update := range queue.updates {
		update.ticks--
		if update.ticks == 0 {
			updates = append(updates, update.index)
		} else {
			queue.updates[i] = update
			i++
		}
	}
	queue.updates = queue.updates[:i]
	queue.lock.Unlock()
	return
}

type WaterSimulator struct {
	Level *gomcc.Level
	queue BlockUpdateQueue
}

func (simulator *WaterSimulator) Update(block, old byte, index int) {
	if block == gomcc.BlockActiveWater || (block == gomcc.BlockWater && block == old) {
		simulator.queue.Add(index, 5)
	} else {
		level := simulator.Level
		x, y, z := level.Position(index)
		if block == gomcc.BlockAir && simulator.checkEdge(x, y, z) {
			level.SetBlock(x, y, z, gomcc.BlockActiveWater)
		} else if block != old {
			if block == gomcc.BlockSponge {
				simulator.placeSponge(x, y, z)
			} else if old == gomcc.BlockSponge {
				simulator.breakSponge(x, y, z)
			}
		}
	}
}

func (simulator *WaterSimulator) Tick() {
	level := simulator.Level
	for _, index := range simulator.queue.Tick() {
		block := level.Blocks[index]
		if block != gomcc.BlockActiveWater && block != gomcc.BlockWater {
			return
		}

		x, y, z := level.Position(index)
		if x < level.Width-1 {
			simulator.spread(x+1, y, z)
		}
		if x > 0 {
			simulator.spread(x-1, y, z)
		}
		if z < level.Length-1 {
			simulator.spread(x, y, z+1)
		}
		if z > 0 {
			simulator.spread(x, y, z-1)
		}
		if y > 0 {
			simulator.spread(x, y-1, z)
		}
	}
}

func (simulator *WaterSimulator) checkEdge(x, y, z int) bool {
	level := simulator.Level
	env := level.EnvConfig
	return (env.EdgeBlock == gomcc.BlockActiveWater || env.EdgeBlock == gomcc.BlockWater) &&
		y >= (env.EdgeHeight+env.SideOffset) && y < env.EdgeHeight &&
		(x == 0 || z == 0 || x == level.Width-1 || z == level.Length-1)
}

func (simulator *WaterSimulator) spread(x, y, z int) {
	level := simulator.Level
	switch level.GetBlock(x, y, z) {
	case gomcc.BlockAir:
		for yy := max(y-2, 0); yy <= min(y+2, level.Height-1); yy++ {
			for zz := max(z-2, 0); zz <= min(z+2, level.Length-1); zz++ {
				for xx := max(x-2, 0); xx <= min(x+2, level.Width-1); xx++ {
					if level.GetBlock(xx, yy, zz) == gomcc.BlockSponge {
						return
					}
				}
			}
		}

		level.SetBlock(x, y, z, gomcc.BlockActiveWater)

	case gomcc.BlockActiveLava, gomcc.BlockLava:
		level.SetBlock(x, y, z, gomcc.BlockStone)
	}
}

func (simulator *WaterSimulator) placeSponge(x, y, z int) {
	level := simulator.Level
	for yy := max(y-2, 0); yy <= min(y+2, level.Height-1); yy++ {
		for zz := max(z-2, 0); zz <= min(z+2, level.Length-1); zz++ {
			for xx := max(x-2, 0); xx <= min(x+2, level.Width-1); xx++ {
				switch level.GetBlock(xx, yy, zz) {
				case gomcc.BlockActiveWater, gomcc.BlockWater:
					level.SetBlock(xx, yy, zz, gomcc.BlockAir)
				}
			}
		}
	}
}

func (simulator *WaterSimulator) breakSponge(x, y, z int) {
	level := simulator.Level
	for yy := max(y-3, 0); yy <= min(y+3, level.Height-1); yy++ {
		for zz := max(z-3, 0); zz <= min(z+3, level.Length-1); zz++ {
			for xx := max(x-3, 0); xx <= min(x+3, level.Width-1); xx++ {
				if abs(xx-x) == 3 || abs(yy-y) == 3 || abs(zz-z) == 3 {
					switch level.GetBlock(xx, yy, zz) {
					case gomcc.BlockActiveWater, gomcc.BlockWater:
						level.UpdateBlock(xx, yy, zz)
					}
				}
			}
		}
	}
}

type LavaSimulator struct {
	Level *gomcc.Level
	queue BlockUpdateQueue
}

func (simulator *LavaSimulator) Update(block, old byte, index int) {
	if block == gomcc.BlockActiveLava || (block == gomcc.BlockLava && block == old) {
		simulator.queue.Add(index, 30)
	}
}

func (simulator *LavaSimulator) Tick() {
	level := simulator.Level
	for _, index := range simulator.queue.Tick() {
		block := level.Blocks[index]
		if block != gomcc.BlockActiveLava && block != gomcc.BlockLava {
			return
		}

		x, y, z := level.Position(index)
		if x < level.Width-1 {
			simulator.spread(x+1, y, z)
		}
		if x > 0 {
			simulator.spread(x-1, y, z)
		}
		if z < level.Length-1 {
			simulator.spread(x, y, z+1)
		}
		if z > 0 {
			simulator.spread(x, y, z-1)
		}
		if y > 0 {
			simulator.spread(x, y-1, z)
		}
	}
}

func (simulator *LavaSimulator) spread(x, y, z int) {
	level := simulator.Level
	switch level.GetBlock(x, y, z) {
	case gomcc.BlockAir:
		level.SetBlock(x, y, z, gomcc.BlockActiveLava)

	case gomcc.BlockActiveWater, gomcc.BlockWater:
		level.SetBlock(x, y, z, gomcc.BlockStone)
	}
}

type SandSimulator struct {
	Level *gomcc.Level
}

func (simulator *SandSimulator) Update(block, old byte, index int) {
	if block != gomcc.BlockSand && block != gomcc.BlockGravel {
		return
	}

	level := simulator.Level
	x, y0, z := level.Position(index)
	y1 := y0
	for y1 >= 0 && simulator.check(x, y1-1, z) {
		y1--
	}

	if y0 != y1 {
		level.SetBlock(x, y0, z, gomcc.BlockAir)
		level.SetBlock(x, y1, z, block)
	}
}

func (simulator *SandSimulator) Tick() {}

func (simulator *SandSimulator) check(x, y, z int) bool {
	switch simulator.Level.GetBlock(x, y, z) {
	case gomcc.BlockAir, gomcc.BlockActiveWater, gomcc.BlockWater,
		gomcc.BlockActiveLava, gomcc.BlockLava:
		return true
	default:
		return false
	}
}
<|endoftext|>