<commit_before>package digitalocean

import (
	gossh "code.google.com/p/go.crypto/ssh"
	"errors"
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/communicator/ssh"
	"github.com/mitchellh/packer/packer"
	"log"
	"net"
	"time"
)

type stepConnectSSH struct {
	conn net.Conn
}

func (s *stepConnectSSH) Run(state map[string]interface{}) multistep.StepAction {
	config := state["config"].(config)
	privateKey := state["privateKey"].(string)
	ui := state["ui"].(packer.Ui)
	ipAddress := state["droplet_ip"]

	// Build the keyring for authentication. This stores the private key
	// we'll use to authenticate.
	keyring := &ssh.SimpleKeychain{}
	err := keyring.AddPEMKey(privateKey)
	if err != nil {
		err := fmt.Errorf("Error setting up SSH config: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Build the actual SSH client configuration
	sshConfig := &gossh.ClientConfig{
		User: config.SSHUsername,
		Auth: []gossh.ClientAuth{
			gossh.ClientAuthKeyring(keyring),
		},
	}

	// Start trying to connect to SSH
	connected := make(chan bool, 1)
	connectQuit := make(chan bool, 1)
	defer func() {
		connectQuit <- true
	}()

	go func() {
		var err error

		ui.Say("Connecting to the droplet via SSH...")
		attempts := 0
		for {
			select {
			case <-connectQuit:
				return
			default:
			}

			attempts += 1
			log.Printf(
				"Opening TCP conn for SSH to %s:%d (attempt %d)",
				ipAddress, config.SSHPort, attempts)
			s.conn, err = net.DialTimeout(
				"tcp",
				fmt.Sprintf("%s:%d", ipAddress, config.SSHPort),
				10*time.Second)
			if err == nil {
				break
			}

			// A brief sleep so we're not being overly zealous attempting
			// to connect to the instance.
			time.Sleep(500 * time.Millisecond)
		}

		connected <- true
	}()

	log.Printf("Waiting up to %s for SSH connection", config.SSHTimeout)
	timeout := time.After(config.SSHTimeout)

ConnectWaitLoop:
	for {
		select {
		case <-connected:
			// We connected. Just break the loop.
			break ConnectWaitLoop
		case <-timeout:
			err := errors.New("Timeout waiting for SSH to become available.")
			state["error"] = err
			ui.Error(err.Error())
			return multistep.ActionHalt
		case <-time.After(1 * time.Second):
			if _, ok := state[multistep.StateCancelled]; ok {
				log.Println("Interrupt detected, quitting waiting for SSH.")
				return multistep.ActionHalt
			}
		}
	}

	var comm packer.Communicator
	if err == nil {
		comm, err = ssh.New(s.conn, sshConfig)
	}

	if err != nil {
		err := fmt.Errorf("Error connecting to SSH: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Set the communicator on the state bag so it can be used later
	state["communicator"] = comm

	return multistep.ActionContinue
}

func (s *stepConnectSSH) Cleanup(map[string]interface{}) {
	if s.conn != nil {
		s.conn.Close()
	}
}
<commit_msg>builder/digitalocean: Reattempt SSH handshake a few times<commit_after>package digitalocean

import (
	gossh "code.google.com/p/go.crypto/ssh"
	"errors"
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/communicator/ssh"
	"github.com/mitchellh/packer/packer"
	"log"
	"net"
	"time"
)

type stepConnectSSH struct {
	conn net.Conn
}

func (s *stepConnectSSH) Run(state map[string]interface{}) multistep.StepAction {
	config := state["config"].(config)
	privateKey := state["privateKey"].(string)
	ui := state["ui"].(packer.Ui)
	ipAddress := state["droplet_ip"]

	// Build the keyring for authentication. This stores the private key
	// we'll use to authenticate.
	keyring := &ssh.SimpleKeychain{}
	err := keyring.AddPEMKey(privateKey)
	if err != nil {
		err := fmt.Errorf("Error setting up SSH config: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Build the actual SSH client configuration
	sshConfig := &gossh.ClientConfig{
		User: config.SSHUsername,
		Auth: []gossh.ClientAuth{
			gossh.ClientAuthKeyring(keyring),
		},
	}

	// Start trying to connect to SSH
	connected := make(chan error, 1)
	connectQuit := make(chan bool, 1)
	defer func() {
		connectQuit <- true
	}()

	var comm packer.Communicator
	go func() {
		var err error

		ui.Say("Connecting to the droplet via SSH...")
		attempts := 0
		handshakeAttempts := 0
		for {
			select {
			case <-connectQuit:
				return
			default:
			}

			attempts += 1
			log.Printf(
				"Opening TCP conn for SSH to %s:%d (attempt %d)",
				ipAddress, config.SSHPort, attempts)
			s.conn, err = net.DialTimeout(
				"tcp",
				fmt.Sprintf("%s:%d", ipAddress, config.SSHPort),
				10*time.Second)
			if err == nil {
				log.Println("TCP connection made. Attempting SSH handshake.")
				comm, err = ssh.New(s.conn, sshConfig)
				if err == nil {
					log.Println("Connected to SSH!")
					break
				}

				handshakeAttempts += 1
				log.Printf("SSH handshake error: %s", err)

				if handshakeAttempts > 5 {
					connected <- err
					return
				}
			}

			// A brief sleep so we're not being overly zealous attempting
			// to connect to the instance.
			time.Sleep(500 * time.Millisecond)
		}

		connected <- nil
	}()

	log.Printf("Waiting up to %s for SSH connection", config.SSHTimeout)
	timeout := time.After(config.SSHTimeout)

ConnectWaitLoop:
	for {
		select {
		case err := <-connected:
			if err != nil {
				err := fmt.Errorf("Error connecting to SSH: %s", err)
				state["error"] = err
				ui.Error(err.Error())
				return multistep.ActionHalt
			}

			// We connected. Just break the loop.
			break ConnectWaitLoop
		case <-timeout:
			err := errors.New("Timeout waiting for SSH to become available.")
			state["error"] = err
			ui.Error(err.Error())
			return multistep.ActionHalt
		case <-time.After(1 * time.Second):
			if _, ok := state[multistep.StateCancelled]; ok {
				log.Println("Interrupt detected, quitting waiting for SSH.")
				return multistep.ActionHalt
			}
		}
	}

	// Set the communicator on the state bag so it can be used later
	state["communicator"] = comm

	return multistep.ActionContinue
}

func (s *stepConnectSSH) Cleanup(map[string]interface{}) {
	if s.conn != nil {
		s.conn.Close()
	}
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"log"
	"path/filepath"
	"time"
)

// This step cleans up forwarded ports and exports the VM to an OVF.
//
// Uses:
//
// Produces:
//   exportPath string - The path to the resulting export.
type StepExport struct {
	Format     string
	OutputDir  string
	ExportOpts string
}

func (s *StepExport) Run(state multistep.StateBag) multistep.StepAction {
	driver := state.Get("driver").(Driver)
	ui := state.Get("ui").(packer.Ui)
	vmName := state.Get("vmName").(string)

	// Wait a second to ensure VM is really shutdown.
	log.Println("1 second timeout to ensure VM is really shutdown")
	time.Sleep(1 * time.Second)

	// Clear out the Packer-created forwarding rule
	ui.Say("Preparing to export machine...")
	ui.Message(fmt.Sprintf(
		"Deleting forwarded port mapping for SSH (host port %d)",
		state.Get("sshHostPort")))
	command := []string{"modifyvm", vmName, "--natpf1", "delete", "packerssh"}
	if err := driver.VBoxManage(command...); err != nil {
		err := fmt.Errorf("Error deleting port forwarding rule: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Export the VM to an OVF
	outputPath := filepath.Join(s.OutputDir, vmName+"."+s.Format)

	command = []string{
		"export",
		vmName,
		"--output",
		outputPath,
		s.ExportOpts,
	}

	ui.Say("Exporting virtual machine...")
	err := driver.VBoxManage(command...)
	if err != nil {
		err := fmt.Errorf("Error exporting virtual machine: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	state.Put("exportPath", outputPath)

	return multistep.ActionContinue
}

func (s *StepExport) Cleanup(state multistep.StateBag) {}
<commit_msg>Pass export_options individually to VBoxManage export<commit_after>package common

import (
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"log"
	"path/filepath"
	"strings"
	"time"
)

// This step cleans up forwarded ports and exports the VM to an OVF.
//
// Uses:
//
// Produces:
//   exportPath string - The path to the resulting export.
type StepExport struct {
	Format     string
	OutputDir  string
	ExportOpts string
}

func (s *StepExport) Run(state multistep.StateBag) multistep.StepAction {
	driver := state.Get("driver").(Driver)
	ui := state.Get("ui").(packer.Ui)
	vmName := state.Get("vmName").(string)

	// Wait a second to ensure VM is really shutdown.
	log.Println("1 second timeout to ensure VM is really shutdown")
	time.Sleep(1 * time.Second)

	// Clear out the Packer-created forwarding rule
	ui.Say("Preparing to export machine...")
	ui.Message(fmt.Sprintf(
		"Deleting forwarded port mapping for SSH (host port %d)",
		state.Get("sshHostPort")))
	command := []string{"modifyvm", vmName, "--natpf1", "delete", "packerssh"}
	if err := driver.VBoxManage(command...); err != nil {
		err := fmt.Errorf("Error deleting port forwarding rule: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Export the VM to an OVF
	outputPath := filepath.Join(s.OutputDir, vmName+"."+s.Format)

	command = []string{
		"export",
		vmName,
		"--output",
		outputPath,
	}

	command = append(command, strings.Fields(s.ExportOpts)...)

	ui.Say("Exporting virtual machine...")
	err := driver.VBoxManage(command...)
	if err != nil {
		err := fmt.Errorf("Error exporting virtual machine: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	state.Put("exportPath", outputPath)

	return multistep.ActionContinue
}

func (s *StepExport) Cleanup(state multistep.StateBag) {}
<|endoftext|>


<commit_before>//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    sflow.go
//: details: TODO
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//:     http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//: ----------------------------------------------------------------------------
package main

import (
	"bytes"
	"log"
	"net"
	"strconv"
	"sync"
	"time"

	"git.edgecastcdn.net/vflow/packet"
	"git.edgecastcdn.net/vflow/sflow"
)

type SFUDPMsg struct {
	raddr *net.UDPAddr
	body  []byte
}

var (
	sFlowUdpCh = make(chan SFUDPMsg, 1000)
	logger     *log.Logger
	verbose    bool
)

type SFlow struct {
	port        int
	addr        string
	laddr       *net.UDPAddr
	readTimeout time.Duration
	udpSize     int
	workers     int
	stop        bool
}

func NewSFlow(opts *Options) *SFlow {
	logger = opts.Logger
	verbose = opts.Verbose

	return &SFlow{
		port:    opts.SFlowPort,
		udpSize: opts.SFlowUDPSize,
		workers: opts.SFlowWorkers,
	}
}

func (s *SFlow) run() {
	var wg sync.WaitGroup

	hostPort := net.JoinHostPort(s.addr, strconv.Itoa(s.port))
	udpAddr, _ := net.ResolveUDPAddr("udp", hostPort)

	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		logger.Fatal(err)
	}

	for i := 0; i < s.workers; i++ {
		go func() {
			wg.Add(1)
			defer wg.Done()
			sFlowWorker()

		}()
	}

	logger.Printf("sFlow is running (workers#: %d)", s.workers)

	for !s.stop {
		b := make([]byte, s.udpSize)
		conn.SetReadDeadline(time.Now().Add(1e9))
		n, raddr, err := conn.ReadFromUDP(b)
		if err != nil {
			continue
		}
		sFlowUdpCh <- SFUDPMsg{raddr, b[:n]}
	}

	wg.Wait()
}

func (s *SFlow) shutdown() {
	s.stop = true
	logger.Println("stopped sflow service gracefully ...")
	time.Sleep(1 * time.Second)
	logger.Println("vFlow has been shutdown")
	close(sFlowUdpCh)
}

func sFlowWorker() {
	var (
		msg    SFUDPMsg
		ok     bool
		reader *bytes.Reader
		filter = []uint32{sflow.DataCounterSample}
	)

	for {
		if msg, ok = <-sFlowUdpCh; !ok {
			break
		}

		if verbose {
			logger.Printf("rcvd sflow data from: %s, size: %d bytes",
				msg.raddr, len(msg.body))
		}

		reader = bytes.NewReader(msg.body)
		d := sflow.NewSFDecoder(reader, filter)
		records, err := d.SFDecode()
		if err != nil {
			logger.Println(err)
		}
		for _, data := range records {
			switch data.(type) {
			case *packet.Packet:
				if verbose {
					logger.Printf("%#v\n", data)
				}
			case *sflow.ExtSwitchData:
				if verbose {
					logger.Printf("%#v\n", data)
				}
			case *sflow.FlowSample:
				if verbose {
					logger.Printf("%#v\n", data)
				}
			}
		}
	}
}
<commit_msg>optimize<commit_after>//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    sflow.go
//: details: TODO
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//:     http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//: ----------------------------------------------------------------------------
package main

import (
	"bytes"
	"net"
	"strconv"
	"sync"
	"time"

	"git.edgecastcdn.net/vflow/packet"
	"git.edgecastcdn.net/vflow/sflow"
)

type SFUDPMsg struct {
	raddr *net.UDPAddr
	body  []byte
}

var sFlowUdpCh = make(chan SFUDPMsg, 1000)

type SFlow struct {
	port        int
	addr        string
	laddr       *net.UDPAddr
	readTimeout time.Duration
	udpSize     int
	workers     int
	stop        bool
}

func NewSFlow() *SFlow {
	logger = opts.Logger
	verbose = opts.Verbose

	return &SFlow{
		port:    opts.SFlowPort,
		udpSize: opts.SFlowUDPSize,
		workers: opts.SFlowWorkers,
	}
}

func (s *SFlow) run() {
	var wg sync.WaitGroup

	hostPort := net.JoinHostPort(s.addr, strconv.Itoa(s.port))
	udpAddr, _ := net.ResolveUDPAddr("udp", hostPort)

	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		logger.Fatal(err)
	}

	for i := 0; i < s.workers; i++ {
		go func() {
			wg.Add(1)
			defer wg.Done()
			sFlowWorker()

		}()
	}

	logger.Printf("sFlow is running (workers#: %d)", s.workers)

	for !s.stop {
		b := make([]byte, s.udpSize)
		conn.SetReadDeadline(time.Now().Add(1e9))
		n, raddr, err := conn.ReadFromUDP(b)
		if err != nil {
			continue
		}
		sFlowUdpCh <- SFUDPMsg{raddr, b[:n]}
	}

	wg.Wait()
}

func (s *SFlow) shutdown() {
	s.stop = true
	logger.Println("stopped sflow service gracefully ...")
	time.Sleep(1 * time.Second)
	logger.Println("vFlow has been shutdown")
	close(sFlowUdpCh)
}

func sFlowWorker() {
	var (
		msg    SFUDPMsg
		ok     bool
		reader *bytes.Reader
		filter = []uint32{sflow.DataCounterSample}
	)

	for {
		if msg, ok = <-sFlowUdpCh; !ok {
			break
		}

		if verbose {
			logger.Printf("rcvd sflow data from: %s, size: %d bytes",
				msg.raddr, len(msg.body))
		}

		reader = bytes.NewReader(msg.body)
		d := sflow.NewSFDecoder(reader, filter)
		records, err := d.SFDecode()
		if err != nil {
			logger.Println(err)
		}
		for _, data := range records {
			switch data.(type) {
			case *packet.Packet:
				if verbose {
					logger.Printf("%#v\n", data)
				}
			case *sflow.ExtSwitchData:
				if verbose {
					logger.Printf("%#v\n", data)
				}
			case *sflow.FlowSample:
				if verbose {
					logger.Printf("%#v\n", data)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package xlsx

import (
	"errors"
	"fmt"
	"strconv"
)

// Sheet is a high level structure intended to provide user access to
// the contents of a particular sheet within an XLSX file.
type Sheet struct {
	Name        string
	File        *File
	Rows        []*Row
	Cols        []*Col
	MaxRow      int
	MaxCol      int
	Hidden      bool
	Selected    bool
	SheetViews  []SheetView
	SheetFormat SheetFormat
	AutoFilter  *AutoFilter
}

type SheetView struct {
	Pane *Pane
}

type Pane struct {
	XSplit      float64
	YSplit      float64
	TopLeftCell string
	ActivePane  string
	State       string // Either "split" or "frozen"
}

type SheetFormat struct {
	DefaultColWidth  float64
	DefaultRowHeight float64
	OutlineLevelCol  uint8
	OutlineLevelRow  uint8
}

type AutoFilter struct {
	TopLeftCell     string
	BottomRightCell string
}

// Add a new Row to a Sheet
func (s *Sheet) AddRow() *Row {
	row := &Row{Sheet: s}
	s.Rows = append(s.Rows, row)
	if len(s.Rows) > s.MaxRow {
		s.MaxRow = len(s.Rows)
	}
	return row
}

// Make sure we always have as many Rows as we do cells.
func (s *Sheet) maybeAddRow(rowCount int) {
	if rowCount > s.MaxRow {
		loopCnt := rowCount - s.MaxRow
		for i := 0; i < loopCnt; i++ {

			row := &Row{Sheet: s}
			s.Rows = append(s.Rows, row)
		}
		s.MaxRow = rowCount
	}
}

// Make sure we always have as many Rows as we do cells.
func (s *Sheet) Row(idx int) *Row {
	s.maybeAddRow(idx + 1)
	return s.Rows[idx]
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) maybeAddCol(cellCount int) {
	if cellCount > s.MaxCol {
		loopCnt := cellCount - s.MaxCol
		currIndex := s.MaxCol + 1
		for i := 0; i < loopCnt; i++ {

			col := &Col{
				style:     NewStyle(),
				Min:       currIndex,
				Max:       currIndex,
				Hidden:    false,
				Collapsed: false}
			s.Cols = append(s.Cols, col)
			currIndex++
		}

		s.MaxCol = cellCount
	}
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) Col(idx int) *Col {
	s.maybeAddCol(idx + 1)
	return s.Cols[idx]
}

// Get a Cell by passing it's cartesian coordinates (zero based) as
// row and column integer indexes.
//
// For example:
//
//    cell := sheet.Cell(0,0)
//
// ... would set the variable "cell" to contain a Cell struct
// containing the data from the field "A1" on the spreadsheet.
func (sh *Sheet) Cell(row, col int) *Cell {

	// If the user requests a row beyond what we have, then extend.
	for len(sh.Rows) <= row {
		sh.AddRow()
	}

	r := sh.Rows[row]
	for len(r.Cells) <= col {
		r.AddCell()
	}

	return r.Cells[col]
}

//Set the width of a single column or multiple columns.
func (s *Sheet) SetColWidth(startcol, endcol int, width float64) error {
	if startcol > endcol {
		return fmt.Errorf("Could not set width for range %d-%d: startcol must be less than endcol.", startcol, endcol)
	}
	end := endcol + 1
	s.maybeAddCol(end)
	for ; startcol < end; startcol++ {
		s.Cols[startcol].Width = width
	}

	return nil
}

// When merging cells, the cell may be the 'original' or the 'covered'.
// First, figure out which cells are merge starting points. Then create
// the necessary cells underlying the merge area.
// Then go through all the underlying cells and apply the appropriate
// border, based on the original cell.
func (s *Sheet) handleMerged() {
	merged := make(map[string]*Cell)

	for r, row := range s.Rows {
		for c, cell := range row.Cells {
			if cell.HMerge > 0 || cell.VMerge > 0 {
				coord := GetCellIDStringFromCoords(c, r)
				merged[coord] = cell
			}
		}
	}

	// This loop iterates over all cells that should be merged and applies the correct
	// borders to them depending on their position. If any cells required by the merge
	// are missing, they will be allocated by s.Cell().
	for key, cell := range merged {
		mainstyle := cell.GetStyle()

		top := mainstyle.Border.Top
		left := mainstyle.Border.Left
		right := mainstyle.Border.Right
		bottom := mainstyle.Border.Bottom

		// When merging cells, the upper left cell does not maintain
		// the original borders
		mainstyle.Border.Top = "none"
		mainstyle.Border.Left = "none"
		mainstyle.Border.Right = "none"
		mainstyle.Border.Bottom = "none"

		maincol, mainrow, _ := GetCoordsFromCellIDString(key)
		for rownum := 0; rownum <= cell.VMerge; rownum++ {
			for colnum := 0; colnum <= cell.HMerge; colnum++ {
				tmpcell := s.Cell(mainrow+rownum, maincol+colnum)
				style := tmpcell.GetStyle()
				style.ApplyBorder = true

				if rownum == 0 {
					style.Border.Top = top
				}

				if rownum == (cell.VMerge) {
					style.Border.Bottom = bottom
				}

				if colnum == 0 {
					style.Border.Left = left
				}

				if colnum == (cell.HMerge) {
					style.Border.Right = right
				}
			}
		}
	}
}

// Dump sheet to its XML representation, intended for internal use only
func (s *Sheet) makeXLSXSheet(refTable *RefTable, styles *xlsxStyleSheet) *xlsxWorksheet {
	worksheet := newXlsxWorksheet()
	xSheet := xlsxSheetData{}
	maxRow := 0
	maxCell := 0
	var maxLevelCol, maxLevelRow uint8

	// Scan through the sheet and see if there are any merged cells. If there
	// are, we may need to extend the size of the sheet. There needs to be
	// phantom cells underlying the area covered by the merged cell
	s.handleMerged()

	for index, sheetView := range s.SheetViews {
		if sheetView.Pane != nil {
			worksheet.SheetViews.SheetView[index].Pane = &xlsxPane{
				XSplit:      sheetView.Pane.XSplit,
				YSplit:      sheetView.Pane.YSplit,
				TopLeftCell: sheetView.Pane.TopLeftCell,
				ActivePane:  sheetView.Pane.ActivePane,
				State:       sheetView.Pane.State,
			}

		}
	}

	if s.Selected {
		worksheet.SheetViews.SheetView[0].TabSelected = true
	}

	if s.SheetFormat.DefaultRowHeight != 0 {
		worksheet.SheetFormatPr.DefaultRowHeight = s.SheetFormat.DefaultRowHeight
	}
	worksheet.SheetFormatPr.DefaultColWidth = s.SheetFormat.DefaultColWidth

	colsXfIdList := make([]int, len(s.Cols))
	for c, col := range s.Cols {
		XfId := 0
		if col.Min == 0 {
			col.Min = 1
		}
		if col.Max == 0 {
			col.Max = 1
		}
		style := col.GetStyle()
		//col's style always not nil
		if style != nil {
			xNumFmt := styles.newNumFmt(col.numFmt)
			XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
		}
		colsXfIdList[c] = XfId

		var customWidth bool
		if col.Width == 0 {
			col.Width = ColWidth
			customWidth = false

		} else {
			customWidth = true
		}
		if worksheet.Cols == nil {
			worksheet.Cols = &xlsxCols{Col: []xlsxCol{}}
		}
		worksheet.Cols.Col = append(worksheet.Cols.Col,
			xlsxCol{Min: col.Min,
				Max:          col.Max,
				Hidden:       col.Hidden,
				Width:        col.Width,
				CustomWidth:  customWidth,
				Collapsed:    col.Collapsed,
				OutlineLevel: col.OutlineLevel,
				Style:        XfId,
			})

		if col.OutlineLevel > maxLevelCol {
			maxLevelCol = col.OutlineLevel
		}
	}

	for r, row := range s.Rows {
		if r > maxRow {
			maxRow = r
		}
		xRow := xlsxRow{}
		xRow.R = r + 1
		if row.isCustom {
			xRow.CustomHeight = true
			xRow.Ht = fmt.Sprintf("%g", row.Height)
		}
		xRow.OutlineLevel = row.OutlineLevel
		if row.OutlineLevel > maxLevelRow {
			maxLevelRow = row.OutlineLevel
		}
		for c, cell := range row.Cells {
			XfId := colsXfIdList[c]

			// generate NumFmtId and add new NumFmt
			xNumFmt := styles.newNumFmt(cell.NumFmt)

			style := cell.style
			if style != nil {
				XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
			} else if len(cell.NumFmt) > 0 && !compareFormatString(s.Cols[c].numFmt, cell.NumFmt) {
				XfId = handleNumFmtIdForXLSX(xNumFmt.NumFmtId, styles)
			}

			if c > maxCell {
				maxCell = c
			}
			xC := xlsxC{
				S: XfId,
				R: GetCellIDStringFromCoords(c, r),
			}
			if cell.formula != "" {
				xC.F = &xlsxF{Content: cell.formula}
			}
			switch cell.cellType {
			case CellTypeInline:
				// Inline strings are turned into shared strings since they are more efficient.
				// This is what Excel does as well.
				fallthrough
			case CellTypeString:
				if len(cell.Value) > 0 {
					xC.V = strconv.Itoa(refTable.AddString(cell.Value))
				}
				xC.T = "s"
			case CellTypeNumeric:
				// Numeric is the default, so the type can be left blank
				xC.V = cell.Value
			case CellTypeBool:
				xC.V = cell.Value
				xC.T = "b"
			case CellTypeError:
				xC.V = cell.Value
				xC.T = "e"
			case CellTypeDate:
				xC.V = cell.Value
				xC.T = "d"
			case CellTypeStringFormula:
				xC.V = cell.Value
				xC.T = "str"
			default:
				panic(errors.New("unknown cell type cannot be marshaled"))
			}

			xRow.C = append(xRow.C, xC)

			if cell.HMerge > 0 || cell.VMerge > 0 {
				// r == rownum, c == colnum
				mc := xlsxMergeCell{}
				start := GetCellIDStringFromCoords(c, r)
				endCol := c + cell.HMerge
				endRow := r + cell.VMerge
				end := GetCellIDStringFromCoords(endCol, endRow)
				mc.Ref = start + ":" + end
				if worksheet.MergeCells == nil {
					worksheet.MergeCells = &xlsxMergeCells{}
				}
				worksheet.MergeCells.Cells = append(worksheet.MergeCells.Cells, mc)
			}
		}
		xSheet.Row = append(xSheet.Row, xRow)
	}

	// Update sheet format with the freshly determined max levels
	s.SheetFormat.OutlineLevelCol = maxLevelCol
	s.SheetFormat.OutlineLevelRow = maxLevelRow
	// .. and then also apply this to the xml worksheet
	worksheet.SheetFormatPr.OutlineLevelCol = s.SheetFormat.OutlineLevelCol
	worksheet.SheetFormatPr.OutlineLevelRow = s.SheetFormat.OutlineLevelRow

	if worksheet.MergeCells != nil {
		worksheet.MergeCells.Count = len(worksheet.MergeCells.Cells)
	}

	if s.AutoFilter != nil {
		worksheet.AutoFilter = &xlsxAutoFilter{Ref: fmt.Sprintf("%v:%v", s.AutoFilter.TopLeftCell, s.AutoFilter.BottomRightCell)}
	}

	worksheet.SheetData = xSheet
	dimension := xlsxDimension{}
	dimension.Ref = "A1:" + GetCellIDStringFromCoords(maxCell, maxRow)
	if dimension.Ref == "A1:A1" {
		dimension.Ref = "A1"
	}
	worksheet.Dimension = dimension
	return worksheet
}

func handleStyleForXLSX(style *Style, NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xFont, xFill, xBorder, xCellXf := style.makeXLSXStyleElements()
	fontId := styles.addFont(xFont)
	fillId := styles.addFill(xFill)

	// HACK - adding light grey fill, as in OO and Google
	greyfill := xlsxFill{}
	greyfill.PatternFill.PatternType = "lightGray"
	styles.addFill(greyfill)

	borderId := styles.addBorder(xBorder)
	xCellXf.FontId = fontId
	xCellXf.FillId = fillId
	xCellXf.BorderId = borderId
	xCellXf.NumFmtId = NumFmtId
	// apply the numFmtId when it is not the default cellxf
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}

	xCellXf.Alignment.Horizontal = style.Alignment.Horizontal
	xCellXf.Alignment.Indent = style.Alignment.Indent
	xCellXf.Alignment.ShrinkToFit = style.Alignment.ShrinkToFit
	xCellXf.Alignment.TextRotation = style.Alignment.TextRotation
	xCellXf.Alignment.Vertical = style.Alignment.Vertical
	xCellXf.Alignment.WrapText = style.Alignment.WrapText

	XfId = styles.addCellXf(xCellXf)
	return
}

func handleNumFmtIdForXLSX(NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xCellXf := makeXLSXCellElement()
	xCellXf.NumFmtId = NumFmtId
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}
	XfId = styles.addCellXf(xCellXf)
	return
}
<commit_msg>fix:open excel after save, excel file format error issue #432<commit_after>package xlsx

import (
	"errors"
	"fmt"
	"strconv"
)

// Sheet is a high level structure intended to provide user access to
// the contents of a particular sheet within an XLSX file.
type Sheet struct {
	Name        string
	File        *File
	Rows        []*Row
	Cols        []*Col
	MaxRow      int
	MaxCol      int
	Hidden      bool
	Selected    bool
	SheetViews  []SheetView
	SheetFormat SheetFormat
	AutoFilter  *AutoFilter
}

type SheetView struct {
	Pane *Pane
}

type Pane struct {
	XSplit      float64
	YSplit      float64
	TopLeftCell string
	ActivePane  string
	State       string // Either "split" or "frozen"
}

type SheetFormat struct {
	DefaultColWidth  float64
	DefaultRowHeight float64
	OutlineLevelCol  uint8
	OutlineLevelRow  uint8
}

type AutoFilter struct {
	TopLeftCell     string
	BottomRightCell string
}

// Add a new Row to a Sheet
func (s *Sheet) AddRow() *Row {
	row := &Row{Sheet: s}
	s.Rows = append(s.Rows, row)
	if len(s.Rows) > s.MaxRow {
		s.MaxRow = len(s.Rows)
	}
	return row
}

// Make sure we always have as many Rows as we do cells.
func (s *Sheet) maybeAddRow(rowCount int) {
	if rowCount > s.MaxRow {
		loopCnt := rowCount - s.MaxRow
		for i := 0; i < loopCnt; i++ {

			row := &Row{Sheet: s}
			s.Rows = append(s.Rows, row)
		}
		s.MaxRow = rowCount
	}
}

// Make sure we always have as many Rows as we do cells.
func (s *Sheet) Row(idx int) *Row {
	s.maybeAddRow(idx + 1)
	return s.Rows[idx]
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) maybeAddCol(cellCount int) {
	if cellCount > s.MaxCol {
		loopCnt := cellCount - s.MaxCol
		currIndex := s.MaxCol + 1
		for i := 0; i < loopCnt; i++ {

			col := &Col{
				style:     NewStyle(),
				Min:       currIndex,
				Max:       currIndex,
				Hidden:    false,
				Collapsed: false}
			s.Cols = append(s.Cols, col)
			currIndex++
		}

		s.MaxCol = cellCount
	}
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) Col(idx int) *Col {
	s.maybeAddCol(idx + 1)
	return s.Cols[idx]
}

// Get a Cell by passing it's cartesian coordinates (zero based) as
// row and column integer indexes.
//
// For example:
//
//    cell := sheet.Cell(0,0)
//
// ... would set the variable "cell" to contain a Cell struct
// containing the data from the field "A1" on the spreadsheet.
func (sh *Sheet) Cell(row, col int) *Cell {

	// If the user requests a row beyond what we have, then extend.
	for len(sh.Rows) <= row {
		sh.AddRow()
	}

	r := sh.Rows[row]
	for len(r.Cells) <= col {
		r.AddCell()
	}

	return r.Cells[col]
}

//Set the width of a single column or multiple columns.
func (s *Sheet) SetColWidth(startcol, endcol int, width float64) error {
	if startcol > endcol {
		return fmt.Errorf("Could not set width for range %d-%d: startcol must be less than endcol.", startcol, endcol)
	}
	end := endcol + 1
	s.maybeAddCol(end)
	for ; startcol < end; startcol++ {
		s.Cols[startcol].Width = width
	}

	return nil
}

// When merging cells, the cell may be the 'original' or the 'covered'.
// First, figure out which cells are merge starting points. Then create
// the necessary cells underlying the merge area.
// Then go through all the underlying cells and apply the appropriate
// border, based on the original cell.
func (s *Sheet) handleMerged() {
	merged := make(map[string]*Cell)

	for r, row := range s.Rows {
		for c, cell := range row.Cells {
			if cell.HMerge > 0 || cell.VMerge > 0 {
				coord := GetCellIDStringFromCoords(c, r)
				merged[coord] = cell
			}
		}
	}

	// This loop iterates over all cells that should be merged and applies the correct
	// borders to them depending on their position. If any cells required by the merge
	// are missing, they will be allocated by s.Cell().
	for key, cell := range merged {
		mainstyle := cell.GetStyle()

		top := mainstyle.Border.Top
		left := mainstyle.Border.Left
		right := mainstyle.Border.Right
		bottom := mainstyle.Border.Bottom

		// When merging cells, the upper left cell does not maintain
		// the original borders
		mainstyle.Border.Top = "none"
		mainstyle.Border.Left = "none"
		mainstyle.Border.Right = "none"
		mainstyle.Border.Bottom = "none"

		maincol, mainrow, _ := GetCoordsFromCellIDString(key)
		for rownum := 0; rownum <= cell.VMerge; rownum++ {
			for colnum := 0; colnum <= cell.HMerge; colnum++ {
				tmpcell := s.Cell(mainrow+rownum, maincol+colnum)
				style := tmpcell.GetStyle()
				style.ApplyBorder = true

				if rownum == 0 {
					style.Border.Top = top
				}

				if rownum == (cell.VMerge) {
					style.Border.Bottom = bottom
				}

				if colnum == 0 {
					style.Border.Left = left
				}

				if colnum == (cell.HMerge) {
					style.Border.Right = right
				}
			}
		}
	}
}

// Dump sheet to its XML representation, intended for internal use only
func (s *Sheet) makeXLSXSheet(refTable *RefTable, styles *xlsxStyleSheet) *xlsxWorksheet {
	worksheet := newXlsxWorksheet()
	xSheet := xlsxSheetData{}
	maxRow := 0
	maxCell := 0
	var maxLevelCol, maxLevelRow uint8

	// Scan through the sheet and see if there are any merged cells. If there
	// are, we may need to extend the size of the sheet. There needs to be
	// phantom cells underlying the area covered by the merged cell
	s.handleMerged()

	for index, sheetView := range s.SheetViews {
		if sheetView.Pane != nil {
			worksheet.SheetViews.SheetView[index].Pane = &xlsxPane{
				XSplit:      sheetView.Pane.XSplit,
				YSplit:      sheetView.Pane.YSplit,
				TopLeftCell: sheetView.Pane.TopLeftCell,
				ActivePane:  sheetView.Pane.ActivePane,
				State:       sheetView.Pane.State,
			}

		}
	}

	if s.Selected {
		worksheet.SheetViews.SheetView[0].TabSelected = true
	}

	if s.SheetFormat.DefaultRowHeight != 0 {
		worksheet.SheetFormatPr.DefaultRowHeight = s.SheetFormat.DefaultRowHeight
	}
	worksheet.SheetFormatPr.DefaultColWidth = s.SheetFormat.DefaultColWidth

	colsXfIdList := make([]int, len(s.Cols))
	for c, col := range s.Cols {
		XfId := 0
		if col.Min == 0 {
			col.Min = 1
		}
		if col.Max == 0 {
			col.Max = 1
		}
		style := col.GetStyle()
		//col's style always not nil
		if style != nil {
			xNumFmt := styles.newNumFmt(col.numFmt)
			XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
		}
		colsXfIdList[c] = XfId

		var customWidth bool
		if col.Width == 0 {
			col.Width = ColWidth
			customWidth = false

		} else {
			customWidth = true
		}
		// When the cols content is empty, the cols flag is not output in the xml file.
		if worksheet.Cols == nil {
			worksheet.Cols = &xlsxCols{Col: []xlsxCol{}}
		}
		worksheet.Cols.Col = append(worksheet.Cols.Col,
			xlsxCol{Min: col.Min,
				Max:          col.Max,
				Hidden:       col.Hidden,
				Width:        col.Width,
				CustomWidth:  customWidth,
				Collapsed:    col.Collapsed,
				OutlineLevel: col.OutlineLevel,
				Style:        XfId,
			})

		if col.OutlineLevel > maxLevelCol {
			maxLevelCol = col.OutlineLevel
		}
	}

	for r, row := range s.Rows {
		if r > maxRow {
			maxRow = r
		}
		xRow := xlsxRow{}
		xRow.R = r + 1
		if row.isCustom {
			xRow.CustomHeight = true
			xRow.Ht = fmt.Sprintf("%g", row.Height)
		}
		xRow.OutlineLevel = row.OutlineLevel
		if row.OutlineLevel > maxLevelRow {
			maxLevelRow = row.OutlineLevel
		}
		for c, cell := range row.Cells {
			XfId := colsXfIdList[c]

			// generate NumFmtId and add new NumFmt
			xNumFmt := styles.newNumFmt(cell.NumFmt)

			style := cell.style
			if style != nil {
				XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
			} else if len(cell.NumFmt) > 0 && !compareFormatString(s.Cols[c].numFmt, cell.NumFmt) {
				XfId = handleNumFmtIdForXLSX(xNumFmt.NumFmtId, styles)
			}

			if c > maxCell {
				maxCell = c
			}
			xC := xlsxC{
				S: XfId,
				R: GetCellIDStringFromCoords(c, r),
			}
			if cell.formula != "" {
				xC.F = &xlsxF{Content: cell.formula}
			}
			switch cell.cellType {
			case CellTypeInline:
				// Inline strings are turned into shared strings since they are more efficient.
				// This is what Excel does as well.
				fallthrough
			case CellTypeString:
				if len(cell.Value) > 0 {
					xC.V = strconv.Itoa(refTable.AddString(cell.Value))
				}
				xC.T = "s"
			case CellTypeNumeric:
				// Numeric is the default, so the type can be left blank
				xC.V = cell.Value
			case CellTypeBool:
				xC.V = cell.Value
				xC.T = "b"
			case CellTypeError:
				xC.V = cell.Value
				xC.T = "e"
			case CellTypeDate:
				xC.V = cell.Value
				xC.T = "d"
			case CellTypeStringFormula:
				xC.V = cell.Value
				xC.T = "str"
			default:
				panic(errors.New("unknown cell type cannot be marshaled"))
			}

			xRow.C = append(xRow.C, xC)

			if cell.HMerge > 0 || cell.VMerge > 0 {
				// r == rownum, c == colnum
				mc := xlsxMergeCell{}
				start := GetCellIDStringFromCoords(c, r)
				endCol := c + cell.HMerge
				endRow := r + cell.VMerge
				end := GetCellIDStringFromCoords(endCol, endRow)
				mc.Ref = start + ":" + end
				if worksheet.MergeCells == nil {
					worksheet.MergeCells = &xlsxMergeCells{}
				}
				worksheet.MergeCells.Cells = append(worksheet.MergeCells.Cells, mc)
			}
		}
		xSheet.Row = append(xSheet.Row, xRow)
	}

	// Update sheet format with the freshly determined max levels
	s.SheetFormat.OutlineLevelCol = maxLevelCol
	s.SheetFormat.OutlineLevelRow = maxLevelRow
	// .. and then also apply this to the xml worksheet
	worksheet.SheetFormatPr.OutlineLevelCol = s.SheetFormat.OutlineLevelCol
	worksheet.SheetFormatPr.OutlineLevelRow = s.SheetFormat.OutlineLevelRow

	if worksheet.MergeCells != nil {
		worksheet.MergeCells.Count = len(worksheet.MergeCells.Cells)
	}

	if s.AutoFilter != nil {
		worksheet.AutoFilter = &xlsxAutoFilter{Ref: fmt.Sprintf("%v:%v", s.AutoFilter.TopLeftCell, s.AutoFilter.BottomRightCell)}
	}

	worksheet.SheetData = xSheet
	dimension := xlsxDimension{}
	dimension.Ref = "A1:" + GetCellIDStringFromCoords(maxCell, maxRow)
	if dimension.Ref == "A1:A1" {
		dimension.Ref = "A1"
	}
	worksheet.Dimension = dimension
	return worksheet
}

func handleStyleForXLSX(style *Style, NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xFont, xFill, xBorder, xCellXf := style.makeXLSXStyleElements()
	fontId := styles.addFont(xFont)
	fillId := styles.addFill(xFill)

	// HACK - adding light grey fill, as in OO and Google
	greyfill := xlsxFill{}
	greyfill.PatternFill.PatternType = "lightGray"
	styles.addFill(greyfill)

	borderId := styles.addBorder(xBorder)
	xCellXf.FontId = fontId
	xCellXf.FillId = fillId
	xCellXf.BorderId = borderId
	xCellXf.NumFmtId = NumFmtId
	// apply the numFmtId when it is not the default cellxf
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}

	xCellXf.Alignment.Horizontal = style.Alignment.Horizontal
	xCellXf.Alignment.Indent = style.Alignment.Indent
	xCellXf.Alignment.ShrinkToFit = style.Alignment.ShrinkToFit
	xCellXf.Alignment.TextRotation = style.Alignment.TextRotation
	xCellXf.Alignment.Vertical = style.Alignment.Vertical
	xCellXf.Alignment.WrapText = style.Alignment.WrapText

	XfId = styles.addCellXf(xCellXf)
	return
}

func handleNumFmtIdForXLSX(NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xCellXf := makeXLSXCellElement()
	xCellXf.NumFmtId = NumFmtId
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}
	XfId = styles.addCellXf(xCellXf)
	return
}
<|endoftext|>


<commit_before>package main

/*
* Link Shortener, with a Redis backend.
*
* Released under and MIT License, please see the LICENSE.md file.
*
* John Nye
*
 */
import (
	"./utils"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

var host = flag.String("h", "localhost", "Bind address to listen on")
var base = flag.String("b", "http://localhost/", "Base URL for the shortener")
var port = flag.String("p", "8080", "Port you want to listen on, defaults to 8080")
var maxConnections = flag.Int("c", 512, "The maximum number of active connections") //Currently Not Used
var redisConn = flag.String("r", "localhost:6379", "Redis Address, defaults to localhost:6379")

type Data struct {
	Original  string
	Short     string
	FullShort string
	HitCount  int
}

var redisPool = &redis.Pool{
	MaxIdle:   3,
	MaxActive: 50, // max number of connections
	Dial: func() (redis.Conn, error) {
		c, err := redis.Dial("tcp", *redisConn)
		if err != nil {
			panic(err.Error())
		}
		return c, err
	},
}

func handler(w http.ResponseWriter, r *http.Request) {

	log.Println(r.UserAgent())

	type NewURL struct {
		URL string
	}
	var url NewURL
	var domain Data

	conn := redisPool.Get()

	if r.Method == "GET" {
		domain = getLongURL(r.URL.Path[1:], conn)
		if len(domain.Original) > 0 {
			http.Redirect(w, r, domain.Original, http.StatusFound)
			conn.Close()
			return
		}
		http.ServeFile(w, r, "./index.html")
		log.Println("Served Homepage")
		conn.Close()
		return
	}

	create, err := ioutil.ReadAll(r.Body)

	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	err = json.Unmarshal(create, &url)
	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), 500)
		return
	}

	search := strings.Join([]string{"*||", url.URL}, "")

	keys, err := redis.Strings(conn.Do("KEYS", search))

	if len(keys) < 1 {
		domain = createShortURL(url.URL, conn)
	} else {
		domain = getInfoForKey(keys[0], conn)
	}

	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), 500)
		return
	}

	output, err := json.Marshal(domain)

	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "%s", output)
	conn.Close()
}

func getInfoForKey(key string, conn redis.Conn) Data {
	var d Data
	parts := strings.Split(key, "||")
	d.Short = parts[0]
	d.Original = parts[1]
	d.FullShort = strings.Join([]string{*base, parts[0]}, "")
	newCount, err := redis.Int(conn.Do("HGET", key, "count"))
	if err != nil {
		log.Print(err)
	}
	d.HitCount = newCount
	return d
}

func createShortURL(url string, conn redis.Conn) Data {
	var d Data
	count, err := redis.Int(conn.Do("INCR", "global:size"))
	if err != nil {
		log.Print(err)
		return d
	}
	log.Print("Total: ",count)
	encodedVar := base62.EncodeInt(int64(count))
	key := strings.Join([]string{encodedVar, url}, "||")
	conn.Send("MULTI")
	conn.Send("HSET", key, "count", 0)
	_, err2 := conn.Do("EXEC")

	if err2 != nil {
		log.Print(err)
		return d
	}

	d.Original = url
	d.HitCount = 0
	d.Short = encodedVar
	d.FullShort = strings.Join([]string{*base, encodedVar}, "")

	return d
}

func getLongURL(short string, conn redis.Conn) Data {
	var d Data

	search := strings.Join([]string{short, "||*"}, "")
	fmt.Println(search)
	n, err := redis.Strings(conn.Do("KEYS", search))

	if err != nil {
		log.Print(err)
		return d
	}

	if len(n) < 1 {
		log.Print("Nothing Found")
	} else {
		parts := strings.Split(n[0], "||")

		d.Short = parts[0]
		d.Original = parts[1]
		d.FullShort = strings.Join([]string{*base, parts[0]}, "")
		newCount, err := redis.Int(conn.Do("HINCRBY", n[0], "count", 1))
		if err != nil {
			log.Println(err)
		}
		d.HitCount = newCount
	}
	log.Println("Served: ",d.Original)
	return d
}

func main() {
	flag.Parse()

	http.HandleFunc("/", handler)
	err := http.ListenAndServe(*host+":"+*port, nil)
	if err != nil {
		fmt.Println(err)
	}
}
<commit_msg>Close the redis connection reliably.<commit_after>package main

/*
* Link Shortener, with a Redis backend.
*
* Released under and MIT License, please see the LICENSE.md file.
*
* John Nye
*
 */
import (
	"./utils"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

var host = flag.String("h", "localhost", "Bind address to listen on")
var base = flag.String("b", "http://localhost/", "Base URL for the shortener")
var port = flag.String("p", "8080", "Port you want to listen on, defaults to 8080")
var maxConnections = flag.Int("c", 512, "The maximum number of active connections") //Currently Not Used
var redisConn = flag.String("r", "localhost:6379", "Redis Address, defaults to localhost:6379")

type Data struct {
	Original  string
	Short     string
	FullShort string
	HitCount  int
}

var redisPool = &redis.Pool{
	MaxIdle:   3,
	MaxActive: 50, // max number of connections
	Dial: func() (redis.Conn, error) {
		c, err := redis.Dial("tcp", *redisConn)
		if err != nil {
			panic(err.Error())
		}
		return c, err
	},
}

func handler(w http.ResponseWriter, r *http.Request) {

	log.Println(r.UserAgent())

	type NewURL struct {
		URL string
	}
	var url NewURL
	var domain Data

	conn := redisPool.Get()
	defer conn.Close()

	if r.Method == "GET" {
		domain = getLongURL(r.URL.Path[1:], conn)
		if len(domain.Original) > 0 {
			http.Redirect(w, r, domain.Original, http.StatusFound)
			return
		}
		http.ServeFile(w, r, "./index.html")
		log.Println("Served Homepage")
		return
	}

	create, err := ioutil.ReadAll(r.Body)

	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	err = json.Unmarshal(create, &url)
	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), 500)
		return
	}

	search := strings.Join([]string{"*||", url.URL}, "")

	keys, err := redis.Strings(conn.Do("KEYS", search))

	if len(keys) < 1 {
		domain = createShortURL(url.URL, conn)
	} else {
		domain = getInfoForKey(keys[0], conn)
	}

	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), 500)
		return
	}

	output, err := json.Marshal(domain)

	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "%s", output)
}

func getInfoForKey(key string, conn redis.Conn) Data {
	var d Data
	parts := strings.Split(key, "||")
	d.Short = parts[0]
	d.Original = parts[1]
	d.FullShort = strings.Join([]string{*base, parts[0]}, "")
	newCount, err := redis.Int(conn.Do("HGET", key, "count"))
	if err != nil {
		log.Print(err)
	}
	d.HitCount = newCount
	return d
}

func createShortURL(url string, conn redis.Conn) Data {
	var d Data
	count, err := redis.Int(conn.Do("INCR", "global:size"))
	if err != nil {
		log.Print(err)
		return d
	}
	log.Print("Total: ",count)
	encodedVar := base62.EncodeInt(int64(count))
	key := strings.Join([]string{encodedVar, url}, "||")
	conn.Send("MULTI")
	conn.Send("HSET", key, "count", 0)
	_, err2 := conn.Do("EXEC")

	if err2 != nil {
		log.Print(err)
		return d
	}

	d.Original = url
	d.HitCount = 0
	d.Short = encodedVar
	d.FullShort = strings.Join([]string{*base, encodedVar}, "")

	return d
}

func getLongURL(short string, conn redis.Conn) Data {
	var d Data

	search := strings.Join([]string{short, "||*"}, "")
	fmt.Println(search)
	n, err := redis.Strings(conn.Do("KEYS", search))

	if err != nil {
		log.Print(err)
		return d
	}

	if len(n) < 1 {
		log.Print("Nothing Found")
	} else {
		parts := strings.Split(n[0], "||")

		d.Short = parts[0]
		d.Original = parts[1]
		d.FullShort = strings.Join([]string{*base, parts[0]}, "")
		newCount, err := redis.Int(conn.Do("HINCRBY", n[0], "count", 1))
		if err != nil {
			log.Println(err)
		}
		d.HitCount = newCount
	}
	log.Println("Served: ",d.Original)
	return d
}

func main() {
	flag.Parse()

	http.HandleFunc("/", handler)
	err := http.ListenAndServe(*host+":"+*port, nil)
	if err != nil {
		fmt.Println(err)
	}
}
<|endoftext|>


<commit_before>package nopaste

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"time"
)

