<commit_before>package nsq

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type Writer struct {
	net.Conn
	sync.Mutex
	transactionChan   chan *writerTransaction
	dataChan          chan []byte
	WriteTimeout      time.Duration
	transactions      []*writerTransaction
	state             int32
	stopFlag          int32
	HeartbeatInterval int
	ShortIdentifier   string
	LongIdentifier    string
	exitChan          chan int
}

type writerTransaction struct {
	doneChan  chan int
	cmd       *Command
	frameType int32
	data      []byte
	err       error
}

func NewWriter(heartbeatInterval int) *Writer {
	hostname, err := os.Hostname()
	if err != nil {
		log.Fatalf("ERROR: unable to get hostname %s", err.Error())
	}
	this := &Writer{
		transactionChan:   make(chan *writerTransaction),
		exitChan:          make(chan int),
		dataChan:          make(chan []byte),
		state:             StateDisconnected,
		stopFlag:          0,
		WriteTimeout:      time.Second,
		HeartbeatInterval: heartbeatInterval,
		ShortIdentifier:   strings.Split(hostname, ".")[0],
		LongIdentifier:    hostname,
	}
	return this
}

func (this *Writer) Stop() {
	if !atomic.CompareAndSwapInt32(&this.stopFlag, 0, 1) {
		return
	}
	if atomic.CompareAndSwapInt32(&this.state, StateConnected, StateDisconnected) {
		this.Close()
	}
	close(this.exitChan)
}

func (this *Writer) Publish(topic string, body []byte) (int32, []byte, error) {
	cmd := Publish(topic, body)
	return this.sendCommand(cmd)
}

func (this *Writer) MultiPublish(topic string, body [][]byte) (int32, []byte, error) {
	cmd, err := MultiPublish(topic, body)
	if err != nil {
		return -1, nil, err
	}
	return this.sendCommand(cmd)
}

func (this *Writer) sendCommand(cmd *Command) (int32, []byte, error) {
	if atomic.LoadInt32(&this.state) != StateConnected {
		return -1, nil, errors.New("not connected")
	}
	t := &writerTransaction{
		cmd:       cmd,
		frameType: -1,
		doneChan:  make(chan int),
	}
	this.transactionChan <- t
	<-t.doneChan
	return t.frameType, t.data, t.err
}

func (this *Writer) ConnectToNSQ(addr string) error {
	if atomic.LoadInt32(&this.stopFlag) == 1 {
		return errors.New("writer stopped")
	}
	this.Lock()
	defer this.Unlock()
	if !atomic.CompareAndSwapInt32(&this.state,
		StateDisconnected, StateConnected) {
		return nil
	}
	var err error
	this.Conn, err = net.DialTimeout("tcp", addr, time.Second*5)
	if err != nil {
		return errors.New("failed to connect nsq")
	}
	this.SetWriteDeadline(time.Now().Add(this.WriteTimeout))
	if _, err := this.Conn.Write(MagicV2); err != nil {
		this.Close()
		return err
	}
	atomic.StoreInt32(&this.state, StateConnected)
	ci := make(map[string]interface{})
	ci["short_id"] = this.ShortIdentifier
	ci["long_id"] = this.LongIdentifier
	ci["heartbeat_interval"] = this.HeartbeatInterval
	ci["feature_negotiation"] = true
	cmd, err := Identify(ci)
	if err != nil {
		this.Close()
		return fmt.Errorf("[%s] failed to create identify command - %s", this.RemoteAddr(), err.Error())
	}
	go this.readLoop()
	go this.messageRouter()
	frameType, data, err := this.sendCommand(cmd)
	if frameType == FrameTypeError {
		if err == nil {
			this.Close()
			err = fmt.Errorf("[%s] error failed to identify - %s", this.RemoteAddr(), string(data))
		}
	}
	return err
}

func (this *Writer) messageRouter() {
	var err error
	defer this.transactionCleanup()
	for {
		select {
		case t := <-this.transactionChan:
			this.transactions = append(this.transactions, t)
			this.SetWriteDeadline(time.Now().Add(this.WriteTimeout))
			if err = t.cmd.Write(this.Conn); err != nil {
				log.Printf("[%s] error writing %s", this.RemoteAddr(), err.Error())
				this.Close()
				return
			}
		case buf := <-this.dataChan:
			frameType, data, err := UnpackResponse(buf)
			if err != nil {
				log.Printf("[%s] error (%s) unpacking response %d %s", this.RemoteAddr(), err.Error(), frameType, data)
				return
			}
			if frameType == FrameTypeResponse &&
				bytes.Equal(data, []byte("_heartbeat_")) {
				log.Printf("[%s] received heartbeat", this.RemoteAddr())
				if err := this.heartbeat(); err != nil {
					log.Printf("[%s] error sending heartbeat - %s", this.RemoteAddr(), err.Error())
					this.Close()
					return
				}
			} else {
				t := this.transactions[0]
				this.transactions = this.transactions[1:]
				t.frameType = frameType
				t.data = data
				t.err = err
				t.doneChan <- 1
			}
		case <-this.exitChan:
			return
		}
	}
}

//send heartbeat
func (this *Writer) heartbeat() error {
	this.SetWriteDeadline(time.Now().Add(this.WriteTimeout))
	if err := Nop().Write(this.Conn); err != nil {
		return err
	}
	return nil
}

// cleanup transactions
func (this *Writer) transactionCleanup() {
	this.Lock()
	defer this.Unlock()
	for _, t := range this.transactions {
		t.err = errors.New("not connected")
		t.doneChan <- 1
	}
	this.transactions = this.transactions[:0]
	atomic.CompareAndSwapInt32(&this.state, StateConnected, StateDisconnected)
}

func (this *Writer) readLoop() {
	rbuf := bufio.NewReader(this.Conn)
	for {
		resp, err := ReadResponse(rbuf)
		if err != nil {
			log.Printf("[%s] error reading response %s", this.RemoteAddr(), err.Error())
			if !strings.Contains(err.Error(), "use of closed network connection") {
				this.Close()
			}
			break
		}
		select {
		case this.dataChan <- resp:
		case <-this.exitChan:
			return
		}
	}
}
<commit_msg>replace writer.Close() with write.close()<commit_after>package nsq

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"sync/atomic"
	"time"
)

type Writer struct {
	net.Conn
	transactionChan   chan *writerTransaction
	dataChan          chan []byte
	WriteTimeout      time.Duration
	transactions      []*writerTransaction
	state             int32
	stopFlag          int32
	transactionStat   int32
	HeartbeatInterval int
	ShortIdentifier   string
	LongIdentifier    string
	exitChan          chan int
}

type writerTransaction struct {
	doneChan  chan int
	cmd       *Command
	frameType int32
	data      []byte
	err       error
}

func NewWriter(heartbeatInterval int) *Writer {
	hostname, err := os.Hostname()
	if err != nil {
		log.Fatalf("ERROR: unable to get hostname %s", err.Error())
	}
	this := &Writer{
		transactionChan:   make(chan *writerTransaction),
		exitChan:          make(chan int),
		dataChan:          make(chan []byte),
		state:             StateDisconnected,
		stopFlag:          0,
		transactionStat:   0,
		WriteTimeout:      time.Second,
		HeartbeatInterval: heartbeatInterval,
		ShortIdentifier:   strings.Split(hostname, ".")[0],
		LongIdentifier:    hostname,
	}
	return this
}

func (this *Writer) Stop() {
	if !atomic.CompareAndSwapInt32(&this.stopFlag, 0, 1) {
		return
	}
	this.close()
}

func (this *Writer) Publish(topic string, body []byte) (int32, []byte, error) {
	cmd := Publish(topic, body)
	return this.sendCommand(cmd)
}

func (this *Writer) MultiPublish(topic string, body [][]byte) (int32, []byte, error) {
	cmd, err := MultiPublish(topic, body)
	if err != nil {
		return -1, nil, err
	}
	return this.sendCommand(cmd)
}

func (this *Writer) sendCommand(cmd *Command) (int32, []byte, error) {
	if atomic.LoadInt32(&this.state) != StateConnected {
		return -1, nil, errors.New("not connected")
	}
	t := &writerTransaction{
		cmd:       cmd,
		frameType: -1,
		doneChan:  make(chan int),
	}
	this.transactionChan <- t
	<-t.doneChan
	return t.frameType, t.data, t.err
}

func (this *Writer) ConnectToNSQ(addr string) error {
	if atomic.LoadInt32(&this.stopFlag) == 1 {
		return errors.New("writer stopped")
	}
	if atomic.LoadInt32(&this.transactionStat) != 0 {
		return errors.New("writer transactions not cleaned")
	}
	if !atomic.CompareAndSwapInt32(&this.state, StateDisconnected, StateConnected) {
		return nil
	}
	var err error
	this.Conn, err = net.DialTimeout("tcp", addr, time.Second*5)
	if err != nil {
		atomic.StoreInt32(&this.state, StateDisconnected)
		return errors.New("failed to connect nsq")
	}
	this.SetWriteDeadline(time.Now().Add(this.WriteTimeout))
	if _, err := this.Conn.Write(MagicV2); err != nil {
		this.close()
		return err
	}
	atomic.StoreInt32(&this.state, StateConnected)
	this.exitChan = make(chan int)
	ci := make(map[string]interface{})
	ci["short_id"] = this.ShortIdentifier
	ci["long_id"] = this.LongIdentifier
	ci["heartbeat_interval"] = this.HeartbeatInterval
	ci["feature_negotiation"] = true
	cmd, err := Identify(ci)
	if err != nil {
		this.close()
		return fmt.Errorf("[%s] failed to create identify command - %s", this.RemoteAddr(), err.Error())
	}
	go this.readLoop()
	go this.messageRouter()
	frameType, data, err := this.sendCommand(cmd)
	if frameType == FrameTypeError {
		if err == nil {
			this.close()
			err = fmt.Errorf("[%s] error failed to identify - %s", this.RemoteAddr(), string(data))
		}
	}
	return err
}

func (this *Writer) close() {
	if atomic.CompareAndSwapInt32(&this.state, StateConnected, StateDisconnected) {
		close(this.exitChan)
		this.Conn.Close()
	}
}

func (this *Writer) messageRouter() {
	var err error
	defer this.transactionCleanup()
	atomic.StoreInt32(&this.transactionStat, 1)
	for {
		select {
		case t := <-this.transactionChan:
			this.transactions = append(this.transactions, t)
			this.SetWriteDeadline(time.Now().Add(this.WriteTimeout))
			if err = t.cmd.Write(this.Conn); err != nil {
				log.Printf("[%s] error writing %s", this.RemoteAddr(), err.Error())
				this.close()
				return
			}
		case buf := <-this.dataChan:
			frameType, data, err := UnpackResponse(buf)
			if err != nil {
				log.Printf("[%s] error (%s) unpacking response %d %s", this.RemoteAddr(), err.Error(), frameType, data)
				return
			}
			if frameType == FrameTypeResponse &&
				bytes.Equal(data, []byte("_heartbeat_")) {
				log.Printf("[%s] received heartbeat", this.RemoteAddr())
				if err := this.heartbeat(); err != nil {
					log.Printf("[%s] error sending heartbeat - %s", this.RemoteAddr(), err.Error())
					this.close()
					return
				}
			} else {
				t := this.transactions[0]
				this.transactions = this.transactions[1:]
				t.frameType = frameType
				t.data = data
				t.err = err
				t.doneChan <- 1
			}
		case <-this.exitChan:
			return
		}
	}
}

//send heartbeat
func (this *Writer) heartbeat() error {
	this.SetWriteDeadline(time.Now().Add(this.WriteTimeout))
	if err := Nop().Write(this.Conn); err != nil {
		return err
	}
	return nil
}

// cleanup transactions
func (this *Writer) transactionCleanup() {
	for _, t := range this.transactions {
		t.err = errors.New("not connected")
		t.doneChan <- 1
	}
	this.transactions = this.transactions[:0]
	atomic.StoreInt32(&this.transactionStat, 0)
}

