<commit_before>package scheduler

import (
	"github.com/uswitch/dagr/program"
	"log"
)

type Executor struct {
	executionRequests  chan *executionRequest
	executions         chan *program.Execution
	recordedExecutions map[string]*program.Execution
}

type executionResult struct {
	execution *program.Execution
	err       error
}

type executionRequest struct {
	program *program.Program
	result  chan *executionResult
}

func NewExecutor() *Executor {
	return &Executor{
		executionRequests:  make(chan *executionRequest),
		executions:         make(chan *program.Execution),
		recordedExecutions: make(map[string]*program.Execution),
	}
}

func (e *Executor) FindExecution(executionId string) *program.Execution {
	return e.recordedExecutions[executionId]
}

func (e *Executor) doExecute(er *executionRequest) (*program.Execution, error) {
	log.Println("executing", er.program.Name)

	execution, err := er.program.Execute()

	log.Println(er.program.Name, "executed")

	if err != nil {
		log.Println("execution error", err)
		er.result <- &executionResult{nil, err}
		// record error as well?
		return nil, err
	}

	log.Println("execution ok -- sending result to channel")
	er.result <- &executionResult{execution, nil}

	log.Println("result sent")
	e.recordedExecutions[execution.Id] = execution
	return execution, nil
}

func (e *Executor) Execute(p *program.Program) (*program.Execution, error) {
	ch := make(chan *executionResult)
	log.Println("sending execution request for program", p.Name)
	e.executionRequests <- &executionRequest{p, ch}
	log.Println("request sent -- awaiting result")
	result := <-ch
	log.Println("got result")
	return result.execution, result.err
}

func (e *Executor) RunExecutorLoop() {
	log.Println("running executor loop")
	for er := range e.executionRequests {
		log.Println("got an execution request")
		execution, err := e.doExecute(er)
		if err == nil {
			e.executions <- execution
			e.recordedExecutions[execution.Id] = execution
		} else {
			log.Println(err)
		}
	}
}
<commit_msg>ok -- works if we don't send to the executions channel (because nobody is listening to that yet)<commit_after>package scheduler

import (
	"github.com/uswitch/dagr/program"
	"log"
)

type Executor struct {
	executionRequests  chan *executionRequest
	executions         chan *program.Execution
	recordedExecutions map[string]*program.Execution
}

type executionResult struct {
	execution *program.Execution
	err       error
}

type executionRequest struct {
	program *program.Program
	result  chan *executionResult
}

func NewExecutor() *Executor {
	return &Executor{
		executionRequests:  make(chan *executionRequest),
		executions:         make(chan *program.Execution),
		recordedExecutions: make(map[string]*program.Execution),
	}
}

func (e *Executor) FindExecution(executionId string) *program.Execution {
	return e.recordedExecutions[executionId]
}

func (e *Executor) doExecute(er *executionRequest) (*program.Execution, error) {
	log.Println("executing", er.program.Name)

	execution, err := er.program.Execute()

	log.Println(er.program.Name, "executed")

	if err != nil {
		log.Println("execution error", err)
		er.result <- &executionResult{nil, err}
		// record error as well?
		return nil, err
	}

	log.Println("execution ok -- sending result to channel")
	er.result <- &executionResult{execution, nil}

	log.Println("result sent")
	e.recordedExecutions[execution.Id] = execution
	return execution, nil
}

func (e *Executor) Execute(p *program.Program) (*program.Execution, error) {
	ch := make(chan *executionResult)
	log.Println("sending execution request for program", p.Name)
	e.executionRequests <- &executionRequest{p, ch}
	log.Println("request sent -- awaiting result")
	result := <-ch
	log.Println("got result")
	return result.execution, result.err
}