const SlackMaxBackOff = 3600

var (
	SlackThrottleWindow = 1 * time.Second
	SlackInitialBackOff = 30
	Epoch               = time.Unix(0, 0)
)

type SlackMessage struct {
	Channel   string `json:"channel"`
	Text      string `json:"text"`
	IconEmoji string `json:"icon_emoji,omitempty"`
	IconURL   string `json:"icon_url,omitempty"`
	Username  string `json:"username"`
}

type SlackMessageChan chan SlackMessage

func (ch SlackMessageChan) PostNopaste(np nopasteContent, url string) {
	summary := np.Summary
	nick := np.Nick
	var text string
	if summary == "" {
		text = fmt.Sprintf("<%s|%s>", url, url)
	} else {
		text = fmt.Sprintf("%s <%s|show details>", summary, url)
	}
	msg := SlackMessage{
		Channel:   np.Channel,
		Username:  nick,
		Text:      text,
		IconEmoji: np.IconEmoji,
		IconURL:   np.IconURL,
	}
	select {
	case ch <- msg:
	default:
		log.Println("Can't send msg to Slack")
	}
}

func (ch SlackMessageChan) PostMsgr(req *http.Request) {
	username := req.FormValue("username")
	if username == "" {
		username = "msgr"
	}
	msg := SlackMessage{
		Channel:   req.FormValue("channel"),
		Text:      req.FormValue("msg"),
		Username:  username,
		IconEmoji: req.FormValue("icon_emoji"),
		IconURL:   req.FormValue("icon_url"),
	}
	select {
	case ch <- msg:
	default:
		log.Println("Can't send msg to Slack")
	}
}