func (this *Writer) readLoop() {
	rbuf := bufio.NewReader(this.Conn)
	for {
		resp, err := ReadResponse(rbuf)
		if err != nil {
			log.Printf("[%s] error reading response %s", this.RemoteAddr(), err.Error())
			if !strings.Contains(err.Error(), "use of closed network connection") {
				this.close()
			}
			break
		}
		select {
		case this.dataChan <- resp:
		case <-this.exitChan:
			return
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://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 raczlib

import (
	"io"

	"github.com/google/wuffs/lib/cgozlib"
	"github.com/google/wuffs/lib/rac"
)

// MakeDecompressor implements rac.CodecReader.
func (r *CodecReader) MakeDecompressor(compressed io.Reader, rctx rac.ReaderContext) (io.Reader, error) {
	if r.cachedZlibReader == nil {
		r.cachedZlibReader = &cgozlib.Reader{}
	}
	if err := r.cachedZlibReader.Reset(compressed, rctx.Secondary); err != nil {
		return nil, err
	}
	return r.cachedZlibReader, nil
}
<commit_msg>Fix lib/raczlib build for CGO_ENABLED=0<commit_after>// Copyright 2019 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://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.

// +build cgo

package raczlib

import (
	"io"

	"github.com/google/wuffs/lib/cgozlib"
	"github.com/google/wuffs/lib/rac"
)

// MakeDecompressor implements rac.CodecReader.
func (r *CodecReader) MakeDecompressor(compressed io.Reader, rctx rac.ReaderContext) (io.Reader, error) {
	if r.cachedZlibReader == nil {
		r.cachedZlibReader = &cgozlib.Reader{}
	}
	if err := r.cachedZlibReader.Reset(compressed, rctx.Secondary); err != nil {
		return nil, err
	}
	return r.cachedZlibReader, nil
}
<|endoftext|>


<commit_before>// +build linux

package mptcp

import (
	"net"
	"os"
	"strings"
	"testing"
)

// Swap in mock MPTCP lookup function for tests
func init() {
	lookupMPTCPLinux = generateMockLookupMPTCPLinux()
}

// TestLinux_mptcpEnabled verifies that mptcpEnabled properly detects
// multipath TCP functionality on the current Linux system.
func TestLinux_mptcpEnabled(t *testing.T) {
	// Check function result immediately
	enabled, err := mptcpEnabled()
	if err != nil {
		t.Fatal(err)
	}

	// Check if multipath TCP is available by checking for
	// connections table
	_, err = os.Stat(procMPTCP)
	if os.IsNotExist(err) {
		if enabled {
			t.Fatalf("could not find %s, but mptcpEnabled returned true", procMPTCP)
		}

		return
	}

	// Fatal on other errors
	if err != nil {
		t.Fatal(err)
	}

	// Verify multipath TCP is enabled
	if !enabled {
		t.Fatalf("found %s, but mptcpEnabled returned false", procMPTCP)
	}
}

// TestLinux_hostToHex verifies that hostToHex generates the proper hex
// representation of an input IP address string.
func TestLinux_hostToHex(t *testing.T) {
	var tests = []struct {
		host    string
		hexHost string
		err     error
	}{
		// All tests are constants, to ensure test will break if
		// functionality is changed

		// Invalid IP addresses
		{"localhost", "", ErrInvalidIPAddress},
		{"foobar", "", ErrInvalidIPAddress},

		// Valid IPv4 addresses
		{"8.8.4.4", "04040808", nil},
		{"8.8.8.8", "08080808", nil},
		{"10.10.10.10", "0a0a0a0a", nil},
		{"192.168.1.1", "0101a8c0", nil},
		{"255.255.255.0", "00ffffff", nil},

		// Valid IPv6 addresses (not yet implemented)
		{"0000:0000:0000::0000", "", ErrIPv6NotImplemented},
		{"1111:1111:1111::1111", "", ErrIPv6NotImplemented},
		{"2001:4860:4860::8844", "", ErrIPv6NotImplemented},
		{"2001:4860:4860::8888", "", ErrIPv6NotImplemented},
	}

	for i, test := range tests {
		// Convert IP address to hex representation, check results
		hexHost, err := hostToHex(test.host)
		if err != test.err {
			t.Fatalf("[%02d] unexpected err: %v != %v [test: %v]", i, err, test.err, test)
		}

		if hexHost != test.hexHost {
			t.Fatalf("[%02d] unexpected hexHost: %v != %v [test: %v]", i, hexHost, test.hexHost, test)
		}
	}
}

// TestLinux_u16PortToHex verifies that u16PortToHex generates the proper hex
// representation of an input uint16.
func TestLinux_u16PortToHex(t *testing.T) {
	var tests = []struct {
		port    uint16
		hexPort string
	}{
		// All tests are constants, to ensure test will break if
		// functionality is changed
		{0, "0000"},
		{1, "0001"},
		{100, "0064"},
		{1024, "0400"},
		{2123, "084b"},
		{4873, "1309"},
		{8925, "22dd"},
		{65535, "ffff"},
	}

	for i, test := range tests {
		// Convert port to hex representation, check results
		if hexPort := u16PortToHex(test.port); hexPort != test.hexPort {
			t.Fatalf("[%02d] unexpected hexPort: %v != %v [test: %v]", i, hexPort, test.hexPort, test)
		}
	}
}

// generateMockLookupMPTCPLinux generates a mock Linux MPTCP lookup table, using
// known data.
func generateMockLookupMPTCPLinux() func(string) (bool, error) {
	// Generate lookup table from known hosts and ports
	lookupSet := make(map[string]struct{})
	for host, port := range hostPorts {
		// Convert host to hex
		hexHost, err := hostToHex(host)
		if err != nil {
			if err == ErrIPv6NotImplemented {
				continue
			}

			panic(err)
		}

		// Generate table key with host and port in hex
		key := strings.ToUpper(net.JoinHostPort(hexHost, u16PortToHex(port)))
		lookupSet[key] = struct{}{}
	}

	// Return function which does lookups with mock data
	return func(hexHostPort string) (bool, error) {
		_, ok := lookupSet[hexHostPort]
		return ok, nil
	}
}
<commit_msg>check_linux_test: add TestLinux_mptcpTableReaderLinux<commit_after>// +build linux

package mptcp

import (
	"bytes"
	"io"
	"net"
	"os"
	"strings"
	"testing"
)

var (
	// Entries taken from a real MPTCP connections table, used for testing
	testIPv4MPTCPEntry = []byte(" 1: 9C290BF6 4CC0A727  0 E70E8368:0016                         1134B018:BBE8                         01 01 00000000:00000000 15666")
	testIPv6MPTCPEntry = []byte(" 0: F6635734 353F1E98  1 80A80426100000080000000001C07400:1F90 80A80426100000080000000001208902:93A5 01 01 00000000:00000000 39893")
)

// Swap in mock MPTCP lookup function for tests
func init() {
	lookupMPTCPLinux = generateMockLookupMPTCPLinux()
}

// TestLinux_mptcpEnabled verifies that mptcpEnabled properly detects
// multipath TCP functionality on the current Linux system.
func TestLinux_mptcpEnabled(t *testing.T) {
	// Check function result immediately
	enabled, err := mptcpEnabled()
	if err != nil {
		t.Fatal(err)
	}

	// Check if multipath TCP is available by checking for
	// connections table
	_, err = os.Stat(procMPTCP)
	if os.IsNotExist(err) {
		if enabled {
			t.Fatalf("could not find %s, but mptcpEnabled returned true", procMPTCP)
		}

		return
	}

	// Fatal on other errors
	if err != nil {
		t.Fatal(err)
	}

	// Verify multipath TCP is enabled
	if !enabled {
		t.Fatalf("found %s, but mptcpEnabled returned false", procMPTCP)
	}
}

// TestLinux_hostToHex verifies that hostToHex generates the proper hex
// representation of an input IP address string.
func TestLinux_hostToHex(t *testing.T) {
	var tests = []struct {
		host    string
		hexHost string
		err     error
	}{
		// All tests are constants, to ensure test will break if
		// functionality is changed

		// Invalid IP addresses
		{"localhost", "", ErrInvalidIPAddress},
		{"foobar", "", ErrInvalidIPAddress},

		// Valid IPv4 addresses
		{"8.8.4.4", "04040808", nil},
		{"8.8.8.8", "08080808", nil},
		{"10.10.10.10", "0a0a0a0a", nil},
		{"192.168.1.1", "0101a8c0", nil},
		{"255.255.255.0", "00ffffff", nil},

		// Valid IPv6 addresses (not yet implemented)
		{"0000:0000:0000::0000", "", ErrIPv6NotImplemented},
		{"1111:1111:1111::1111", "", ErrIPv6NotImplemented},
		{"2001:4860:4860::8844", "", ErrIPv6NotImplemented},
		{"2001:4860:4860::8888", "", ErrIPv6NotImplemented},
	}

	for i, test := range tests {
		// Convert IP address to hex representation, check results
		hexHost, err := hostToHex(test.host)
		if err != test.err {
			t.Fatalf("[%02d] unexpected err: %v != %v [test: %v]", i, err, test.err, test)
		}

		if hexHost != test.hexHost {
			t.Fatalf("[%02d] unexpected hexHost: %v != %v [test: %v]", i, hexHost, test.hexHost, test)
		}
	}
}

// TestLinux_u16PortToHex verifies that u16PortToHex generates the proper hex
// representation of an input uint16.
func TestLinux_u16PortToHex(t *testing.T) {
	var tests = []struct {
		port    uint16
		hexPort string
	}{
		// All tests are constants, to ensure test will break if
		// functionality is changed
		{0, "0000"},
		{1, "0001"},
		{100, "0064"},
		{1024, "0400"},
		{2123, "084b"},
		{4873, "1309"},
		{8925, "22dd"},
		{65535, "ffff"},
	}

	for i, test := range tests {
		// Convert port to hex representation, check results
		if hexPort := u16PortToHex(test.port); hexPort != test.hexPort {
			t.Fatalf("[%02d] unexpected hexPort: %v != %v [test: %v]", i, hexPort, test.hexPort, test)
		}
	}
}

// TestLinux_mptcpTableReaderLinux verifies that mptcpTableReaderLinux can properly
// parse a Linux MPTCP connections table for entries.
func TestLinux_mptcpTableReaderLinux(t *testing.T) {
	var tests = []struct {
		lines [][]byte
		entry string
		ok    bool
		err   error
	}{
		// Empty file
		{nil, "", false, io.ErrUnexpectedEOF},
		// Invalid header
		{[][]byte{[]byte("foobar")}, "", false, errInvalidMPTCPTable},
		// Header only, no entries
		{[][]byte{mptcpTableHeader}, "", false, nil},
		// Header, bad entry
		{[][]byte{mptcpTableHeader, []byte("foobar")}, "", false, errInvalidMPTCPEntry},
		// Header, not found IPv4 entry
		{[][]byte{mptcpTableHeader, testIPv4MPTCPEntry}, "1134B018:FFFF", false, nil},
		// Header, good IPv4 entry
		{[][]byte{mptcpTableHeader, testIPv4MPTCPEntry}, "1134B018:BBE8", true, nil},
		// Header, good IPv6 entry
		{[][]byte{mptcpTableHeader, testIPv6MPTCPEntry}, "80A80426100000080000000001208902:FFFF", false, nil},
		// Header, good IPv6 entry
		{[][]byte{mptcpTableHeader, testIPv6MPTCPEntry}, "80A80426100000080000000001208902:93A5", true, nil},
	}

	for i, test := range tests {
		// Store input lines in a buffer, appending each with newline
		buf := bytes.NewBuffer(nil)
		for _, l := range test.lines {
			if _, err := buf.Write(append(l, '\n')); err != nil {
				t.Fatal(err)
			}
		}

		// Attempt to check MPTCP table for entry
		ok, err := mptcpTableReaderLinux(buf, test.entry)
		if err != test.err {
			t.Fatalf("[%02d] unexpected err: %v != %v [test: %v]", i, err, test.err, test)
		}

		if ok != test.ok {
			t.Fatalf("[%02d] unexpected ok: %v != %v [test: %v]", i, ok, test.ok, test)
		}
	}
}

// generateMockLookupMPTCPLinux generates a mock Linux MPTCP lookup table, using
// known data.
func generateMockLookupMPTCPLinux() func(string) (bool, error) {
	// Generate lookup table from known hosts and ports
	lookupSet := make(map[string]struct{})
	for host, port := range hostPorts {
		// Convert host to hex
		hexHost, err := hostToHex(host)
		if err != nil {
			if err == ErrIPv6NotImplemented {
				continue
			}

			panic(err)
		}

		// Generate table key with host and port in hex
		key := strings.ToUpper(net.JoinHostPort(hexHost, u16PortToHex(port)))
		lookupSet[key] = struct{}{}
	}

	// Return function which does lookups with mock data
	return func(hexHostPort string) (bool, error) {
		_, ok := lookupSet[hexHostPort]
		return ok, nil
	}
}
<|endoftext|>


<commit_before>package weave

import (
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"net"
	"time"
)

const (
	InitialInterval = 5 * time.Second
	MaxInterval     = 10 * time.Minute
)

const (
	CMInitiate   = iota
	CMStatus     = iota
	CMTerminated = iota
)

func StartConnectionMaker(router *Router) *ConnectionMaker {
	queryChan := make(chan *ConnectionMakerInteraction, ChannelSize)
	state := &ConnectionMaker{
		router:         router,
		queryChan:      queryChan,
		cmdLineAddress: make(map[string]bool),
		targets:        make(map[string]*Target)}
	go state.queryLoop(queryChan)
	return state
}

func (cm *ConnectionMaker) InitiateConnection(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMInitiate},
		address:     address}
}

func (cm *ConnectionMaker) ConnectionTerminated(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMTerminated},
		address:     address}
}