func (e *Executor) RunExecutorLoop() {
	log.Println("running executor loop")
	for er := range e.executionRequests {
		log.Println("got an execution request")
		execution, err := e.doExecute(er)
		if err == nil {
			//e.executions <- execution // nothing is listening to this yet?
			e.recordedExecutions[execution.Id] = execution
		} else {
			log.Println(err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 ljy2010a
//
// 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 sentinel

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
	"testing"
	"time"

	"github.com/garyburd/redigo/redis"
)

// go test -v -race -coverprofile=c.out
// go tool cover -html=c.out -o c.html
// open c.html

func init() {
	log.SetFlags(log.Lshortfile | log.LstdFlags)
	log.SetPrefix(fmt.Sprintf("[Sentinel] "))
}

func TestSentinel(t *testing.T) {

	startAll()
	time.Sleep(time.Second * 3)
	defer func() {
		closeAll()
	}()

	sentinel := newDefaultSentinel()
	err := sentinel.Load()
	if err != nil {
		t.Fatalf("%v\n", err)
	}

	sentinel.Pool()
	sentinel.LastMasterAddr()

	timeTicker := time.NewTicker(time.Second)
	defer timeTicker.Stop()
	i := -1
	for {
		select {
		case <-timeTicker.C:
			i++
			if i > 180 {
				goto Exit
			}
			log.Printf("sentinels : %v \n", sentinel.SentinelsAddrs())
			// SETEX(sentinel, i)

			if i == 30 {
				log.Println("================ closeMaster ================")
				master.close()
			}

			if i == 70 {
				log.Println("================ closeSentinel1 ================")
				sentinel1.close()
			}

			if i == 90 {
				log.Println("================ startSentinel1 ================")
				go sentinel1.startCmd()
			}

			if i == 100 {
				log.Println("================ startMaster ================")
				go master.startCmd()
			}

			if i == 130 {
				log.Println("================ closeSlave ================")
				slave.close()
			}

		}
	}
Exit:
	sentinel.Close()
	log.Printf("Exit \n")

}

func SETEX(sentinel *Sentinel, i int) {
	pool := sentinel.Pool()
	if pool != nil {
		rconn := pool.Get()
		_, err := rconn.Do(
			"SETEX",
			fmt.Sprintf("test:%d", i),
			time.Second.Seconds()*3600,
			i,
		)
		rconn.Close()
		if err != nil {
			log.Printf("setex error :  %v\n", err)
		}
	}

}

func newDefaultSentinel() *Sentinel {
	sentinel := &Sentinel{
		// SentinelAddrs: []string{"127.0.0.1:26379", "127.0.0.1:26378"},
		SentinelAddrs: []string{"127.0.0.1:26379"},
		MasterName:    "mymaster",
		SentinelDial: func(addr string) (redis.Conn, error) {
			c, err := redis.Dial("tcp", addr)
			if err != nil {
				log.Printf("sentinel not Available %v \n", addr)
				return nil, err
			}
			log.Printf("sentinel Available %v \n", addr)
			return c, nil
		},
		PoolDial: func(addr string) (redis.Conn, error) {
			c, err := redis.Dial("tcp", addr)
			if err != nil {
				log.Printf("masterpool not Available %v \n", addr)
				return nil, err
			}
			log.Printf("masterpool Available at %v \n", addr)
			return c, nil
		},
		MasterPool: &redis.Pool{
			MaxIdle:     10,
			MaxActive:   200,
			Wait:        true,
			IdleTimeout: 60 * time.Second,
			TestOnBorrow: func(c redis.Conn, t time.Time) error {
				if getRole(c) != "master" {
					return fmt.Errorf("Role is not master")
				}
				return nil
			},
		},
		EnableSlaves: true,
		SlavesPoolTe: &redis.Pool{
			MaxIdle:     10,
			MaxActive:   200,
			Wait:        true,
			IdleTimeout: 60 * time.Second,
			TestOnBorrow: func(c redis.Conn, t time.Time) error {
				if getRole(c) != "slaves" {
					return fmt.Errorf("Role is not slaves")
				}
				return nil
			},
		},
		SlavesDial: func(addr string) (redis.Conn, error) {
			c, err := redis.Dial("tcp", addr)
			if err != nil {
				log.Printf("slavespool not Available %v \n", addr)
				return nil, err
			}
			log.Printf("slavespool Available at %v \n", addr)
			return c, nil
		},
	}
	return sentinel
}

var sentinel1 *serverCmd
var sentinel2 *serverCmd
var master *serverCmd
var slave *serverCmd

func closeAll() {
	sentinel1.close()
	time.Sleep(time.Second * 3)
	sentinel2.close()
	time.Sleep(time.Second * 3)
	master.close()
	time.Sleep(time.Second * 3)
	slave.close()
}

func startAll() {

	sentinel1 = newServerCmd("redis-sentinel", "test/redis-sentinel-26379", "redis-sentinel \\*:26379")
	sentinel2 = newServerCmd("redis-sentinel", "test/redis-sentinel-26378", "redis-sentinel \\*:26378")
	master = newServerCmd("redis-server", "test/redis-master", "redis-server 127.0.0.1:6378")
	slave = newServerCmd("redis-server", "test/redis-slave", "redis-server 127.0.0.1:6377")

	go sentinel1.startCmd()
	go sentinel2.startCmd()
	go master.startCmd()
	go slave.startCmd()
}

type serverCmd struct {
	cclose chan int
	cmd    string
	arg    string
	kill   string
	t      *testing.T
}

func newServerCmd(cmd, arg, kill string) *serverCmd {
	serverCmd := &serverCmd{
		cclose: make(chan int, 1),
		cmd:    cmd,
		arg:    arg,
		kill:   kill,
	}
	return serverCmd
}

func (s *serverCmd) startCmd() {
	cmd := exec.Command(s.cmd, s.arg)
	var out bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &out
	err := cmd.Start()
	cmd.Wait()
	log.Printf("kill ProcessState : %v : cmd is %v \n", cmd.ProcessState.Success, cmd.Args)
	if err != nil {
		// log.Printf("cmd out : %v \n", out.String())
	}

}

func (s *serverCmd) close() {
	// cmd.Process.Kill()

	cmdstr := fmt.Sprintf("ps -ef | grep '%s' | awk '{print $2}' | xargs kill -9 ", s.kill)
	cmd := exec.Command("bash", "-c", cmdstr)
	var out bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &out
	err := cmd.Run()
	log.Printf("kill ProcessState : %v : cmd is %v \n", cmd.ProcessState.Success, cmd.Args)
	if err != nil {
		// log.Printf("cmd out : %v \n", out.String())
	}
}
<commit_msg>* fix the go vet check<commit_after>// Copyright 2016 ljy2010a
//
// 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 sentinel

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
	"testing"
	"time"

	"github.com/garyburd/redigo/redis"
)

// go test -v -race -coverprofile=c.out
// go tool cover -html=c.out -o c.html
// open c.html

func init() {
	log.SetFlags(log.Lshortfile | log.LstdFlags)
	log.SetPrefix(fmt.Sprintf("[Sentinel] "))
}

func TestSentinel(t *testing.T) {

	startAll()
	time.Sleep(time.Second * 3)
	defer func() {
		closeAll()
	}()

	sentinel := newDefaultSentinel()
	err := sentinel.Load()
	if err != nil {
		t.Fatalf("%v\n", err)
	}

	sentinel.Pool()
	sentinel.LastMasterAddr()

	timeTicker := time.NewTicker(time.Second)
	defer timeTicker.Stop()
	i := -1
	for {
		select {
		case <-timeTicker.C:
			i++
			if i > 180 {
				goto Exit
			}
			log.Printf("sentinels : %v \n", sentinel.SentinelsAddrs())
			// SETEX(sentinel, i)

			if i == 30 {
				log.Println("================ closeMaster ================")
				master.close()
			}

			if i == 70 {
				log.Println("================ closeSentinel1 ================")
				sentinel1.close()
			}

			if i == 90 {
				log.Println("================ startSentinel1 ================")
				go sentinel1.startCmd()
			}

			if i == 100 {
				log.Println("================ startMaster ================")
				go master.startCmd()
			}

			if i == 130 {
				log.Println("================ closeSlave ================")
				slave.close()
			}

		}
	}
Exit:
	sentinel.Close()
	log.Printf("Exit \n")

}

func SETEX(sentinel *Sentinel, i int) {
	pool := sentinel.Pool()
	if pool != nil {
		rconn := pool.Get()
		_, err := rconn.Do(
			"SETEX",
			fmt.Sprintf("test:%d", i),
			time.Second.Seconds()*3600,
			i,
		)
		rconn.Close()
		if err != nil {
			log.Printf("setex error :  %v\n", err)
		}
	}

}

func newDefaultSentinel() *Sentinel {
	sentinel := &Sentinel{
		// SentinelAddrs: []string{"127.0.0.1:26379", "127.0.0.1:26378"},
		SentinelAddrs: []string{"127.0.0.1:26379"},
		MasterName:    "mymaster",
		SentinelDial: func(addr string) (redis.Conn, error) {
			c, err := redis.Dial("tcp", addr)
			if err != nil {
				log.Printf("sentinel not Available %v \n", addr)
				return nil, err
			}
			log.Printf("sentinel Available %v \n", addr)
			return c, nil
		},
		PoolDial: func(addr string) (redis.Conn, error) {
			c, err := redis.Dial("tcp", addr)
			if err != nil {
				log.Printf("masterpool not Available %v \n", addr)
				return nil, err
			}
			log.Printf("masterpool Available at %v \n", addr)
			return c, nil
		},
		MasterPool: &redis.Pool{
			MaxIdle:     10,
			MaxActive:   200,
			Wait:        true,
			IdleTimeout: 60 * time.Second,
			TestOnBorrow: func(c redis.Conn, t time.Time) error {
				if getRole(c) != "master" {
					return fmt.Errorf("Role is not master")
				}
				return nil
			},
		},
		EnableSlaves: true,
		SlavesPoolTe: &redis.Pool{
			MaxIdle:     10,
			MaxActive:   200,
			Wait:        true,
			IdleTimeout: 60 * time.Second,
			TestOnBorrow: func(c redis.Conn, t time.Time) error {
				if getRole(c) != "slaves" {
					return fmt.Errorf("Role is not slaves")
				}
				return nil
			},
		},
		SlavesDial: func(addr string) (redis.Conn, error) {
			c, err := redis.Dial("tcp", addr)
			if err != nil {
				log.Printf("slavespool not Available %v \n", addr)
				return nil, err
			}
			log.Printf("slavespool Available at %v \n", addr)
			return c, nil
		},
	}
	return sentinel
}

var sentinel1 *serverCmd
var sentinel2 *serverCmd
var master *serverCmd
var slave *serverCmd

func closeAll() {
	sentinel1.close()
	time.Sleep(time.Second * 3)
	sentinel2.close()
	time.Sleep(time.Second * 3)
	master.close()
	time.Sleep(time.Second * 3)
	slave.close()
}

func startAll() {

	sentinel1 = newServerCmd("redis-sentinel", "test/redis-sentinel-26379", "redis-sentinel \\*:26379")
	sentinel2 = newServerCmd("redis-sentinel", "test/redis-sentinel-26378", "redis-sentinel \\*:26378")
	master = newServerCmd("redis-server", "test/redis-master", "redis-server 127.0.0.1:6378")
	slave = newServerCmd("redis-server", "test/redis-slave", "redis-server 127.0.0.1:6377")

	go sentinel1.startCmd()
	go sentinel2.startCmd()
	go master.startCmd()
	go slave.startCmd()
}

type serverCmd struct {
	cclose chan int
	cmd    string
	arg    string
	kill   string
	t      *testing.T
}

func newServerCmd(cmd, arg, kill string) *serverCmd {
	serverCmd := &serverCmd{
		cclose: make(chan int, 1),
		cmd:    cmd,
		arg:    arg,
		kill:   kill,
	}
	return serverCmd
}

func (s *serverCmd) startCmd() {
	cmd := exec.Command(s.cmd, s.arg)
	var out bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &out
	err := cmd.Start()
	cmd.Wait()
	log.Printf("kill ProcessState : %v : cmd is %v \n", cmd.ProcessState.Success(), cmd.Args)
	if err != nil {
		// log.Printf("cmd out : %v \n", out.String())
	}

}

func (s *serverCmd) close() {
	// cmd.Process.Kill()

	cmdstr := fmt.Sprintf("ps -ef | grep '%s' | awk '{print $2}' | xargs kill -9 ", s.kill)
	cmd := exec.Command("bash", "-c", cmdstr)
	var out bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &out
	err := cmd.Run()
	log.Printf("kill ProcessState : %v : cmd is %v \n", cmd.ProcessState.Success(), cmd.Args)
	if err != nil {
		// log.Printf("cmd out : %v \n", out.String())
	}
}
<|endoftext|>


<commit_before>package server

import (
	"log"
	"net"

	"github.com/lologarithm/survival/server/messages"
)

// TODO: Track 'reliable' messages. Decide which need to be resent.

type Client struct {
	ID      uint32 // Unique ID for this session
	buffer  []byte
	wIdx    int
	address *net.UDPAddr

	// These channels are written to by another process
	FromNetwork     *BytePipe            // Bytes from client to server
	FromGameManager chan InternalMessage //

	// These channels can be written to in the client but not read from.
	toGameManager chan<- GameMessage // Messages to the main game manager.
	toActiveGame  chan<- GameMessage // Messages to the current game

	Seq   uint16
	Alive bool
}

// ProcessBytes accepts raw bytes from a socket and turns them into NetMessage objects and then
// later into GameMessages. These are passed into the GameManager. This function also
// accepts outgoing messages from the GameManager to the client.
func (client *Client) ProcessBytes(toClient chan OutgoingMessage, disconClient chan Client) {
	client.toGameManager <- GameMessage{
		client: client,
		net: &messages.Connected{
			IsConnected: 1,
		},
		mtype: messages.ConnectedMsgType,
	}
	client.Alive = true

	var toGame chan<- GameMessage // used once client is connected to a game. TODO: Shoudl this be cached on the cilent struct?
	for client.Alive {
		msgFrame, ok := messages.ParseFrame(client.buffer[:client.wIdx])
		numMsgBytes := messages.FrameLen + int(msgFrame.ContentLength)
		if msgFrame.MsgType == 255 {
			// TODO: this should probably not be a random 1off?
			client.Alive = false
			break
		} else if !ok || numMsgBytes > client.wIdx {
			if len(client.buffer) < client.wIdx+client.FromNetwork.Len() {
				newBuffer := make([]byte, client.wIdx+client.FromNetwork.Len())
				copy(newBuffer, client.buffer)
				client.buffer = newBuffer
			}
			n := client.FromNetwork.Read(client.buffer[client.wIdx:])
			client.wIdx += n
			continue
		}
		// Only try to parse if we have collected enough bytes.
		if ok && numMsgBytes <= client.wIdx {
			netMsg := messages.ParseNetMessage(msgFrame, client.buffer[messages.FrameLen:numMsgBytes])
			switch msgFrame.MsgType {
			case messages.CreateAcctMsgType, messages.LoginMsgType, messages.CreateCharMsgType, messages.DeleteCharMsgType, messages.ListGamesMsgType, messages.JoinGameMsgType, messages.CreateGameMsgType:
				client.toGameManager <- GameMessage{net: netMsg, client: client, mtype: msgFrame.MsgType}
			default:
				if toGame == nil {
					log.Printf("Client sent message type %d(%v) before in a game!", msgFrame.MsgType, netMsg)
					break
				}
				toGame <- GameMessage{net: netMsg, client: client, mtype: msgFrame.MsgType}
			}

			// Remove the used bytes from the buffer.
			copy(client.buffer, client.buffer[numMsgBytes:])
			client.wIdx -= numMsgBytes
		}
	}
	client.toGameManager <- GameMessage{
		client: client,
		net: &messages.Connected{
			IsConnected: 0,
		},
		mtype: messages.ConnectedMsgType,
	}
}
<commit_msg>fixed buffer expansion<commit_after>package server

import (
	"log"
	"net"

	"github.com/lologarithm/survival/server/messages"
)

// TODO: Track 'reliable' messages. Decide which need to be resent.

type Client struct {
	ID      uint32 // Unique ID for this session
	buffer  []byte
	wIdx    int
	address *net.UDPAddr

	// These channels are written to by another process
	FromNetwork     *BytePipe            // Bytes from client to server
	FromGameManager chan InternalMessage //

	// These channels can be written to in the client but not read from.
	toGameManager chan<- GameMessage // Messages to the main game manager.
	toActiveGame  chan<- GameMessage // Messages to the current game

	Seq   uint16
	Alive bool
}

// ProcessBytes accepts raw bytes from a socket and turns them into NetMessage objects and then
// later into GameMessages. These are passed into the GameManager. This function also
// accepts outgoing messages from the GameManager to the client.
func (client *Client) ProcessBytes(toClient chan OutgoingMessage, disconClient chan Client) {
	client.toGameManager <- GameMessage{
		client: client,
		net: &messages.Connected{
			IsConnected: 1,
		},
		mtype: messages.ConnectedMsgType,
	}
	client.Alive = true

	var toGame chan<- GameMessage // used once client is connected to a game. TODO: Shoudl this be cached on the cilent struct?
	for client.Alive {
		msgFrame, ok := messages.ParseFrame(client.buffer[:client.wIdx])
		numMsgBytes := messages.FrameLen + int(msgFrame.ContentLength)

		if len(client.buffer) < numMsgBytes {
			newBuffer := make([]byte, numMsgBytes*2)
			copy(newBuffer, client.buffer)
			client.buffer = newBuffer
		}

		if msgFrame.MsgType == 255 {
			// TODO: this should probably not be a random 1off?
			client.Alive = false
			break
		} else if !ok || numMsgBytes > client.wIdx {
			n := client.FromNetwork.Read(client.buffer[client.wIdx:])
			client.wIdx += n
			continue
		}
		// Only try to parse if we have collected enough bytes.
		if ok && numMsgBytes <= client.wIdx {
			netMsg := messages.ParseNetMessage(msgFrame, client.buffer[messages.FrameLen:numMsgBytes])
			switch msgFrame.MsgType {
			case messages.CreateAcctMsgType, messages.LoginMsgType, messages.CreateCharMsgType, messages.DeleteCharMsgType, messages.ListGamesMsgType, messages.JoinGameMsgType, messages.CreateGameMsgType:
				client.toGameManager <- GameMessage{net: netMsg, client: client, mtype: msgFrame.MsgType}
			default:
				if toGame == nil {
					log.Printf("Client sent message type %d(%v) before in a game!", msgFrame.MsgType, netMsg)
					break
				}
				toGame <- GameMessage{net: netMsg, client: client, mtype: msgFrame.MsgType}
			}

			// Remove the used bytes from the buffer.
			copy(client.buffer, client.buffer[numMsgBytes:])
			client.wIdx -= numMsgBytes
		}
	}
	client.toGameManager <- GameMessage{
		client: client,
		net: &messages.Connected{
			IsConnected: 0,
		},
		mtype: messages.ConnectedMsgType,
	}
}
<|endoftext|>


<commit_before>package main

import "github.com/BurntSushi/toml"

type Config struct {
	Key   string
	Token string
}

func ReadConfig(filename string) (Config, error) {
	var c Config
	_, err := toml.DecodeFile(filename, &c)
	if err != nil {
		return Config{}, err
	}
	return c, nil
}
<commit_msg>Token no longer needed with encryption of whole message<commit_after>package main

import "github.com/BurntSushi/toml"

type Config struct {
	Key string
}

func ReadConfig(filename string) (Config, error) {
	var c Config
	_, err := toml.DecodeFile(filename, &c)
	if err != nil {
		return Config{}, err
	}
	return c, nil
}
<|endoftext|>


<commit_before>package main

import (
    "flag"
    "io"
    "log"
    "os"
    "github.com/johnny-morrice/godelbrot/libgodelbrot"
)

func main() {
    var input io.Reader = os.Stdin
    var output io.Writer = os.Stdout

    args := readArgs()

    z, zerr := libgodelbrot.ReadZoom(input)
    if zerr != nil {
        log.Fatal("Could not read zoom:", zerr)
    }

    frames, moverr := z.Movie(args.count)
    if moverr != nil {
        log.Fatal("Error zooming:", moverr)
    }

    for _, info := range frames {
        outerr := libgodelbrot.WriteInfo(output, info)
        if outerr != nil {
            log.Println("Error writing output:", outerr)
            break
        }
    }
}

func readArgs() params {
    args := params{}
    flag.UintVar(&args.count, "frames", 1, "Number of frames in zoom")
    flag.Parse()

    return args
}

type params struct {
    count uint
}<commit_msg>Zoombrot provides useful process API<commit_after>package main

import (
    "errors"
    "flag"
    "io"
    "log"
    "os"
    lib "github.com/johnny-morrice/godelbrot/libgodelbrot"
)

func main() {
    var input io.Reader = os.Stdin
    var output io.Writer = os.Stdout

    args := readArgs()
    validerr := validateZoom(args)
    if validerr != nil {
        log.Fatal(validerr)
    }

    info, readerr := lib.ReadInfo(input)
    if readerr != nil {
        log.Fatal("Could not read info:", readerr)
    }

    z := lib.Zoom{}
    z.ZoomTarget = args.zt
    z.Prev = *info

    frames, moverr := z.Movie(args.count)
    if moverr != nil {
        log.Fatal("Error zooming:", moverr)
    }

    for _, info := range frames {
        outerr := lib.WriteInfo(output, info)
        if outerr != nil {
            log.Println("Error writing output:", outerr)
            break
        }
    }
}

func validateZoom(args params) error {
    if args.zt.Xmin >= args.zt.Xmax || args.zt.Ymin >= args.zt.Ymax {
        return errors.New("Min and max zoom boundaries are invalid.")
    }
    return nil
}

func readArgs() params {
    args := params{}
    flag.UintVar(&args.count, "frames", 1, "Number of frames in zoom")
    flag.UintVar(&args.zt.Xmin, "xmin", 0, "X-Min")
    flag.UintVar(&args.zt.Xmax, "xmax", 0, "X-Max")
    flag.UintVar(&args.zt.Ymin, "ymin", 0, "Y-Min")
    flag.UintVar(&args.zt.Ymax, "ymax", 0, "Y-Max")
    flag.BoolVar(&args.zt.Reconfigure, "reconf", true, "Reconfigure magnified request")
    flag.BoolVar(&args.zt.UpPrec, "incprec", true, "Increase precision for zoom")
    flag.Parse()

    return args
}

type params struct {
    count uint
    zt lib.ZoomTarget
}<|endoftext|>


<commit_before>package server

import (
    "fmt"
    "net/http"
    "encoding/json"
    "runtime"
    "flag"
    "log"
    "github.com/furio/icycle/idworker"
)

var (
    workerId = flag.Int64("w", 5, "Worker id")
    datacenterId = flag.Int64("d", 1, "Datacenter id")
    port = flag.String("p", "9000", "Port to listen on")
    lastStamp = flag.Int64("t", -1, "Last timestamp in milliseconds")
)
var idGenerator *idworker.IdWorker

type Sequence struct {
    Sequence int64
    Error error
}

func handlerTest(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

func handlerId(w http.ResponseWriter, r *http.Request) {
    seq,err := idGenerator.NextId();

    profile := Sequence{seq, err}

    js, err := json.Marshal(profile)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    log.Printf("%s", js)
    w.Header().Set("Content-Type", "application/json")
    w.Write(js)
}

func handlerWorker(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s", idGenerator.String())
}

func Main() {
    if (!initWorker()) {
        log.Fatal("Enable to init worker")
        return
    }

    runtime.GOMAXPROCS(runtime.NumCPU())
    http.HandleFunc("/", handlerTest)

    http.HandleFunc("/id", handlerId)
    http.HandleFunc("/worker", handlerWorker)

    log.Printf("Serving on port :%s", *port)
    http.ListenAndServe(":" + *port, nil)
}

func initWorker() bool {
    flag.Parse()

    var err error = nil
    idGenerator,err = idworker.NewIdWorker(*workerId,*datacenterId,*lastStamp)

    if (idGenerator == nil) {
        log.Fatal(err)
        return false
    }

    return true
}<commit_msg>Added /id/str to experiment from JS as well<commit_after>package server

import (
    "fmt"
    "net/http"
    "encoding/json"
    "runtime"
    "flag"
    "log"
    "strconv"
    "github.com/furio/icycle/idworker"
)

var (
    workerId = flag.Int64("w", 5, "Worker id")
    datacenterId = flag.Int64("d", 1, "Datacenter id")
    port = flag.String("p", "9000", "Port to listen on")
    lastStamp = flag.Int64("t", -1, "Last timestamp in milliseconds")
)
var idGenerator *idworker.IdWorker

type Sequence struct {
    Sequence int64
    Error error
}
type SequenceStr struct {
    Sequence string
    Error error
}

func handlerTest(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}

func handlerId(w http.ResponseWriter, r *http.Request) {
    seq,err := idGenerator.NextId();

    profile := Sequence{seq, err}

    js, err := json.Marshal(profile)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    log.Printf("%s", js)
    w.Header().Set("Content-Type", "application/json")
    w.Write(js)
}

func handlerIdStr(w http.ResponseWriter, r *http.Request) {
    seq,err := idGenerator.NextId();

    profile := SequenceStr{strconv.FormatInt(seq, 10), err}

    js, err := json.Marshal(profile)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    log.Printf("%s", js)
    w.Header().Set("Content-Type", "application/json")
    w.Write(js)
}

func handlerWorker(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s", idGenerator.String())
}

func Main() {
    if (!initWorker()) {
        log.Fatal("Enable to init worker")
        return
    }

    runtime.GOMAXPROCS(runtime.NumCPU())
    http.HandleFunc("/", handlerTest)

    http.HandleFunc("/id", handlerId)
    http.HandleFunc("/id/str", handlerIdStr)
    http.HandleFunc("/worker", handlerWorker)

    log.Printf("Serving on port :%s", *port)
    http.ListenAndServe(":" + *port, nil)
}

func initWorker() bool {
    flag.Parse()

    var err error = nil
    idGenerator,err = idworker.NewIdWorker(*workerId,*datacenterId,*lastStamp)

    if (idGenerator == nil) {
        log.Fatal(err)
        return false
    }

    return true
}<|endoftext|>


<commit_before>package server

import (
	"context"
	"io/ioutil"
	"net"
	"net/http"
	"reflect"
	"strings"
	"time"

	"github.com/getlantern/errors"
	"github.com/getlantern/golog"
	"github.com/getlantern/ops"
	"github.com/getlantern/proxy"
	"github.com/getlantern/proxy/filters"
	"github.com/getlantern/tlsdefaults"

	"github.com/getlantern/http-proxy/buffers"
	"github.com/getlantern/http-proxy/listeners"
)

var (
	testingLocal = false
	log          = golog.LoggerFor("server")
)

type listenerGenerator func(net.Listener) net.Listener

// Opts are used to configure a Server
type Opts struct {
	IdleTimeout time.Duration
	Filter      filters.Filter
	Dial        proxy.DialFunc
}

// Server is an HTTP proxy server.
type Server struct {
	// Allow is a function that determines whether or not to allow connections
	// from the given IP address. If unspecified, all connections are allowed.
	Allow              func(string) bool
	proxy              proxy.Proxy
	listenerGenerators []listenerGenerator
}

// New constructs a new HTTP proxy server using the given options
func New(opts *Opts) *Server {
	p, _ := proxy.New(&proxy.Opts{
		IdleTimeout:        opts.IdleTimeout,
		Dial:               opts.Dial,
		Filter:             opts.Filter,
		BufferSource:       buffers.Pool(),
		OKWaitsForUpstream: true,
		OnError: func(ctx filters.Context, req *http.Request, read bool, err error) *http.Response {
			status := http.StatusBadGateway
			if read {
				status = http.StatusBadRequest
			}
			return &http.Response{
				Request:    req,
				StatusCode: status,
				Body:       ioutil.NopCloser(strings.NewReader(err.Error())),
			}
		},
	})
	return &Server{
		proxy: p,
	}
}

func (s *Server) AddListenerWrappers(listenerGens ...listenerGenerator) {
	for _, g := range listenerGens {
		s.listenerGenerators = append(s.listenerGenerators, g)
	}
}

func (s *Server) ListenAndServeHTTP(addr string, readyCb func(addr string)) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	log.Debugf("Listen http on %s", addr)
	return s.serve(s.wrapListenerIfNecessary(listener), readyCb)
}

func (s *Server) ListenAndServeHTTPS(addr, keyfile, certfile string, readyCb func(addr string)) error {
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	listener, err := tlsdefaults.NewListener(s.wrapListenerIfNecessary(l), keyfile, certfile)
	if err != nil {
		return err
	}
	log.Debugf("Listen https on %s", addr)
	return s.serve(listener, readyCb)
}

func (s *Server) Serve(listener net.Listener, readyCb func(addr string)) error {
	return s.serve(s.wrapListenerIfNecessary(listener), readyCb)
}

func (s *Server) serve(listener net.Listener, readyCb func(addr string)) error {
	l := listeners.NewDefaultListener(listener)

	for _, wrap := range s.listenerGenerators {
		l = wrap(l)
	}

	if readyCb != nil {
		readyCb(l.Addr().String())
	}

	var tempDelay time.Duration // how long to sleep on accept failure
	for {
		conn, err := l.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				// delay code based on net/http.Server
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				log.Errorf("http: Accept error: %v; retrying in %v", err, tempDelay)
				time.Sleep(tempDelay)
				continue
			}
			return errors.New("Error accepting: %v", err)
		}
		tempDelay = 0
		s.handle(conn)
	}
}