type SlackAgent struct {
	WebhookURL string
	client     *http.Client
}

func (a *SlackAgent) Post(m SlackMessage) error {
	payload, _ := json.Marshal(&m)
	v := url.Values{}
	v.Set("payload", string(payload))
	log.Println("post to slack", a, string(payload))
	resp, err := a.client.PostForm(a.WebhookURL, v)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusOK {
		return nil
	}
	if body, err := ioutil.ReadAll(resp.Body); err == nil {
		return fmt.Errorf("failed post to slack:%s", body)
	} else {
		return err
	}
}

func RunSlackAgent(c *Config, ch chan SlackMessage) {
	log.Println("runing slack agent")
	joined := make(map[string]chan SlackMessage)
	agent := &SlackAgent{
		WebhookURL: c.Slack.WebhookURL,
		client:     &http.Client{},
	}
	for {
		select {
		case msg := <-ch:
			if _, ok := joined[msg.Channel]; !ok {
				joined[msg.Channel] = make(chan SlackMessage, MsgBufferLen)
				go sendMsgToSlackChannel(agent, joined[msg.Channel])
			}
			select {
			case joined[msg.Channel] <- msg:
			default:
				log.Println("Can't send msg to Slack. Channel buffer flooding.")
			}
		}
	}
}

func sendMsgToSlackChannel(agent *SlackAgent, ch chan SlackMessage) {
	lastPostedAt := time.Now()
	ignoreUntil := Epoch
	backoff := SlackInitialBackOff
	for {
		select {
		case msg := <-ch:
			if time.Now().Before(ignoreUntil) {
				// ignored
				continue
			}
			throttle(lastPostedAt, SlackThrottleWindow)
			err := agent.Post(msg)
			lastPostedAt = time.Now()
			if err != nil {
				backoff = int(math.Min(float64(backoff)*2, SlackMaxBackOff))
				d, _ := time.ParseDuration(fmt.Sprintf("%ds", backoff))
				ignoreUntil = lastPostedAt.Add(d)
				log.Println(err, msg.Channel, "will be ignored until", ignoreUntil)
			} else if !ignoreUntil.Equal(Epoch) {
				ignoreUntil = Epoch
				backoff = SlackInitialBackOff
			}
		}
	}
}
<commit_msg>irc-msgr: link_names=1(default)<commit_after>package nopaste

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"time"
)