func (cm *ConnectionMaker) String() string {
	resultChan := make(chan interface{}, 0)
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMStatus, resultChan: resultChan}}
	result := <-resultChan
	return result.(string)
}

func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) {
	var tick <-chan time.Time
	maybeTick := func() {
		// would be nice to optimise this to stop ticking when there is nothing worth trying
		if tick == nil {
			tick = time.After(5 * time.Second)
		}
	}
	for {
		select {
		case query, ok := <-queryChan:
			if !ok {
				return
			}
			switch {
			case query.code == CMInitiate:
				cm.cmdLineAddress[NormalisePeerAddr(query.address)] = true
				cm.checkStateAndAttemptConnections(time.Now())
				maybeTick()
			case query.code == CMStatus:
				query.resultChan <- cm.status()
			case query.code == CMTerminated:
				if target, found := cm.targets[query.address]; found {
					target.attempting = false
					target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
				}
				cm.checkStateAndAttemptConnections(time.Now())
				maybeTick()
			default:
				log.Fatal("Unexpected connection maker query:", query)
			}
		case now := <-tick:
			cm.checkStateAndAttemptConnections(now)
			tick = nil
			maybeTick()
		}
	}
}

func (cm *ConnectionMaker) checkStateAndAttemptConnections(now time.Time) {
	ourself := cm.router.Ourself
	validTarget := make(map[string]bool)

	// copy the set of things we are connected to, so we can access them without locking
	our_connected_peers := make(map[PeerName]bool)
	our_connected_targets := make(map[string]bool)
	ourself.ForEachConnection(func(peer PeerName, conn Connection) {
		our_connected_peers[peer] = true
		our_connected_targets[conn.RemoteTCPAddr()] = true
	})

	addTarget := func(address string) {
		if !our_connected_targets[address] {
			validTarget[address] = true
			cm.addTarget(address)
		}
	}

	// Add command-line targets that are not connected
	for address, _ := range cm.cmdLineAddress {
		addTarget(address)
	}

	// Add targets for peers that someone else is connected to, but we
	// aren't
	cm.router.Peers.ForEach(func(name PeerName, peer *Peer) {
		peer.ForEachConnection(func(otherPeer PeerName, conn Connection) {
			if otherPeer == ourself.Name || our_connected_peers[otherPeer] {
				return
			}
			address := conn.RemoteTCPAddr()
			// try both portnumber of connection and standard port
			addTarget(address)
			if host, _, err := net.SplitHostPort(address); err == nil {
				addTarget(NormalisePeerAddr(host))
			}
		})
	})

	now = time.Now() // make sure we catch items just added
	for address, target := range cm.targets {
		if our_connected_targets[address] {
			delete(cm.targets, address)
			continue
		}
		if target.attempting {
			continue
		}
		if !validTarget[address] {
			delete(cm.targets, address)
			continue
		}
		if now.After(target.tryAfter) {
			target.attempting = true
			go cm.attemptConnection(address, cm.cmdLineAddress[address])
		}
	}
}

func (cm *ConnectionMaker) addTarget(address string) {
	if _, found := cm.targets[address]; !found {
		target := &Target{}
		target.tryAfter, target.tryInterval = tryImmediately()
		cm.targets[address] = target
	}
}

func (cm *ConnectionMaker) status() string {
	var buf bytes.Buffer
	for address, target := range cm.targets {
		var fmtStr string
		if target.attempting {
			fmtStr = "%s (trying since %v)\n"
		} else {
			fmtStr = "%s (next try at %v)\n"
		}
		buf.WriteString(fmt.Sprintf(fmtStr, address, target.tryAfter))
	}
	return buf.String()
}

func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	log.Println("Attempting connection to", address)
	if err := cm.router.Ourself.CreateConnection(address, acceptNewPeer); err != nil {
		log.Println(err)
		cm.ConnectionTerminated(address)
	}
}

func tryImmediately() (time.Time, time.Duration) {
	interval := time.Duration(rand.Int63n(int64(InitialInterval)))
	return time.Now(), interval
}

func tryAfter(interval time.Duration) (time.Time, time.Duration) {
	interval += time.Duration(rand.Int63n(int64(interval)))
	if interval > MaxInterval {
		interval = MaxInterval
	}
	return time.Now().Add(interval), interval
}
<commit_msg>cosmetic - remove comment for which we have an issue filed<commit_after>package weave

import (
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"net"
	"time"
)

const (
	InitialInterval = 5 * time.Second
	MaxInterval     = 10 * time.Minute
)

const (
	CMInitiate   = iota
	CMStatus     = iota
	CMTerminated = iota
)

func StartConnectionMaker(router *Router) *ConnectionMaker {
	queryChan := make(chan *ConnectionMakerInteraction, ChannelSize)
	state := &ConnectionMaker{
		router:         router,
		queryChan:      queryChan,
		cmdLineAddress: make(map[string]bool),
		targets:        make(map[string]*Target)}
	go state.queryLoop(queryChan)
	return state
}

func (cm *ConnectionMaker) InitiateConnection(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMInitiate},
		address:     address}
}

func (cm *ConnectionMaker) ConnectionTerminated(address string) {
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMTerminated},
		address:     address}
}

func (cm *ConnectionMaker) String() string {
	resultChan := make(chan interface{}, 0)
	cm.queryChan <- &ConnectionMakerInteraction{
		Interaction: Interaction{code: CMStatus, resultChan: resultChan}}
	result := <-resultChan
	return result.(string)
}

func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) {
	var tick <-chan time.Time
	maybeTick := func() {
		if tick == nil {
			tick = time.After(5 * time.Second)
		}
	}
	for {
		select {
		case query, ok := <-queryChan:
			if !ok {
				return
			}
			switch {
			case query.code == CMInitiate:
				cm.cmdLineAddress[NormalisePeerAddr(query.address)] = true
				cm.checkStateAndAttemptConnections(time.Now())
				maybeTick()
			case query.code == CMStatus:
				query.resultChan <- cm.status()
			case query.code == CMTerminated:
				if target, found := cm.targets[query.address]; found {
					target.attempting = false
					target.tryAfter, target.tryInterval = tryAfter(target.tryInterval)
				}
				cm.checkStateAndAttemptConnections(time.Now())
				maybeTick()
			default:
				log.Fatal("Unexpected connection maker query:", query)
			}
		case now := <-tick:
			cm.checkStateAndAttemptConnections(now)
			tick = nil
			maybeTick()
		}
	}
}

func (cm *ConnectionMaker) checkStateAndAttemptConnections(now time.Time) {
	ourself := cm.router.Ourself
	validTarget := make(map[string]bool)

	// copy the set of things we are connected to, so we can access them without locking
	our_connected_peers := make(map[PeerName]bool)
	our_connected_targets := make(map[string]bool)
	ourself.ForEachConnection(func(peer PeerName, conn Connection) {
		our_connected_peers[peer] = true
		our_connected_targets[conn.RemoteTCPAddr()] = true
	})

	addTarget := func(address string) {
		if !our_connected_targets[address] {
			validTarget[address] = true
			cm.addTarget(address)
		}
	}

	// Add command-line targets that are not connected
	for address, _ := range cm.cmdLineAddress {
		addTarget(address)
	}

	// Add targets for peers that someone else is connected to, but we
	// aren't
	cm.router.Peers.ForEach(func(name PeerName, peer *Peer) {
		peer.ForEachConnection(func(otherPeer PeerName, conn Connection) {
			if otherPeer == ourself.Name || our_connected_peers[otherPeer] {
				return
			}
			address := conn.RemoteTCPAddr()
			// try both portnumber of connection and standard port
			addTarget(address)
			if host, _, err := net.SplitHostPort(address); err == nil {
				addTarget(NormalisePeerAddr(host))
			}
		})
	})

	now = time.Now() // make sure we catch items just added
	for address, target := range cm.targets {
		if our_connected_targets[address] {
			delete(cm.targets, address)
			continue
		}
		if target.attempting {
			continue
		}
		if !validTarget[address] {
			delete(cm.targets, address)
			continue
		}
		if now.After(target.tryAfter) {
			target.attempting = true
			go cm.attemptConnection(address, cm.cmdLineAddress[address])
		}
	}
}

func (cm *ConnectionMaker) addTarget(address string) {
	if _, found := cm.targets[address]; !found {
		target := &Target{}
		target.tryAfter, target.tryInterval = tryImmediately()
		cm.targets[address] = target
	}
}

func (cm *ConnectionMaker) status() string {
	var buf bytes.Buffer
	for address, target := range cm.targets {
		var fmtStr string
		if target.attempting {
			fmtStr = "%s (trying since %v)\n"
		} else {
			fmtStr = "%s (next try at %v)\n"
		}
		buf.WriteString(fmt.Sprintf(fmtStr, address, target.tryAfter))
	}
	return buf.String()
}

func (cm *ConnectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	log.Println("Attempting connection to", address)
	if err := cm.router.Ourself.CreateConnection(address, acceptNewPeer); err != nil {
		log.Println(err)
		cm.ConnectionTerminated(address)
	}
}

func tryImmediately() (time.Time, time.Duration) {
	interval := time.Duration(rand.Int63n(int64(InitialInterval)))
	return time.Now(), interval
}

func tryAfter(interval time.Duration) (time.Time, time.Duration) {
	interval += time.Duration(rand.Int63n(int64(interval)))
	if interval > MaxInterval {
		interval = MaxInterval
	}
	return time.Now().Add(interval), interval
}
<|endoftext|>


<commit_before>package css

import (
	"bytes"
	"testing"
)

func helperTestParseString(t *testing.T, input string, expected string) {
	p, err := Parse(bytes.NewBufferString(input))
	if err != nil {
		t.Error(err)
		return
	}

	if p.String() != expected {
		t.Error(p.String(), "!=", expected)
	}
}

func TestParser(t *testing.T) {
	// helperTestParseString(t, "<!-- x:y; -->", "<!--x:y;-->")
	// helperTestParseString(t, "color: red;", "color:red;")
	// helperTestParseString(t, "color: red; border: 0;", "color:red;border:0;")
	// helperTestParseString(t, "a { color: red; border: 0; }", "a{color:red;border:0;}")
	// helperTestParseString(t, "a { color: red; border: 0; } b { padding: 0; }", "a{color:red;border:0;}b{padding:0;}")
	// helperTestParseString(t, "color: rgb(1,2,3);", "color:rgb(1,2,3);")
	// helperTestParseString(t, "@media condition { x:y; .f { z:q; } }", "@media condition{x:y;.f{z:q;}}")

	// helperTestParseString(t, "color: red;;", "color:red;")
	// helperTestParseString(t, "@import;;", "@import;")
	// helperTestParseString(t, ".a .b#c, .d<.e { x:y; }", ".a .b#c,.d<.e{x:y;}")
	// helperTestParseString(t, ".a[b~=c]d { x:y; }", ".a[b~=c]d{x:y;}")

	// helperTestParseString(t, "{x:y;}", "x:y;")
	// helperTestParseString(t, "a{}", "")
	// helperTestParseString(t, "a,{x:y;}", "a{x:y;}")
	// helperTestParseString(t, "a,.b/*comment*/ {x:y;}", "a,.b{x:y;}")
	// helperTestParseString(t, "a,.b/*comment*/.c {x:y;}", "a,.b.c{x:y;}")
	// helperTestParseString(t, "a{x:; z:q;}", "a{z:q;}")
	// helperTestParseString(t, "@import { @media; x:y; }", "@import{x:y;}")

	helperTestParseString(t, "a:not([controls]){x:y;}", "a:not([controls]){x:y;}")
}
<commit_msg>Re-enable tests<commit_after>package css

import (
	"bytes"
	"testing"
)

func helperTestParseString(t *testing.T, input string, expected string) {
	p, err := Parse(bytes.NewBufferString(input))
	if err != nil {
		t.Error(err)
		return
	}

	if p.String() != expected {
		t.Error(p.String(), "!=", expected)
	}
}

func TestParser(t *testing.T) {
	helperTestParseString(t, "<!-- x:y; -->", "<!--x:y;-->")
	helperTestParseString(t, "color: red;", "color:red;")
	helperTestParseString(t, "color: red; border: 0;", "color:red;border:0;")
	helperTestParseString(t, "a { color: red; border: 0; }", "a{color:red;border:0;}")
	helperTestParseString(t, "a { color: red; border: 0; } b { padding: 0; }", "a{color:red;border:0;}b{padding:0;}")
	helperTestParseString(t, "color: rgb(1,2,3);", "color:rgb(1,2,3);")
	helperTestParseString(t, "@media condition { x:y; .f { z:q; } }", "@media condition{x:y;.f{z:q;}}")

	helperTestParseString(t, "color: red;;", "color:red;")
	helperTestParseString(t, "@import;;", "@import;")
	helperTestParseString(t, ".a .b#c, .d<.e { x:y; }", ".a .b#c,.d<.e{x:y;}")
	helperTestParseString(t, ".a[b~=c]d { x:y; }", ".a[b~=c]d{x:y;}")

	helperTestParseString(t, "{x:y;}", "x:y;")
	helperTestParseString(t, "a{}", "")
	helperTestParseString(t, "a,{x:y;}", "a{x:y;}")
	helperTestParseString(t, "a,.b/*comment*/ {x:y;}", "a,.b{x:y;}")
	helperTestParseString(t, "a,.b/*comment*/.c {x:y;}", "a,.b.c{x:y;}")
	helperTestParseString(t, "a{x:; z:q;}", "a{z:q;}")
	helperTestParseString(t, "@import { @media; x:y; }", "@import{x:y;}")

	helperTestParseString(t, "a:not([controls]){x:y;}", "a:not([controls]){x:y;}")
}
<|endoftext|>