func (s *Server) handle(conn net.Conn) {
	wrapConn, isWrapConn := conn.(listeners.WrapConn)
	if isWrapConn {
		wrapConn.OnState(http.StateNew)
	}
	go s.doHandle(conn, isWrapConn, wrapConn)
}

func (s *Server) doHandle(conn net.Conn, isWrapConn bool, wrapConn listeners.WrapConn) {
	clientIP := ""
	remoteAddr := conn.RemoteAddr()
	if remoteAddr != nil {
		clientIP, _, _ = net.SplitHostPort(remoteAddr.String())
	}
	op := ops.Begin("http_proxy_handle").Set("client_ip", clientIP)
	defer op.End()

	defer func() {
		p := recover()
		if p != nil {
			err := log.Errorf("Caught panic handling connection from %v: %v", conn.RemoteAddr(), p)
			if op != nil {
				op.FailIf(err)
			}
			safeClose(conn)
		}
	}()

	err := s.proxy.Handle(context.Background(), conn, conn)
	if err != nil {
		op.FailIf(errors.New("Error handling connection from %v: %v", conn.RemoteAddr(), err))
	}
	if isWrapConn {
		wrapConn.OnState(http.StateClosed)
	}
}

func safeClose(conn net.Conn) {
	defer func() {
		p := recover()
		if p != nil {
			log.Errorf("Panic on closing connection from %v: %v", conn.RemoteAddr(), p)
		}
	}()

	conn.Close()
}

func (s *Server) wrapListenerIfNecessary(l net.Listener) net.Listener {
	if s.Allow != nil {
		log.Debug("Wrapping listener with Allow")
		return &allowinglistener{l, s.Allow}
	}
	return l
}

type allowinglistener struct {
	wrapped net.Listener
	allow   func(string) bool
}

func (l *allowinglistener) Accept() (net.Conn, error) {
	conn, err := l.wrapped.Accept()
	if err != nil {
		return conn, err
	}

	ip := ""
	remoteAddr := conn.RemoteAddr()
	switch addr := remoteAddr.(type) {
	case *net.TCPAddr:
		ip = addr.IP.String()
	case *net.UDPAddr:
		ip = addr.IP.String()
	default:
		log.Errorf("Remote addr %v is of unknown type %v, unable to determine IP", remoteAddr, reflect.TypeOf(remoteAddr))
		return conn, err
	}
	if !l.allow(ip) {
		conn.Close()
		// Note - we don't return an error, because that causes http.Server to stop
		// serving.
	}

	return conn, err
}

func (l *allowinglistener) Close() error {
	return l.wrapped.Close()
}

func (l *allowinglistener) Addr() net.Addr {
	return l.wrapped.Addr()
}
<commit_msg>sends Server-Timing header with CONNECT response<commit_after>package server

import (
	"context"
	"io/ioutil"
	"net"
	"net/http"
	"reflect"
	"strings"
	"time"

	"github.com/getlantern/errors"
	"github.com/getlantern/golog"
	"github.com/getlantern/ops"
	"github.com/getlantern/proxy"
	"github.com/getlantern/proxy/filters"
	"github.com/getlantern/tlsdefaults"

	"github.com/getlantern/http-proxy/buffers"
	"github.com/getlantern/http-proxy/listeners"
)

var (
	testingLocal = false
	log          = golog.LoggerFor("server")
)

type listenerGenerator func(net.Listener) net.Listener

// Opts are used to configure a Server
type Opts struct {
	IdleTimeout time.Duration
	Filter      filters.Filter
	Dial        proxy.DialFunc
}

// Server is an HTTP proxy server.
type Server struct {
	// Allow is a function that determines whether or not to allow connections
	// from the given IP address. If unspecified, all connections are allowed.
	Allow              func(string) bool
	proxy              proxy.Proxy
	listenerGenerators []listenerGenerator
}

// New constructs a new HTTP proxy server using the given options
func New(opts *Opts) *Server {
	p, _ := proxy.New(&proxy.Opts{
		IdleTimeout:         opts.IdleTimeout,
		Dial:                opts.Dial,
		Filter:              opts.Filter,
		BufferSource:        buffers.Pool(),
		OKWaitsForUpstream:  true,
		OKSendsServerTiming: true,
		OnError: func(ctx filters.Context, req *http.Request, read bool, err error) *http.Response {
			status := http.StatusBadGateway
			if read {
				status = http.StatusBadRequest
			}
			return &http.Response{
				Request:    req,
				StatusCode: status,
				Body:       ioutil.NopCloser(strings.NewReader(err.Error())),
			}
		},
	})
	return &Server{
		proxy: p,
	}
}

func (s *Server) AddListenerWrappers(listenerGens ...listenerGenerator) {
	for _, g := range listenerGens {
		s.listenerGenerators = append(s.listenerGenerators, g)
	}
}

func (s *Server) ListenAndServeHTTP(addr string, readyCb func(addr string)) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	log.Debugf("Listen http on %s", addr)
	return s.serve(s.wrapListenerIfNecessary(listener), readyCb)
}

func (s *Server) ListenAndServeHTTPS(addr, keyfile, certfile string, readyCb func(addr string)) error {
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	listener, err := tlsdefaults.NewListener(s.wrapListenerIfNecessary(l), keyfile, certfile)
	if err != nil {
		return err
	}
	log.Debugf("Listen https on %s", addr)
	return s.serve(listener, readyCb)
}