const SlackMaxBackOff = 3600

var (
	SlackThrottleWindow = 1 * time.Second
	SlackInitialBackOff = 30
	Epoch               = time.Unix(0, 0)
)

type SlackMessage struct {
	Channel   string `json:"channel"`
	Text      string `json:"text"`
	IconEmoji string `json:"icon_emoji,omitempty"`
	IconURL   string `json:"icon_url,omitempty"`
	Username  string `json:"username"`
	LinkNames int    `json:"link_names,omitempty"`
}

type SlackMessageChan chan SlackMessage

func (ch SlackMessageChan) PostNopaste(np nopasteContent, url string) {
	summary := np.Summary
	nick := np.Nick
	var text string
	if summary == "" {
		text = fmt.Sprintf("<%s|%s>", url, url)
	} else {
		text = fmt.Sprintf("%s <%s|show details>", summary, url)
	}
	msg := SlackMessage{
		Channel:   np.Channel,
		Username:  nick,
		Text:      text,
		IconEmoji: np.IconEmoji,
		IconURL:   np.IconURL,
	}
	select {
	case ch <- msg:
	default:
		log.Println("Can't send msg to Slack")
	}
}

func (ch SlackMessageChan) PostMsgr(req *http.Request) {
	username := req.FormValue("username")
	if username == "" {
		username = "msgr"
	}
	msg := SlackMessage{
		Channel:   req.FormValue("channel"),
		Text:      req.FormValue("msg"),
		Username:  username,
		IconEmoji: req.FormValue("icon_emoji"),
		IconURL:   req.FormValue("icon_url"),
		LinkNames: 1,
	}
	if _notice := req.FormValue("notice"); _notice == "1" {
		msg.LinkNames = 0
	}
	select {
	case ch <- msg:
	default:
		log.Println("Can't send msg to Slack")
	}
}