<commit_before>package struc

import (
	"reflect"
	"testing"
)

func parseTest(data interface{}) error {
	_, err := parseFields(reflect.ValueOf(data))
	return err
}

type empty struct{}

func TestEmptyStruc(t *testing.T) {
	if err := parseTest(&empty{}); err == nil {
		t.Fatal("failed to error on empty struct")
	}
}

type chanStruct struct {
	Test chan int
}

func TestChanError(t *testing.T) {
	if err := parseTest(&chanStruct{}); err == nil {
		// TODO: should probably ignore channel fields
		t.Fatal("failed to error on struct containing channel")
	}
}

type badSizeof struct {
	Size int `struc:"sizeof=Bad"`
}

func TestBadSizeof(t *testing.T) {
	if err := parseTest(&badSizeof{}); err == nil {
		t.Fatal("failed to error on missing Sizeof target")
	}
}

type missingSize struct {
	Test []byte
}

func TestMissingSize(t *testing.T) {
	if err := parseTest(&missingSize{}); err == nil {
		t.Fatal("failed to error on missing field size")
	}
}
<commit_msg>add parse error test for a nested empty struct<commit_after>package struc

import (
	"bytes"
	"reflect"
	"testing"
)

func parseTest(data interface{}) error {
	_, err := parseFields(reflect.ValueOf(data))
	return err
}

type empty struct{}

func TestEmptyStruc(t *testing.T) {
	if err := parseTest(&empty{}); err == nil {
		t.Fatal("failed to error on empty struct")
	}
}

type chanStruct struct {
	Test chan int
}

func TestChanError(t *testing.T) {
	if err := parseTest(&chanStruct{}); err == nil {
		// TODO: should probably ignore channel fields
		t.Fatal("failed to error on struct containing channel")
	}
}

type badSizeof struct {
	Size int `struc:"sizeof=Bad"`
}

func TestBadSizeof(t *testing.T) {
	if err := parseTest(&badSizeof{}); err == nil {
		t.Fatal("failed to error on missing Sizeof target")
	}
}

type missingSize struct {
	Test []byte
}

func TestMissingSize(t *testing.T) {
	if err := parseTest(&missingSize{}); err == nil {
		t.Fatal("failed to error on missing field size")
	}
}

type badNested struct {
	Empty empty
}

func TestNestedParseError(t *testing.T) {
	var buf bytes.Buffer
	if err := Pack(&buf, &badNested{}); err == nil {
		t.Fatal("failed to error on bad nested struct")
	}
}
<|endoftext|>


<commit_before>package parser

import (
	"errors"
	"io"
	"strconv"
	"strings"
	"text/template"

	"github.com/ezbuy/utils/container/set"
)

var Tpl *template.Template

func init() {
	tmp, err := template.ParseGlob("src/code.1dmy.com/xyz/xuanwu/tmpl/*.tmpl")
	Tpl = tmp
	if err != nil {
		panic(err)
	}
}

type Obj struct {
	DefaultOrder string
	Extend       string
	Fields       []*Field
	Label        string
	Name         string
	GenType      string
	Package      string
	SearchIndex  string
	SearchType   string
	FilterFields []string
	TplWriter    io.Writer
}

func (o *Obj) init() {
	if strings.HasSuffix(o.Name, "Form") {
		o.GenType = "form"
	}
}

func (o *Obj) LoadTpl(tpl string) string {
	err := Tpl.ExecuteTemplate(o.TplWriter, tpl, o)
	if err != nil {
		println("LoadTpl", tpl, err.Error())
		panic(err)
	}
	return ""
}

func (o *Obj) LoadField(f *Field) string {
	err := Tpl.ExecuteTemplate(o.TplWriter, "field_"+f.Type, f)
	if err != nil {
		println("LoadField", f.Name, f.Type, err.Error())
		panic(err)
	}
	return ""
}

func (o *Obj) GetGenTypes() []string {
	switch o.GenType {
	case "form":
		return []string{"struct", "form"}
	case "enum":
		return []string{"enum"}
	default:
		return []string{"struct", "thrift_serial", "form", "orm"}
	}
}

func (o *Obj) GetFormImports() (imports []string) {
	data := set.NewStringSet()
	numberTypes := set.NewStringSet("float64", "int", "int32", "int64")
	for _, f := range o.Fields {
		if f.Type == "[]string" {
			data.Add("strings")
			continue
		}
		if numberTypes.Contains(f.Type) {
			data.Add("strconv")
			continue
		}
	}
	return data.ToArray()
}

func (o *Obj) GetOrmImports() (imports []string) {
	data := set.NewStringSet()
	for _, f := range o.Fields {
		if f.FK != "" {
			tmp := strings.SplitN(f.FK, ".", 2)
			if len(tmp) == 2 {
				packageName := tmp[0]
				data.Add(packageName)
			}
		}
	}
	return data.ToArray()
}

func (o *Obj) NeedOrm() bool {
	return true
}

func (o *Obj) NeedSearch() bool {
	return false
}

func (o *Obj) NeedIndex() bool {
	return false
}

func (o *Obj) NeedMapping() bool {
	return false
}

func (o *Obj) GetStringFilterFields() []*Field {
	return nil
}

func (o *Obj) GetListedFields() []*ListedField {
	return nil
}

func (o *Obj) GetFilterFields() []*Field {
	return nil
}

func (o *Obj) GetNonIDFields() []*Field {
	return o.Fields[1:]
}

func ToStringSlice(val []interface{}) (result []string) {
	result = make([]string, len(val))
	for i, v := range val {
		result[i] = v.(string)
	}
	return
}

func (o *Obj) Read(data map[string]interface{}) error {
	o.init()
	hasType := false
	for key, val := range data {
		switch key {
		case "type":
			o.GenType = val.(string)
			hasType = true
			break
		}
	}

	if hasType {
		delete(data, "type")
	}

	for key, val := range data {
		switch key {
		case "label":
			o.Label = val.(string)
		case "extend":
			o.Extend = val.(string)
		case "filterFields":
			o.FilterFields = ToStringSlice(val.([]interface{}))
		case "fields":
			fieldData := val.([]interface{})
			startPos := 0
			// println(o.GenType, o.Name)
			if o.GenType == "" {
				o.Fields = make([]*Field, len(fieldData)+1)
				f := new(Field)
				f.init()
				f.Obj = o
				f.Name = "ID"
				f.Tag = "1"
				f.Type = "string"
				o.Fields[0] = f
				startPos = 1
			} else {
				o.Fields = make([]*Field, len(fieldData))
			}

			for i, field := range fieldData {
				f := new(Field)
				f.Obj = o
				f.Tag = strconv.Itoa(i + 2)

				err := f.Read(field.(map[interface{}]interface{}))
				if err != nil {
					return errors.New(o.Name + " obj has " + err.Error())
				}
				o.Fields[i+startPos] = f
			}
		default:
			return errors.New(o.Name + " has invalid obj property: " + key)
		}
	}
	return nil
}
<commit_msg>change resource<commit_after>package parser

import (
	"errors"
	"io"
	"strconv"
	"strings"
	"text/template"

	"github.com/ezbuy/ezorm/tpl"
	"github.com/ezbuy/utils/container/set"
)

var Tpl *template.Template

func init() {
	Tpl = template.New("ezorm")
	files := []string{
		"mongo.gogo",
	}
	for _, fname := range files {
		data, _ := tpl.Asset(fname)
		_, err := tmp.Parse(string(data))
		if err != nil {
			panic(err)
		}
	}
}

type Obj struct {
	DefaultOrder string
	Extend       string
	Fields       []*Field
	Label        string
	Name         string
	GenType      string
	Package      string
	SearchIndex  string
	SearchType   string
	FilterFields []string
	TplWriter    io.Writer
}

func (o *Obj) init() {
	if strings.HasSuffix(o.Name, "Form") {
		o.GenType = "form"
	}
}

func (o *Obj) LoadTpl(tpl string) string {
	err := Tpl.ExecuteTemplate(o.TplWriter, tpl, o)
	if err != nil {
		println("LoadTpl", tpl, err.Error())
		panic(err)
	}
	return ""
}

func (o *Obj) LoadField(f *Field) string {
	err := Tpl.ExecuteTemplate(o.TplWriter, "field_"+f.Type, f)
	if err != nil {
		println("LoadField", f.Name, f.Type, err.Error())
		panic(err)
	}
	return ""
}

func (o *Obj) GetGenTypes() []string {
	switch o.GenType {
	case "form":
		return []string{"struct", "form"}
	case "enum":
		return []string{"enum"}
	default:
		return []string{"struct", "thrift_serial", "form", "orm"}
	}
}

func (o *Obj) GetFormImports() (imports []string) {
	data := set.NewStringSet()
	numberTypes := set.NewStringSet("float64", "int", "int32", "int64")
	for _, f := range o.Fields {
		if f.Type == "[]string" {
			data.Add("strings")
			continue
		}
		if numberTypes.Contains(f.Type) {
			data.Add("strconv")
			continue
		}
	}
	return data.ToArray()
}

func (o *Obj) GetOrmImports() (imports []string) {
	data := set.NewStringSet()
	for _, f := range o.Fields {
		if f.FK != "" {
			tmp := strings.SplitN(f.FK, ".", 2)
			if len(tmp) == 2 {
				packageName := tmp[0]
				data.Add(packageName)
			}
		}
	}
	return data.ToArray()
}

func (o *Obj) NeedOrm() bool {
	return true
}

func (o *Obj) NeedSearch() bool {
	return false
}

func (o *Obj) NeedIndex() bool {
	return false
}

func (o *Obj) NeedMapping() bool {
	return false
}

func (o *Obj) GetStringFilterFields() []*Field {
	return nil
}

func (o *Obj) GetListedFields() []*ListedField {
	return nil
}

func (o *Obj) GetFilterFields() []*Field {
	return nil
}

func (o *Obj) GetNonIDFields() []*Field {
	return o.Fields[1:]
}

func ToStringSlice(val []interface{}) (result []string) {
	result = make([]string, len(val))
	for i, v := range val {
		result[i] = v.(string)
	}
	return
}