func (s *Server) Serve(listener net.Listener, readyCb func(addr string)) error {
	return s.serve(s.wrapListenerIfNecessary(listener), readyCb)
}

func (s *Server) serve(listener net.Listener, readyCb func(addr string)) error {
	l := listeners.NewDefaultListener(listener)

	for _, wrap := range s.listenerGenerators {
		l = wrap(l)
	}

	if readyCb != nil {
		readyCb(l.Addr().String())
	}

	var tempDelay time.Duration // how long to sleep on accept failure
	for {
		conn, err := l.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				// delay code based on net/http.Server
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				log.Errorf("http: Accept error: %v; retrying in %v", err, tempDelay)
				time.Sleep(tempDelay)
				continue
			}
			return errors.New("Error accepting: %v", err)
		}
		tempDelay = 0
		s.handle(conn)
	}
}

func (s *Server) handle(conn net.Conn) {
	wrapConn, isWrapConn := conn.(listeners.WrapConn)
	if isWrapConn {
		wrapConn.OnState(http.StateNew)
	}
	go s.doHandle(conn, isWrapConn, wrapConn)
}

func (s *Server) doHandle(conn net.Conn, isWrapConn bool, wrapConn listeners.WrapConn) {
	clientIP := ""
	remoteAddr := conn.RemoteAddr()
	if remoteAddr != nil {
		clientIP, _, _ = net.SplitHostPort(remoteAddr.String())
	}
	op := ops.Begin("http_proxy_handle").Set("client_ip", clientIP)
	defer op.End()

	defer func() {
		p := recover()
		if p != nil {
			err := log.Errorf("Caught panic handling connection from %v: %v", conn.RemoteAddr(), p)
			if op != nil {
				op.FailIf(err)
			}
			safeClose(conn)
		}
	}()

	err := s.proxy.Handle(context.Background(), conn, conn)
	if err != nil {
		op.FailIf(errors.New("Error handling connection from %v: %v", conn.RemoteAddr(), err))
	}
	if isWrapConn {
		wrapConn.OnState(http.StateClosed)
	}
}

func safeClose(conn net.Conn) {
	defer func() {
		p := recover()
		if p != nil {
			log.Errorf("Panic on closing connection from %v: %v", conn.RemoteAddr(), p)
		}
	}()

	conn.Close()
}

func (s *Server) wrapListenerIfNecessary(l net.Listener) net.Listener {
	if s.Allow != nil {
		log.Debug("Wrapping listener with Allow")
		return &allowinglistener{l, s.Allow}
	}
	return l
}

type allowinglistener struct {
	wrapped net.Listener
	allow   func(string) bool
}

func (l *allowinglistener) Accept() (net.Conn, error) {
	conn, err := l.wrapped.Accept()
	if err != nil {
		return conn, err
	}

	ip := ""
	remoteAddr := conn.RemoteAddr()
	switch addr := remoteAddr.(type) {
	case *net.TCPAddr:
		ip = addr.IP.String()
	case *net.UDPAddr:
		ip = addr.IP.String()
	default:
		log.Errorf("Remote addr %v is of unknown type %v, unable to determine IP", remoteAddr, reflect.TypeOf(remoteAddr))
		return conn, err
	}
	if !l.allow(ip) {
		conn.Close()
		// Note - we don't return an error, because that causes http.Server to stop
		// serving.
	}

	return conn, err
}

func (l *allowinglistener) Close() error {
	return l.wrapped.Close()
}

func (l *allowinglistener) Addr() net.Addr {
	return l.wrapped.Addr()
}
<|endoftext|>


<commit_before>package server

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

	"github.com/zyfdegh/hiupdate/server/conf"
	"github.com/zyfdegh/hiupdate/server/entity"
	"github.com/zyfdegh/hiupdate/server/service"
)

var port = conf.OptionsReady.Port

// Serve do router mapping and start http server
func Serve() {
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	http.HandleFunc("/", handleRoot)
	http.HandleFunc("/update/", handleUpdate)

	s := &http.Server{Addr: fmt.Sprintf(":%d", port)}
	log.Printf("server start on localhost:%d", port)
	if err := s.ListenAndServe(); err != nil {
		log.Fatalf("start server error: %v", err)
	}
}

func handleRoot(w http.ResponseWriter, req *http.Request) {
	http.ServeFile(w, req, "static/html/index.html")
}

func handleUpdate(w http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case http.MethodGet:
		getUpdate(w, req)
	case http.MethodPut:
		putUpdate(w, req)
	default:
		io.WriteString(w, "method not allowed")
	}
	return
}

// GET /update?name="Zhang"
func getUpdate(w http.ResponseWriter, req *http.Request) {
	var name = req.FormValue("name")
	var date = req.FormValue("date")
	fmt.Println(name)
	fmt.Println(date)
	resp, err := service.GetUpdate(name, date)
	if err != nil {
		log.Printf("serve get update request error: %v", err)
		return
	}
	body, err := json.Marshal(resp)
	if err != nil {
		log.Printf("marshal object error: %v", err)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, string(body))
}

// PUT /update
// Body entity.ReqUpdate
func putUpdate(w http.ResponseWriter, req *http.Request) {
	var reqUpdate = &entity.ReqUpdate{}
	data, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Printf("read request error: %v", err)
		return
	}
	err = json.Unmarshal(data, reqUpdate)
	if err != nil {
		log.Printf("unmarshal to object error: %v", err)
		return
	}

	resp, err := service.PutUpdate(reqUpdate)
	if err != nil {
		log.Printf("serve put update request error: %v", err)
		return
	}
	body, err := json.Marshal(resp)
	if err != nil {
		log.Printf("marshal object error: %v", err)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, string(body))
	return
}
<commit_msg>log request<commit_after>package server

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

	"github.com/zyfdegh/hiupdate/server/conf"
	"github.com/zyfdegh/hiupdate/server/entity"
	"github.com/zyfdegh/hiupdate/server/service"
)

var port = conf.OptionsReady.Port

// Serve do router mapping and start http server
func Serve() {
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	http.HandleFunc("/", handleRoot)
	http.HandleFunc("/update/", handleUpdate)

	s := &http.Server{Addr: fmt.Sprintf(":%d", port)}
	log.Printf("server start on localhost:%d", port)
	if err := s.ListenAndServe(); err != nil {
		log.Fatalf("start server error: %v", err)
	}
}

func handleRoot(w http.ResponseWriter, req *http.Request) {
	http.ServeFile(w, req, "static/html/index.html")
}

func handleUpdate(w http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case http.MethodGet:
		getUpdate(w, req)
	case http.MethodPut:
		putUpdate(w, req)
	default:
		io.WriteString(w, "method not allowed")
	}
	return
}

// GET /update?name="Zhang"
func getUpdate(w http.ResponseWriter, req *http.Request) {
	var name = req.FormValue("name")
	var date = req.FormValue("date")
	fmt.Println(name)
	fmt.Println(date)
	resp, err := service.GetUpdate(name, date)
	if err != nil {
		log.Printf("serve get update request error: %v", err)
		return
	}
	body, err := json.Marshal(resp)
	if err != nil {
		log.Printf("marshal object error: %v", err)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, string(body))
}

// PUT /update
// Body entity.ReqUpdate
func putUpdate(w http.ResponseWriter, req *http.Request) {
	var reqUpdate = &entity.ReqUpdate{}
	data, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Printf("read request error: %v", err)
		return
	}
	err = json.Unmarshal(data, reqUpdate)
	if err != nil {
		log.Printf("unmarshal to object error: %v", err)
		return
	}

	fmt.Println("/**********")
	fmt.Printf("Name: %s\n", reqUpdate.Name)
	fmt.Printf("Done: %s\n", reqUpdate.Done)
	fmt.Printf("Todo: %s\n", reqUpdate.Todo)
	fmt.Printf("Issue: %s\n", reqUpdate.Issue)
	fmt.Println("**********/")

	resp, err := service.PutUpdate(reqUpdate)
	if err != nil {
		log.Printf("serve put update request error: %v", err)
		return
	}
	body, err := json.Marshal(resp)
	if err != nil {
		log.Printf("marshal object error: %v", err)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, string(body))
	return
}
<|endoftext|>


<commit_before>package server

import (
	"net"
	"net/url"

	"github.com/tchap/steemwatch/config"
	"github.com/tchap/steemwatch/server/auth"
	"github.com/tchap/steemwatch/server/auth/facebook"
	"github.com/tchap/steemwatch/server/auth/github"
	"github.com/tchap/steemwatch/server/auth/google"
	"github.com/tchap/steemwatch/server/context"
	"github.com/tchap/steemwatch/server/db"
	"github.com/tchap/steemwatch/server/routes/api/notifiers/slack"
	"github.com/tchap/steemwatch/server/routes/home"
	"github.com/tchap/steemwatch/server/routes/logout"
	"github.com/tchap/steemwatch/server/sessions"
	"github.com/tchap/steemwatch/server/users/stores/mongodb"
	"github.com/tchap/steemwatch/server/views"

	"github.com/labstack/echo"
	"github.com/labstack/echo/engine"
	"github.com/labstack/echo/engine/fasthttp"
	"github.com/labstack/echo/middleware"
	"github.com/pkg/errors"
	"gopkg.in/mgo.v2"
	"gopkg.in/tomb.v2"
)

type Context struct {
	listener net.Listener

	t tomb.Tomb
}

func Run(mongo *mgo.Database, cfg *config.Config) (*Context, error) {
	serverCtx := &context.Context{}

	// Database.
	serverCtx.DB = mongo

	// User store.
	userStore := mongodb.NewUserStore(mongo.C("users"))

	// Session manager.
	hashKey, blockKey, err := getSecureCookieKeys(mongo)
	if err != nil {
		return nil, err
	}
	sessionManager, err := sessions.NewSessionManager(hashKey, blockKey, userStore)
	if err != nil {
		return nil, err
	}

	serverCtx.SessionManager = sessionManager

	// Server context.
	canonicalURL, err := url.Parse(cfg.CanonicalURL)
	if err != nil {
		return nil, errors.Wrap(err, "invalid canonical URL")
	}

	serverCtx.CanonicalURL = canonicalURL

	// Echo.
	e := echo.New()

	// Templates.
	renderer, err := views.NewRenderer("./server/views/*.html")
	if err != nil {
		return nil, err
	}
	e.SetRenderer(renderer)

	// Assets.
	e.Static("/app", "server/app")
	e.Static("/modules", "server/app/node_modules")
	e.Static("/assets/css", "server/assets/css")
	e.Static("/assets/js", "server/assets/js")
	e.Static("/assets/img", "server/assets/img")
	e.Static("/assets/fonts", "server/assets/fonts")
	e.Static("/assets/bootstrap", "server/app/node_modules/bootstrap/dist")

	// Middleware
	e.Pre(middleware.AddTrailingSlash())
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.CSRF([]byte("secret")))
	e.Use(middleware.Secure())

	// Web
	homeHandler := home.NewHandlerFunc(serverCtx)

	e.GET("/", homeHandler)
	e.GET("/logout/", logout.NewHandlerFunc(serverCtx))

	e.GET("/home/", homeHandler)
	e.GET("/events/", homeHandler)
	e.GET("/notifications/", homeHandler)

	facebookCallbackPath, _ := url.Parse("/auth/facebook/callback")
	facebookCallback := serverCtx.CanonicalURL.ResolveReference(facebookCallbackPath).String()
	facebookAuth := facebook.NewAuthenticator(cfg.FacebookClientId, cfg.FacebookClientSecret, facebookCallback)
	auth.Bind(serverCtx, e.Group("/auth/facebook"), facebookAuth)

	googleCallbackPath, _ := url.Parse("/auth/google/callback")
	googleCallback := serverCtx.CanonicalURL.ResolveReference(googleCallbackPath).String()
	googleAuth := google.NewAuthenticator(cfg.GoogleClientId, cfg.GoogleClientSecret, googleCallback)
	auth.Bind(serverCtx, e.Group("/auth/google"), googleAuth)

	githubCallbackPath, _ := url.Parse("/auth/github/callback")
	githubCallback := serverCtx.CanonicalURL.ResolveReference(githubCallbackPath).String()
	githubAuth := github.NewAuthenticator(cfg.GitHubClientId, cfg.GitHubClientSecret, githubCallback)
	auth.Bind(serverCtx, e.Group("/auth/github"), githubAuth)

	// API
	api := e.Group("/api", auth.Required(serverCtx))
	db.BindList(serverCtx, api.Group("/events/:kind/:list"))
	slack.Bind(serverCtx, api.Group("/notifiers/slack"))

	// Start server
	listener, err := net.Listen("tcp", cfg.ListenAddress)
	if err != nil {
		return nil, errors.Wrap(err, "failed to start the web server")
	}

	ctx := &Context{
		listener: listener,
	}

	ctx.t.Go(func() error {
		e.Run(fasthttp.WithConfig(engine.Config{
			Listener: listener,
		}))
		return nil
	})

	go func() {
		<-ctx.t.Dying()
		listener.Close()
	}()

	return ctx, nil
}