type SlackAgent struct {
	WebhookURL string
	client     *http.Client
}

func (a *SlackAgent) Post(m SlackMessage) error {
	payload, _ := json.Marshal(&m)
	v := url.Values{}
	v.Set("payload", string(payload))
	log.Println("post to slack", a, string(payload))
	resp, err := a.client.PostForm(a.WebhookURL, v)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusOK {
		return nil
	}
	if body, err := ioutil.ReadAll(resp.Body); err == nil {
		return fmt.Errorf("failed post to slack:%s", body)
	} else {
		return err
	}
}

func RunSlackAgent(c *Config, ch chan SlackMessage) {
	log.Println("runing slack agent")
	joined := make(map[string]chan SlackMessage)
	agent := &SlackAgent{
		WebhookURL: c.Slack.WebhookURL,
		client:     &http.Client{},
	}
	for {
		select {
		case msg := <-ch:
			if _, ok := joined[msg.Channel]; !ok {
				joined[msg.Channel] = make(chan SlackMessage, MsgBufferLen)
				go sendMsgToSlackChannel(agent, joined[msg.Channel])
			}
			select {
			case joined[msg.Channel] <- msg:
			default:
				log.Println("Can't send msg to Slack. Channel buffer flooding.")
			}
		}
	}
}

func sendMsgToSlackChannel(agent *SlackAgent, ch chan SlackMessage) {
	lastPostedAt := time.Now()
	ignoreUntil := Epoch
	backoff := SlackInitialBackOff
	for {
		select {
		case msg := <-ch:
			if time.Now().Before(ignoreUntil) {
				// ignored
				continue
			}
			throttle(lastPostedAt, SlackThrottleWindow)
			err := agent.Post(msg)
			lastPostedAt = time.Now()
			if err != nil {
				backoff = int(math.Min(float64(backoff)*2, SlackMaxBackOff))
				d, _ := time.ParseDuration(fmt.Sprintf("%ds", backoff))
				ignoreUntil = lastPostedAt.Add(d)
				log.Println(err, msg.Channel, "will be ignored until", ignoreUntil)
			} else if !ignoreUntil.Equal(Epoch) {
				ignoreUntil = Epoch
				backoff = SlackInitialBackOff
			}
		}
	}
}
<|endoftext|>


<commit_before>package pino

import (
	"crypto/md5"
	"fmt"
	"strings"

	slack "github.com/nlopes/slack"
)

type slackProxy struct {
	config           *SlackConfig
	client           *slack.Client
	rtm              *slack.RTM
	channelNameToID  map[SlackChannel]string
	channelIDToName  map[string]SlackChannel
	ownerID          string
	ownerIMChannelID string
}

func newSlackProxy(config *SlackConfig) (*slackProxy, error) {
	proxy := new(slackProxy)
	proxy.config = config

	token := config.Token
	if token == "" {
		return nil, fmt.Errorf("Token must be defined in Slack config")
	}

	proxy.client = slack.New(token)
	proxy.rtm = proxy.client.NewRTM()

	proxy.channelNameToID = make(map[SlackChannel]string)
	proxy.channelIDToName = make(map[string]SlackChannel)

	return proxy, nil
}