func (o *Obj) Read(data map[string]interface{}) error {
	o.init()
	hasType := false
	for key, val := range data {
		switch key {
		case "type":
			o.GenType = val.(string)
			hasType = true
			break
		}
	}

	if hasType {
		delete(data, "type")
	}

	for key, val := range data {
		switch key {
		case "label":
			o.Label = val.(string)
		case "extend":
			o.Extend = val.(string)
		case "filterFields":
			o.FilterFields = ToStringSlice(val.([]interface{}))
		case "fields":
			fieldData := val.([]interface{})
			startPos := 0
			// println(o.GenType, o.Name)
			if o.GenType == "" {
				o.Fields = make([]*Field, len(fieldData)+1)
				f := new(Field)
				f.init()
				f.Obj = o
				f.Name = "ID"
				f.Tag = "1"
				f.Type = "string"
				o.Fields[0] = f
				startPos = 1
			} else {
				o.Fields = make([]*Field, len(fieldData))
			}

			for i, field := range fieldData {
				f := new(Field)
				f.Obj = o
				f.Tag = strconv.Itoa(i + 2)

				err := f.Read(field.(map[interface{}]interface{}))
				if err != nil {
					return errors.New(o.Name + " obj has " + err.Error())
				}
				o.Fields[i+startPos] = f
			}
		default:
			return errors.New(o.Name + " has invalid obj property: " + key)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package cluster

import (
	"sort"
	"sync"

	"github.com/Shopify/sarama"
)

type partitionConsumer struct {
	pcm sarama.PartitionConsumer

	state partitionState
	mutex sync.Mutex

	closed      bool
	dying, dead chan none
}

func newPartitionConsumer(manager sarama.Consumer, topic string, partition int32, info offsetInfo, defaultOffset int64) (*partitionConsumer, error) {
	pcm, err := manager.ConsumePartition(topic, partition, info.NextOffset(defaultOffset))

	// Resume from default offset, if requested offset is out-of-range
	if err == sarama.ErrOffsetOutOfRange {
		info.Offset = -1
		pcm, err = manager.ConsumePartition(topic, partition, defaultOffset)
	}
	if err != nil {
		return nil, err
	}

	return &partitionConsumer{
		pcm:   pcm,
		state: partitionState{Info: info},

		dying: make(chan none),
		dead:  make(chan none),
	}, nil
}

func (c *partitionConsumer) Loop(messages chan<- *sarama.ConsumerMessage, errors chan<- error) {
	defer close(c.dead)

	for {
		select {
		case msg, ok := <-c.pcm.Messages():
			if !ok {
				return
			}
			select {
			case messages <- msg:
			case <-c.dying:
				return
			}
		case err, ok := <-c.pcm.Errors():
			if !ok {
				return
			}
			select {
			case errors <- err:
			case <-c.dying:
				return
			}
		case <-c.dying:
			return
		}
	}
}

func (c *partitionConsumer) Close() error {
	if c.closed {
		return nil
	}

	c.closed = true
	close(c.dying)
	<-c.dead

	return c.pcm.Close()
}

func (c *partitionConsumer) State() partitionState {
	if c == nil {
		return partitionState{}
	}

	c.mutex.Lock()
	state := c.state
	c.mutex.Unlock()

	return state
}

func (c *partitionConsumer) MarkCommitted(offset int64) {
	if c == nil {
		return
	}

	c.mutex.Lock()
	if offset == c.state.Info.Offset {
		c.state.Dirty = false
	}
	c.mutex.Unlock()
}

func (c *partitionConsumer) MarkOffset(offset int64, metadata string) {
	if c == nil {
		return
	}

	c.mutex.Lock()
	if offset > c.state.Info.Offset {
		c.state.Info.Offset = offset
		c.state.Info.Metadata = metadata
		c.state.Dirty = true
	}
	c.mutex.Unlock()
}

// --------------------------------------------------------------------

type partitionState struct {
	Info  offsetInfo
	Dirty bool
}

// --------------------------------------------------------------------

type partitionMap struct {
	data  map[topicPartition]*partitionConsumer
	mutex sync.RWMutex
}

func newPartitionMap() *partitionMap {
	return &partitionMap{
		data: make(map[topicPartition]*partitionConsumer),
	}
}

func (m *partitionMap) Fetch(topic string, partition int32) *partitionConsumer {
	m.mutex.RLock()
	pc, _ := m.data[topicPartition{topic, partition}]
	m.mutex.RUnlock()
	return pc
}

func (m *partitionMap) Store(topic string, partition int32, pc *partitionConsumer) {
	m.mutex.Lock()
	m.data[topicPartition{topic, partition}] = pc
	m.mutex.Unlock()
}

func (m *partitionMap) HasDirty() bool {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	for _, pc := range m.data {
		if state := pc.State(); state.Dirty {
			return true
		}
	}
	return false
}

func (m *partitionMap) Snapshot() map[topicPartition]partitionState {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	snap := make(map[topicPartition]partitionState, len(m.data))
	for tp, pc := range m.data {
		snap[tp] = pc.State()
	}
	return snap
}

func (m *partitionMap) Stop() {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	wg := new(sync.WaitGroup)
	for tp := range m.data {
		wg.Add(1)
		go func(p *partitionConsumer) {
			_ = p.Close()
			wg.Done()
		}(m.data[tp])
	}
	wg.Wait()
}

func (m *partitionMap) Clear() {
	m.mutex.Lock()
	for tp := range m.data {
		delete(m.data, tp)
	}
	m.mutex.Unlock()
}

func (m *partitionMap) Info() map[string][]int32 {
	info := make(map[string][]int32)
	m.mutex.RLock()
	for tp := range m.data {
		info[tp.Topic] = append(info[tp.Topic], tp.Partition)
	}
	m.mutex.RUnlock()

	for topic := range info {
		sort.Sort(int32Slice(info[topic]))
	}
	return info
}
<commit_msg>Close consumer first<commit_after>package cluster

import (
	"sort"
	"sync"

	"github.com/Shopify/sarama"
)

type partitionConsumer struct {
	pcm sarama.PartitionConsumer

	state partitionState
	mutex sync.Mutex

	closed      bool
	dying, dead chan none
}

func newPartitionConsumer(manager sarama.Consumer, topic string, partition int32, info offsetInfo, defaultOffset int64) (*partitionConsumer, error) {
	pcm, err := manager.ConsumePartition(topic, partition, info.NextOffset(defaultOffset))

	// Resume from default offset, if requested offset is out-of-range
	if err == sarama.ErrOffsetOutOfRange {
		info.Offset = -1
		pcm, err = manager.ConsumePartition(topic, partition, defaultOffset)
	}
	if err != nil {
		return nil, err
	}

	return &partitionConsumer{
		pcm:   pcm,
		state: partitionState{Info: info},

		dying: make(chan none),
		dead:  make(chan none),
	}, nil
}

func (c *partitionConsumer) Loop(messages chan<- *sarama.ConsumerMessage, errors chan<- error) {
	defer close(c.dead)

	for {
		select {
		case msg, ok := <-c.pcm.Messages():
			if !ok {
				return
			}
			select {
			case messages <- msg:
			case <-c.dying:
				return
			}
		case err, ok := <-c.pcm.Errors():
			if !ok {
				return
			}
			select {
			case errors <- err:
			case <-c.dying:
				return
			}
		case <-c.dying:
			return
		}
	}
}

func (c *partitionConsumer) Close() error {
	if c.closed {
		return nil
	}

	err := c.pcm.Close()
	c.closed = true
	close(c.dying)
	<-c.dead

	return err
}

func (c *partitionConsumer) State() partitionState {
	if c == nil {
		return partitionState{}
	}

	c.mutex.Lock()
	state := c.state
	c.mutex.Unlock()

	return state
}

func (c *partitionConsumer) MarkCommitted(offset int64) {
	if c == nil {
		return
	}

	c.mutex.Lock()
	if offset == c.state.Info.Offset {
		c.state.Dirty = false
	}
	c.mutex.Unlock()
}

func (c *partitionConsumer) MarkOffset(offset int64, metadata string) {
	if c == nil {
		return
	}

	c.mutex.Lock()
	if offset > c.state.Info.Offset {
		c.state.Info.Offset = offset
		c.state.Info.Metadata = metadata
		c.state.Dirty = true
	}
	c.mutex.Unlock()
}

// --------------------------------------------------------------------

type partitionState struct {
	Info  offsetInfo
	Dirty bool
}

// --------------------------------------------------------------------

type partitionMap struct {
	data  map[topicPartition]*partitionConsumer
	mutex sync.RWMutex
}

func newPartitionMap() *partitionMap {
	return &partitionMap{
		data: make(map[topicPartition]*partitionConsumer),
	}
}

func (m *partitionMap) Fetch(topic string, partition int32) *partitionConsumer {
	m.mutex.RLock()
	pc, _ := m.data[topicPartition{topic, partition}]
	m.mutex.RUnlock()
	return pc
}

func (m *partitionMap) Store(topic string, partition int32, pc *partitionConsumer) {
	m.mutex.Lock()
	m.data[topicPartition{topic, partition}] = pc
	m.mutex.Unlock()
}

func (m *partitionMap) HasDirty() bool {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	for _, pc := range m.data {
		if state := pc.State(); state.Dirty {
			return true
		}
	}
	return false
}

func (m *partitionMap) Snapshot() map[topicPartition]partitionState {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	snap := make(map[topicPartition]partitionState, len(m.data))
	for tp, pc := range m.data {
		snap[tp] = pc.State()
	}
	return snap
}

func (m *partitionMap) Stop() {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	wg := new(sync.WaitGroup)
	for tp := range m.data {
		wg.Add(1)
		go func(p *partitionConsumer) {
			_ = p.Close()
			wg.Done()
		}(m.data[tp])
	}
	wg.Wait()
}

func (m *partitionMap) Clear() {
	m.mutex.Lock()
	for tp := range m.data {
		delete(m.data, tp)
	}
	m.mutex.Unlock()
}

func (m *partitionMap) Info() map[string][]int32 {
	info := make(map[string][]int32)
	m.mutex.RLock()
	for tp := range m.data {
		info[tp.Topic] = append(info[tp.Topic], tp.Partition)
	}
	m.mutex.RUnlock()

	for topic := range info {
		sort.Sort(int32Slice(info[topic]))
	}
	return info
}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"net/http"
	"text/template"
	"encoding/json"
	"bytes"
	"mime/multipart"
	"sync"
	"strings"
)

var indexTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html",
	"views/index.html", "views/footer.html"))

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	err := indexTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var liveTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html",
	"views/live.html", "views/footer.html"))

func LiveHandler(w http.ResponseWriter, r *http.Request) {
	err := liveTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var historyTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html",
	"views/history.html", "views/footer.html"))

func HistoryHandler(w http.ResponseWriter, r *http.Request) {
	err := historyTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var uploadTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html",
	"views/upload.html", "views/footer.html"))

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	err := uploadTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var resourcesTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html", "views/navbar2.html",
	"views/resources.html", "views/footer.html"))

func ResourcesHandler(w http.ResponseWriter, r *http.Request) {
	err := resourcesTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

type FileInfo struct {
	Filename 		string
	Size 				int64
	ContentType string
	Contents 		string
}

type PostResponse struct {
	StatusCode 	int
	Filename 	 	string
}

func sendFile(fh *multipart.FileHeader, c chan PostResponse, wg *sync.WaitGroup) {

	defer wg.Done()
	f, err := fh.Open()
  if err != nil {
		fmt.Println(err)
	}

	var buf bytes.Buffer
	fileSize, err := buf.ReadFrom(f)
	if err != nil {
		fmt.Println(err)
	}

	// url := "http://localhost:8080/api/upload"
	url := "https://luft-184208.appspot.com/api/upload"

	// Remove Windows-style path
	pathAndFilename := strings.Split(fh.Filename, "\\")
	filename := pathAndFilename[len(pathAndFilename)-1]

	// Remove unix path
	pathAndFilename = strings.Split(filename, "/")
	filename = pathAndFilename[len(pathAndFilename)-1]

	fi := FileInfo {

		Filename: filename,
		Size: fileSize,
		ContentType: fh.Header["Content-Type"][0],
		Contents: buf.String(),
	}

	file, err := json.Marshal(fi)
	if err != nil {
		fmt.Println(err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(file))
  req.Header.Set("X-Custom-Header", "myvalue")
  req.Header.Set("Content-Type", "application/json")

  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    panic(err)
  }

	response := PostResponse{
		StatusCode: resp.StatusCode,
		Filename: fh.Filename,
	}

	c <- response
}

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

	if r.Method == "POST" {
		c := make(chan PostResponse, 10)
		var wg sync.WaitGroup
		var succResponses []string
		var failResponses []string

		r.ParseMultipartForm(32 << 20) // 32MB is the default used by FormFile
		fhs := r.MultipartForm.File["uploadFile"]

		for _, fh := range fhs {
			wg.Add(1)
			go sendFile(fh, c, &wg)
		}

		wg.Wait()
		for i := 0; i < len(fhs); i++ {
			response := <- c
			if (response.StatusCode == 200) {
				succResponses = append(succResponses, response.Filename)
			} else {
				failResponses = append(failResponses, response.Filename)
			}
		}
		close(c)

		if (len(failResponses) == 0) {
			fmt.Fprintf(w, "Opplasting vellykket!")
			return
		}	else {
			fmt.Fprintf(w, "Følgene filer ble ikke lastet opp: ")
			return
		}
 	}
}
<commit_msg>Add navbar2 parsing to index template<commit_after>package controllers

import (
	"fmt"
	"net/http"
	"text/template"
	"encoding/json"
	"bytes"
	"mime/multipart"
	"sync"
	"strings"
)

var indexTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html", "views/navbar2.html",
	"views/index.html", "views/footer.html"))

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	err := indexTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var liveTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html",
	"views/live.html", "views/footer.html"))

func LiveHandler(w http.ResponseWriter, r *http.Request) {
	err := liveTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var historyTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html",
	"views/history.html", "views/footer.html"))

func HistoryHandler(w http.ResponseWriter, r *http.Request) {
	err := historyTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var uploadTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html",
	"views/upload.html", "views/footer.html"))

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	err := uploadTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

var resourcesTemplate = template.Must(template.ParseFiles("views/base.html",
	"views/header.html", "views/navbar.html", "views/navbar2.html",
	"views/resources.html", "views/footer.html"))

func ResourcesHandler(w http.ResponseWriter, r *http.Request) {
	err := resourcesTemplate.Execute(w, nil)
	if err != nil {
		fmt.Println(err)
	}
}

type FileInfo struct {
	Filename 		string
	Size 				int64
	ContentType string
	Contents 		string
}

type PostResponse struct {
	StatusCode 	int
	Filename 	 	string
}