func (ctx *Context) Interrupt() {
	ctx.t.Kill(nil)
}

func (ctx *Context) Wait() error {
	return ctx.t.Wait()
}
<commit_msg>server: Close connections after 30 seconds<commit_after>package server

import (
	"net"
	"net/url"
	"time"

	"github.com/tchap/steemwatch/config"
	"github.com/tchap/steemwatch/server/auth"
	"github.com/tchap/steemwatch/server/auth/facebook"
	"github.com/tchap/steemwatch/server/auth/github"
	"github.com/tchap/steemwatch/server/auth/google"
	"github.com/tchap/steemwatch/server/context"
	"github.com/tchap/steemwatch/server/db"
	"github.com/tchap/steemwatch/server/routes/api/notifiers/slack"
	"github.com/tchap/steemwatch/server/routes/home"
	"github.com/tchap/steemwatch/server/routes/logout"
	"github.com/tchap/steemwatch/server/sessions"
	"github.com/tchap/steemwatch/server/users/stores/mongodb"
	"github.com/tchap/steemwatch/server/views"

	"github.com/labstack/echo"
	"github.com/labstack/echo/engine"
	"github.com/labstack/echo/engine/fasthttp"
	"github.com/labstack/echo/middleware"
	"github.com/pkg/errors"
	"gopkg.in/mgo.v2"
	"gopkg.in/tomb.v2"
)

type Context struct {
	listener net.Listener

	t tomb.Tomb
}

func Run(mongo *mgo.Database, cfg *config.Config) (*Context, error) {
	serverCtx := &context.Context{}

	// Database.
	serverCtx.DB = mongo

	// User store.
	userStore := mongodb.NewUserStore(mongo.C("users"))

	// Session manager.
	hashKey, blockKey, err := getSecureCookieKeys(mongo)
	if err != nil {
		return nil, err
	}
	sessionManager, err := sessions.NewSessionManager(hashKey, blockKey, userStore)
	if err != nil {
		return nil, err
	}

	serverCtx.SessionManager = sessionManager

	// Server context.
	canonicalURL, err := url.Parse(cfg.CanonicalURL)
	if err != nil {
		return nil, errors.Wrap(err, "invalid canonical URL")
	}

	serverCtx.CanonicalURL = canonicalURL

	// Echo.
	e := echo.New()

	// Templates.
	renderer, err := views.NewRenderer("./server/views/*.html")
	if err != nil {
		return nil, err
	}
	e.SetRenderer(renderer)

	// Assets.
	e.Static("/app", "server/app")
	e.Static("/modules", "server/app/node_modules")
	e.Static("/assets/css", "server/assets/css")
	e.Static("/assets/js", "server/assets/js")
	e.Static("/assets/img", "server/assets/img")
	e.Static("/assets/fonts", "server/assets/fonts")
	e.Static("/assets/bootstrap", "server/app/node_modules/bootstrap/dist")

	// Middleware
	e.Pre(middleware.AddTrailingSlash())
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.CSRF([]byte("secret")))
	e.Use(middleware.Secure())

	// Web
	homeHandler := home.NewHandlerFunc(serverCtx)

	e.GET("/", homeHandler)
	e.GET("/logout/", logout.NewHandlerFunc(serverCtx))

	e.GET("/home/", homeHandler)
	e.GET("/events/", homeHandler)
	e.GET("/notifications/", homeHandler)

	facebookCallbackPath, _ := url.Parse("/auth/facebook/callback")
	facebookCallback := serverCtx.CanonicalURL.ResolveReference(facebookCallbackPath).String()
	facebookAuth := facebook.NewAuthenticator(cfg.FacebookClientId, cfg.FacebookClientSecret, facebookCallback)
	auth.Bind(serverCtx, e.Group("/auth/facebook"), facebookAuth)

	googleCallbackPath, _ := url.Parse("/auth/google/callback")
	googleCallback := serverCtx.CanonicalURL.ResolveReference(googleCallbackPath).String()
	googleAuth := google.NewAuthenticator(cfg.GoogleClientId, cfg.GoogleClientSecret, googleCallback)
	auth.Bind(serverCtx, e.Group("/auth/google"), googleAuth)

	githubCallbackPath, _ := url.Parse("/auth/github/callback")
	githubCallback := serverCtx.CanonicalURL.ResolveReference(githubCallbackPath).String()
	githubAuth := github.NewAuthenticator(cfg.GitHubClientId, cfg.GitHubClientSecret, githubCallback)
	auth.Bind(serverCtx, e.Group("/auth/github"), githubAuth)

	// API
	api := e.Group("/api", auth.Required(serverCtx))
	db.BindList(serverCtx, api.Group("/events/:kind/:list"))
	slack.Bind(serverCtx, api.Group("/notifiers/slack"))

	// Start server
	listener, err := net.Listen("tcp", cfg.ListenAddress)
	if err != nil {
		return nil, errors.Wrap(err, "failed to start the web server")
	}

	ctx := &Context{
		listener: listener,
	}

	ctx.t.Go(func() error {
		srv := fasthttp.WithConfig(engine.Config{
			Listener: listener,
		})
		srv.MaxKeepaliveDuration = 30 * time.Second

		e.Run(srv)
		return nil
	})

	go func() {
		<-ctx.t.Dying()
		listener.Close()
	}()

	return ctx, nil
}

func (ctx *Context) Interrupt() {
	ctx.t.Kill(nil)
}

func (ctx *Context) Wait() error {
	return ctx.t.Wait()
}
<|endoftext|>


<commit_before>package server

import (
	"context"
	"crypto/tls"
	"log"
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/gabstv/manners"
	"github.com/gabstv/sandpiper/pathtree"
	"github.com/gabstv/sandpiper/route"
	"github.com/gabstv/sandpiper/util"
	"golang.org/x/crypto/acme"
	"golang.org/x/crypto/acme/autocert"
)

// Server is the structure that controls, routes and certificates.
type Server interface {
	Add(r route.Route) error
	Run() error
	Close()
	Init()
	ServeHTTP(w http.ResponseWriter, r *http.Request)
	Routes() map[string]route.Route
}

type sServer struct {
	Cfg         Config
	trieDomains *pathtree.Trie
	domains     map[string]*route.Route
	Logger      *log.Logger
	closeChan   chan os.Signal
	htps        *http.Server
}

// Default starts a server with the default configuration options
func Default(cfg *Config) Server {
	s := &sServer{}
	if cfg != nil {
		s.Cfg = *cfg
	}
	s.trieDomains = pathtree.NewTrie(".")
	s.domains = make(map[string]*route.Route, 0)
	s.Logger = log.New(os.Stderr, "[sp server] ", log.LstdFlags)
	return s
}

func (s *sServer) Routes() map[string]route.Route {
	mm := make(map[string]route.Route)
	for k, v := range s.domains {
		mm[k] = *v
	}
	return mm
}

func (s *sServer) startAPI(ctx context.Context) error {
	if s.Cfg.APIListen == "" {
		return nil
	}
	go runAPIV1(ctx, s, s.Cfg.APIListen, s.Cfg.APIKey, s.Cfg.Debug)
	if s.Cfg.APIDomain != "" {
		s.Add(route.Route{
			Autocert: s.Cfg.APIDomainAutocert,
			Domain:   s.Cfg.APIDomain,
			Server: route.RouteServer{
				OutAddress:  s.Cfg.APIListen,
				OutConnType: route.HTTP,
			},
			WsCFG: util.WsConfig{
				Enabled: false,
			},
		})
	}
	return nil
}

func (s *sServer) Add(r route.Route) error {
	rr := &route.Route{}
	*rr = r
	if rr.WsCFG.ReadBufferSize == 0 {
		rr.WsCFG.ReadBufferSize = 2048
	}
	if rr.WsCFG.WriteBufferSize == 0 {
		rr.WsCFG.WriteBufferSize = 2048
	}
	if rr.WsCFG.ReadDeadlineSeconds == 0 {
		rr.WsCFG.ReadDeadlineSeconds = time.Second * 60
	} else {
		if rr.WsCFG.ReadDeadlineSeconds < time.Millisecond {
			rr.WsCFG.ReadDeadlineSeconds = time.Duration(rr.WsCFG.ReadDeadlineSeconds) * time.Second
		}
	}
	err := s.trieDomains.Add(r.Domain, rr)
	if err != nil {
		return err
	}
	s.domains[r.Domain] = rr
	s.updateCertificates()
	return nil
}

func (s *sServer) updateCertificates() *autocert.Manager {
	autocdomains := make([]string, 0)
	for _, v := range s.domains {
		if v.Autocert {
			autocdomains = append(autocdomains, v.Domain)
		}
	}
	if len(autocdomains) < 1 {
		return nil
	}
	var m *autocert.Manager
	cpath := "/tmp/sandpiper"
	if s.Cfg.CachePath != "" {
		cpath = s.Cfg.CachePath
	}
	dcache := autocert.DirCache(cpath)
	m = &autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		HostPolicy: autocert.HostWhitelist(autocdomains...),
		Cache:      &dcache,
	}
	if s.Cfg.LetsEncryptURL != "" {
		m.Client = &acme.Client{DirectoryURL: s.Cfg.LetsEncryptURL}
	}

	certs := make(map[string]tls.Certificate)
	for k, v := range s.domains {
		if !v.Autocert && len(v.Certificate.KeyFile) > 0 && len(v.Certificate.CertFile) > 0 {
			ncert, err := tls.LoadX509KeyPair(v.Certificate.CertFile, v.Certificate.KeyFile)
			if err != nil {
				s.Logger.Println("Error loading certificate for", k, err.Error())
			} else {
				certs[k] = ncert
			}
		}
	}

	getcertfn := func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
		if dom, ok := certs[clientHello.ServerName]; ok {
			return &dom, nil
		}
		return m.GetCertificate(clientHello)
	}
	if s.Cfg.LetsEncryptURL == "dev" {
		getcertfn = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
			if dom, ok := certs[clientHello.ServerName]; ok {
				return &dom, nil
			}
			cccert, err := createCert(clientHello)
			if err != nil {
				return nil, err
			}
			certs[clientHello.ServerName] = cccert
			return &cccert, nil
		}
	}
	s.htps.TLSConfig = &tls.Config{GetCertificate: getcertfn}
	return m
}

func (s *sServer) Run() error {
	s.Init()
	errc := make(chan error, 3)
	ctx, cancelf := context.WithCancel(context.Background())

	s.htps = &http.Server{
		Addr: s.Cfg.ListenAddrTLS,
	}
	autocertManager := s.updateCertificates()

	s.htps.Handler = s

	go func() {
		if autocertManager == nil || s.Cfg.DisableTLS {
			s.Logger.Println("Listening HTTP")
			errc <- http.ListenAndServe(s.Cfg.ListenAddr, s)
		} else {
			s.Logger.Println("Listening accepting HTTP requests to the SNI challenge")
			errc <- http.ListenAndServe(s.Cfg.ListenAddr, autocertManager.HTTPHandler(s))
		}
	}()

	certs := make([]util.Certificate, 0, len(s.domains))
	for _, v := range s.domains {
		if v.Certificate.CertFile != "" {
			certs = append(certs, v.Certificate)
		}
	}
	var wrapper *util.ServerWrapper
	if !s.Cfg.DisableTLS {
		go func() {
			if s.Cfg.Graceful {
				s.Logger.Println("Listening HTTPS (Graceful)")
				wrapper = util.NewGracefulServer(manners.NewWithServer(s.htps))
			} else {
				s.Logger.Println("Listening HTTPS (Vanilla)")
				wrapper = util.NewVanillaServer(s.htps)
			}
			errc <- util.ListenAndServeTLSSNI(wrapper, certs)
		}()
	}
	//
	// API
	if err := s.startAPI(ctx); err != nil {
		s.Logger.Println("START API ERROR:", err.Error())
	}
	//
	go func() {
		s.closeChan = make(chan os.Signal, 1)
		<-s.closeChan
		cancelf()
		if wrapper != nil {
			wrapper.Close()
		}
		errc <- nil
	}()
	//
	err := <-errc
	return err
}

func (s *sServer) Close() {
	s.closeChan <- os.Interrupt
}

func (s *sServer) Init() {
	// first start setting the number of cpu cores to use
	ncpu := runtime.NumCPU()
	if s.Cfg.NumCPU > 0 && s.Cfg.NumCPU < ncpu {
		ncpu = s.Cfg.NumCPU
	}
	runtime.GOMAXPROCS(ncpu)
}