func (proxy *slackProxy) connect() error {
	go proxy.rtm.ManageConnection()

	// generate the mapping of channel name to ID, and vice versa
	channels, err := proxy.rtm.GetChannels(true)
	if err != nil {
		return fmt.Errorf("Could not get Slack channels: %v", err)
	}
	for _, channel := range channels {
		// The channel names returned by the API don't have the pound
		channelName := SlackChannel(fmt.Sprintf("#%v", channel.Name))

		// We don't care about unregistered channel
		if _, ok := proxy.config.Channels[channelName]; ok {
			proxy.channelNameToID[channelName] = channel.ID
			proxy.channelIDToName[channel.ID] = channelName
		}
	}
	fmt.Printf("Generated the following Slack channel name to ID mapping: %v\n", proxy.channelNameToID)

	users, err := proxy.rtm.GetUsers()
	if err != nil {
		return fmt.Errorf("Could not get Slack users: %v", err)
	}

	foundOwner := false
	for _, user := range users {
		if user.Name == proxy.config.Owner {
			// We found the user struct representing the owner!
			foundOwner = true

			proxy.ownerID = user.ID
			break
		}
	}
	if !foundOwner {
		return fmt.Errorf("Could not find a Slack user that matched the configured owner: %v", proxy.config.Owner)
	}

	_, _, imChannelID, err := proxy.rtm.OpenIMChannel(proxy.ownerID)
	if err != nil {
		return fmt.Errorf("Could not open a Slack IM channel with the owner: %v (%v)", proxy.config.Owner, proxy.ownerID)
	}
	proxy.ownerIMChannelID = imChannelID

	return nil
}

func generateUserIconURL(username string) string {
	return fmt.Sprintf("http://www.gravatar.com/avatar/%x?d=identicon", md5.Sum([]byte(username)))
}

func (proxy *slackProxy) sendMessageAsUser(channelName SlackChannel, username string, text string) {
	channelID := proxy.channelNameToID[channelName]
	params := slack.NewPostMessageParameters()
	params.Username = username
	params.AsUser = false
	params.IconURL = generateUserIconURL(username)

	_, _, err := proxy.rtm.PostMessage(channelID, text, params)
	if err != nil {
		fmt.Printf("Error while sending message: %v\n", err)
	}
}

func (proxy *slackProxy) sendMessageAsBot(channelName SlackChannel, text string) {
	channelID := proxy.channelNameToID[channelName]
	params := slack.NewPostMessageParameters()
	params.Username = "IRC"
	params.AsUser = false
	params.LinkNames = 1

	_, _, err := proxy.rtm.PostMessage(channelID, text, params)
	if err != nil {
		fmt.Printf("Error while sending message: %v\n", err)
	}
}

func (proxy *slackProxy) sendMessageToOwner(text string) {
	proxy.rtm.SendMessage(proxy.rtm.NewOutgoingMessage(text, proxy.ownerIMChannelID))
}

func (proxy *slackProxy) getChannelName(channelID string) SlackChannel {
	return proxy.channelIDToName[channelID]
}

// Slack decodes '&', '<', and '>' per https://api.slack.com/docs/formatting#how_to_escape_characters
// so we need to decode them.
func decodeSlackHTMLEntities(input string) string {
	output := input

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

	return output
}
<commit_msg>Store user ID -> name mappings<commit_after>package pino

import (
	"crypto/md5"
	"fmt"
	"strings"

	slack "github.com/nlopes/slack"
)

type slackProxy struct {
	config           *SlackConfig
	client           *slack.Client
	rtm              *slack.RTM
	channelNameToID  map[SlackChannel]string
	channelIDToName  map[string]SlackChannel
	userIDToName     map[string]string
	ownerID          string
	ownerIMChannelID string
}

func newSlackProxy(config *SlackConfig) (*slackProxy, error) {
	proxy := new(slackProxy)
	proxy.config = config

	token := config.Token
	if token == "" {
		return nil, fmt.Errorf("Token must be defined in Slack config")
	}

	proxy.client = slack.New(token)
	proxy.rtm = proxy.client.NewRTM()

	proxy.channelNameToID = make(map[SlackChannel]string)
	proxy.channelIDToName = make(map[string]SlackChannel)

	proxy.userIDToName = make(map[string]string)

	return proxy, nil
}

func (proxy *slackProxy) connect() error {
	go proxy.rtm.ManageConnection()

	// generate the mapping of channel name to ID, and vice versa
	channels, err := proxy.rtm.GetChannels(true)
	if err != nil {
		return fmt.Errorf("Could not get Slack channels: %v", err)
	}
	for _, channel := range channels {
		// The channel names returned by the API don't have the pound
		channelName := SlackChannel(fmt.Sprintf("#%v", channel.Name))

		proxy.channelNameToID[channelName] = channel.ID
		proxy.channelIDToName[channel.ID] = channelName
	}
	fmt.Printf("Generated the following Slack channel name to ID mapping: %v\n", proxy.channelNameToID)

	users, err := proxy.rtm.GetUsers()
	if err != nil {
		return fmt.Errorf("Could not get Slack users: %v", err)
	}

	foundOwner := false
	for _, user := range users {
		if user.Name == proxy.config.Owner {
			// We found the user struct representing the owner!
			foundOwner = true
			proxy.ownerID = user.ID
		}

		proxy.userIDToName[user.ID] = user.Name
	}
	if !foundOwner {
		return fmt.Errorf("Could not find a Slack user that matched the configured owner: %v", proxy.config.Owner)
	}
	fmt.Printf("Generated the following Slack user ID to name mapping: %v\n", proxy.userIDToName)

	_, _, imChannelID, err := proxy.rtm.OpenIMChannel(proxy.ownerID)
	if err != nil {
		return fmt.Errorf("Could not open a Slack IM channel with the owner: %v (%v)", proxy.config.Owner, proxy.ownerID)
	}
	proxy.ownerIMChannelID = imChannelID

	return nil
}

func generateUserIconURL(username string) string {
	return fmt.Sprintf("http://www.gravatar.com/avatar/%x?d=identicon", md5.Sum([]byte(username)))
}

func (proxy *slackProxy) sendMessageAsUser(channelName SlackChannel, username string, text string) {
	channelID := proxy.channelNameToID[channelName]
	params := slack.NewPostMessageParameters()
	params.Username = username
	params.AsUser = false
	params.IconURL = generateUserIconURL(username)

	_, _, err := proxy.rtm.PostMessage(channelID, text, params)
	if err != nil {
		fmt.Printf("Error while sending message: %v\n", err)
	}
}

func (proxy *slackProxy) sendMessageAsBot(channelName SlackChannel, text string) {
	channelID := proxy.channelNameToID[channelName]
	params := slack.NewPostMessageParameters()
	params.Username = "IRC"
	params.AsUser = false
	params.LinkNames = 1

	_, _, err := proxy.rtm.PostMessage(channelID, text, params)
	if err != nil {
		fmt.Printf("Error while sending message: %v\n", err)
	}
}

func (proxy *slackProxy) sendMessageToOwner(text string) {
	proxy.rtm.SendMessage(proxy.rtm.NewOutgoingMessage(text, proxy.ownerIMChannelID))
}

func (proxy *slackProxy) getChannelName(channelID string) SlackChannel {
	return proxy.channelIDToName[channelID]
}

// Slack decodes '&', '<', and '>' per https://api.slack.com/docs/formatting#how_to_escape_characters
// so we need to decode them.
func decodeSlackHTMLEntities(input string) string {
	output := input

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

	return output
}
<|endoftext|>


<commit_before>package pt

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
)

const (
	socksVersion         = 0x04
	socksCmdConnect      = 0x01
	socksResponseVersion = 0x00
	socksRequestGranted  = 0x5a
	socksRequestRejected = 0x5b
)

// SocksRequest describes a SOCKS request.
type SocksRequest struct {
	// The endpoint requested by the client as a "host:port" string.
	Target string
	// The userid string sent by the client.
	Username string
	// The parsed contents of Username as a key–value mapping.
	Args Args
}

// SocksConn encapsulates a net.Conn and information associated with a SOCKS request.
type SocksConn struct {
	net.Conn
	Req SocksRequest
}

// Send a message to the proxy client that access to the given address is
// granted.
func (conn *SocksConn) Grant(addr *net.TCPAddr) error {
	return sendSocks4aResponseGranted(conn, addr)
}

// Send a message to the proxy client that access was rejected or failed.
func (conn *SocksConn) Reject() error {
	return sendSocks4aResponseRejected(conn)
}

// SocksListener wraps a net.Listener in order to read a SOCKS request on Accept.
//
// 	func handleConn(conn *pt.SocksConn) error {
// 		defer conn.Close()
// 		remote, err := net.Dial("tcp", conn.Req.Target)
// 		if err != nil {
// 			conn.Reject()
// 			return err
// 		}
// 		defer remote.Close()
// 		err = conn.Grant(remote.RemoteAddr().(*net.TCPAddr))
// 		if err != nil {
// 			return err
// 		}
//
// 		// do something with conn and remote
//
// 		return nil
// 	}
// 	...
// 	ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
// 	if err != nil {
// 		panic(err.Error())
// 	}
// 	for {
// 		conn, err := ln.AcceptSocks()
// 		if err != nil {
// 			break
// 		}
// 		go handleConn(conn)
// 	}
type SocksListener struct {
	net.Listener
}

// Open a net.Listener according to network and laddr, and return it as a
// SocksListener.
func ListenSocks(network, laddr string) (*SocksListener, error) {
	ln, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return NewSocksListener(ln), nil
}

// Create a new SocksListener wrapping the given net.Listener.
func NewSocksListener(ln net.Listener) *SocksListener {
	return &SocksListener{ln}
}

// Accept is the same as AcceptSocks, except that it returns a generic net.Conn.
// It is present for the sake of satisfying the net.Listener interface.
func (ln *SocksListener) Accept() (net.Conn, error) {
	return ln.AcceptSocks()
}

// Returns "socks4", suitable to be included in a call to pt.Cmethod.
func (ln *SocksListener) Version() string {
	return "socks4"
}

// Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
// SocksConn. After accepting, you must call either conn.Grant or conn.Reject
// (presumably after trying to connect to conn.Req.Target).
func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
	c, err := ln.Listener.Accept()
	if err != nil {
		return nil, err
	}
	conn := new(SocksConn)
	conn.Conn = c
	conn.Req, err = readSocks4aConnect(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}
	return conn, nil
}

// Read a SOCKS4a connect request. Returns a SocksRequest.
func readSocks4aConnect(s io.Reader) (req SocksRequest, err error) {
	r := bufio.NewReader(s)

	var h [8]byte
	_, err = io.ReadFull(r, h[:])
	if err != nil {
		return
	}
	if h[0] != socksVersion {
		err = errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, not 0x%02x", h[0], socksVersion))
		return
	}
	if h[1] != socksCmdConnect {
		err = errors.New(fmt.Sprintf("SOCKS header had command 0x%02x, not 0x%02x", h[1], socksCmdConnect))
		return
	}

	var usernameBytes []byte
	usernameBytes, err = r.ReadBytes('\x00')
	if err != nil {
		return
	}
	req.Username = string(usernameBytes[:len(usernameBytes)-1])

	req.Args, err = parseClientParameters(req.Username)
	if err != nil {
		return
	}

	var port int
	var host string

	port = int(h[2])<<8 | int(h[3])<<0
	if h[4] == 0 && h[5] == 0 && h[6] == 0 && h[7] != 0 {
		var hostBytes []byte
		hostBytes, err = r.ReadBytes('\x00')
		if err != nil {
			return
		}
		host = string(hostBytes[:len(hostBytes)-1])
	} else {
		host = net.IPv4(h[4], h[5], h[6], h[7]).String()
	}

	if r.Buffered() != 0 {
		err = errors.New(fmt.Sprintf("%d bytes left after SOCKS header", r.Buffered()))
		return
	}

	req.Target = fmt.Sprintf("%s:%d", host, port)
	return
}

// Send a SOCKS4a response with the given code and address. If the IP field
// inside addr is not an IPv4 address, the IP portion of the response will be
// four zero bytes.
func sendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
	var resp [8]byte
	resp[0] = socksResponseVersion
	resp[1] = code
	resp[2] = byte((addr.Port >> 8) & 0xff)
	resp[3] = byte((addr.Port >> 0) & 0xff)
	ipv4 := addr.IP.To4()
	if ipv4 != nil {
		resp[4] = ipv4[0]
		resp[5] = ipv4[1]
		resp[6] = ipv4[2]
		resp[7] = ipv4[3]
	}
	_, err := w.Write(resp[:])
	return err
}

var emptyAddr = net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}

// Send a SOCKS4a response code 0x5a.
func sendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
	return sendSocks4aResponse(w, socksRequestGranted, addr)
}