func sendFile(fh *multipart.FileHeader, c chan PostResponse, wg *sync.WaitGroup) {

	defer wg.Done()
	f, err := fh.Open()
  if err != nil {
		fmt.Println(err)
	}

	var buf bytes.Buffer
	fileSize, err := buf.ReadFrom(f)
	if err != nil {
		fmt.Println(err)
	}

	// url := "http://localhost:8080/api/upload"
	url := "https://luft-184208.appspot.com/api/upload"

	// Remove Windows-style path
	pathAndFilename := strings.Split(fh.Filename, "\\")
	filename := pathAndFilename[len(pathAndFilename)-1]

	// Remove unix path
	pathAndFilename = strings.Split(filename, "/")
	filename = pathAndFilename[len(pathAndFilename)-1]

	fi := FileInfo {

		Filename: filename,
		Size: fileSize,
		ContentType: fh.Header["Content-Type"][0],
		Contents: buf.String(),
	}

	file, err := json.Marshal(fi)
	if err != nil {
		fmt.Println(err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(file))
  req.Header.Set("X-Custom-Header", "myvalue")
  req.Header.Set("Content-Type", "application/json")

  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    panic(err)
  }

	response := PostResponse{
		StatusCode: resp.StatusCode,
		Filename: fh.Filename,
	}

	c <- response
}

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

	if r.Method == "POST" {
		c := make(chan PostResponse, 10)
		var wg sync.WaitGroup
		var succResponses []string
		var failResponses []string

		r.ParseMultipartForm(32 << 20) // 32MB is the default used by FormFile
		fhs := r.MultipartForm.File["uploadFile"]

		for _, fh := range fhs {
			wg.Add(1)
			go sendFile(fh, c, &wg)
		}

		wg.Wait()
		for i := 0; i < len(fhs); i++ {
			response := <- c
			if (response.StatusCode == 200) {
				succResponses = append(succResponses, response.Filename)
			} else {
				failResponses = append(failResponses, response.Filename)
			}
		}
		close(c)

		if (len(failResponses) == 0) {
			fmt.Fprintf(w, "Opplasting vellykket!")
			return
		}	else {
			fmt.Fprintf(w, "Følgene filer ble ikke lastet opp: ")
			return
		}
 	}
}
<|endoftext|>


<commit_before>//
// Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen
//
// 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 ciscoasa

import (
	"errors"
	"fmt"
	"net"
)

type routingService struct {
	*Client
}

// RoutingObjectCollection represents a collection of routing objects.
type RoutingObjectCollection struct {
	RangeInfo RangeInfo        `json:"rangeInfo"`
	Items     []*RoutingObject `json:"items"`
	Kind      string           `json:"kind"`
	SelfLink  string           `json:"selfLink"`
}

// RoutingObject represents a routing object.
type RoutingObject struct {
	DistanceMetric int            `json:"distanceMetric"`
	Gateway        *AddressObject `json:"gateway"`
	Interface      struct {
		Name     string `json:"name"`
		Kind     string `json:"kind"`
		ObjectID string `json:"objectId,omitempty"`
	} `json:"interface"`
	Network  *AddressObject `json:"network"`
	Tracked  bool           `json:"tracked,omitempty"`
	Tunneled bool           `json:"tunneled,omitempty"`
	Kind     string         `json:"kind"`
	ObjectID string         `json:"objectId,omitempty"`
	SelfLink string         `json:"selfLink,omitempty"`
}

// ListStaticRoutes returns a collection of static routes.
func (s *routingService) ListStaticRoutes() (*RoutingObjectCollection, error) {
	u := "/api/routing/static"

	req, err := s.newRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}

	r := &RoutingObjectCollection{}
	_, err = s.do(req, r)

	return r, err
}

// CreateStaticRoute creates a static route.
func (s *routingService) CreateStaticRoute(iface, network, gateway string, metric int, tracked, tunneled bool) (string, error) {
	u := "/api/routing/static"

	if metric < 1 || metric > 255 {
		return "", errors.New("metric must be between 0 and 255")
	}

	// Confirm that the gateway specifies an IP address before trying to
	// create an AddressObject from the given value.
	addr := net.ParseIP(gateway)
	if addr == nil {
		return "", fmt.Errorf("gateway must be an IP address")
	}

	gatewayObject, err := s.Objects.objectFromAddress(gateway)
	if err != nil {
		return "", err
	}

	networkObject, err := s.Objects.objectFromAddress(network)
	if err != nil {
		return "", err
	}

	r := &RoutingObject{
		DistanceMetric: metric,
		Gateway:        gatewayObject,
		Network:        networkObject,
		Tracked:        tracked,
		Tunneled:       tunneled,
		Kind:           fmt.Sprintf("object#%sRoute", networkObject.Kind[:4]),
	}

	r.Interface.Name = iface
	r.Interface.Kind = "objectRef#Interface"

	req, err := s.newRequest("POST", u, r)
	if err != nil {
		return "", err
	}

	resp, err := s.do(req, nil)
	if err != nil {
		return "", err
	}

	return idFromResponse(resp)
}

// GetNetworkObject retrieves a network object.
func (s *routingService) GetStaticRoute(routeID string) (*RoutingObject, error) {
	u := fmt.Sprintf("/api/routing/static/%s", routeID)

	req, err := s.newRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}

	r := &RoutingObject{}
	_, err = s.do(req, r)

	return r, err
}

// UpdateStaticRoute updates a static route.
func (s *routingService) UpdateStaticRoute(routeID, iface, network, gateway string, metric int, tracked, tunneled bool) (string, error) {
	u := fmt.Sprintf("/api/routing/static/%s", routeID)

	if metric < 1 || metric > 255 {
		return "", errors.New("metric must be between 0 and 255")
	}

	// Confirm that the gateway specifies an IP address before trying to
	// create an AddressObject from the given value.
	addr := net.ParseIP(gateway)
	if addr == nil {
		return "", fmt.Errorf("gateway must be an IP address")
	}

	gatewayObject, err := s.Objects.objectFromAddress(gateway)
	if err != nil {
		return "", err
	}

	networkObject, err := s.Objects.objectFromAddress(network)
	if err != nil {
		return "", err
	}

	r := &RoutingObject{
		DistanceMetric: metric,
		Gateway:        gatewayObject,
		Network:        networkObject,
		Tracked:        tracked,
		Tunneled:       tunneled,
		Kind:           fmt.Sprintf("object#%sRoute", networkObject.Kind[:4]),
	}

	r.Interface.Name = iface
	r.Interface.Kind = "objectRef#Interface"

	req, err := s.newRequest("POST", u, r)
	if err != nil {
		return "", err
	}

	resp, err := s.do(req, nil)
	if err != nil {
		return "", err
	}

	return idFromResponse(resp)
}

// DeleteStaticRoute deletes a static route.
func (s *routingService) DeleteStaticRoute(routeID string) error {
	u := fmt.Sprintf("/api/routing/static/%s", routeID)

	req, err := s.newRequest("DELETE", u, nil)
	if err != nil {
		return err
	}

	_, err = s.do(req, nil)

	return err
}
<commit_msg>fixes updating of existing route<commit_after>//
// Copyright 2017, Rutger te Nijenhuis & Sander van Harmelen
//
// 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 ciscoasa

import (
	"errors"
	"fmt"
	"net"
)

type routingService struct {
	*Client
}

// RoutingObjectCollection represents a collection of routing objects.
type RoutingObjectCollection struct {
	RangeInfo RangeInfo        `json:"rangeInfo"`
	Items     []*RoutingObject `json:"items"`
	Kind      string           `json:"kind"`
	SelfLink  string           `json:"selfLink"`
}

// RoutingObject represents a routing object.
type RoutingObject struct {
	DistanceMetric int            `json:"distanceMetric"`
	Gateway        *AddressObject `json:"gateway"`
	Interface      struct {
		Name     string `json:"name"`
		Kind     string `json:"kind"`
		ObjectID string `json:"objectId,omitempty"`
	} `json:"interface"`
	Network  *AddressObject `json:"network"`
	Tracked  bool           `json:"tracked,omitempty"`
	Tunneled bool           `json:"tunneled,omitempty"`
	Kind     string         `json:"kind"`
	ObjectID string         `json:"objectId,omitempty"`
	SelfLink string         `json:"selfLink,omitempty"`
}

// ListStaticRoutes returns a collection of static routes.
func (s *routingService) ListStaticRoutes() (*RoutingObjectCollection, error) {
	u := "/api/routing/static"

	req, err := s.newRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}

	r := &RoutingObjectCollection{}
	_, err = s.do(req, r)

	return r, err
}

// CreateStaticRoute creates a static route.
func (s *routingService) CreateStaticRoute(iface, network, gateway string, metric int, tracked, tunneled bool) (string, error) {
	u := "/api/routing/static"

	if metric < 1 || metric > 255 {
		return "", errors.New("metric must be between 0 and 255")
	}

	// Confirm that the gateway specifies an IP address before trying to
	// create an AddressObject from the given value.
	addr := net.ParseIP(gateway)
	if addr == nil {
		return "", fmt.Errorf("gateway must be an IP address")
	}

	gatewayObject, err := s.Objects.objectFromAddress(gateway)
	if err != nil {
		return "", err
	}

	networkObject, err := s.Objects.objectFromAddress(network)
	if err != nil {
		return "", err
	}

	r := &RoutingObject{
		DistanceMetric: metric,
		Gateway:        gatewayObject,
		Network:        networkObject,
		Tracked:        tracked,
		Tunneled:       tunneled,
		Kind:           fmt.Sprintf("object#%sRoute", networkObject.Kind[:4]),
	}

	r.Interface.Name = iface
	r.Interface.Kind = "objectRef#Interface"

	req, err := s.newRequest("POST", u, r)
	if err != nil {
		return "", err
	}

	resp, err := s.do(req, nil)
	if err != nil {
		return "", err
	}

	return idFromResponse(resp)
}

// GetNetworkObject retrieves a network object.
func (s *routingService) GetStaticRoute(routeID string) (*RoutingObject, error) {
	u := fmt.Sprintf("/api/routing/static/%s", routeID)

	req, err := s.newRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}

	r := &RoutingObject{}
	_, err = s.do(req, r)

	return r, err
}

// UpdateStaticRoute updates a static route.
func (s *routingService) UpdateStaticRoute(routeID, iface, network, gateway string, metric int, tracked, tunneled bool) (string, error) {
	u := fmt.Sprintf("/api/routing/static/%s", routeID)

	if metric < 1 || metric > 255 {
		return "", errors.New("metric must be between 0 and 255")
	}

	// Confirm that the gateway specifies an IP address before trying to
	// create an AddressObject from the given value.
	addr := net.ParseIP(gateway)
	if addr == nil {
		return "", fmt.Errorf("gateway must be an IP address")
	}

	gatewayObject, err := s.Objects.objectFromAddress(gateway)
	if err != nil {
		return "", err
	}

	networkObject, err := s.Objects.objectFromAddress(network)
	if err != nil {
		return "", err
	}

	r := &RoutingObject{
		DistanceMetric: metric,
		Gateway:        gatewayObject,
		Network:        networkObject,
		Tracked:        tracked,
		Tunneled:       tunneled,
		Kind:           fmt.Sprintf("object#%sRoute", networkObject.Kind[:4]),
	}

	r.Interface.Name = iface
	r.Interface.Kind = "objectRef#Interface"

	req, err := s.newRequest("PUT", u, r)
	if err != nil {
		return "", err
	}

	resp, err := s.do(req, nil)
	if err != nil {
		return "", err
	}

	return idFromResponse(resp)
}

// DeleteStaticRoute deletes a static route.
func (s *routingService) DeleteStaticRoute(routeID string) error {
	u := fmt.Sprintf("/api/routing/static/%s", routeID)

	req, err := s.newRequest("DELETE", u, nil)
	if err != nil {
		return err
	}

	_, err = s.do(req, nil)

	return err
}
<|endoftext|>


<commit_before>package command

import (
	"context"
	"encoding/gob"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"syscall"
	"unsafe"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/hashicorp/yamux"
	"github.com/kr/pty"
	"github.com/spolu/wrp"
	"github.com/spolu/wrp/cli"
	"github.com/spolu/wrp/lib/errors"
	"github.com/spolu/wrp/lib/out"
	"github.com/spolu/wrp/lib/token"
)

const (
	// CmdNmOpen is the command name.
	CmdNmOpen cli.CmdName = "open"
)

func init() {
	cli.Registrar[CmdNmOpen] = NewOpen
}

// Open spawns a new shared terminal.
type Open struct {
	shell string

	address string
	session string
	user    wrp.User

	username string

	cmd *exec.Cmd
	pty *os.File

	dataC   net.Conn
	stateC  net.Conn
	stateR  *gob.Decoder
	updateC net.Conn
	updateW *gob.Encoder
	hostC   net.Conn
	hostW   *gob.Encoder
}

// NewOpen constructs and initializes the command.
func NewOpen() cli.Command {
	return &Open{}
}

// Name returns the command name.
func (c *Open) Name() cli.CmdName {
	return CmdNmOpen
}