func (s *sServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h := r.Host
	if s.Cfg.Debug {
		if ho := r.Header.Get("X-Sandpiper-Host"); ho != "" {
			h = ho
		}
		s.Logger.Println("Host: " + h)
	}
	res := s.trieDomains.Find(h)
	if res == nil {
		if len(s.Cfg.FallbackDomain) > 0 {
			if s.Cfg.Debug {
				s.Logger.Println("FALLBACK DOMAIN", s.Cfg.FallbackDomain)
			}
			dom := s.domains[s.Cfg.FallbackDomain]
			if dom != nil {
				if dom.AuthMode != "" {
					switch dom.AuthMode {
					case "apikey":
						if dom.AuthValue != r.Header.Get(dom.AuthKey) {
							w.WriteHeader(http.StatusUnauthorized)
							return
						}
					}
				}
				dom.ReverseProxy(w, r)
				return
			}
		} else {
			if s.Cfg.Debug {
				s.Logger.Println("DOMAIN NOT FOUND")
			}
			http.Error(w, "domain not found "+h, http.StatusInternalServerError)
			return
		}
	}
	if res.EndRoute == nil {
		if s.Cfg.Debug {
			s.Logger.Println("ROUTE IS NULL")
		}
		http.Error(w, "route is null", http.StatusInternalServerError)
		return
	}
	if res.EndRoute.AuthMode != "" {
		switch res.EndRoute.AuthMode {
		case "apikey":
			if res.EndRoute.AuthValue != r.Header.Get(res.EndRoute.AuthKey) {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}
		}
	}
	res.EndRoute.ReverseProxy(w, r)
}
<commit_msg>server catch null fallback domain<commit_after>package server

import (
	"context"
	"crypto/tls"
	"log"
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/gabstv/manners"
	"github.com/gabstv/sandpiper/pathtree"
	"github.com/gabstv/sandpiper/route"
	"github.com/gabstv/sandpiper/util"
	"golang.org/x/crypto/acme"
	"golang.org/x/crypto/acme/autocert"
)

// Server is the structure that controls, routes and certificates.
type Server interface {
	Add(r route.Route) error
	Run() error
	Close()
	Init()
	ServeHTTP(w http.ResponseWriter, r *http.Request)
	Routes() map[string]route.Route
}

type sServer struct {
	Cfg         Config
	trieDomains *pathtree.Trie
	domains     map[string]*route.Route
	Logger      *log.Logger
	closeChan   chan os.Signal
	htps        *http.Server
}

// Default starts a server with the default configuration options
func Default(cfg *Config) Server {
	s := &sServer{}
	if cfg != nil {
		s.Cfg = *cfg
	}
	s.trieDomains = pathtree.NewTrie(".")
	s.domains = make(map[string]*route.Route, 0)
	s.Logger = log.New(os.Stderr, "[sp server] ", log.LstdFlags)
	return s
}

func (s *sServer) Routes() map[string]route.Route {
	mm := make(map[string]route.Route)
	for k, v := range s.domains {
		mm[k] = *v
	}
	return mm
}

func (s *sServer) startAPI(ctx context.Context) error {
	if s.Cfg.APIListen == "" {
		return nil
	}
	go runAPIV1(ctx, s, s.Cfg.APIListen, s.Cfg.APIKey, s.Cfg.Debug)
	if s.Cfg.APIDomain != "" {
		s.Add(route.Route{
			Autocert: s.Cfg.APIDomainAutocert,
			Domain:   s.Cfg.APIDomain,
			Server: route.RouteServer{
				OutAddress:  s.Cfg.APIListen,
				OutConnType: route.HTTP,
			},
			WsCFG: util.WsConfig{
				Enabled: false,
			},
		})
	}
	return nil
}

func (s *sServer) Add(r route.Route) error {
	rr := &route.Route{}
	*rr = r
	if rr.WsCFG.ReadBufferSize == 0 {
		rr.WsCFG.ReadBufferSize = 2048
	}
	if rr.WsCFG.WriteBufferSize == 0 {
		rr.WsCFG.WriteBufferSize = 2048
	}
	if rr.WsCFG.ReadDeadlineSeconds == 0 {
		rr.WsCFG.ReadDeadlineSeconds = time.Second * 60
	} else {
		if rr.WsCFG.ReadDeadlineSeconds < time.Millisecond {
			rr.WsCFG.ReadDeadlineSeconds = time.Duration(rr.WsCFG.ReadDeadlineSeconds) * time.Second
		}
	}
	err := s.trieDomains.Add(r.Domain, rr)
	if err != nil {
		return err
	}
	s.domains[r.Domain] = rr
	s.updateCertificates()
	return nil
}

func (s *sServer) updateCertificates() *autocert.Manager {
	autocdomains := make([]string, 0)
	for _, v := range s.domains {
		if v.Autocert {
			autocdomains = append(autocdomains, v.Domain)
		}
	}
	if len(autocdomains) < 1 {
		return nil
	}
	var m *autocert.Manager
	cpath := "/tmp/sandpiper"
	if s.Cfg.CachePath != "" {
		cpath = s.Cfg.CachePath
	}
	dcache := autocert.DirCache(cpath)
	m = &autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		HostPolicy: autocert.HostWhitelist(autocdomains...),
		Cache:      &dcache,
	}
	if s.Cfg.LetsEncryptURL != "" {
		m.Client = &acme.Client{DirectoryURL: s.Cfg.LetsEncryptURL}
	}

	certs := make(map[string]tls.Certificate)
	for k, v := range s.domains {
		if !v.Autocert && len(v.Certificate.KeyFile) > 0 && len(v.Certificate.CertFile) > 0 {
			ncert, err := tls.LoadX509KeyPair(v.Certificate.CertFile, v.Certificate.KeyFile)
			if err != nil {
				s.Logger.Println("Error loading certificate for", k, err.Error())
			} else {
				certs[k] = ncert
			}
		}
	}

	getcertfn := func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
		if dom, ok := certs[clientHello.ServerName]; ok {
			return &dom, nil
		}
		return m.GetCertificate(clientHello)
	}
	if s.Cfg.LetsEncryptURL == "dev" {
		getcertfn = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
			if dom, ok := certs[clientHello.ServerName]; ok {
				return &dom, nil
			}
			cccert, err := createCert(clientHello)
			if err != nil {
				return nil, err
			}
			certs[clientHello.ServerName] = cccert
			return &cccert, nil
		}
	}
	s.htps.TLSConfig = &tls.Config{GetCertificate: getcertfn}
	return m
}

func (s *sServer) Run() error {
	s.Init()
	errc := make(chan error, 3)
	ctx, cancelf := context.WithCancel(context.Background())

	s.htps = &http.Server{
		Addr: s.Cfg.ListenAddrTLS,
	}
	autocertManager := s.updateCertificates()

	s.htps.Handler = s

	go func() {
		if autocertManager == nil || s.Cfg.DisableTLS {
			s.Logger.Println("Listening HTTP")
			errc <- http.ListenAndServe(s.Cfg.ListenAddr, s)
		} else {
			s.Logger.Println("Listening accepting HTTP requests to the SNI challenge")
			errc <- http.ListenAndServe(s.Cfg.ListenAddr, autocertManager.HTTPHandler(s))
		}
	}()

	certs := make([]util.Certificate, 0, len(s.domains))
	for _, v := range s.domains {
		if v.Certificate.CertFile != "" {
			certs = append(certs, v.Certificate)
		}
	}
	var wrapper *util.ServerWrapper
	if !s.Cfg.DisableTLS {
		go func() {
			if s.Cfg.Graceful {
				s.Logger.Println("Listening HTTPS (Graceful)")
				wrapper = util.NewGracefulServer(manners.NewWithServer(s.htps))
			} else {
				s.Logger.Println("Listening HTTPS (Vanilla)")
				wrapper = util.NewVanillaServer(s.htps)
			}
			errc <- util.ListenAndServeTLSSNI(wrapper, certs)
		}()
	}
	//
	// API
	if err := s.startAPI(ctx); err != nil {
		s.Logger.Println("START API ERROR:", err.Error())
	}
	//
	go func() {
		s.closeChan = make(chan os.Signal, 1)
		<-s.closeChan
		cancelf()
		if wrapper != nil {
			wrapper.Close()
		}
		errc <- nil
	}()
	//
	err := <-errc
	return err
}

func (s *sServer) Close() {
	s.closeChan <- os.Interrupt
}

func (s *sServer) Init() {
	// first start setting the number of cpu cores to use
	ncpu := runtime.NumCPU()
	if s.Cfg.NumCPU > 0 && s.Cfg.NumCPU < ncpu {
		ncpu = s.Cfg.NumCPU
	}
	runtime.GOMAXPROCS(ncpu)
}

func (s *sServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h := r.Host
	if s.Cfg.Debug {
		if ho := r.Header.Get("X-Sandpiper-Host"); ho != "" {
			h = ho
		}
		s.Logger.Println("Host: " + h)
	}
	res := s.trieDomains.Find(h)
	if res == nil {
		if len(s.Cfg.FallbackDomain) > 0 {
			if s.Cfg.Debug {
				s.Logger.Println("FALLBACK DOMAIN", s.Cfg.FallbackDomain)
			}
			dom := s.domains[s.Cfg.FallbackDomain]
			if dom != nil {
				if dom.AuthMode != "" {
					switch dom.AuthMode {
					case "apikey":
						if dom.AuthValue != r.Header.Get(dom.AuthKey) {
							w.WriteHeader(http.StatusUnauthorized)
							return
						}
					}
				}
				dom.ReverseProxy(w, r)
				return
			} else {
				if s.Cfg.Debug {
					s.Logger.Println("FALLBACK DOMAIN NOT FOUND")
				}
				http.Error(w, "fallback domain not found "+h, http.StatusInternalServerError)
				return
			}
		} else {
			if s.Cfg.Debug {
				s.Logger.Println("DOMAIN NOT FOUND")
			}
			http.Error(w, "domain not found "+h, http.StatusInternalServerError)
			return
		}
	}
	if res.EndRoute == nil {
		if s.Cfg.Debug {
			s.Logger.Println("ROUTE IS NULL")
		}
		http.Error(w, "route is null", http.StatusInternalServerError)
		return
	}
	if res.EndRoute.AuthMode != "" {
		switch res.EndRoute.AuthMode {
		case "apikey":
			if res.EndRoute.AuthValue != r.Header.Get(res.EndRoute.AuthKey) {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}
		}
	}
	res.EndRoute.ReverseProxy(w, r)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/distribution/manifest/schema1"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/engine-api/types"
	humanize "github.com/dustin/go-humanize"
	"github.com/jessfraz/reg/registry"
	"github.com/urfave/cli"
)

const (
	// VERSION is the binary version.
	VERSION = "v0.1.0"

	dockerConfigPath = ".docker/config.json"
)

var (
	updating = false
)

// preload initializes any global options and configuration
// before the main or sub commands are run.
func preload(c *cli.Context) (err error) {
	if c.GlobalBool("debug") {
		logrus.SetLevel(logrus.DebugLevel)
	}

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "reg-server"
	app.Version = VERSION
	app.Author = "@jessfraz"
	app.Email = "no-reply@butts.com"
	app.Usage = "Docker registry v2 static UI server."
	app.Before = preload
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "run in debug mode",
		},
		cli.StringFlag{
			Name:  "username, u",
			Usage: "username for the registry",
		},
		cli.StringFlag{
			Name:  "password, p",
			Usage: "password for the registry",
		},
		cli.StringFlag{
			Name:  "registry, r",
			Usage: "URL to the provate registry (ex. r.j3ss.co)",
		},
		cli.StringFlag{
			Name:  "port",
			Value: "8080",
			Usage: "port for server to run on",
		},
		cli.StringFlag{
			Name:  "cert",
			Usage: "path to ssl cert",
		},
		cli.StringFlag{
			Name:  "key",
			Usage: "path to ssl key",
		},
		cli.StringFlag{
			Name:  "interval",
			Value: "5m",
			Usage: "interval to generate new index.html's at",
		},
	}
	app.Action = func(c *cli.Context) error {
		auth, err := getAuthConfig(c)
		if err != nil {
			return err
		}

		// create the registry client
		r, err := registry.New(auth, c.GlobalBool("debug"))
		if err != nil {
			return err
		}

		// get the path to the static directory
		wd, err := os.Getwd()
		if err != nil {
			return err
		}
		staticDir := filepath.Join(wd, "static")

		// create the initial index
		if err := createStaticIndex(r, staticDir); err != nil {
			return err
		}

		// parse the duration
		dur, err := time.ParseDuration(c.String("interval"))
		if err != nil {
			logrus.Fatalf("parsing %s as duration failed: %v", c.String("interval"), err)
		}
		ticker := time.NewTicker(dur)

		go func() {
			// create more indexes every X minutes based off interval
			for range ticker.C {
				if !updating {
					if err := createStaticIndex(r, staticDir); err != nil {
						logrus.Warnf("creating static index failed: %v", err)
					}
				}
			}
		}()

		// create mux server
		mux := http.NewServeMux()

		// static files handler
		staticHandler := http.FileServer(http.Dir(staticDir))
		mux.Handle("/", staticHandler)
		// TODO: add handler for individual repos

		// set up the server
		port := c.String("port")
		server := &http.Server{
			Addr:    ":" + port,
			Handler: mux,
		}
		logrus.Infof("Starting server on port %q", port)
		if c.String("cert") != "" && c.String("key") != "" {
			logrus.Fatal(server.ListenAndServeTLS(c.String("cert"), c.String("key")))
		} else {
			logrus.Fatal(server.ListenAndServe())
		}

		return nil
	}

	app.Run(os.Args)
}