// Send a SOCKS4a response code 0x5b (with an all-zero address).
func sendSocks4aResponseRejected(w io.Writer) error {
	return sendSocks4aResponse(w, socksRequestRejected, &emptyAddr)
}
<commit_msg>Put the non-IPv4 zero bytes comment on an exposed function too.<commit_after>package pt

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
)

const (
	socksVersion         = 0x04
	socksCmdConnect      = 0x01
	socksResponseVersion = 0x00
	socksRequestGranted  = 0x5a
	socksRequestRejected = 0x5b
)

// SocksRequest describes a SOCKS request.
type SocksRequest struct {
	// The endpoint requested by the client as a "host:port" string.
	Target string
	// The userid string sent by the client.
	Username string
	// The parsed contents of Username as a key–value mapping.
	Args Args
}

// SocksConn encapsulates a net.Conn and information associated with a SOCKS request.
type SocksConn struct {
	net.Conn
	Req SocksRequest
}

// Send a message to the proxy client that access to the given address is
// granted. If the IP field inside addr is not an IPv4 address, the IP portion
// of the response will be four zero bytes.
func (conn *SocksConn) Grant(addr *net.TCPAddr) error {
	return sendSocks4aResponseGranted(conn, addr)
}

// Send a message to the proxy client that access was rejected or failed.
func (conn *SocksConn) Reject() error {
	return sendSocks4aResponseRejected(conn)
}

// SocksListener wraps a net.Listener in order to read a SOCKS request on Accept.
//
// 	func handleConn(conn *pt.SocksConn) error {
// 		defer conn.Close()
// 		remote, err := net.Dial("tcp", conn.Req.Target)
// 		if err != nil {
// 			conn.Reject()
// 			return err
// 		}
// 		defer remote.Close()
// 		err = conn.Grant(remote.RemoteAddr().(*net.TCPAddr))
// 		if err != nil {
// 			return err
// 		}
//
// 		// do something with conn and remote
//
// 		return nil
// 	}
// 	...
// 	ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
// 	if err != nil {
// 		panic(err.Error())
// 	}
// 	for {
// 		conn, err := ln.AcceptSocks()
// 		if err != nil {
// 			break
// 		}
// 		go handleConn(conn)
// 	}
type SocksListener struct {
	net.Listener
}

// Open a net.Listener according to network and laddr, and return it as a
// SocksListener.
func ListenSocks(network, laddr string) (*SocksListener, error) {
	ln, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return NewSocksListener(ln), nil
}

// Create a new SocksListener wrapping the given net.Listener.
func NewSocksListener(ln net.Listener) *SocksListener {
	return &SocksListener{ln}
}

// Accept is the same as AcceptSocks, except that it returns a generic net.Conn.
// It is present for the sake of satisfying the net.Listener interface.
func (ln *SocksListener) Accept() (net.Conn, error) {
	return ln.AcceptSocks()
}

// Returns "socks4", suitable to be included in a call to pt.Cmethod.
func (ln *SocksListener) Version() string {
	return "socks4"
}

// Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
// SocksConn. After accepting, you must call either conn.Grant or conn.Reject
// (presumably after trying to connect to conn.Req.Target).
func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
	c, err := ln.Listener.Accept()
	if err != nil {
		return nil, err
	}
	conn := new(SocksConn)
	conn.Conn = c
	conn.Req, err = readSocks4aConnect(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}
	return conn, nil
}

// Read a SOCKS4a connect request. Returns a SocksRequest.
func readSocks4aConnect(s io.Reader) (req SocksRequest, err error) {
	r := bufio.NewReader(s)

	var h [8]byte
	_, err = io.ReadFull(r, h[:])
	if err != nil {
		return
	}
	if h[0] != socksVersion {
		err = errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, not 0x%02x", h[0], socksVersion))
		return
	}
	if h[1] != socksCmdConnect {
		err = errors.New(fmt.Sprintf("SOCKS header had command 0x%02x, not 0x%02x", h[1], socksCmdConnect))
		return
	}

	var usernameBytes []byte
	usernameBytes, err = r.ReadBytes('\x00')
	if err != nil {
		return
	}
	req.Username = string(usernameBytes[:len(usernameBytes)-1])

	req.Args, err = parseClientParameters(req.Username)
	if err != nil {
		return
	}

	var port int
	var host string

	port = int(h[2])<<8 | int(h[3])<<0
	if h[4] == 0 && h[5] == 0 && h[6] == 0 && h[7] != 0 {
		var hostBytes []byte
		hostBytes, err = r.ReadBytes('\x00')
		if err != nil {
			return
		}
		host = string(hostBytes[:len(hostBytes)-1])
	} else {
		host = net.IPv4(h[4], h[5], h[6], h[7]).String()
	}

	if r.Buffered() != 0 {
		err = errors.New(fmt.Sprintf("%d bytes left after SOCKS header", r.Buffered()))
		return
	}

	req.Target = fmt.Sprintf("%s:%d", host, port)
	return
}

// Send a SOCKS4a response with the given code and address. If the IP field
// inside addr is not an IPv4 address, the IP portion of the response will be
// four zero bytes.
func sendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
	var resp [8]byte
	resp[0] = socksResponseVersion
	resp[1] = code
	resp[2] = byte((addr.Port >> 8) & 0xff)
	resp[3] = byte((addr.Port >> 0) & 0xff)
	ipv4 := addr.IP.To4()
	if ipv4 != nil {
		resp[4] = ipv4[0]
		resp[5] = ipv4[1]
		resp[6] = ipv4[2]
		resp[7] = ipv4[3]
	}
	_, err := w.Write(resp[:])
	return err
}

var emptyAddr = net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}

// Send a SOCKS4a response code 0x5a.
func sendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
	return sendSocks4aResponse(w, socksRequestGranted, addr)
}

// Send a SOCKS4a response code 0x5b (with an all-zero address).
func sendSocks4aResponseRejected(w io.Writer) error {
	return sendSocks4aResponse(w, socksRequestRejected, &emptyAddr)
}
<|endoftext|>


<commit_before>package boardgame

import (
	"encoding/json"
)

//State represents the entire semantic state of a game at a given version. For
//your specific game, Game and Players will actually be concrete structs to
//your particular game. Games often define a top-level concreteStates()
//*myGameState, []*myPlayerState so at the top of methods that accept a State
//they can quickly get concrete, type-checked types with only a single
//conversion leap of faith at the top. States are intended to be read-only;
//methods where you are allowed to mutate the state (e.g. Move.Apply()) will
//take a MutableState instead as a signal that it is permissable to modify the
//state. That is why the states only return non-mutable states
//(PropertyReaders, not PropertyReadSetters, although realistically it is
//possible to cast them and modify directly. The MarshalJSON output of a State
//is appropriate for sending to a client or serializing a state to be put in
//storage. Given a blob serialized in that fashion, GameManager.StateFromBlob
//will return a state.
type State interface {
	//Game returns the GameState for this State
	Game() GameState
	//Players returns a slice of all PlayerStates for this State
	Players() []PlayerState
	//DynamicComponentValues returns a map of deck name to array of component
	//values, one per component in that deck.
	DynamicComponentValues() map[string][]DynamicComponentValues
	//Copy returns a deep copy of the State, including copied version of the Game
	//and Player States.
	Copy(sanitized bool) State
	//Diagram returns a basic, ascii rendering of the state for debug rendering.
	//It thunks out to Delegate.Diagram.
	Diagram() string
	//Santizied will return false if this is a full-fidelity State object, or
	//true if it has been sanitized, which means that some properties might be
	//hidden or otherwise altered. This should return true if the object was
	//created with Copy(true)
	Sanitized() bool
	//Computed returns the computed properties for this state.
	Computed() ComputedProperties
	//SanitizedForPlayer produces a copy state object that has been sanitized for
	//the player at the given index. The state object returned will have
	//Sanitized() return true. Will call GameDelegate.StateSanitizationPolicy to
	//retrieve the policy in place. See the package level comment for an overview
	//of how state sanitization works.
	SanitizedForPlayer(playerIndex int) State
}

//A MutableState is a state that is designed to be modified in place. These
//are passed to methods (instead of normal States) as a signal that
//modifications are intended to be done on the state.
type MutableState interface {
	//MutableState contains all of the methods of a read-only state.
	State
	//MutableGame is a reference to the MutableGameState for this MutableState.
	MutableGame() MutableGameState
	//MutablePlayers returns a slice of MutablePlayerStates for this MutableState.
	MutablePlayers() []MutablePlayerState
}

//state implements both State and MutableState, so it can always be passed for
//either, and what it's interpreted as is primarily a function of what the
//method signature is that it's passed to
type state struct {
	game                   MutableGameState
	players                []MutablePlayerState
	computed               *computedPropertiesImpl
	dynamicComponentValues map[string][]DynamicComponentValues
	sanitized              bool
	delegate               GameDelegate
}

func (s *state) MutableGame() MutableGameState {
	return s.game
}

func (s *state) MutablePlayers() []MutablePlayerState {
	return s.players
}

func (s *state) Game() GameState {
	return s.game
}

func (s *state) Players() []PlayerState {
	result := make([]PlayerState, len(s.players))
	for i := 0; i < len(s.players); i++ {
		result[i] = s.players[i]
	}
	return result
}

func (s *state) Copy(sanitized bool) State {
	return s.copy(sanitized)
}

func (s *state) copy(sanitized bool) *state {
	players := make([]MutablePlayerState, len(s.players))

	for i, player := range s.players {
		players[i] = player.MutableCopy()
	}

	result := &state{
		game:                   s.game.MutableCopy(),
		players:                players,
		dynamicComponentValues: make(map[string][]DynamicComponentValues),
		sanitized:              sanitized,
		delegate:               s.delegate,
	}

	for deckName, values := range s.dynamicComponentValues {
		arr := make([]DynamicComponentValues, len(values))
		for i := 0; i < len(values); i++ {
			arr[i] = values[i].Copy()
			if err := verifyReaderStacks(arr[i].Reader(), result); err != nil {
				return nil
			}
		}
		result.dynamicComponentValues[deckName] = arr
	}

	//FixUp stacks to make sure they point to this new state.
	if err := verifyReaderStacks(result.game.Reader(), result); err != nil {
		return nil
	}
	for _, player := range result.players {
		if err := verifyReaderStacks(player.Reader(), result); err != nil {
			return nil
		}
	}

	return result
}

func (s *state) MarshalJSON() ([]byte, error) {
	obj := map[string]interface{}{
		"Game":     s.game,
		"Players":  s.players,
		"Computed": s.Computed(),
	}

	dynamic := s.DynamicComponentValues()

	if dynamic != nil && len(dynamic) != 0 {
		obj["Components"] = dynamic
	}

	return json.Marshal(obj)
}

func (s *state) Diagram() string {
	return s.delegate.Diagram(s)
}

func (s *state) Sanitized() bool {
	return s.sanitized
}

func (s *state) DynamicComponentValues() map[string][]DynamicComponentValues {
	return s.dynamicComponentValues
}

func (s *state) Computed() ComputedProperties {
	if s.computed == nil {
		s.computed = newComputedPropertiesImpl(s.delegate.ComputedPropertiesConfig(), s)
	}
	return s.computed
}

func (s *state) SanitizedForPlayer(playerIndex int) State {

	//If the playerIndex isn't an actuall player's index, just return self.
	if playerIndex < 0 || playerIndex >= len(s.players) {
		return s
	}

	policy := s.delegate.StateSanitizationPolicy()

	if policy == nil {
		policy = &StatePolicy{}
	}

	sanitized := s.copy(true)

	//We need to figure out which components that have dynamicvalues are
	//visible after sanitizing game and player states. We'll have
	//sanitizeStateObj tell us which ones are visible, and which player's
	//state they're visible through, by accumulating the information in
	//visibleDyanmicComponents.
	visibleDynamicComponents := make(map[string]map[int]int)

	for deckName, _ := range s.dynamicComponentValues {
		visibleDynamicComponents[deckName] = make(map[int]int)
	}

	sanitizeStateObj(sanitized.game.ReadSetter(), policy.Game, -1, playerIndex, PolicyVisible, visibleDynamicComponents)

	playerStates := sanitized.players

	for i := 0; i < len(playerStates); i++ {
		sanitizeStateObj(playerStates[i].ReadSetter(), policy.Player, i, playerIndex, PolicyVisible, visibleDynamicComponents)
	}

	//TODO: now we have to go through and reason about each of the components
	//that are children of the dynamicvalues that are revealed. :-/

	//Now that all dynamic components are marked, we need to go through and
	//sanitize all of those objects according to the policy.
	sanitizeDynamicComponentValues(sanitized.dynamicComponentValues, visibleDynamicComponents, policy.DynamicComponentValues, playerIndex)

	return sanitized

}