// Help prints out the help message for the command.
func (c *Open) Help(
	ctx context.Context,
) {
	out.Normf("\nUsage: ")
	out.Boldf("wrp open [<id>]\n")
	out.Normf("\n")
	out.Normf("  Spawns a shared terminal with the provided id. Others can use the id to connect.\n")
	out.Normf("  If no id is provided a random one is generated.\n")
	out.Normf("\n")
	out.Normf("Arguments:\n")
	out.Boldf("  id\n")
	out.Normf("    The id to assign to the newly shared terminal.\n")
	out.Valuf("    spolu-dev\n")
	out.Normf("\n")
	out.Normf("Examples:\n")
	out.Valuf("  wrp open\n")
	out.Valuf("  wrp open spolu-dev\n")
	out.Normf("\n")
}

// Parse parses the arguments passed to the command.
func (c *Open) Parse(
	ctx context.Context,
	args []string,
) error {
	if len(args) == 0 {
		c.session = token.RandStr()
	} else {
		c.session = args[0]
	}

	c.address = wrp.DefaultAddress
	if os.Getenv("WRPD_ADDRESS") != "" {
		c.address = os.Getenv("WRPD_ADDRESS")
	}

	c.shell = "/bin/bash"
	if os.Getenv("SHELL") != "" {
		c.shell = os.Getenv("SHELL")
	}

	user, err := user.Current()
	if err != nil {
		return errors.Trace(
			errors.Newf("Error retrieving current user: %v", err),
		)
	}
	c.username = user.Username

	// Sets the BASH prompt
	os.Setenv(
		"PS1",
		fmt.Sprintf(
			"\\[\033[01;31m\\][wrp:%s]\\[\033[00m\\] \\[\033[01;34m\\]\\W\\[\033[00m\\]\\$ ",
			c.session,
		),
	)

	c.user = wrp.User{
		Token:   token.New("guest"),
		Secret:  "",
		Session: token.New("session"),
	}

	return nil
}

// Execute the command or return a human-friendly error.
func (c *Open) Execute(
	ctx context.Context,
) error {
	ctx, cancel := context.WithCancel(ctx)

	out.Normf("\n")
	out.Normf("wrp id: ")
	out.Boldf("%s\n", c.session)
	out.Normf("\n")

	conn, err := net.Dial("tcp", c.address)
	if err != nil {
		return errors.Trace(
			errors.Newf("Connection error: %v", err),
		)
	}

	mux, err := yamux.Client(conn, nil)
	if err != nil {
		return errors.Trace(
			errors.Newf("Session error: %v", err),
		)
	}
	// Closes stateC, updateC, hostC, dataC, mux and conn.
	defer mux.Close()

	// Setup pty
	c.cmd = exec.Command(c.shell)
	c.pty, err = pty.Start(c.cmd)
	if err != nil {
		return errors.Trace(
			errors.Newf("PTY error: %v", err),
		)
	}
	go func() {
		if err := c.cmd.Wait(); err != nil {
			out.Errof("[Error] Cmd wait error: %v\n", err)
		}
		cancel()
	}()
	// Closes the newly created pty.
	defer c.pty.Close()

	// Setup local term.
	stdin := int(os.Stdin.Fd())
	if !terminal.IsTerminal(stdin) {
		return errors.Trace(
			errors.Newf("Not running in a terminal."),
		)
	}
	old, err := terminal.MakeRaw(stdin)
	if err != nil {
		return errors.Trace(
			errors.Newf("Unable to make terminal raw: %v", err),
		)
	}
	// Restores the terminal once we're done.
	defer terminal.Restore(stdin, old)

	// Opens state channel stateC.
	c.stateC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("State channel open error: %v", err),
		)
	}
	c.stateR = gob.NewDecoder(c.stateC)

	// Open update channel updateC.
	c.updateC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("Update channel open error: %v", err),
		)
	}
	c.updateW = gob.NewEncoder(c.updateC)

	// Send initial client update.
	if err := c.updateW.Encode(wrp.ClientUpdate{
		Session:  c.session,
		From:     c.user,
		Hosting:  true,
		Username: c.username,
	}); err != nil {
		return errors.Trace(
			errors.Newf("Send client update error: %v", err),
		)
	}

	// Open data channel dataC.
	c.dataC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("Data channel open error: %v", err),
		)
	}

	// Open host channel hostC.
	c.hostC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("Host channel open error: %v", err),
		)
	}
	c.hostW = gob.NewEncoder(c.hostC)

	// Send initial host update.
	cols, rows, err := terminal.GetSize(stdin)
	if err != nil {
		return errors.Trace(
			errors.Newf("Getsize error: %v", err),
		)
	}

	if err := c.updateW.Encode(wrp.HostUpdate{
		Session:    c.session,
		From:       c.user,
		WindowSize: wrp.Size{Rows: rows, Cols: cols},
	}); err != nil {
		return errors.Trace(
			errors.Newf("Send host update error: %v", err),
		)
	}

	// Main loops.

	// Listen for state updates.
	go func() {
		for {
			var st wrp.State
			if err := c.stateR.Decode(&st); err != nil {
				out.Errof("[Error] State channel decode error: %v\n", err)
				break
			}

			select {
			case <-ctx.Done():
				break
			default:
			}
		}
		cancel()
	}()

	// Forward window resizes to pty and hostC
	go func() {
		ch := make(chan os.Signal, 1)
		signal.Notify(ch, syscall.SIGWINCH)
		for {
			cols, rows, err := terminal.GetSize(stdin)
			if err != nil {
				out.Errof("[Error] Getsize error: %v\n", err)
				break
			}
			if err := Setsize(c.pty, rows, cols); err != nil {
				out.Errof("[Error] Setsize error: %v\n", err)
				break
			}
			if err := syscall.Kill(c.cmd.Process.Pid, syscall.SIGWINCH); err != nil {
				out.Errof("[Error] Sigwinch error: %v\n", err)
				break
			}

			if err := c.hostW.Encode(wrp.HostUpdate{
				Session:    c.session,
				From:       c.user,
				WindowSize: wrp.Size{Rows: rows, Cols: cols},
			}); err != nil {
				out.Errof("[Error] Send host update error: %v\n", err)
				break
			}
			<-ch
		}
		cancel()
	}()

	// Multiplex shell to dataC, Stdout
	go func() {
		cli.Multiplex(ctx, []io.Writer{c.dataC, os.Stdout}, c.pty)
		cancel()
	}()

	// Multiplex dataC to pty
	go func() {
		cli.Multiplex(ctx, []io.Writer{c.pty}, c.dataC)
		cancel()
	}()

	// Multiplex Stdin to pty
	go func() {
		cli.Multiplex(ctx, []io.Writer{c.pty}, os.Stdin)
		cancel()
	}()

	<-ctx.Done()

	return nil
}

type winsize struct {
	ws_row    uint16
	ws_col    uint16
	ws_xpixel uint16
	ws_ypixel uint16
}

func Setsize(f *os.File, rows, cols int) error {
	ws := winsize{ws_row: uint16(rows), ws_col: uint16(cols)}
	_, _, errno := syscall.Syscall(
		syscall.SYS_IOCTL,
		f.Fd(),
		syscall.TIOCSWINSZ,
		uintptr(unsafe.Pointer(&ws)),
	)
	if errno != 0 {
		return syscall.Errno(errno)
	}
	return nil
}
<commit_msg>Set PROMPT along PS1<commit_after>package command

import (
	"context"
	"encoding/gob"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"syscall"
	"unsafe"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/hashicorp/yamux"
	"github.com/kr/pty"
	"github.com/spolu/wrp"
	"github.com/spolu/wrp/cli"
	"github.com/spolu/wrp/lib/errors"
	"github.com/spolu/wrp/lib/out"
	"github.com/spolu/wrp/lib/token"
)

const (
	// CmdNmOpen is the command name.
	CmdNmOpen cli.CmdName = "open"
)

func init() {
	cli.Registrar[CmdNmOpen] = NewOpen
}

// Open spawns a new shared terminal.
type Open struct {
	shell string

	address string
	session string
	user    wrp.User

	username string

	cmd *exec.Cmd
	pty *os.File

	dataC   net.Conn
	stateC  net.Conn
	stateR  *gob.Decoder
	updateC net.Conn
	updateW *gob.Encoder
	hostC   net.Conn
	hostW   *gob.Encoder
}

// NewOpen constructs and initializes the command.
func NewOpen() cli.Command {
	return &Open{}
}

// Name returns the command name.
func (c *Open) Name() cli.CmdName {
	return CmdNmOpen
}

// Help prints out the help message for the command.
func (c *Open) Help(
	ctx context.Context,
) {
	out.Normf("\nUsage: ")
	out.Boldf("wrp open [<id>]\n")
	out.Normf("\n")
	out.Normf("  Spawns a shared terminal with the provided id. Others can use the id to connect.\n")
	out.Normf("  If no id is provided a random one is generated.\n")
	out.Normf("\n")
	out.Normf("Arguments:\n")
	out.Boldf("  id\n")
	out.Normf("    The id to assign to the newly shared terminal.\n")
	out.Valuf("    spolu-dev\n")
	out.Normf("\n")
	out.Normf("Examples:\n")
	out.Valuf("  wrp open\n")
	out.Valuf("  wrp open spolu-dev\n")
	out.Normf("\n")
}

// Parse parses the arguments passed to the command.
func (c *Open) Parse(
	ctx context.Context,
	args []string,
) error {
	if len(args) == 0 {
		c.session = token.RandStr()
	} else {
		c.session = args[0]
	}

	c.address = wrp.DefaultAddress
	if os.Getenv("WRPD_ADDRESS") != "" {
		c.address = os.Getenv("WRPD_ADDRESS")
	}

	c.shell = "/bin/bash"
	if os.Getenv("SHELL") != "" {
		c.shell = os.Getenv("SHELL")
	}

	user, err := user.Current()
	if err != nil {
		return errors.Trace(
			errors.Newf("Error retrieving current user: %v", err),
		)
	}
	c.username = user.Username

	// Sets the BASH prompt
	prompt := fmt.Sprintf(
		"\\[\033[01;31m\\][wrp:%s]\\[\033[00m\\] \\[\033[01;34m\\]\\W\\[\033[00m\\]\\$ ",
		c.session,
	)
	os.Setenv("PS1", prompt)
	os.Setenv("PROMPT", prompt)

	c.user = wrp.User{
		Token:   token.New("guest"),
		Secret:  "",
		Session: token.New("session"),
	}

	return nil
}

// Execute the command or return a human-friendly error.
func (c *Open) Execute(
	ctx context.Context,
) error {
	ctx, cancel := context.WithCancel(ctx)

	out.Normf("\n")
	out.Normf("wrp id: ")
	out.Boldf("%s\n", c.session)
	out.Normf("\n")

	conn, err := net.Dial("tcp", c.address)
	if err != nil {
		return errors.Trace(
			errors.Newf("Connection error: %v", err),
		)
	}

	mux, err := yamux.Client(conn, nil)
	if err != nil {
		return errors.Trace(
			errors.Newf("Session error: %v", err),
		)
	}
	// Closes stateC, updateC, hostC, dataC, mux and conn.
	defer mux.Close()

	// Setup pty
	c.cmd = exec.Command(c.shell)
	c.pty, err = pty.Start(c.cmd)
	if err != nil {
		return errors.Trace(
			errors.Newf("PTY error: %v", err),
		)
	}
	go func() {
		if err := c.cmd.Wait(); err != nil {
			out.Errof("[Error] Cmd wait error: %v\n", err)
		}
		cancel()
	}()
	// Closes the newly created pty.
	defer c.pty.Close()

	// Setup local term.
	stdin := int(os.Stdin.Fd())
	if !terminal.IsTerminal(stdin) {
		return errors.Trace(
			errors.Newf("Not running in a terminal."),
		)
	}
	old, err := terminal.MakeRaw(stdin)
	if err != nil {
		return errors.Trace(
			errors.Newf("Unable to make terminal raw: %v", err),
		)
	}
	// Restores the terminal once we're done.
	defer terminal.Restore(stdin, old)

	// Opens state channel stateC.
	c.stateC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("State channel open error: %v", err),
		)
	}
	c.stateR = gob.NewDecoder(c.stateC)

	// Open update channel updateC.
	c.updateC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("Update channel open error: %v", err),
		)
	}
	c.updateW = gob.NewEncoder(c.updateC)

	// Send initial client update.
	if err := c.updateW.Encode(wrp.ClientUpdate{
		Session:  c.session,
		From:     c.user,
		Hosting:  true,
		Username: c.username,
	}); err != nil {
		return errors.Trace(
			errors.Newf("Send client update error: %v", err),
		)
	}

	// Open data channel dataC.
	c.dataC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("Data channel open error: %v", err),
		)
	}

	// Open host channel hostC.
	c.hostC, err = mux.Open()
	if err != nil {
		return errors.Trace(
			errors.Newf("Host channel open error: %v", err),
		)
	}
	c.hostW = gob.NewEncoder(c.hostC)

	// Send initial host update.
	cols, rows, err := terminal.GetSize(stdin)
	if err != nil {
		return errors.Trace(
			errors.Newf("Getsize error: %v", err),
		)
	}

	if err := c.updateW.Encode(wrp.HostUpdate{
		Session:    c.session,
		From:       c.user,
		WindowSize: wrp.Size{Rows: rows, Cols: cols},
	}); err != nil {
		return errors.Trace(
			errors.Newf("Send host update error: %v", err),
		)
	}

	// Main loops.

	// Listen for state updates.
	go func() {
		for {
			var st wrp.State
			if err := c.stateR.Decode(&st); err != nil {
				out.Errof("[Error] State channel decode error: %v\n", err)
				break
			}

			select {
			case <-ctx.Done():
				break
			default:
			}
		}
		cancel()
	}()

	// Forward window resizes to pty and hostC
	go func() {
		ch := make(chan os.Signal, 1)
		signal.Notify(ch, syscall.SIGWINCH)
		for {
			cols, rows, err := terminal.GetSize(stdin)
			if err != nil {
				out.Errof("[Error] Getsize error: %v\n", err)
				break
			}
			if err := Setsize(c.pty, rows, cols); err != nil {
				out.Errof("[Error] Setsize error: %v\n", err)
				break
			}
			if err := syscall.Kill(c.cmd.Process.Pid, syscall.SIGWINCH); err != nil {
				out.Errof("[Error] Sigwinch error: %v\n", err)
				break
			}

			if err := c.hostW.Encode(wrp.HostUpdate{
				Session:    c.session,
				From:       c.user,
				WindowSize: wrp.Size{Rows: rows, Cols: cols},
			}); err != nil {
				out.Errof("[Error] Send host update error: %v\n", err)
				break
			}
			<-ch
		}
		cancel()
	}()

	// Multiplex shell to dataC, Stdout
	go func() {
		cli.Multiplex(ctx, []io.Writer{c.dataC, os.Stdout}, c.pty)
		cancel()
	}()

	// Multiplex dataC to pty
	go func() {
		cli.Multiplex(ctx, []io.Writer{c.pty}, c.dataC)
		cancel()
	}()

	// Multiplex Stdin to pty
	go func() {
		cli.Multiplex(ctx, []io.Writer{c.pty}, os.Stdin)
		cancel()
	}()

	<-ctx.Done()

	return nil
}