func getAuthConfig(c *cli.Context) (types.AuthConfig, error) {
	if c.GlobalString("username") != "" && c.GlobalString("password") != "" && c.GlobalString("registry") != "" {
		return types.AuthConfig{
			Username:      c.GlobalString("username"),
			Password:      c.GlobalString("password"),
			ServerAddress: c.GlobalString("registry"),
		}, nil
	}

	dcfg, err := cliconfig.Load(cliconfig.ConfigDir())
	if err != nil {
		return types.AuthConfig{}, fmt.Errorf("Loading config file failed: %v", err)
	}

	// return error early if there are no auths saved
	if !dcfg.ContainsAuth() {
		if c.GlobalString("registry") != "" {
			return types.AuthConfig{
				ServerAddress: c.GlobalString("registry"),
			}, nil
		}
		return types.AuthConfig{}, fmt.Errorf("No auth was present in %s, please pass a registry, username, and password", cliconfig.ConfigDir())
	}

	// if they passed a specific registry, return those creds _if_ they exist
	if c.GlobalString("registry") != "" {
		if creds, ok := dcfg.AuthConfigs[c.GlobalString("registry")]; ok {
			return creds, nil
		}
		return types.AuthConfig{}, fmt.Errorf("No authentication credentials exist for %s", c.GlobalString("registry"))
	}

	// set the auth config as the registryURL, username and Password
	for _, creds := range dcfg.AuthConfigs {
		return creds, nil
	}

	return types.AuthConfig{}, fmt.Errorf("Could not find any authentication credentials")
}

func getRepoAndRef(c *cli.Context) (repo, ref string, err error) {
	if len(c.Args()) < 1 {
		return "", "", errors.New("pass the name of the repository")
	}

	arg := c.Args()[0]
	parts := []string{}
	if strings.Contains(arg, "@") {
		parts = strings.Split(c.Args()[0], "@")
	} else if strings.Contains(arg, ":") {
		parts = strings.Split(c.Args()[0], ":")
	} else {
		parts = []string{arg}
	}

	repo = parts[0]
	ref = "latest"
	if len(parts) > 1 {
		ref = parts[1]
	}

	return
}

type data struct {
	RegistryURL string
	LastUpdated string
	Repos       []repository
}

type repository struct {
	Name        string
	Tag         string
	RepoURI     string
	CreatedDate string
}

type v1Compatibility struct {
	ID      string    `json:"id"`
	Created time.Time `json:"created"`
}

func createStaticIndex(r *registry.Registry, staticDir string) error {
	updating = true
	logrus.Info("fetching catalog")
	repoList, err := r.Catalog("")
	if err != nil {
		return fmt.Errorf("getting catalog failed: %v", err)
	}

	logrus.Info("fetching tags")
	var repos []repository
	for _, repo := range repoList {
		// get the tags
		tags, err := r.Tags(repo)
		if err != nil {
			return fmt.Errorf("getting tags for %s failed: %v", repo, err)
		}
		for _, tag := range tags {
			// get the manifest

			manifest, err := r.Manifest(repo, tag)
			if err != nil {
				return fmt.Errorf("getting tags for %s:%s failed: %v", repo, tag, err)
			}

			var createdDate string
			if m1, ok := manifest.(schema1.SignedManifest); ok {
				history := m1.History
				for _, h := range history {
					var comp v1Compatibility
					if err := json.Unmarshal([]byte(h.V1Compatibility), &comp); err != nil {
						return fmt.Errorf("unmarshal v1compatibility failed: %v", err)
					}
					createdDate = humanize.Time(comp.Created)
					break
				}
			}

			repoURI := fmt.Sprintf("%s/%s", r.Domain, repo)
			if tag != "latest" {
				repoURI += ":" + tag
			}

			repos = append(repos, repository{
				Name:        repo,
				Tag:         tag,
				RepoURI:     repoURI,
				CreatedDate: createdDate,
			})
		}
	}

	// create temporoary file to save template to
	logrus.Info("creating temporary file for template")
	f, err := ioutil.TempFile("", "reg-server")
	if err != nil {
		return fmt.Errorf("creating temp file failed: %v", err)
	}
	defer f.Close()
	defer os.Remove(f.Name())

	// parse & execute the template
	logrus.Info("parsing and executing the template")
	templateDir := filepath.Join(staticDir, "../templates")
	lp := filepath.Join(templateDir, "layout.html")

	d := data{
		RegistryURL: r.Domain,
		Repos:       repos,
		LastUpdated: time.Now().Local().Format(time.RFC1123),
	}
	tmpl := template.Must(template.New("").ParseFiles(lp))
	if err := tmpl.ExecuteTemplate(f, "layout", d); err != nil {
		return fmt.Errorf("execute template failed: %v", err)
	}
	f.Close()

	logrus.Info("renaming the temporary file to index.html")
	index := filepath.Join(staticDir, "index.html")
	if err := os.Rename(f.Name(), index); err != nil {
		return fmt.Errorf("renaming result from %s to %s failed: %v", f.Name(), index, err)
	}
	updating = false
	return nil
}
<commit_msg>additional logging<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/distribution/manifest/schema1"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/engine-api/types"
	humanize "github.com/dustin/go-humanize"
	"github.com/jessfraz/reg/registry"
	"github.com/urfave/cli"
)

const (
	// VERSION is the binary version.
	VERSION = "v0.1.0"

	dockerConfigPath = ".docker/config.json"
)

var (
	updating = false
)

// preload initializes any global options and configuration
// before the main or sub commands are run.
func preload(c *cli.Context) (err error) {
	if c.GlobalBool("debug") {
		logrus.SetLevel(logrus.DebugLevel)
	}

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "reg-server"
	app.Version = VERSION
	app.Author = "@jessfraz"
	app.Email = "no-reply@butts.com"
	app.Usage = "Docker registry v2 static UI server."
	app.Before = preload
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "run in debug mode",
		},
		cli.StringFlag{
			Name:  "username, u",
			Usage: "username for the registry",
		},
		cli.StringFlag{
			Name:  "password, p",
			Usage: "password for the registry",
		},
		cli.StringFlag{
			Name:  "registry, r",
			Usage: "URL to the provate registry (ex. r.j3ss.co)",
		},
		cli.StringFlag{
			Name:  "port",
			Value: "8080",
			Usage: "port for server to run on",
		},
		cli.StringFlag{
			Name:  "cert",
			Usage: "path to ssl cert",
		},
		cli.StringFlag{
			Name:  "key",
			Usage: "path to ssl key",
		},
		cli.StringFlag{
			Name:  "interval",
			Value: "5m",
			Usage: "interval to generate new index.html's at",
		},
	}
	app.Action = func(c *cli.Context) error {
		auth, err := getAuthConfig(c)
		if err != nil {
			return err
		}

		// create the registry client
		r, err := registry.New(auth, c.GlobalBool("debug"))
		if err != nil {
			return err
		}

		// get the path to the static directory
		wd, err := os.Getwd()
		if err != nil {
			return err
		}
		staticDir := filepath.Join(wd, "static")

		// create the initial index
		if err := createStaticIndex(r, staticDir); err != nil {
			return err
		}

		// parse the duration
		dur, err := time.ParseDuration(c.String("interval"))
		if err != nil {
			logrus.Fatalf("parsing %s as duration failed: %v", c.String("interval"), err)
		}
		ticker := time.NewTicker(dur)

		go func() {
			// create more indexes every X minutes based off interval
			for range ticker.C {
				if !updating {
					if err := createStaticIndex(r, staticDir); err != nil {
						logrus.Warnf("creating static index failed: %v", err)
					}
				}
			}
		}()

		// create mux server
		mux := http.NewServeMux()

		// static files handler
		staticHandler := http.FileServer(http.Dir(staticDir))
		mux.Handle("/", staticHandler)
		// TODO: add handler for individual repos

		// set up the server
		port := c.String("port")
		server := &http.Server{
			Addr:    ":" + port,
			Handler: mux,
		}
		logrus.Infof("Starting server on port %q", port)
		if c.String("cert") != "" && c.String("key") != "" {
			logrus.Fatal(server.ListenAndServeTLS(c.String("cert"), c.String("key")))
		} else {
			logrus.Fatal(server.ListenAndServe())
		}

		return nil
	}

	app.Run(os.Args)
}

func getAuthConfig(c *cli.Context) (types.AuthConfig, error) {
	if c.GlobalString("username") != "" && c.GlobalString("password") != "" && c.GlobalString("registry") != "" {
		return types.AuthConfig{
			Username:      c.GlobalString("username"),
			Password:      c.GlobalString("password"),
			ServerAddress: c.GlobalString("registry"),
		}, nil
	}

	dcfg, err := cliconfig.Load(cliconfig.ConfigDir())
	if err != nil {
		return types.AuthConfig{}, fmt.Errorf("Loading config file failed: %v", err)
	}

	// return error early if there are no auths saved
	if !dcfg.ContainsAuth() {
		if c.GlobalString("registry") != "" {
			return types.AuthConfig{
				ServerAddress: c.GlobalString("registry"),
			}, nil
		}
		return types.AuthConfig{}, fmt.Errorf("No auth was present in %s, please pass a registry, username, and password", cliconfig.ConfigDir())
	}

	// if they passed a specific registry, return those creds _if_ they exist
	if c.GlobalString("registry") != "" {
		if creds, ok := dcfg.AuthConfigs[c.GlobalString("registry")]; ok {
			return creds, nil
		}
		return types.AuthConfig{}, fmt.Errorf("No authentication credentials exist for %s", c.GlobalString("registry"))
	}

	// set the auth config as the registryURL, username and Password
	for _, creds := range dcfg.AuthConfigs {
		return creds, nil
	}

	return types.AuthConfig{}, fmt.Errorf("Could not find any authentication credentials")
}

func getRepoAndRef(c *cli.Context) (repo, ref string, err error) {
	if len(c.Args()) < 1 {
		return "", "", errors.New("pass the name of the repository")
	}

	arg := c.Args()[0]
	parts := []string{}
	if strings.Contains(arg, "@") {
		parts = strings.Split(c.Args()[0], "@")
	} else if strings.Contains(arg, ":") {
		parts = strings.Split(c.Args()[0], ":")
	} else {
		parts = []string{arg}
	}

	repo = parts[0]
	ref = "latest"
	if len(parts) > 1 {
		ref = parts[1]
	}

	return
}

type data struct {
	RegistryURL string
	LastUpdated string
	Repos       []repository
}

type repository struct {
	Name        string
	Tag         string
	RepoURI     string
	CreatedDate string
}

type v1Compatibility struct {
	ID      string    `json:"id"`
	Created time.Time `json:"created"`
}

func createStaticIndex(r *registry.Registry, staticDir string) error {
	updating = true
	logrus.Info("fetching catalog")
	repoList, err := r.Catalog("")
	if err != nil {
		return fmt.Errorf("getting catalog failed: %v", err)
	}

	logrus.Info("fetching tags")
	var repos []repository
	for _, repo := range repoList {
		// get the tags
		tags, err := r.Tags(repo)
		if err != nil {
			return fmt.Errorf("getting tags for %s failed: %v", repo, err)
		}
		for _, tag := range tags {
			// get the manifest

			manifest, err := r.Manifest(repo, tag)
			if err != nil {
				return fmt.Errorf("getting tags for %s:%s failed: %v", repo, tag, err)
			}

			var createdDate string
			if m1, ok := manifest.(schema1.SignedManifest); ok {
				history := m1.History
				for _, h := range history {
					var comp v1Compatibility
					if err := json.Unmarshal([]byte(h.V1Compatibility), &comp); err != nil {
						return fmt.Errorf("unmarshal v1compatibility failed: %v", err)
					}
					createdDate = humanize.Time(comp.Created)
					break
				}
			}

			repoURI := fmt.Sprintf("%s/%s", r.Domain, repo)
			if tag != "latest" {
				repoURI += ":" + tag
			}

			repos = append(repos, repository{
				Name:        repo,
				Tag:         tag,
				RepoURI:     repoURI,
				CreatedDate: createdDate,
			})
		}
	}

	// create temporoary file to save template to
	logrus.Info("creating temporary file for template")
	f, err := ioutil.TempFile("", "reg-server")
	if err != nil {
		return fmt.Errorf("creating temp file failed: %v", err)
	}
	defer f.Close()
	defer os.Remove(f.Name())

	// parse & execute the template
	logrus.Info("parsing and executing the template")
	templateDir := filepath.Join(staticDir, "../templates")
	lp := filepath.Join(templateDir, "layout.html")

	d := data{
		RegistryURL: r.Domain,
		Repos:       repos,
		LastUpdated: time.Now().Local().Format(time.RFC1123),
	}
	tmpl := template.Must(template.New("").ParseFiles(lp))
	if err := tmpl.ExecuteTemplate(f, "layout", d); err != nil {
		return fmt.Errorf("execute template failed: %v", err)
	}
	f.Close()

	index := filepath.Join(staticDir, "index.html")
	logrus.Infof("renaming the temporary file %s to %s", f.Name(), index)
	if err := os.Rename(f.Name(), index); err != nil {
		return fmt.Errorf("renaming result from %s to %s failed: %v", f.Name(), index, err)
	}
	updating = false
	return nil
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"github.com/itsankoff/gotcha/common"
	"log"
)