//sanitizedWithExceptions will return a Sanitized() State where properties
//that are not in the passed policy are treated as PolicyRandom. Useful in
//computing properties.
func (s *state) sanitizedWithExceptions(policy *StatePolicy) State {

	sanitized := s.copy(true)

	sanitizeStateObj(sanitized.game.ReadSetter(), policy.Game, -1, -1, PolicyRandom, nil)

	playerStates := sanitized.players

	for i := 0; i < len(playerStates); i++ {
		sanitizeStateObj(playerStates[i].ReadSetter(), policy.Player, -1, -1, PolicyRandom, nil)
	}

	return sanitized

}

//BaseState is the interface that all state objects--PlayerStates and GameStates
//--implement.
type BaseState interface {
	Reader() PropertyReader
}

//MutableBaseState is the interface that Mutable{Game,Player}State's
//implement.
type MutableBaseState interface {
	ReadSetter() PropertyReadSetter
}

//PlayerState represents the state of a game associated with a specific user.
type PlayerState interface {
	//PlayerIndex encodes the index this user's state is in the containing
	//state object.
	PlayerIndex() int
	//Copy produces a copy of our current state. Be sure it's a deep copy that
	//makes a copy of any pointer arguments.
	Copy() PlayerState
	BaseState
}

//A MutablePlayerState is a PlayerState that is allowed to be mutated.
type MutablePlayerState interface {
	PlayerState
	MutableCopy() MutablePlayerState
	MutableBaseState
}

//GameState represents the state of a game that is not associated with a
//particular user. For example, the draw stack of cards, who the current
//player is, and other properites.
type GameState interface {
	//Copy returns a copy of our current state. Be sure it's a deep copy that
	//makes a copy of any pointer arguments.
	Copy() GameState
	BaseState
}

//A MutableGameState is a GameState that is allowed to be mutated.
type MutableGameState interface {
	GameState
	MutableCopy() MutableGameState
	MutableBaseState
}

//DefaultMarshalJSON is a simple wrapper around json.MarshalIndent, with the
//right defaults set. If your structs need to implement MarshaLJSON to output
//JSON, use this to encode it.
func DefaultMarshalJSON(obj interface{}) ([]byte, error) {
	return json.MarshalIndent(obj, "", "  ")
}
<commit_msg>Beefed up a TODO. Part of #41.<commit_after>package boardgame

import (
	"encoding/json"
)

//State represents the entire semantic state of a game at a given version. For
//your specific game, Game and Players will actually be concrete structs to
//your particular game. Games often define a top-level concreteStates()
//*myGameState, []*myPlayerState so at the top of methods that accept a State
//they can quickly get concrete, type-checked types with only a single
//conversion leap of faith at the top. States are intended to be read-only;
//methods where you are allowed to mutate the state (e.g. Move.Apply()) will
//take a MutableState instead as a signal that it is permissable to modify the
//state. That is why the states only return non-mutable states
//(PropertyReaders, not PropertyReadSetters, although realistically it is
//possible to cast them and modify directly. The MarshalJSON output of a State
//is appropriate for sending to a client or serializing a state to be put in
//storage. Given a blob serialized in that fashion, GameManager.StateFromBlob
//will return a state.
type State interface {
	//Game returns the GameState for this State
	Game() GameState
	//Players returns a slice of all PlayerStates for this State
	Players() []PlayerState
	//DynamicComponentValues returns a map of deck name to array of component
	//values, one per component in that deck.
	DynamicComponentValues() map[string][]DynamicComponentValues
	//Copy returns a deep copy of the State, including copied version of the Game
	//and Player States.
	Copy(sanitized bool) State
	//Diagram returns a basic, ascii rendering of the state for debug rendering.
	//It thunks out to Delegate.Diagram.
	Diagram() string
	//Santizied will return false if this is a full-fidelity State object, or
	//true if it has been sanitized, which means that some properties might be
	//hidden or otherwise altered. This should return true if the object was
	//created with Copy(true)
	Sanitized() bool
	//Computed returns the computed properties for this state.
	Computed() ComputedProperties
	//SanitizedForPlayer produces a copy state object that has been sanitized for
	//the player at the given index. The state object returned will have
	//Sanitized() return true. Will call GameDelegate.StateSanitizationPolicy to
	//retrieve the policy in place. See the package level comment for an overview
	//of how state sanitization works.
	SanitizedForPlayer(playerIndex int) State
}

//A MutableState is a state that is designed to be modified in place. These
//are passed to methods (instead of normal States) as a signal that
//modifications are intended to be done on the state.
type MutableState interface {
	//MutableState contains all of the methods of a read-only state.
	State
	//MutableGame is a reference to the MutableGameState for this MutableState.
	MutableGame() MutableGameState
	//MutablePlayers returns a slice of MutablePlayerStates for this MutableState.
	MutablePlayers() []MutablePlayerState
}

//state implements both State and MutableState, so it can always be passed for
//either, and what it's interpreted as is primarily a function of what the
//method signature is that it's passed to
type state struct {
	game                   MutableGameState
	players                []MutablePlayerState
	computed               *computedPropertiesImpl
	dynamicComponentValues map[string][]DynamicComponentValues
	sanitized              bool
	delegate               GameDelegate
}

func (s *state) MutableGame() MutableGameState {
	return s.game
}

func (s *state) MutablePlayers() []MutablePlayerState {
	return s.players
}

func (s *state) Game() GameState {
	return s.game
}

func (s *state) Players() []PlayerState {
	result := make([]PlayerState, len(s.players))
	for i := 0; i < len(s.players); i++ {
		result[i] = s.players[i]
	}
	return result
}

func (s *state) Copy(sanitized bool) State {
	return s.copy(sanitized)
}

func (s *state) copy(sanitized bool) *state {
	players := make([]MutablePlayerState, len(s.players))

	for i, player := range s.players {
		players[i] = player.MutableCopy()
	}

	result := &state{
		game:                   s.game.MutableCopy(),
		players:                players,
		dynamicComponentValues: make(map[string][]DynamicComponentValues),
		sanitized:              sanitized,
		delegate:               s.delegate,
	}

	for deckName, values := range s.dynamicComponentValues {
		arr := make([]DynamicComponentValues, len(values))
		for i := 0; i < len(values); i++ {
			arr[i] = values[i].Copy()
			if err := verifyReaderStacks(arr[i].Reader(), result); err != nil {
				return nil
			}
		}
		result.dynamicComponentValues[deckName] = arr
	}

	//FixUp stacks to make sure they point to this new state.
	if err := verifyReaderStacks(result.game.Reader(), result); err != nil {
		return nil
	}
	for _, player := range result.players {
		if err := verifyReaderStacks(player.Reader(), result); err != nil {
			return nil
		}
	}

	return result
}

func (s *state) MarshalJSON() ([]byte, error) {
	obj := map[string]interface{}{
		"Game":     s.game,
		"Players":  s.players,
		"Computed": s.Computed(),
	}

	dynamic := s.DynamicComponentValues()

	if dynamic != nil && len(dynamic) != 0 {
		obj["Components"] = dynamic
	}

	return json.Marshal(obj)
}

func (s *state) Diagram() string {
	return s.delegate.Diagram(s)
}

func (s *state) Sanitized() bool {
	return s.sanitized
}

func (s *state) DynamicComponentValues() map[string][]DynamicComponentValues {
	return s.dynamicComponentValues
}

func (s *state) Computed() ComputedProperties {
	if s.computed == nil {
		s.computed = newComputedPropertiesImpl(s.delegate.ComputedPropertiesConfig(), s)
	}
	return s.computed
}

func (s *state) SanitizedForPlayer(playerIndex int) State {

	//If the playerIndex isn't an actuall player's index, just return self.
	if playerIndex < 0 || playerIndex >= len(s.players) {
		return s
	}

	policy := s.delegate.StateSanitizationPolicy()

	if policy == nil {
		policy = &StatePolicy{}
	}

	sanitized := s.copy(true)

	//We need to figure out which components that have dynamicvalues are
	//visible after sanitizing game and player states. We'll have
	//sanitizeStateObj tell us which ones are visible, and which player's
	//state they're visible through, by accumulating the information in
	//visibleDyanmicComponents.
	visibleDynamicComponents := make(map[string]map[int]int)

	for deckName, _ := range s.dynamicComponentValues {
		visibleDynamicComponents[deckName] = make(map[int]int)
	}

	sanitizeStateObj(sanitized.game.ReadSetter(), policy.Game, -1, playerIndex, PolicyVisible, visibleDynamicComponents)

	playerStates := sanitized.players

	for i := 0; i < len(playerStates); i++ {
		sanitizeStateObj(playerStates[i].ReadSetter(), policy.Player, i, playerIndex, PolicyVisible, visibleDynamicComponents)
	}

	//TODO: now we have to go through and reason about each of the components
	//that are children of the dynamicvalues that are revealed.... and then
	//keep on doing that until no new ones are found. :-/

	//Now that all dynamic components are marked, we need to go through and
	//sanitize all of those objects according to the policy.
	sanitizeDynamicComponentValues(sanitized.dynamicComponentValues, visibleDynamicComponents, policy.DynamicComponentValues, playerIndex)

	return sanitized

}

//sanitizedWithExceptions will return a Sanitized() State where properties
//that are not in the passed policy are treated as PolicyRandom. Useful in
//computing properties.
func (s *state) sanitizedWithExceptions(policy *StatePolicy) State {

	sanitized := s.copy(true)

	sanitizeStateObj(sanitized.game.ReadSetter(), policy.Game, -1, -1, PolicyRandom, nil)

	playerStates := sanitized.players

	for i := 0; i < len(playerStates); i++ {
		sanitizeStateObj(playerStates[i].ReadSetter(), policy.Player, -1, -1, PolicyRandom, nil)
	}

	return sanitized

}

//BaseState is the interface that all state objects--PlayerStates and GameStates
//--implement.
type BaseState interface {
	Reader() PropertyReader
}

//MutableBaseState is the interface that Mutable{Game,Player}State's
//implement.
type MutableBaseState interface {
	ReadSetter() PropertyReadSetter
}

//PlayerState represents the state of a game associated with a specific user.
type PlayerState interface {
	//PlayerIndex encodes the index this user's state is in the containing
	//state object.
	PlayerIndex() int
	//Copy produces a copy of our current state. Be sure it's a deep copy that
	//makes a copy of any pointer arguments.
	Copy() PlayerState
	BaseState
}

//A MutablePlayerState is a PlayerState that is allowed to be mutated.
type MutablePlayerState interface {
	PlayerState
	MutableCopy() MutablePlayerState
	MutableBaseState
}

//GameState represents the state of a game that is not associated with a
//particular user. For example, the draw stack of cards, who the current
//player is, and other properites.
type GameState interface {
	//Copy returns a copy of our current state. Be sure it's a deep copy that
	//makes a copy of any pointer arguments.
	Copy() GameState
	BaseState
}

//A MutableGameState is a GameState that is allowed to be mutated.
type MutableGameState interface {
	GameState
	MutableCopy() MutableGameState
	MutableBaseState
}

//DefaultMarshalJSON is a simple wrapper around json.MarshalIndent, with the
//right defaults set. If your structs need to implement MarshaLJSON to output
//JSON, use this to encode it.
func DefaultMarshalJSON(obj interface{}) ([]byte, error) {
	return json.MarshalIndent(obj, "", "  ")
}
<|endoftext|>