type winsize struct {
	ws_row    uint16
	ws_col    uint16
	ws_xpixel uint16
	ws_ypixel uint16
}

func Setsize(f *os.File, rows, cols int) error {
	ws := winsize{ws_row: uint16(rows), ws_col: uint16(cols)}
	_, _, errno := syscall.Syscall(
		syscall.SYS_IOCTL,
		f.Fd(),
		syscall.TIOCSWINSZ,
		uintptr(unsafe.Pointer(&ws)),
	)
	if errno != 0 {
		return syscall.Errno(errno)
	}
	return nil
}
<|endoftext|>


<commit_before>package coreapi

import (
	"context"
	"fmt"

	coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
	caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
	corerepo "github.com/ipfs/go-ipfs/core/corerepo"
	merkledag "github.com/ipfs/go-ipfs/merkledag"
	pin "github.com/ipfs/go-ipfs/pin"

	cid "gx/ipfs/QmeSrf6pzut73u6zLQkRFQ3ygt3k6XFT2kjdYP8Tnkwwyg/go-cid"
)

type PinAPI struct {
	*CoreAPI
	*caopts.PinOptions
}

func (api *PinAPI) Add(ctx context.Context, p coreiface.Path, opts ...caopts.PinAddOption) error {
	settings, err := caopts.PinAddOptions(opts...)
	if err != nil {
		return err
	}

	defer api.node.Blockstore.PinLock().Unlock()

	_, err = corerepo.Pin(api.node, ctx, []string{p.String()}, settings.Recursive)
	if err != nil {
		return err
	}

	return nil
}

func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreiface.Pin, error) {
	settings, err := caopts.PinLsOptions(opts...)
	if err != nil {
		return nil, err
	}

	switch settings.Type {
	case "all", "direct", "indirect", "recursive":
	default:
		return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type)
	}

	return pinLsAll(settings.Type, ctx, api.node.Pinning, api.node.DAG)
}

func (api *PinAPI) Rm(ctx context.Context, p coreiface.Path) error {
	_, err := corerepo.Unpin(api.node, ctx, []string{p.String()}, true)
	if err != nil {
		return err
	}

	return nil
}

func (api *PinAPI) Update(ctx context.Context, from coreiface.Path, to coreiface.Path, opts ...caopts.PinUpdateOption) error {
	settings, err := caopts.PinUpdateOptions(opts...)
	if err != nil {
		return err
	}

	return api.node.Pinning.Update(ctx, from.Cid(), to.Cid(), settings.Unpin)
}

type pinStatus struct {
	cid      *cid.Cid
	ok       bool
	badNodes []coreiface.BadPinNode
}

// BadNode is used in PinVerifyRes
type badNode struct {
	cid *cid.Cid
	err error
}

func (s *pinStatus) Ok() bool {
	return s.ok
}

func (s *pinStatus) BadNodes() []coreiface.BadPinNode {
	return s.badNodes
}

func (n *badNode) Path() coreiface.Path {
	return ParseCid(n.cid)
}

func (n *badNode) Err() error {
	return n.err
}

func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, error) {
	visited := make(map[string]*pinStatus)
	getLinks := api.node.DAG.GetOfflineLinkService().GetLinks
	recPins := api.node.Pinning.RecursiveKeys()

	var checkPin func(root *cid.Cid) *pinStatus
	checkPin = func(root *cid.Cid) *pinStatus {
		key := root.String()
		if status, ok := visited[key]; ok {
			return status
		}

		links, err := getLinks(ctx, root)
		if err != nil {
			status := &pinStatus{ok: false, cid: root}
			status.badNodes = []coreiface.BadPinNode{&badNode{cid: root, err: err}}
			visited[key] = status
			return status
		}

		status := &pinStatus{ok: true, cid: root}
		for _, lnk := range links {
			res := checkPin(lnk.Cid)
			if !res.ok {
				status.ok = false
				status.badNodes = append(status.badNodes, res.badNodes...)
			}
		}

		visited[key] = status
		return status
	}

	out := make(chan coreiface.PinStatus)
	go func() {
		defer close(out)
		for _, c := range recPins {
			out <- checkPin(c)
		}
	}()

	return out, nil
}

type pinInfo struct {
	pinType string
	object  *cid.Cid
}

func (p *pinInfo) Path() coreiface.Path {
	return ParseCid(p.object)
}

func (p *pinInfo) Type() string {
	return p.pinType
}

func pinLsAll(typeStr string, ctx context.Context, pinning pin.Pinner, dag merkledag.DAGService) ([]coreiface.Pin, error) {

	keys := make(map[string]*pinInfo)

	AddToResultKeys := func(keyList []*cid.Cid, typeStr string) {
		for _, c := range keyList {
			keys[c.String()] = &pinInfo{
				pinType: typeStr,
				object:  c,
			}
		}
	}

	if typeStr == "direct" || typeStr == "all" {
		AddToResultKeys(pinning.DirectKeys(), "direct")
	}
	if typeStr == "indirect" || typeStr == "all" {
		set := cid.NewSet()
		for _, k := range pinning.RecursiveKeys() {
			err := merkledag.EnumerateChildren(ctx, dag.GetLinks, k, set.Visit)
			if err != nil {
				return nil, err
			}
		}
		AddToResultKeys(set.Keys(), "indirect")
	}
	if typeStr == "recursive" || typeStr == "all" {
		AddToResultKeys(pinning.RecursiveKeys(), "recursive")
	}

	out := make([]coreiface.Pin, 0, len(keys))
	for _, v := range keys {
		out = append(out, v)
	}

	return out, nil
}
<commit_msg>coreapi: update after rebase<commit_after>package coreapi

import (
	"context"
	"fmt"

	bserv "github.com/ipfs/go-ipfs/blockservice"
	coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
	caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
	corerepo "github.com/ipfs/go-ipfs/core/corerepo"
	offline "github.com/ipfs/go-ipfs/exchange/offline"
	merkledag "github.com/ipfs/go-ipfs/merkledag"
	pin "github.com/ipfs/go-ipfs/pin"

	cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
	ipld "gx/ipfs/Qme5bWv7wtjUNGsK2BNGVUFPKiuxWrsqrtvYwCLRw8YFES/go-ipld-format"
)

type PinAPI struct {
	*CoreAPI
	*caopts.PinOptions
}

func (api *PinAPI) Add(ctx context.Context, p coreiface.Path, opts ...caopts.PinAddOption) error {
	settings, err := caopts.PinAddOptions(opts...)
	if err != nil {
		return err
	}

	defer api.node.Blockstore.PinLock().Unlock()

	_, err = corerepo.Pin(api.node, ctx, []string{p.String()}, settings.Recursive)
	if err != nil {
		return err
	}

	return nil
}

func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreiface.Pin, error) {
	settings, err := caopts.PinLsOptions(opts...)
	if err != nil {
		return nil, err
	}

	switch settings.Type {
	case "all", "direct", "indirect", "recursive":
	default:
		return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type)
	}

	return pinLsAll(settings.Type, ctx, api.node.Pinning, api.node.DAG)
}

func (api *PinAPI) Rm(ctx context.Context, p coreiface.Path) error {
	_, err := corerepo.Unpin(api.node, ctx, []string{p.String()}, true)
	if err != nil {
		return err
	}

	return nil
}

func (api *PinAPI) Update(ctx context.Context, from coreiface.Path, to coreiface.Path, opts ...caopts.PinUpdateOption) error {
	settings, err := caopts.PinUpdateOptions(opts...)
	if err != nil {
		return err
	}

	return api.node.Pinning.Update(ctx, from.Cid(), to.Cid(), settings.Unpin)
}

type pinStatus struct {
	cid      *cid.Cid
	ok       bool
	badNodes []coreiface.BadPinNode
}

// BadNode is used in PinVerifyRes
type badNode struct {
	cid *cid.Cid
	err error
}

func (s *pinStatus) Ok() bool {
	return s.ok
}

func (s *pinStatus) BadNodes() []coreiface.BadPinNode {
	return s.badNodes
}

func (n *badNode) Path() coreiface.Path {
	return ParseCid(n.cid)
}

func (n *badNode) Err() error {
	return n.err
}

func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, error) {
	visited := make(map[string]*pinStatus)
	bs := api.node.Blocks.Blockstore()
	DAG := merkledag.NewDAGService(bserv.New(bs, offline.Exchange(bs)))
	getLinks := merkledag.GetLinksWithDAG(DAG)
	recPins := api.node.Pinning.RecursiveKeys()

	var checkPin func(root *cid.Cid) *pinStatus
	checkPin = func(root *cid.Cid) *pinStatus {
		key := root.String()
		if status, ok := visited[key]; ok {
			return status
		}

		links, err := getLinks(ctx, root)
		if err != nil {
			status := &pinStatus{ok: false, cid: root}
			status.badNodes = []coreiface.BadPinNode{&badNode{cid: root, err: err}}
			visited[key] = status
			return status
		}

		status := &pinStatus{ok: true, cid: root}
		for _, lnk := range links {
			res := checkPin(lnk.Cid)
			if !res.ok {
				status.ok = false
				status.badNodes = append(status.badNodes, res.badNodes...)
			}
		}

		visited[key] = status
		return status
	}

	out := make(chan coreiface.PinStatus)
	go func() {
		defer close(out)
		for _, c := range recPins {
			out <- checkPin(c)
		}
	}()

	return out, nil
}

type pinInfo struct {
	pinType string
	object  *cid.Cid
}

func (p *pinInfo) Path() coreiface.Path {
	return ParseCid(p.object)
}

func (p *pinInfo) Type() string {
	return p.pinType
}

func pinLsAll(typeStr string, ctx context.Context, pinning pin.Pinner, dag ipld.DAGService) ([]coreiface.Pin, error) {

	keys := make(map[string]*pinInfo)

	AddToResultKeys := func(keyList []*cid.Cid, typeStr string) {
		for _, c := range keyList {
			keys[c.String()] = &pinInfo{
				pinType: typeStr,
				object:  c,
			}
		}
	}

	if typeStr == "direct" || typeStr == "all" {
		AddToResultKeys(pinning.DirectKeys(), "direct")
	}
	if typeStr == "indirect" || typeStr == "all" {
		set := cid.NewSet()
		for _, k := range pinning.RecursiveKeys() {
			err := merkledag.EnumerateChildren(ctx, merkledag.GetLinksWithDAG(dag), k, set.Visit)
			if err != nil {
				return nil, err
			}
		}
		AddToResultKeys(set.Keys(), "indirect")
	}
	if typeStr == "recursive" || typeStr == "all" {
		AddToResultKeys(pinning.RecursiveKeys(), "recursive")
	}

	out := make([]coreiface.Pin, 0, len(keys))
	for _, v := range keys {
		out = append(out, v)
	}

	return out, nil
}
<|endoftext|>