type Server struct {
	transports      map[string]Transport
	users           []*common.User
	connected       chan *common.User
	disconnected    chan *common.User
	aggregate       chan *common.Message
	messageHandlers map[string]chan *common.Message

	outputStore  *OutputStore
	history      *History
	contactStore *ContactStore
	authRegistry *AuthRegistry
	fileStore    *FileStore

	control   *Control
	messanger *Messanger
}

func New(config *Config) *Server {
	s := &Server{
		transports:      make(map[string]Transport),
		users:           make([]*common.User, 10),
		connected:       make(chan *common.User),
		disconnected:    make(chan *common.User),
		aggregate:       make(chan *common.Message),
		messageHandlers: make(map[string]chan *common.Message),
	}

	s.outputStore = NewOutputStore()
	s.contactStore = NewContactStore()
	s.fileStore = NewFileStore(config.FileServerFolder,
		config.FileServerHost)

	historyInput := make(chan *common.Message)
	s.history = NewHistory(historyInput, s.outputStore)

	// register control handler
	controlInput := make(chan *common.Message)
	s.control = NewControl(controlInput, s.outputStore, s.contactStore)
	s.messageHandlers["control"] = controlInput

	// register message handler
	messangerInput := make(chan *common.Message)

	s.messanger = NewMessanger(messangerInput, s.history,
		s.outputStore, s.fileStore)
	s.messageHandlers["message"] = messangerInput
	s.messageHandlers["file"] = messangerInput
	s.messageHandlers["history"] = historyInput

	s.authRegistry = NewAuthRegistry()

	return s
}

func (s *Server) startRouter() {
	for {
		select {
		case msg := <-s.aggregate:
			cmdType := msg.CmdType()
			handler, ok := s.messageHandlers[cmdType]
			if ok {
				handler <- msg
			} else {
				log.Println("No registered handler for cmd type", cmdType)
			}
		}
	}
}

func (s *Server) aggregateMessages(user *common.User) {
	// 0: connected
	// 1: registered
	// 2: authenticated
	var state int
	for {
		select {
		case msg := <-user.In:
			if msg == nil {
				log.Println("Nil message in aggregate for id %s userId %s",
					user.Id, user.UserId)
				s.outputStore.RemoveOutput(user.UserId)
				return
			}

			switch state {
			case 0:
				if msg.CmdType() != "auth" && msg.Cmd() != "register" {
					log.Printf("Wrong message %s for state %d", msg.Cmd(), state)
					user.Disconnect()
					return
				}

				packet, err := msg.ParseJsonData()
				if err != nil {
					log.Println("Failed to parse register message data", err)
					user.Disconnect()
					return
				}

				username := packet["username"].(string)
				pass := packet["password"].(string)
				userId, registered := s.authRegistry.Register(username, pass)
				if !registered {
					log.Println("Registration for %s failed", username)
					user.Disconnect()
					return
				}

				response := common.NewResponse(msg, "user_id", userId)
				user.Out <- response
				state = 1
			case 1:
				if msg.CmdType() != "auth" || msg.Cmd() != "auth" {
					log.Printf("Wrong message %s for state %d", msg.Cmd(), state)
					user.Disconnect()
					return
				}

				packet, err := msg.ParseJsonData()
				if err != nil {
					log.Println("Failed to parse auth message data", err)
					user.Disconnect()
					return
				}

				userId := packet["user_id"].(string)
				pass := packet["password"].(string)
				authenticated := s.authRegistry.Authenticate(userId, pass)
				if !authenticated {
					log.Println("Authentication for %s failed", userId)
					user.Disconnect()
					return
				}

				user.UserId = userId
				s.outputStore.AddOutput(user.UserId, user.Out)
				state = 2

				response := common.NewResponse(msg, "authenticated", true)
				user.Out <- response
			case 2:
				log.Println("Forward message to aggregate", msg.From())
				s.aggregate <- msg
			}
		}
	}
}

func (s *Server) AddTransport(host string, t Transport) error {
	if host == "" {
		return errors.New("Can't add transport for an empty host")
	}

	if t == nil {
		return errors.New("Can't add nil transport")
	}

	_, ok := s.transports[host]
	if ok {
		// prevent adding multiple transports for the same url
		return errors.New("Try to add multiple transports for " + host)
	}

	s.transports[host] = t
	log.Println("Add transport for", host)
	return nil
}

func (s *Server) RemoveTransport(host string) error {
	_, ok := s.transports[host]
	if ok {
		delete(s.transports, host)
		log.Println("Remove transport for", host)
		return nil
	}

	return errors.New("No trasport for host " + host)
}

func (s *Server) userConnected() {
	log.Println("Start user connected observer")
	for {
		select {
		case user := <-s.connected:
			s.users = append(s.users, user)
			log.Println("Add user to server")
			go s.aggregateMessages(user)
		}
	}
}

func (s *Server) userDisconnected() {
	log.Println("Start user disconnected observer")
	for {
		select {
		case user := <-s.disconnected:
			for i, u := range s.users {
				if u == user {
					s.users = append(s.users[:i], s.users[i+1:]...)
					log.Println("Remove user from server", user.Id)
					break
				}
			}
		}
	}
}

func (s Server) echoHandler(user *common.User) {
	select {
	case msg := <-user.In:
		user.Out <- msg
	}
}

func (s *Server) Start(done <-chan interface{}) error {
	if len(s.transports) == 0 {
		return errors.New("Need to add transport before calling Start")
	}

	go s.startRouter()
	go s.userConnected()
	go s.userDisconnected()
	for url, t := range s.transports {
		log.Println("Start transport for", url)
		t.OnUserConnected(s.connected)
		t.OnUserDisconnected(s.disconnected)
		go t.Start(url, done)
	}

	<-done
	close(s.connected)
	close(s.disconnected)
	close(s.aggregate)
	return nil
}

func (s *Server) StartAsync() (chan interface{}, error) {
	if len(s.transports) == 0 {
		return nil, errors.New("Need to add transport before calling Start")
	}

	done := make(chan interface{})
	go s.Start(done)
	return done, nil
}
<commit_msg>Add authregistry as deps in control<commit_after>package server

import (
	"errors"
	"github.com/itsankoff/gotcha/common"
	"log"
)

type Server struct {
	transports      map[string]Transport
	users           []*common.User
	connected       chan *common.User
	disconnected    chan *common.User
	aggregate       chan *common.Message
	messageHandlers map[string]chan *common.Message

	outputStore  *OutputStore
	history      *History
	contactStore *ContactStore
	authRegistry *AuthRegistry
	fileStore    *FileStore

	control   *Control
	messanger *Messanger
}

func New(config *Config) *Server {
	s := &Server{
		transports:      make(map[string]Transport),
		users:           make([]*common.User, 10),
		connected:       make(chan *common.User),
		disconnected:    make(chan *common.User),
		aggregate:       make(chan *common.Message),
		messageHandlers: make(map[string]chan *common.Message),
	}

	s.contactStore = NewContactStore()
	s.authRegistry = NewAuthRegistry()
	s.outputStore = NewOutputStore()
	s.fileStore = NewFileStore(config.FileServerFolder,
		config.FileServerHost)

	historyInput := make(chan *common.Message)
	s.history = NewHistory(historyInput, s.outputStore)

	// register control handler
	controlInput := make(chan *common.Message)
	s.control = NewControl(controlInput, s.outputStore,
		s.contactStore, s.authRegistry)
	s.messageHandlers["control"] = controlInput

	// register message handler
	messangerInput := make(chan *common.Message)

	s.messanger = NewMessanger(messangerInput, s.history,
		s.outputStore, s.fileStore)
	s.messageHandlers["message"] = messangerInput
	s.messageHandlers["file"] = messangerInput
	s.messageHandlers["history"] = historyInput

	return s
}

func (s *Server) startRouter() {
	for {
		select {
		case msg := <-s.aggregate:
			cmdType := msg.CmdType()
			handler, ok := s.messageHandlers[cmdType]
			if ok {
				handler <- msg
			} else {
				log.Println("No registered handler for cmd type", cmdType)
			}
		}
	}
}

func (s *Server) aggregateMessages(user *common.User) {
	// 0: connected
	// 1: registered
	// 2: authenticated
	var state int
	for {
		select {
		case msg := <-user.In:
			if msg == nil {
				log.Println("Nil message in aggregate for id %s userId %s",
					user.Id, user.UserId)
				s.outputStore.RemoveOutput(user.UserId)
				return
			}

			switch state {
			case 0:
				if msg.CmdType() != "auth" && msg.Cmd() != "register" {
					log.Printf("Wrong message %s for state %d", msg.Cmd(), state)
					user.Disconnect()
					return
				}

				packet, err := msg.ParseJsonData()
				if err != nil {
					log.Println("Failed to parse register message data", err)
					user.Disconnect()
					return
				}

				username := packet["username"].(string)
				pass := packet["password"].(string)
				userId, registered := s.authRegistry.Register(username, pass)
				if !registered {
					log.Println("Registration for %s failed", username)
					user.Disconnect()
					return
				}

				response := common.NewResponse(msg, "user_id", userId)
				user.Out <- response
				state = 1
			case 1:
				if msg.CmdType() != "auth" || msg.Cmd() != "auth" {
					log.Printf("Wrong message %s for state %d", msg.Cmd(), state)
					user.Disconnect()
					return
				}

				packet, err := msg.ParseJsonData()
				if err != nil {
					log.Println("Failed to parse auth message data", err)
					user.Disconnect()
					return
				}

				userId := packet["user_id"].(string)
				pass := packet["password"].(string)
				authenticated := s.authRegistry.Authenticate(userId, pass)
				if !authenticated {
					log.Println("Authentication for %s failed", userId)
					user.Disconnect()
					return
				}

				user.UserId = userId
				s.outputStore.AddOutput(user.UserId, user.Out)
				state = 2

				response := common.NewResponse(msg, "authenticated", true)
				user.Out <- response
			case 2:
				log.Println("Forward message to aggregate", msg.From())
				s.aggregate <- msg
			}
		}
	}
}

func (s *Server) AddTransport(host string, t Transport) error {
	if host == "" {
		return errors.New("Can't add transport for an empty host")
	}

	if t == nil {
		return errors.New("Can't add nil transport")
	}

	_, ok := s.transports[host]
	if ok {
		// prevent adding multiple transports for the same url
		return errors.New("Try to add multiple transports for " + host)
	}

	s.transports[host] = t
	log.Println("Add transport for", host)
	return nil
}

func (s *Server) RemoveTransport(host string) error {
	_, ok := s.transports[host]
	if ok {
		delete(s.transports, host)
		log.Println("Remove transport for", host)
		return nil
	}

	return errors.New("No trasport for host " + host)
}

func (s *Server) userConnected() {
	log.Println("Start user connected observer")
	for {
		select {
		case user := <-s.connected:
			s.users = append(s.users, user)
			log.Println("Add user to server")
			go s.aggregateMessages(user)
		}
	}
}

func (s *Server) userDisconnected() {
	log.Println("Start user disconnected observer")
	for {
		select {
		case user := <-s.disconnected:
			for i, u := range s.users {
				if u == user {
					s.users = append(s.users[:i], s.users[i+1:]...)
					log.Println("Remove user from server", user.Id)
					break
				}
			}
		}
	}
}

func (s Server) echoHandler(user *common.User) {
	select {
	case msg := <-user.In:
		user.Out <- msg
	}
}

func (s *Server) Start(done <-chan interface{}) error {
	if len(s.transports) == 0 {
		return errors.New("Need to add transport before calling Start")
	}

	go s.startRouter()
	go s.userConnected()
	go s.userDisconnected()
	for url, t := range s.transports {
		log.Println("Start transport for", url)
		t.OnUserConnected(s.connected)
		t.OnUserDisconnected(s.disconnected)
		go t.Start(url, done)
	}

	<-done
	close(s.connected)
	close(s.disconnected)
	close(s.aggregate)
	return nil
}

func (s *Server) StartAsync() (chan interface{}, error) {
	if len(s.transports) == 0 {
		return nil, errors.New("Need to add transport before calling Start")
	}

	done := make(chan interface{})
	go s.Start(done)
	return done, nil
}
<|endoftext|>