<commit_before>package connection

import (
	"bytes"
	"encoding/hex"
	"log"
	"net"

	"github.com/piot/hasty-protocol/authentication"
	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/chunk"
	"github.com/piot/hasty-protocol/commands"
	"github.com/piot/hasty-protocol/packet"
	"github.com/piot/hasty-protocol/packetserializers"
	"github.com/piot/hasty-protocol/realmname"
	"github.com/piot/hasty-protocol/serializer"
	"github.com/piot/hasty-protocol/timestamp"
	"github.com/piot/hasty-server/authenticator"
	"github.com/piot/hasty-server/authorization"
	"github.com/piot/hasty-server/config"
	"github.com/piot/hasty-server/master"
	"github.com/piot/hasty-server/realm"
	"github.com/piot/hasty-server/storage"
	"github.com/piot/hasty-server/subscribers"
	"github.com/piot/hasty-server/users"
)

const systemChannelID = 3

// StreamInfo : todo
type StreamInfo struct {
	lastOffsetSent uint64
}

// ConnectionHandler : todo
type ConnectionHandler struct {
	realm              realmname.Name
	conn               *net.Conn
	storage            *filestorage.StreamStorage
	realmRoot          *realm.RealmRoot
	userStorage        *users.Storage
	subscribers        *subscribers.Subscribers
	streamInfos        map[uint32]*StreamInfo
	connectionID       packet.ConnectionID
	masterHandler      *master.MasterCommandHandler
	chunkStreams       map[uint32]*chunk.Stream
	authenticationInfo authentication.Authenticated
	hastyConfig        config.HastyConfig
}

// NewConnectionHandler : todo
func NewConnectionHandler(connection *net.Conn, realmRoot *realm.RealmRoot, hastyConfig config.HastyConfig, connectionID packet.ConnectionID) *ConnectionHandler {
	return &ConnectionHandler{connectionID: connectionID, realmRoot: realmRoot, conn: connection, hastyConfig: hastyConfig, streamInfos: map[uint32]*StreamInfo{}, chunkStreams: map[uint32]*chunk.Stream{}}
}

// HandleConnect : todo
func (in *ConnectionHandler) HandleConnect(cmd commands.Connect) error {
	log.Printf("%s %s", in.connectionID, cmd)
	in.realm = cmd.Realm()
	octetsToSend := packetserializers.ConnectResultToOctets()
	in.sendPacket(octetsToSend)
	return nil
}

func (in *ConnectionHandler) sendPong(echoedTime timestamp.Time) {
	log.Printf("%s sendPong %s", in.connectionID, echoedTime)
	now := timestamp.Now()
	octetsToSend := packetserializers.PongToOctets(now, echoedTime)
	in.sendPacket(octetsToSend)
}

func (in *ConnectionHandler) sendLoginResult(worked bool, channelID channel.ID) {
	log.Printf("%s sendLoginResult %t", in.connectionID, worked)
	octetsToSend := packetserializers.LoginResultToOctets(channelID)
	in.sendPacket(octetsToSend)
}

// HandlePing : todo
func (in *ConnectionHandler) HandlePing(cmd commands.Ping) {
	log.Printf("%s %s", in.connectionID, cmd)
	in.sendPong(cmd.SentTime())
}

// HandlePong : todo
func (in *ConnectionHandler) HandlePong(cmd commands.Pong) {
	now := timestamp.Now()
	latency := now.Raw() - cmd.EchoedTime().Raw()
	log.Printf("%s Latency: %d ms", in.connectionID, latency)
}

// HandleCreateStream : todo
func (in *ConnectionHandler) HandleCreateStream(cmd commands.CreateStream) (channel.ID, error) {
	log.Println("Handle create stream:", cmd)
	channel, createErr := in.masterHandler.HandleCreateStream(nil, cmd)
	if createErr != nil {
		return channel, createErr
	}

	//	in.subscriber.HandleCreateStream(channel)

	return channel, nil
}

// HandlePublishStreamUser : todo
func (in *ConnectionHandler) HandlePublishStreamUser(cmd commands.PublishStreamUser) error {
	log.Println("Handle publish user:", cmd)
	channelID, _ := in.userStorage.FindOrCreateUserInfo(cmd.User())
	publishStreamCmd := commands.NewPublishStream(channelID, cmd.Chunk())
	return in.masterHandler.HandlePublishStream(nil, publishStreamCmd)
}

// HandlePublishStream : todo
func (in *ConnectionHandler) HandlePublishStream(cmd commands.PublishStream) error {
	log.Println("Handle publish:", cmd)
	return in.masterHandler.HandlePublishStream(nil, cmd)
}

// StreamChanged : todo
func (in *ConnectionHandler) StreamChanged(channelID channel.ID) {
	info := in.fetchOrCreateStreamInfo(channelID)
	in.sendStreamDataFromOffset(channelID, info.lastOffsetSent)
}

func (in *ConnectionHandler) sendStreamDataInChunks(channelID channel.ID, data []byte, octetsRead int, info *StreamInfo) {
	startPos := 0
	const chunkSize int = 4096
	for pos := startPos; pos < octetsRead; pos += chunkSize {
		remaining := octetsRead - pos
		chunkThisTime := chunkSize
		if remaining < chunkSize {
			chunkThisTime = remaining
		}
		in.sendStreamData(channelID, uint32(info.lastOffsetSent), data[pos:pos+chunkThisTime])
		info.lastOffsetSent += uint64(chunkThisTime)
	}
}

func (in *ConnectionHandler) sendStreamData(channelID channel.ID, lastOffsetSent uint32, data []byte) {
	log.Printf("%s sendStreamData %s offset:%d", in.connectionID, channelID, lastOffsetSent)
	payload := packetserializers.StreamDataToOctets(channelID, lastOffsetSent, data)
	in.sendPacket(payload)
}

func (in *ConnectionHandler) sendStreamDataFromOffset(channelID channel.ID, lastOffset uint64) error {
	info := in.fetchOrCreateStreamInfo(channelID)
	info.lastOffsetSent = lastOffset

	readFile, err := in.storage.ReadStream(channelID)
	if err != nil {
		return err
	}
	readFile.Seek(lastOffset)

	const maxSizeBuffer = 64 * 1024 * 1024
	buf := make([]byte, maxSizeBuffer)
	octetsRead, readErr := readFile.Read(buf)
	if readErr == nil {
		data := buf[:octetsRead]
		in.sendStreamDataInChunks(channelID, data, octetsRead, info)
	} else {
		log.Printf("Couldn't read. What is that all about? %v", readErr)
	}
	return nil
}

func (in *ConnectionHandler) fetchOrCreateStreamInfo(channelID channel.ID) *StreamInfo {
	infos := in.streamInfos[channelID.Raw()]
	if infos == nil {
		infos = &StreamInfo{}
		in.streamInfos[channelID.Raw()] = infos
	}
	return infos
}

// HandleSubscribeStream : todo
func (in *ConnectionHandler) HandleSubscribeStream(cmd commands.SubscribeStream) {
	log.Printf("%s %s", in.connectionID, cmd)

	for _, v := range cmd.Infos() {
		_, err := in.storage.ReadStream(v.Channel())
		if err == nil {
			in.sendStreamDataFromOffset(v.Channel(), uint64(v.Offset()))
		} else {
			log.Printf("Stream %v does not exist yet. You are still subscribed to it", v)
		}

		in.subscribers.AddStreamSubscriber(v.Channel(), in)
	}
}

// HandleUnsubscribeStream : todo
func (in *ConnectionHandler) HandleUnsubscribeStream(cmd commands.UnsubscribeStream) {
	log.Println("Handle unsubscribe:", cmd)
	//in.masterHandler.UnsubscribeStream(cmd.Channel())
}

func (in *ConnectionHandler) fetchOrAssoicateChunkStream(channelID channel.ID) *chunk.Stream {
	stream := in.chunkStreams[channelID.Raw()]
	if stream == nil {
		stream = chunk.NewChunkStream(in.connectionID, channelID)
		in.chunkStreams[channelID.Raw()] = stream
	}
	return stream
}

func (in *ConnectionHandler) publishMasterStream(channel channel.ID, payload []byte, authenticated authentication.Authenticated) {
	fakeClient := authorization.AdminClient{}
	hexPayload := hex.Dump(payload)
	log.Printf("publishing to channel: %v data: %v", channel, hexPayload)
	info := authentication.NewInfo(authenticated.UserID())
	authenticationPayload, _ := packetserializers.AuthenticationChunkToOctets(info, payload)
	cmd := commands.NewPublishStream(channel, authenticationPayload)
	in.masterHandler.HandlePublishStream(fakeClient, cmd)
}

func (in *ConnectionHandler) publishNormalStream(channel channel.ID, payload []byte) {
	fakeClient := authorization.AdminClient{}
	hexPayload := hex.Dump(payload)
	log.Printf("publishing to channel: %v data: %v", channel, hexPayload)
	cmd := commands.NewPublishStream(channel, payload)
	in.masterHandler.HandlePublishStream(fakeClient, cmd)
}

func isMasterStream(channelID channel.ID) bool {
	return channelID.Raw() == 3
}

func (in *ConnectionHandler) handleStreamDataForMasterStream(cmd commands.StreamData) {
	log.Printf("Stream Data for Master Stream! %v", cmd)
	chunkStream := in.fetchOrAssoicateChunkStream(cmd.Channel())
	chunkStream.Feed(cmd.Data())
	foundChunk, fetchErr := chunkStream.FetchChunk()
	if fetchErr != nil {
		_, isNotDoneError := fetchErr.(*chunk.NotDoneError)
		if isNotDoneError {
		} else {
			log.Printf("Fetcherror:%s", fetchErr)
		}
	} else {
		in.publishMasterStream(cmd.Channel(), foundChunk.Payload(), in.authenticationInfo)
	}
}

func (in *ConnectionHandler) handleStreamDataForNormalStream(cmd commands.StreamData) {
	log.Printf("Stream Data for Normal Stream! %v", cmd)
	in.publishNormalStream(cmd.Channel(), cmd.Data())
}

// HandleStreamData : todo
func (in *ConnectionHandler) HandleStreamData(cmd commands.StreamData) {
	log.Printf("%s %s", in.connectionID, cmd)
	if isMasterStream(cmd.Channel()) {
		in.handleStreamDataForMasterStream(cmd)
	} else {
		in.handleStreamDataForNormalStream(cmd)
	}
}

// HandleLogin : todo
func (in *ConnectionHandler) HandleLogin(cmd commands.Login) error {
	log.Printf("%s realm: '%s'", cmd, in.realm)

	restAuth := in.hastyConfig.Authentication
	userID, realname, authenticationErr := authenticator.Authenticate(restAuth.URL, restAuth.Path, restAuth.Headers[0].Name, restAuth.Headers[0].Value, cmd.Password())
	if authenticationErr != nil {
		log.Printf("Error: %v", authenticationErr)
		return authenticationErr
	}

	// User is authenticated, we can bring up the realm-specifics
	realmInfo, realmErr := in.realmRoot.GetRealmInfo(in.realm)
	if realmErr != nil {
		return realmErr
	}
	in.masterHandler = realmInfo.MasterCommand()
	in.storage = realmInfo.StreamStorage()
	in.userStorage = realmInfo.UserStorage()
	in.subscribers = realmInfo.Subscribers()

	userAssignedChannel, userInfoErr := in.userStorage.FindOrCreateUserInfo(userID)
	if userInfoErr != nil {
		log.Printf("ERROR:%v", userInfoErr)
		return userInfoErr
	}

	in.authenticationInfo = authentication.NewAuthenticated(userID, userAssignedChannel, realname)
	log.Printf("Logged in:%s", in.authenticationInfo)
	in.sendLoginResult(true, userAssignedChannel)

	authenticatedPayload := packetserializers.AuthenticatedToOctets(in.authenticationInfo)
	in.publishSystemStream(authenticatedPayload)

	return nil
}

// HandleAuthenticated : todo
func (in *ConnectionHandler) HandleAuthenticated(cmd commands.Authenticated) {
}

func (in *ConnectionHandler) publishSystemStream(payload []byte) {
	log.Printf("Publishing to system stream %v", payload)

	buf := new(bytes.Buffer)
	lengthBuf, lengthErr := serializer.SmallLengthToOctets(uint16(len(payload)))
	if lengthErr != nil {
		log.Printf("We couldn't write length")
		return
	}
	buf.Write(lengthBuf)
	buf.Write(payload)
	encapsulatedPayload := buf.Bytes()

	channelToPublishTo, _ := channel.NewFromID(systemChannelID)
	in.publishMasterStream(channelToPublishTo, encapsulatedPayload, in.authenticationInfo)
}

func (in *ConnectionHandler) sendPacket(octets []byte) {
	payloadLength := uint16(len(octets))
	hexPayload := hex.Dump(octets)
	lengthBuf, lengthErr := serializer.SmallLengthToOctets(payloadLength)
	if lengthErr != nil {
		log.Printf("We couldn't write length")
		return
	}
	log.Printf("%s Sending packet (size %d) %s", in.connectionID, payloadLength, hexPayload)
	(*in.conn).Write(lengthBuf)
	(*in.conn).Write(octets)
}

// HandleTransportDisconnect : todo
func (in *ConnectionHandler) HandleTransportDisconnect() {
	log.Printf("%s Transport disconnect", in.connectionID)
}
<commit_msg>Sending proper login result<commit_after>package connection

import (
	"bytes"
	"encoding/hex"
	"log"
	"net"

	"github.com/piot/hasty-protocol/authentication"
	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/chunk"
	"github.com/piot/hasty-protocol/commands"
	"github.com/piot/hasty-protocol/packet"
	"github.com/piot/hasty-protocol/packetserializers"
	"github.com/piot/hasty-protocol/realmname"
	"github.com/piot/hasty-protocol/serializer"
	"github.com/piot/hasty-protocol/timestamp"
	"github.com/piot/hasty-server/authenticator"
	"github.com/piot/hasty-server/authorization"
	"github.com/piot/hasty-server/config"
	"github.com/piot/hasty-server/master"
	"github.com/piot/hasty-server/realm"
	"github.com/piot/hasty-server/storage"
	"github.com/piot/hasty-server/subscribers"
	"github.com/piot/hasty-server/users"
)

const systemChannelID = 3

// StreamInfo : todo
type StreamInfo struct {
	lastOffsetSent uint64
}

// ConnectionHandler : todo
type ConnectionHandler struct {
	realm              realmname.Name
	conn               *net.Conn
	storage            *filestorage.StreamStorage
	realmRoot          *realm.RealmRoot
	userStorage        *users.Storage
	subscribers        *subscribers.Subscribers
	streamInfos        map[uint32]*StreamInfo
	connectionID       packet.ConnectionID
	masterHandler      *master.MasterCommandHandler
	chunkStreams       map[uint32]*chunk.Stream
	authenticationInfo authentication.Authenticated
	hastyConfig        config.HastyConfig
}

// NewConnectionHandler : todo
func NewConnectionHandler(connection *net.Conn, realmRoot *realm.RealmRoot, hastyConfig config.HastyConfig, connectionID packet.ConnectionID) *ConnectionHandler {
	return &ConnectionHandler{connectionID: connectionID, realmRoot: realmRoot, conn: connection, hastyConfig: hastyConfig, streamInfos: map[uint32]*StreamInfo{}, chunkStreams: map[uint32]*chunk.Stream{}}
}

// HandleConnect : todo
func (in *ConnectionHandler) HandleConnect(cmd commands.Connect) error {
	log.Printf("%s %s", in.connectionID, cmd)
	in.realm = cmd.Realm()
	octetsToSend := packetserializers.ConnectResultToOctets()
	in.sendPacket(octetsToSend)
	return nil
}

func (in *ConnectionHandler) sendPong(echoedTime timestamp.Time) {
	log.Printf("%s sendPong %s", in.connectionID, echoedTime)
	now := timestamp.Now()
	octetsToSend := packetserializers.PongToOctets(now, echoedTime)
	in.sendPacket(octetsToSend)
}

func (in *ConnectionHandler) sendLoginResult(worked bool, channelID channel.ID) {
	log.Printf("%s sendLoginResult %t", in.connectionID, worked)
	octetsToSend := packetserializers.LoginResultToOctets(worked, channelID)
	in.sendPacket(octetsToSend)
}

// HandlePing : todo
func (in *ConnectionHandler) HandlePing(cmd commands.Ping) {
	log.Printf("%s %s", in.connectionID, cmd)
	in.sendPong(cmd.SentTime())
}

// HandlePong : todo
func (in *ConnectionHandler) HandlePong(cmd commands.Pong) {
	now := timestamp.Now()
	latency := now.Raw() - cmd.EchoedTime().Raw()
	log.Printf("%s Latency: %d ms", in.connectionID, latency)
}

// HandleCreateStream : todo
func (in *ConnectionHandler) HandleCreateStream(cmd commands.CreateStream) (channel.ID, error) {
	log.Println("Handle create stream:", cmd)
	channel, createErr := in.masterHandler.HandleCreateStream(nil, cmd)
	if createErr != nil {
		return channel, createErr
	}

	//	in.subscriber.HandleCreateStream(channel)

	return channel, nil
}

// HandlePublishStreamUser : todo
func (in *ConnectionHandler) HandlePublishStreamUser(cmd commands.PublishStreamUser) error {
	log.Println("Handle publish user:", cmd)
	channelID, _ := in.userStorage.FindOrCreateUserInfo(cmd.User())
	publishStreamCmd := commands.NewPublishStream(channelID, cmd.Chunk())
	return in.masterHandler.HandlePublishStream(nil, publishStreamCmd)
}

// HandlePublishStream : todo
func (in *ConnectionHandler) HandlePublishStream(cmd commands.PublishStream) error {
	log.Println("Handle publish:", cmd)
	return in.masterHandler.HandlePublishStream(nil, cmd)
}

// StreamChanged : todo
func (in *ConnectionHandler) StreamChanged(channelID channel.ID) {
	info := in.fetchOrCreateStreamInfo(channelID)
	in.sendStreamDataFromOffset(channelID, info.lastOffsetSent)
}

func (in *ConnectionHandler) sendStreamDataInChunks(channelID channel.ID, data []byte, octetsRead int, info *StreamInfo) {
	startPos := 0
	const chunkSize int = 4096
	for pos := startPos; pos < octetsRead; pos += chunkSize {
		remaining := octetsRead - pos
		chunkThisTime := chunkSize
		if remaining < chunkSize {
			chunkThisTime = remaining
		}
		in.sendStreamData(channelID, uint32(info.lastOffsetSent), data[pos:pos+chunkThisTime])
		info.lastOffsetSent += uint64(chunkThisTime)
	}
}

func (in *ConnectionHandler) sendStreamData(channelID channel.ID, lastOffsetSent uint32, data []byte) {
	log.Printf("%s sendStreamData %s offset:%d", in.connectionID, channelID, lastOffsetSent)
	payload := packetserializers.StreamDataToOctets(channelID, lastOffsetSent, data)
	in.sendPacket(payload)
}

func (in *ConnectionHandler) sendStreamDataFromOffset(channelID channel.ID, lastOffset uint64) error {
	info := in.fetchOrCreateStreamInfo(channelID)
	info.lastOffsetSent = lastOffset

	readFile, err := in.storage.ReadStream(channelID)
	if err != nil {
		return err
	}
	readFile.Seek(lastOffset)

	const maxSizeBuffer = 64 * 1024 * 1024
	buf := make([]byte, maxSizeBuffer)
	octetsRead, readErr := readFile.Read(buf)
	if readErr == nil {
		data := buf[:octetsRead]
		in.sendStreamDataInChunks(channelID, data, octetsRead, info)
	} else {
		log.Printf("Couldn't read. What is that all about? %v", readErr)
	}
	return nil
}

func (in *ConnectionHandler) fetchOrCreateStreamInfo(channelID channel.ID) *StreamInfo {
	infos := in.streamInfos[channelID.Raw()]
	if infos == nil {
		infos = &StreamInfo{}
		in.streamInfos[channelID.Raw()] = infos
	}
	return infos
}

// HandleSubscribeStream : todo
func (in *ConnectionHandler) HandleSubscribeStream(cmd commands.SubscribeStream) {
	log.Printf("%s %s", in.connectionID, cmd)

	for _, v := range cmd.Infos() {
		_, err := in.storage.ReadStream(v.Channel())
		if err == nil {
			in.sendStreamDataFromOffset(v.Channel(), uint64(v.Offset()))
		} else {
			log.Printf("Stream %v does not exist yet. You are still subscribed to it", v)
		}

		in.subscribers.AddStreamSubscriber(v.Channel(), in)
	}
}

// HandleUnsubscribeStream : todo
func (in *ConnectionHandler) HandleUnsubscribeStream(cmd commands.UnsubscribeStream) {
	log.Println("Handle unsubscribe:", cmd)
	//in.masterHandler.UnsubscribeStream(cmd.Channel())
}

func (in *ConnectionHandler) fetchOrAssoicateChunkStream(channelID channel.ID) *chunk.Stream {
	stream := in.chunkStreams[channelID.Raw()]
	if stream == nil {
		stream = chunk.NewChunkStream(in.connectionID, channelID)
		in.chunkStreams[channelID.Raw()] = stream
	}
	return stream
}

func (in *ConnectionHandler) publishMasterStream(channel channel.ID, payload []byte, authenticated authentication.Authenticated) {
	fakeClient := authorization.AdminClient{}
	hexPayload := hex.Dump(payload)
	log.Printf("publishing to channel: %v data: %v", channel, hexPayload)
	info := authentication.NewInfo(authenticated.UserID())
	authenticationPayload, _ := packetserializers.AuthenticationChunkToOctets(info, payload)
	cmd := commands.NewPublishStream(channel, authenticationPayload)
	in.masterHandler.HandlePublishStream(fakeClient, cmd)
}

func (in *ConnectionHandler) publishNormalStream(channel channel.ID, payload []byte) {
	fakeClient := authorization.AdminClient{}
	hexPayload := hex.Dump(payload)
	log.Printf("publishing to channel: %v data: %v", channel, hexPayload)
	cmd := commands.NewPublishStream(channel, payload)
	in.masterHandler.HandlePublishStream(fakeClient, cmd)
}

func isMasterStream(channelID channel.ID) bool {
	return channelID.Raw() == 3
}

func (in *ConnectionHandler) handleStreamDataForMasterStream(cmd commands.StreamData) {
	log.Printf("Stream Data for Master Stream! %v", cmd)
	chunkStream := in.fetchOrAssoicateChunkStream(cmd.Channel())
	chunkStream.Feed(cmd.Data())
	foundChunk, fetchErr := chunkStream.FetchChunk()
	if fetchErr != nil {
		_, isNotDoneError := fetchErr.(*chunk.NotDoneError)
		if isNotDoneError {
		} else {
			log.Printf("Fetcherror:%s", fetchErr)
		}
	} else {
		in.publishMasterStream(cmd.Channel(), foundChunk.Payload(), in.authenticationInfo)
	}
}

func (in *ConnectionHandler) handleStreamDataForNormalStream(cmd commands.StreamData) {
	log.Printf("Stream Data for Normal Stream! %v", cmd)
	in.publishNormalStream(cmd.Channel(), cmd.Data())
}

// HandleStreamData : todo
func (in *ConnectionHandler) HandleStreamData(cmd commands.StreamData) {
	log.Printf("%s %s", in.connectionID, cmd)
	if isMasterStream(cmd.Channel()) {
		in.handleStreamDataForMasterStream(cmd)
	} else {
		in.handleStreamDataForNormalStream(cmd)
	}
}

// HandleLogin : todo
func (in *ConnectionHandler) HandleLogin(cmd commands.Login) error {
	log.Printf("%s realm: '%s'", cmd, in.realm)

	restAuth := in.hastyConfig.Authentication
	userID, realname, authenticationErr := authenticator.Authenticate(restAuth.URL, restAuth.Path, restAuth.Headers[0].Name, restAuth.Headers[0].Value, cmd.Password())
	if authenticationErr != nil {
		log.Printf("Error: %v", authenticationErr)
		in.sendLoginResult(false, channel.ID{})
		return authenticationErr
	}

	// User is authenticated, we can bring up the realm-specifics
	realmInfo, realmErr := in.realmRoot.GetRealmInfo(in.realm)
	if realmErr != nil {
		return realmErr
	}
	in.masterHandler = realmInfo.MasterCommand()
	in.storage = realmInfo.StreamStorage()
	in.userStorage = realmInfo.UserStorage()
	in.subscribers = realmInfo.Subscribers()

	userAssignedChannel, userInfoErr := in.userStorage.FindOrCreateUserInfo(userID)
	if userInfoErr != nil {
		log.Printf("ERROR:%v", userInfoErr)
		return userInfoErr
	}

	in.authenticationInfo = authentication.NewAuthenticated(userID, userAssignedChannel, realname)
	log.Printf("Logged in:%s", in.authenticationInfo)
	in.sendLoginResult(true, userAssignedChannel)

	authenticatedPayload := packetserializers.AuthenticatedToOctets(in.authenticationInfo)
	in.publishSystemStream(authenticatedPayload)

	return nil
}

// HandleAuthenticated : todo
func (in *ConnectionHandler) HandleAuthenticated(cmd commands.Authenticated) {
}

func (in *ConnectionHandler) publishSystemStream(payload []byte) {
	log.Printf("Publishing to system stream %v", payload)

	buf := new(bytes.Buffer)
	lengthBuf, lengthErr := serializer.SmallLengthToOctets(uint16(len(payload)))
	if lengthErr != nil {
		log.Printf("We couldn't write length")
		return
	}
	buf.Write(lengthBuf)
	buf.Write(payload)
	encapsulatedPayload := buf.Bytes()

	channelToPublishTo, _ := channel.NewFromID(systemChannelID)
	in.publishMasterStream(channelToPublishTo, encapsulatedPayload, in.authenticationInfo)
}

func (in *ConnectionHandler) sendPacket(octets []byte) {
	payloadLength := uint16(len(octets))
	hexPayload := hex.Dump(octets)
	lengthBuf, lengthErr := serializer.SmallLengthToOctets(payloadLength)
	if lengthErr != nil {
		log.Printf("We couldn't write length")
		return
	}
	log.Printf("%s Sending packet (size %d) %s", in.connectionID, payloadLength, hexPayload)
	(*in.conn).Write(lengthBuf)
	(*in.conn).Write(octets)
}

// HandleTransportDisconnect : todo
func (in *ConnectionHandler) HandleTransportDisconnect() {
	log.Printf("%s Transport disconnect", in.connectionID)
}
<|endoftext|>


<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context

// TODO(ericsnow) Move this file elsewhere?
//  (e.g. top-level resource pkg, charm/resource)

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/juju/errors"
	"github.com/juju/juju/resource"
	"github.com/juju/utils"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	goyaml "gopkg.in/yaml.v2"
)

type resourceDirectorySpec struct {
	name    string
	dirname string

	cleanup func() error
}

func newResourceDirectorySpec(dataDir, name string) resourceDirectorySpec {
	dirname := filepath.Join(dataDir, name)

	rds := resourceDirectorySpec{
		name:    name,
		dirname: dirname,
	}
	return rds
}

type tempDirDeps struct {
	newTempDir func() (string, error)
	removeDir  func(string) error
}

func newTempDirDeps() tempDirDeps {
	return tempDirDeps{
		newTempDir: func() (string, error) { return ioutil.TempDir("", "juju-resource-") },
		removeDir:  os.RemoveAll,
	}
}

//newTempDir func() (string, error), removeDir func(string) error) (resourceDirectorySpec, error) {
func newTempResourceDir(name string, deps tempDirDeps) (resourceDirectorySpec, error) {
	var spec resourceDirectorySpec

	tempDir, err := deps.newTempDir()
	if err != nil {
		return spec, errors.Trace(err)
	}

	spec = newResourceDirectorySpec(tempDir, name)
	spec.cleanup = func() error {
		return deps.removeDir(tempDir)
	}

	return spec, nil
}

func (rds resourceDirectorySpec) resolve(path ...string) string {
	return filepath.Join(append([]string{rds.dirname}, path...)...)
}

func (rds resourceDirectorySpec) infoPath() string {
	return rds.resolve(".info.yaml")
}

func (rds resourceDirectorySpec) CleanUp() error {
	if rds.cleanup != nil {
		return rds.cleanup()
	}
	return nil
}

func (rds resourceDirectorySpec) exists(stat func(string) (os.FileInfo, error)) (bool, error) {
	fileinfo, err := stat(rds.dirname)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, errors.Trace(err)
	}
	if !fileinfo.IsDir() {
		return false, errors.NotFoundf("%q not a directory", rds.dirname)
	}
	return true, nil
}

func (rds resourceDirectorySpec) open(mkdirAll func(string) error) (*resourceDirectory, error) {
	if mkdirAll != nil {
		if err := mkdirAll(rds.dirname); err != nil {
			return nil, errors.Annotate(err, "could not create resource dir")
		}
	}

	return newResourceDirectory(rds), nil
}

// TODO(ericsnow) Need a lockfile around create/write?

type resourceDirectory struct {
	resourceDirectorySpec

	res *resource.Resource
}

func newResourceDirectory(spec resourceDirectorySpec) *resourceDirectory {
	rd := &resourceDirectory{
		resourceDirectorySpec: spec,
	}
	return rd
}

func (rd resourceDirectory) move(dataDir string) *resourceDirectory {
	return &resourceDirectory{
		resourceDirectorySpec: newResourceDirectorySpec(dataDir, rd.name),
		res: rd.res,
	}
}

func (rd *resourceDirectory) readInfo(open func(string) (io.ReadCloser, error)) (resource.Resource, error) {
	if rd.res != nil {
		return *rd.res, nil
	}
	var res resource.Resource

	file, err := open(rd.infoPath())
	if err != nil {
		if os.IsNotExist(err) {
			return res, errors.NotFoundf(".info.yaml for %q", rd.name)
		}
		return res, errors.Trace(err)
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return res, errors.Trace(err)
	}

	if err := goyaml.Unmarshal(data, &res); err != nil {
		return res, errors.Trace(err)
	}

	rd.res = &res
	return res, nil
}

func (rd *resourceDirectory) writeInfo(res resource.Resource, create func(string) (io.WriteCloser, error)) error {
	data, err := goyaml.Marshal(res)
	if err != nil {
		return errors.Trace(err)
	}

	file, err := create(rd.infoPath())
	if err != nil {
		if os.IsNotExist(err) {
			// TODO(ericsnow) Create the directory?
			return errors.NotFoundf("resource directory for %q", rd.name)
		}
		return errors.Trace(err)
	}
	defer file.Close()

	if _, err := file.Write(data); err != nil {
		// TODO(ericsnow) Ensure the file is deleted?
		return errors.Trace(err)
	}

	rd.res = &res
	return nil
}

func (rd *resourceDirectory) openResource(relPath []string, open func(string) (io.ReadCloser, error)) (io.ReadCloser, error) {
	if len(relPath) == 0 {
		res, err := rd.readInfo(open)
		if err != nil {
			return nil, errors.Trace(err)
		}
		relPath = []string{res.Path}
	}
	filename := rd.resolve(relPath...)

	reader, err := open(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, errors.NotFoundf("resource file %q", filename)
		}
		return nil, errors.Trace(err)
	}

	return reader, nil
}

func (rd resourceDirectory) writeResource(relPath []string, content resourceContent, create func(string) (io.WriteCloser, error)) error {
	if len(relPath) == 0 {
		// TODO(ericsnow) Use rd.readInfo().Path, like openResource() does?
		return errors.NotImplementedf("")
	}
	filename := rd.resolve(relPath...)

	var st utils.SizeTracker
	var checksumWriter *charmresource.FingerprintHash

	source := content.data
	if !content.fingerprint.IsZero() {
		checksumWriter = charmresource.NewFingerprintHash()
		hashingReader := io.TeeReader(content.data, checksumWriter)
		source = io.TeeReader(hashingReader, &st)
	}

	target, err := create(filename)
	if err != nil {
		return errors.Annotate(err, "could not create new file for resource")
	}
	defer target.Close()
	// TODO(ericsnow) chmod 0644?

	if _, err := io.Copy(target, source); err != nil {
		return errors.Annotate(err, "could not write resource to file")
	}

	if checksumWriter != nil {
		size := st.Size()
		fp := checksumWriter.Fingerprint()
		if err := content.verify(size, fp); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}
<commit_msg>Move newTempResourceDir down.<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context

// TODO(ericsnow) Move this file elsewhere?
//  (e.g. top-level resource pkg, charm/resource)

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/juju/errors"
	"github.com/juju/juju/resource"
	"github.com/juju/utils"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	goyaml "gopkg.in/yaml.v2"
)

type resourceDirectorySpec struct {
	name    string
	dirname string

	cleanup func() error
}

func newResourceDirectorySpec(dataDir, name string) resourceDirectorySpec {
	dirname := filepath.Join(dataDir, name)

	rds := resourceDirectorySpec{
		name:    name,
		dirname: dirname,
	}
	return rds
}

func (rds resourceDirectorySpec) resolve(path ...string) string {
	return filepath.Join(append([]string{rds.dirname}, path...)...)
}

func (rds resourceDirectorySpec) infoPath() string {
	return rds.resolve(".info.yaml")
}

func (rds resourceDirectorySpec) CleanUp() error {
	if rds.cleanup != nil {
		return rds.cleanup()
	}
	return nil
}

func (rds resourceDirectorySpec) exists(stat func(string) (os.FileInfo, error)) (bool, error) {
	fileinfo, err := stat(rds.dirname)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, errors.Trace(err)
	}
	if !fileinfo.IsDir() {
		return false, errors.NotFoundf("%q not a directory", rds.dirname)
	}
	return true, nil
}

func (rds resourceDirectorySpec) open(mkdirAll func(string) error) (*resourceDirectory, error) {
	if mkdirAll != nil {
		if err := mkdirAll(rds.dirname); err != nil {
			return nil, errors.Annotate(err, "could not create resource dir")
		}
	}

	return newResourceDirectory(rds), nil
}

type tempDirDeps struct {
	newTempDir func() (string, error)
	removeDir  func(string) error
}

func newTempDirDeps() tempDirDeps {
	return tempDirDeps{
		newTempDir: func() (string, error) { return ioutil.TempDir("", "juju-resource-") },
		removeDir:  os.RemoveAll,
	}
}

//newTempDir func() (string, error), removeDir func(string) error) (resourceDirectorySpec, error) {
func newTempResourceDir(name string, deps tempDirDeps) (resourceDirectorySpec, error) {
	var spec resourceDirectorySpec

	tempDir, err := deps.newTempDir()
	if err != nil {
		return spec, errors.Trace(err)
	}

	spec = newResourceDirectorySpec(tempDir, name)
	spec.cleanup = func() error {
		return deps.removeDir(tempDir)
	}

	return spec, nil
}

// TODO(ericsnow) Need a lockfile around create/write?

type resourceDirectory struct {
	resourceDirectorySpec

	res *resource.Resource
}

func newResourceDirectory(spec resourceDirectorySpec) *resourceDirectory {
	rd := &resourceDirectory{
		resourceDirectorySpec: spec,
	}
	return rd
}

func (rd resourceDirectory) move(dataDir string) *resourceDirectory {
	return &resourceDirectory{
		resourceDirectorySpec: newResourceDirectorySpec(dataDir, rd.name),
		res: rd.res,
	}
}

func (rd *resourceDirectory) readInfo(open func(string) (io.ReadCloser, error)) (resource.Resource, error) {
	if rd.res != nil {
		return *rd.res, nil
	}
	var res resource.Resource

	file, err := open(rd.infoPath())
	if err != nil {
		if os.IsNotExist(err) {
			return res, errors.NotFoundf(".info.yaml for %q", rd.name)
		}
		return res, errors.Trace(err)
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return res, errors.Trace(err)
	}

	if err := goyaml.Unmarshal(data, &res); err != nil {
		return res, errors.Trace(err)
	}

	rd.res = &res
	return res, nil
}

func (rd *resourceDirectory) writeInfo(res resource.Resource, create func(string) (io.WriteCloser, error)) error {
	data, err := goyaml.Marshal(res)
	if err != nil {
		return errors.Trace(err)
	}

	file, err := create(rd.infoPath())
	if err != nil {
		if os.IsNotExist(err) {
			// TODO(ericsnow) Create the directory?
			return errors.NotFoundf("resource directory for %q", rd.name)
		}
		return errors.Trace(err)
	}
	defer file.Close()

	if _, err := file.Write(data); err != nil {
		// TODO(ericsnow) Ensure the file is deleted?
		return errors.Trace(err)
	}

	rd.res = &res
	return nil
}

func (rd *resourceDirectory) openResource(relPath []string, open func(string) (io.ReadCloser, error)) (io.ReadCloser, error) {
	if len(relPath) == 0 {
		res, err := rd.readInfo(open)
		if err != nil {
			return nil, errors.Trace(err)
		}
		relPath = []string{res.Path}
	}
	filename := rd.resolve(relPath...)

	reader, err := open(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, errors.NotFoundf("resource file %q", filename)
		}
		return nil, errors.Trace(err)
	}

	return reader, nil
}

func (rd resourceDirectory) writeResource(relPath []string, content resourceContent, create func(string) (io.WriteCloser, error)) error {
	if len(relPath) == 0 {
		// TODO(ericsnow) Use rd.readInfo().Path, like openResource() does?
		return errors.NotImplementedf("")
	}
	filename := rd.resolve(relPath...)

	var st utils.SizeTracker
	var checksumWriter *charmresource.FingerprintHash

	source := content.data
	if !content.fingerprint.IsZero() {
		checksumWriter = charmresource.NewFingerprintHash()
		hashingReader := io.TeeReader(content.data, checksumWriter)
		source = io.TeeReader(hashingReader, &st)
	}

	target, err := create(filename)
	if err != nil {
		return errors.Annotate(err, "could not create new file for resource")
	}
	defer target.Close()
	// TODO(ericsnow) chmod 0644?

	if _, err := io.Copy(target, source); err != nil {
		return errors.Annotate(err, "could not write resource to file")
	}

	if checksumWriter != nil {
		size := st.Size()
		fp := checksumWriter.Fingerprint()
		if err := content.verify(size, fp); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package raft

import (
	"testing"
)

func setupTestFollower() ConsensusModule {
	const TEST_FOLLOWER_TERM = 8
	return ConsensusModule{PersistentState{TEST_FOLLOWER_TERM}}
}

func makeAppendEntriesWithTerm(term TermNo) AppendEntries {
	return AppendEntries{term, 0, 0}
}

// 1. Reply false if term < currentTerm (#5.1)
func TestLeaderTermLessThanCurrentTerm(t *testing.T) {
	follower := setupTestFollower()
	followerTerm := follower.persistentState.currentTerm

	appendEntries := makeAppendEntriesWithTerm(followerTerm - 1)

	var reply AppendEntriesReply
	reply = follower.processRpc(appendEntries)

	if reply.term != followerTerm {
		t.Error()
	}

	if reply.success != false {
		t.Error()
	}
}
<commit_msg>AppendEntries receiver step 2<commit_after>package raft

import (
	"testing"
)

const (
	// Note: value for tests based on Figure 7
	TEST_CURRENT_TERM = 8
)

func setupTestFollower(logTerms []TermNo) ConsensusModule {
	return ConsensusModule{PersistentState{TEST_CURRENT_TERM}}
}

func makeAEWithTerm(term TermNo) AppendEntries {
	return AppendEntries{term, 0, 0}
}

func makeAEWithTermAndPrevLogIndex(term TermNo, li LogIndex) AppendEntries {
	return AppendEntries{term, li, 0}
}

// 1. Reply false if term < currentTerm (#5.1)
func TestRpcAELeaderTermLessThanCurrentTerm(t *testing.T) {
	follower := setupTestFollower(nil)
	followerTerm := follower.persistentState.currentTerm

	appendEntries := makeAEWithTerm(followerTerm - 1)

	var reply AppendEntriesReply
	reply = follower.processRpc(appendEntries)

	if reply.term != followerTerm {
		t.Error()
	}
	if reply.success != false {
		t.Error()
	}
}

// 2. Reply false if log doesn't contain an entry at prevLogIndex whose term
//      matches prevLogTerm (#5.3)
// Note: the above language is slightly ambiguous but I'm assuming that this
// step refers strictly to the follower's log not having any entry at
// prevLogIndex since step 3 covers the alternate conflicting entry case.
// Note: this test based on Figure 7, server (b)
func TestRpcAENoMatchingLogEntry(t *testing.T) {
	follower := setupTestFollower([]TermNo{1, 1, 1, 4})
	followerTerm := follower.persistentState.currentTerm

	appendEntries := makeAEWithTermAndPrevLogIndex(TEST_CURRENT_TERM, 10)

	var reply AppendEntriesReply
	reply = follower.processRpc(appendEntries)

	if reply.term != followerTerm {
		t.Error()
	}
	if reply.success != false {
		t.Error()
	}

}
<|endoftext|>


<commit_before>package configurations

import (
	"os"
	"os/user"
	"path"
	"testing"

	"github.com/luistm/go-bank-cli/elib/testkit"
)

func TestUnitGetDataBasePath(t *testing.T) {

	usr, err := user.Current()
	if err != nil {
		t.Fatal(err)
	}
	expectedDbName := "bank"
	expectedDbPath := path.Join(usr.HomeDir, ".bank")

	dbName, dbPath := DatabasePath()

	testkit.AssertEqual(t, expectedDbName, dbName)
	testkit.AssertEqual(t, expectedDbPath, dbPath)

	os.Setenv("GO_BANK_CLI_DEV", "true")
	defer os.Setenv("GO_BANK_CLI_DEV", "")

	expectedDbName = "bank"
	expectedDbPath = "/tmp"

	dbName, dbPath = DatabasePath()

	testkit.AssertEqual(t, expectedDbName, dbName)
	testkit.AssertEqual(t, expectedDbPath, dbPath)
}
<commit_msg>Fix unit test<commit_after>package configurations

import (
	"os"
	"os/user"
	"path"
	"testing"

	"github.com/luistm/go-bank-cli/elib/testkit"
)

func TestUnitGetDataBasePath(t *testing.T) {

	usr, err := user.Current()
	if err != nil {
		t.Fatal(err)
	}
	expectedDbName := "bank"
	expectedDbPath := path.Join(usr.HomeDir, ".bank")

	dbName, dbPath := DatabasePath()

	testkit.AssertEqual(t, expectedDbName, dbName)
	testkit.AssertEqual(t, expectedDbPath, dbPath)

	os.Setenv("GO_BANK_CLI_DEV", "true")
	defer os.Setenv("GO_BANK_CLI_DEV", "")

	expectedDbName = "bank"
	expectedDbPath = os.TempDir()

	dbName, dbPath = DatabasePath()

	testkit.AssertEqual(t, expectedDbName, dbName)
	testkit.AssertEqual(t, expectedDbPath, dbPath)
}
<|endoftext|>


<commit_before>package schema

import (
	"bytes"
	"fmt"
	"regexp"
	"sort"
	"strings"
	"text/template"
	"unicode"
	"unicode/utf8"
)

var helpers = template.FuncMap{
	"initialCap": initialCap,
	"initialLow": initialLow,
	"methodCap":  methodCap,
	"asComment":  asComment,
	"jsonTag":    jsonTag,
	"params":     params,
	"args":       args,
	"values":     values,
	"goType":     goType,
}

var (
	newlines  = regexp.MustCompile(`(?m:\s*$)`)
	acronyms  = regexp.MustCompile(`(Url|Http|Id|Uuid|Api|Uri|Ssl|Cname|Oauth)$`)
	camelcase = regexp.MustCompile(`(?m)[-.$/:_{}\s]`)
)

func goType(p *Schema) string {
	return p.GoType()
}

func required(n string, def *Schema) bool {
	return contains(n, def.Required)
}

func jsonTag(n string, required bool) string {
	tags := []string{n}
	if !required {
		tags = append(tags, "omitempty")
	}
	return fmt.Sprintf("`json:\"%s\"`", strings.Join(tags, ","))
}

func contains(n string, r []string) bool {
	for _, r := range r {
		if r == n {
			return true
		}
	}
	return false
}

func initialCap(ident string) string {
	if ident == "" {
		panic("blank identifier")
	}
	return depunct(ident, true)
}

func methodCap(ident string) string {
	return initialCap(strings.ToLower(ident))
}

func initialLow(ident string) string {
	if ident == "" {
		panic("blank identifier")
	}
	return depunct(ident, false)
}

func depunct(ident string, initialCap bool) string {
	matches := camelcase.Split(ident, -1)
	for i, m := range matches {
		if initialCap || i > 0 {
			m = capFirst(m)
		}
		matches[i] = acronyms.ReplaceAllStringFunc(m, func(c string) string {
			if len(c) > 4 {
				return strings.ToUpper(c[:2]) + c[2:]
			}
			return strings.ToUpper(c)
		})
	}
	return strings.Join(matches, "")
}

func capFirst(ident string) string {
	r, n := utf8.DecodeRuneInString(ident)
	return string(unicode.ToUpper(r)) + ident[n:]
}

func asComment(c string) string {
	var buf bytes.Buffer
	const maxLen = 70
	removeNewlines := func(s string) string {
		return strings.Replace(s, "\n", "\n// ", -1)
	}
	for len(c) > 0 {
		line := c
		if len(line) < maxLen {
			fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
			break
		}
		line = line[:maxLen]
		si := strings.LastIndex(line, " ")
		if si != -1 {
			line = line[:si]
		}
		fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
		c = c[len(line):]
		if si != -1 {
			c = c[1:]
		}
	}
	return buf.String()
}

func values(n string, s *Schema, l *Link) string {
	v := s.Values(n, l)
	return strings.Join(v, ", ")
}

func params(l *Link) string {
	var p []string
	order, params := l.Parameters()
	for _, n := range order {
		p = append(p, fmt.Sprintf("%s %s", initialLow(n), params[n]))
	}
	return strings.Join(p, ", ")
}

func args(h *HRef) string {
	return strings.Join(h.Order, ", ")
}

func sortedKeys(m map[string]*Schema) (keys []string) {
	for key := range m {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return
}
<commit_msg>add io in acronyms<commit_after>package schema

import (
	"bytes"
	"fmt"
	"regexp"
	"sort"
	"strings"
	"text/template"
	"unicode"
	"unicode/utf8"
)

var helpers = template.FuncMap{
	"initialCap": initialCap,
	"initialLow": initialLow,
	"methodCap":  methodCap,
	"asComment":  asComment,
	"jsonTag":    jsonTag,
	"params":     params,
	"args":       args,
	"values":     values,
	"goType":     goType,
}

var (
	newlines  = regexp.MustCompile(`(?m:\s*$)`)
	acronyms  = regexp.MustCompile(`(Url|Http|Id|Io|Uuid|Api|Uri|Ssl|Cname|Oauth)$`)
	camelcase = regexp.MustCompile(`(?m)[-.$/:_{}\s]`)
)

func goType(p *Schema) string {
	return p.GoType()
}

func required(n string, def *Schema) bool {
	return contains(n, def.Required)
}

func jsonTag(n string, required bool) string {
	tags := []string{n}
	if !required {
		tags = append(tags, "omitempty")
	}
	return fmt.Sprintf("`json:\"%s\"`", strings.Join(tags, ","))
}

func contains(n string, r []string) bool {
	for _, r := range r {
		if r == n {
			return true
		}
	}
	return false
}

func initialCap(ident string) string {
	if ident == "" {
		panic("blank identifier")
	}
	return depunct(ident, true)
}

func methodCap(ident string) string {
	return initialCap(strings.ToLower(ident))
}

func initialLow(ident string) string {
	if ident == "" {
		panic("blank identifier")
	}
	return depunct(ident, false)
}

func depunct(ident string, initialCap bool) string {
	matches := camelcase.Split(ident, -1)
	for i, m := range matches {
		if initialCap || i > 0 {
			m = capFirst(m)
		}
		matches[i] = acronyms.ReplaceAllStringFunc(m, func(c string) string {
			if len(c) > 4 {
				return strings.ToUpper(c[:2]) + c[2:]
			}
			return strings.ToUpper(c)
		})
	}
	return strings.Join(matches, "")
}

func capFirst(ident string) string {
	r, n := utf8.DecodeRuneInString(ident)
	return string(unicode.ToUpper(r)) + ident[n:]
}

func asComment(c string) string {
	var buf bytes.Buffer
	const maxLen = 70
	removeNewlines := func(s string) string {
		return strings.Replace(s, "\n", "\n// ", -1)
	}
	for len(c) > 0 {
		line := c
		if len(line) < maxLen {
			fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
			break
		}
		line = line[:maxLen]
		si := strings.LastIndex(line, " ")
		if si != -1 {
			line = line[:si]
		}
		fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
		c = c[len(line):]
		if si != -1 {
			c = c[1:]
		}
	}
	return buf.String()
}

func values(n string, s *Schema, l *Link) string {
	v := s.Values(n, l)
	return strings.Join(v, ", ")
}

func params(l *Link) string {
	var p []string
	order, params := l.Parameters()
	for _, n := range order {
		p = append(p, fmt.Sprintf("%s %s", initialLow(n), params[n]))
	}
	return strings.Join(p, ", ")
}

func args(h *HRef) string {
	return strings.Join(h.Order, ", ")
}

func sortedKeys(m map[string]*Schema) (keys []string) {
	for key := range m {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return
}
<|endoftext|>


<commit_before>// Copyright 2016 ~ 2018 AlexStocks(https://github.com/AlexStocks).
// All rights reserved.  Use of this source code is
// governed by Apache License 2.0.

// Package gxzookeeper provides a zookeeper registry
package gxzookeeper

import (
	"sync"
)

import (
	log "github.com/AlexStocks/log4go"
	jerrors "github.com/juju/errors"
	"github.com/samuel/go-zookeeper/zk"
)

import (
	"fmt"
	"github.com/AlexStocks/goext/database/registry"
	"github.com/AlexStocks/goext/database/zookeeper"
)

//////////////////////////////////////////////
// Registry
//////////////////////////////////////////////

type Registry struct {
	client          *gxzookeeper.Client
	options         gxregistry.Options
	sync.Mutex      // lock for client + register
	done            chan struct{}
	wg              sync.WaitGroup
	serviceRegistry map[gxregistry.ServiceAttr]gxregistry.Service
}

func NewRegistry(opts ...gxregistry.Option) (gxregistry.Registry, error) {
	var (
		err     error
		r       *Registry
		conn    *zk.Conn
		event   <-chan zk.Event
		options gxregistry.Options
	)

	for _, o := range opts {
		o(&options)
	}
	if options.Addrs == nil {
		return nil, jerrors.Errorf("@options.Addrs is nil")
	}
	if options.Timeout == 0 {
		options.Timeout = gxregistry.DefaultTimeout
	}
	if options.Root == "" {
		options.Root = gxregistry.DefaultServiceRoot
	}
	// connect to zookeeper
	conn, event, err = zk.Connect(options.Addrs, options.Timeout)
	if err != nil {
		return nil, jerrors.Annotatef(err, "zk.Connect(zk addr:%#v, timeout:%d)", options.Addrs, options.Timeout)
	}
	r = &Registry{
		options:         options,
		client:          gxzookeeper.NewClient(conn),
		done:            make(chan struct{}),
		serviceRegistry: make(map[gxregistry.ServiceAttr]gxregistry.Service),
	}
	go r.handleZkEvent(event)

	return r, nil
}

func (r *Registry) handleZkEvent(session <-chan zk.Event) {
}

func (r *Registry) Options() gxregistry.Options {
	return r.options
}

// 如果s.nodes为空，则返回当前registry中的service
// 若非空，则检查其中的每个node是否存在
func (r *Registry) exist(s gxregistry.Service) (gxregistry.Service, bool) {
	// get existing hash
	r.Lock()
	defer r.Unlock()
	v, ok := r.serviceRegistry[*(s.Attr)]
	if len(s.Nodes) == 0 {
		return v, ok
	}

	for i := range s.Nodes {
		flag := false
		for j := range v.Nodes {
			if s.Nodes[i].Equal(v.Nodes[j]) {
				flag = true
				continue
			}
		}
		if !flag {
			return v, false
		}
	}

	return v, true
}

func (r *Registry) addService(s gxregistry.Service) {
	if len(s.Nodes) == 0 {
		return
	}

	// get existing hash
	r.Lock()
	defer r.Unlock()
	v, ok := r.serviceRegistry[*s.Attr]
	if !ok {
		r.serviceRegistry[*s.Attr] = s
		return
	}

	for i := range s.Nodes {
		flag := false
		for j := range v.Nodes {
			if s.Nodes[i].Equal(v.Nodes[j]) {
				flag = true
			}
		}
		if !flag {
			v.Nodes = append(v.Nodes, s.Nodes[i])
		}
	}
	r.serviceRegistry[*s.Attr] = v

	return
}

func (r *Registry) deleteService(s gxregistry.Service) {
	if len(s.Nodes) == 0 {
		return
	}

	// get existing hash
	r.Lock()
	defer r.Unlock()
	v, ok := r.serviceRegistry[*s.Attr]
	if !ok {
		return
	}

	for i := range s.Nodes {
		for j := range v.Nodes {
			if s.Nodes[i].Equal(v.Nodes[j]) {
				v.Nodes = append(v.Nodes[:j], v.Nodes[j+1:]...)
				break
			}
		}
	}
	r.serviceRegistry[*s.Attr] = v

	return
}

func (r *Registry) register(s gxregistry.Service) error {
	service := gxregistry.Service{Metadata: s.Metadata}
	service.Attr = s.Attr

	// serviceRegistry every node
	var zkPath string
	for i, node := range s.Nodes {
		service.Nodes = []*gxregistry.Node{node}
		data, err := gxregistry.EncodeService(&service)
		if err != nil {
			service.Nodes = s.Nodes[:i]
			r.unregister(service)
			return jerrors.Annotatef(err, "gxregistry.EncodeService(service:%+v) = error:%s", service, err)
		}

		zkPath = service.Path(r.options.Root)
		r.Lock()
		defer r.Unlock()
		err = r.client.CreateZkPath(zkPath)
		if err != nil {
			log.Error("zkClient.CreateZkPath(root{%s})", zkPath, err)
			return jerrors.Trace(err)
		}

		zkPath = service.NodePath(r.options.Root, *node)
		_, err = r.client.RegisterTemp(zkPath, []byte(data))
		if err != nil {
			return jerrors.Annotatef(err, "gxregister.RegisterTempSeq(path:%s)", zkPath)
		}
	}

	return nil
}

func (r *Registry) Register(s gxregistry.Service) error {
	if len(s.Nodes) == 0 {
		return jerrors.Errorf("Require at least one node")
	}

	if _, exist := r.exist(s); exist {
		return gxregistry.ErrorAlreadyRegister
	}

	err := r.register(s)
	if err != nil {
		return jerrors.Annotate(err, "Registry.register")
	}

	// save the service
	r.addService(s)

	return nil
}

func (r *Registry) unregister(s gxregistry.Service) error {
	if len(s.Nodes) == 0 {
		return jerrors.Errorf("Require at least one node")
	}

	var err error
	for _, node := range s.Nodes {
		err = r.client.DeleteZkPath(s.NodePath(r.options.Root, *node))
		if err != nil {
			return jerrors.Trace(err)
		}
	}

	return nil
}

func (r *Registry) Deregister(s gxregistry.Service) error {
	r.deleteService(s)
	return jerrors.Trace(r.unregister(s))
}

func (r *Registry) GetServices(attr gxregistry.ServiceAttr) ([]gxregistry.Service, error) {
	svc := gxregistry.Service{Attr: &attr}
	path := svc.Path(r.options.Root)
	children, err := r.client.GetChildren(path)
	if err != nil {
		return nil, jerrors.Annotatef(err, "zkClient.GetChildren(path:%s)", path)
	}
	if len(children) == 0 {
		return nil, gxregistry.ErrorRegistryNotFound
	}

	serviceArray := []gxregistry.Service{}
	var node gxregistry.Node
	for _, name := range children {
		node.ID = name
		zkPath := svc.NodePath(r.options.Root, node)

		childData, err := r.client.Get(zkPath)
		fmt.Println("get zkpath:", zkPath, " children:", childData, ", error:", err)
		if err != nil {
			log.Warn("gxzookeeper.Get(name:%s) = error:%s", zkPath, jerrors.ErrorStack(err))
			continue
		}

		sn, err := gxregistry.DecodeService(childData)
		fmt.Println("decode data, sn:", sn, ", err:", err)
		if err != nil {
			log.Warn("gxregistry.DecodeService(data:%#v) = error:%s", childData, jerrors.ErrorStack(err))
			continue
		}
		if attr.Filter(*sn.Attr) {
			for _, node := range sn.Nodes {
				var service gxregistry.Service
				service.Attr = sn.Attr
				service.Nodes = append(service.Nodes, node)
				serviceArray = append(serviceArray, service)
			}
		}
	}

	return serviceArray, nil
}

func (r *Registry) Watch(opts ...gxregistry.WatchOption) (gxregistry.Watcher, error) {
	return nil, nil
}

func (r *Registry) String() string {
	return "zookeeper registry"
}

func (r *Registry) Close() error {
	r.Lock()
	defer r.Unlock()
	if r.client != nil {
		close(r.done)
		r.client.ZkConn().Close()
		r.wg.Wait()
		r.client = nil
	}

	return nil
}
<commit_msg>handle zk restart<commit_after>// Copyright 2016 ~ 2018 AlexStocks(https://github.com/AlexStocks).
// All rights reserved.  Use of this source code is
// governed by Apache License 2.0.

// Package gxzookeeper provides a zookeeper registry
package gxzookeeper

import (
	"fmt"
	"strings"
	"sync"
)

import (
	log "github.com/AlexStocks/log4go"
	jerrors "github.com/juju/errors"
	"github.com/samuel/go-zookeeper/zk"
)

import (
	"github.com/AlexStocks/goext/database/registry"
	"github.com/AlexStocks/goext/database/zookeeper"
)

//////////////////////////////////////////////
// Registry
//////////////////////////////////////////////

type Registry struct {
	client          *gxzookeeper.Client
	options         gxregistry.Options
	sync.Mutex      // lock for client + register
	done            chan struct{}
	wg              sync.WaitGroup
	eventRegistry   map[string][]*chan struct{}
	serviceRegistry map[gxregistry.ServiceAttr]gxregistry.Service
}

func NewRegistry(opts ...gxregistry.Option) (gxregistry.Registry, error) {
	var (
		err     error
		r       *Registry
		conn    *zk.Conn
		event   <-chan zk.Event
		options gxregistry.Options
	)

	for _, o := range opts {
		o(&options)
	}
	if options.Addrs == nil {
		return nil, jerrors.Errorf("@options.Addrs is nil")
	}
	if options.Timeout == 0 {
		options.Timeout = gxregistry.DefaultTimeout
	}
	if options.Root == "" {
		options.Root = gxregistry.DefaultServiceRoot
	}
	// connect to zookeeper
	conn, event, err = zk.Connect(options.Addrs, options.Timeout)
	if err != nil {
		return nil, jerrors.Annotatef(err, "zk.Connect(zk addr:%#v, timeout:%d)", options.Addrs, options.Timeout)
	}
	r = &Registry{
		options:         options,
		client:          gxzookeeper.NewClient(conn),
		done:            make(chan struct{}),
		eventRegistry:   make(map[string][]*chan struct{}),
		serviceRegistry: make(map[gxregistry.ServiceAttr]gxregistry.Service),
	}
	go r.handleZkEvent(event)

	return r, nil
}

func (r *Registry) registerEvent(path string, event *chan struct{}) {
	if path == "" || event == nil {
		return
	}

	r.Lock()
	a := r.eventRegistry[path]
	a = append(a, event)
	r.eventRegistry[path] = a
	r.Unlock()
	log.Debug("zkClient register event{path:%s, ptr:%p}", path, event)
}

func (r *Registry) unregisterEvent(path string, event *chan struct{}) {
	if path == "" {
		return
	}

	r.Lock()
	for {
		a, ok := r.eventRegistry[path]
		if !ok {
			break
		}
		for i, e := range a {
			if e == event {
				arr := a
				a = append(arr[:i], arr[i+1:]...)
				log.Debug("zkClient unregister event{path:%s, event:%p}", path, event)
			}
		}
		log.Debug("after zkClient unregister event{path:%s, event:%p}, array length %d", path, event, len(a))
		if len(a) == 0 {
			delete(r.eventRegistry, path)
		} else {
			r.eventRegistry[path] = a
		}
		break
	}
	r.Unlock()
}

func (r *Registry) handleZkRestart() {
	var (
		err      error
		services []gxregistry.Service
	)

	// copy c.services
	services = make([]gxregistry.Service, 0, len(r.serviceRegistry))
	r.Lock()
	for _, s := range r.serviceRegistry {
		services = append(services, s)
	}
	r.Unlock()

	for _, s := range services {
		err = r.register(s)
		if err != nil {
			log.Error("(ZookeeperRegistry)register(service:%s) = error:%s", s, jerrors.ErrorStack(err))
		}
	}
}

func (r *Registry) handleZkEvent(session <-chan zk.Event) {
	var (
		state int
		event zk.Event
	)

	r.wg.Add(1)
	defer func() {
		r.wg.Done()
		log.Info("zk{addr:%#v, path:%v} connection goroutine game over.", r.options.Addrs, r.options.Root)
	}()

LOOP:
	for {
		select {
		case <-r.done:
			break LOOP

		case event = <-session:
			log.Warn("client get a zookeeper event{type:%s, server:%s, path:%s, state:%d-%s, err:%#v}",
				event.Type.String(), event.Server, event.Path, event.State, r.client.StateToString(event.State), event.Err)
			switch (int)(event.State) {
			case (int)(zk.StateDisconnected):
				log.Warn("zk{addr:%#v, path:%v} state is StateDisconnected.", r.options.Addrs, r.options.Root)

			case (int)(zk.EventNodeDataChanged), (int)(zk.EventNodeChildrenChanged):
				log.Info("zkClient get zk node changed event{path:%s}", event.Path)
				r.Lock()
				for p, a := range r.eventRegistry {
					if strings.HasPrefix(p, event.Path) {
						log.Info("send event{zk.EventNodeDataChange, zk.Path:%s} to path{%s} related watcher", event.Path, p)
						for _, e := range a {
							*e <- struct{}{}
						}
					}
				}
				r.Unlock()

			case (int)(zk.StateConnecting), (int)(zk.StateConnected), (int)(zk.StateHasSession):
				if state != (int)(zk.StateConnecting) || state != (int)(zk.StateDisconnected) {
					continue
				}
				if a, ok := r.eventRegistry[event.Path]; ok && 0 < len(a) {
					for _, e := range a {
						*e <- struct{}{}
					}
				}
				if state == (int)(zk.StateDisconnected) && (int)(event.State) == (int)(zk.StateConnected) {
					log.Info("start to handle zookeeper restart event.")
					r.handleZkRestart()
				}
			}
			state = (int)(event.State)
		}
	}
}

func (r *Registry) Options() gxregistry.Options {
	return r.options
}

// 如果s.nodes为空，则返回当前registry中的service
// 若非空，则检查其中的每个node是否存在
func (r *Registry) exist(s gxregistry.Service) (gxregistry.Service, bool) {
	// get existing hash
	r.Lock()
	defer r.Unlock()
	v, ok := r.serviceRegistry[*(s.Attr)]
	if len(s.Nodes) == 0 {
		return v, ok
	}

	for i := range s.Nodes {
		flag := false
		for j := range v.Nodes {
			if s.Nodes[i].Equal(v.Nodes[j]) {
				flag = true
				continue
			}
		}
		if !flag {
			return v, false
		}
	}

	return v, true
}

func (r *Registry) addService(s gxregistry.Service) {
	if len(s.Nodes) == 0 {
		return
	}

	// get existing hash
	r.Lock()
	defer r.Unlock()
	v, ok := r.serviceRegistry[*s.Attr]
	if !ok {
		r.serviceRegistry[*s.Attr] = s
		return
	}

	for i := range s.Nodes {
		flag := false
		for j := range v.Nodes {
			if s.Nodes[i].Equal(v.Nodes[j]) {
				flag = true
			}
		}
		if !flag {
			v.Nodes = append(v.Nodes, s.Nodes[i])
		}
	}
	r.serviceRegistry[*s.Attr] = v

	return
}

func (r *Registry) deleteService(s gxregistry.Service) {
	if len(s.Nodes) == 0 {
		return
	}

	// get existing hash
	r.Lock()
	defer r.Unlock()
	v, ok := r.serviceRegistry[*s.Attr]
	if !ok {
		return
	}

	for i := range s.Nodes {
		for j := range v.Nodes {
			if s.Nodes[i].Equal(v.Nodes[j]) {
				v.Nodes = append(v.Nodes[:j], v.Nodes[j+1:]...)
				break
			}
		}
	}
	r.serviceRegistry[*s.Attr] = v

	return
}

func (r *Registry) register(s gxregistry.Service) error {
	service := gxregistry.Service{Metadata: s.Metadata}
	service.Attr = s.Attr

	// serviceRegistry every node
	var zkPath string
	for i, node := range s.Nodes {
		service.Nodes = []*gxregistry.Node{node}
		data, err := gxregistry.EncodeService(&service)
		if err != nil {
			service.Nodes = s.Nodes[:i]
			r.unregister(service)
			return jerrors.Annotatef(err, "gxregistry.EncodeService(service:%+v) = error:%s", service, err)
		}

		zkPath = service.Path(r.options.Root)
		//r.Lock()
		err = r.client.CreateZkPath(zkPath)
		//r.Unlock()
		if err != nil {
			log.Error("zkClient.CreateZkPath(root{%s})", zkPath, err)
			return jerrors.Trace(err)
		}

		zkPath = service.NodePath(r.options.Root, *node)
		//r.Lock()
		_, err = r.client.RegisterTemp(zkPath, []byte(data))
		//r.Unlock()
		if err != nil {
			return jerrors.Annotatef(err, "gxregister.RegisterTempSeq(path:%s)", zkPath)
		}
	}

	return nil
}

func (r *Registry) Register(s gxregistry.Service) error {
	if len(s.Nodes) == 0 {
		return jerrors.Errorf("Require at least one node")
	}

	if _, exist := r.exist(s); exist {
		return gxregistry.ErrorAlreadyRegister
	}

	err := r.register(s)
	if err != nil {
		return jerrors.Annotate(err, "Registry.register")
	}

	// save the service
	r.addService(s)

	return nil
}

func (r *Registry) unregister(s gxregistry.Service) error {
	if len(s.Nodes) == 0 {
		return jerrors.Errorf("Require at least one node")
	}

	var err error
	for _, node := range s.Nodes {
		err = r.client.DeleteZkPath(s.NodePath(r.options.Root, *node))
		if err != nil {
			return jerrors.Trace(err)
		}
	}

	return nil
}

func (r *Registry) Deregister(s gxregistry.Service) error {
	r.deleteService(s)
	return jerrors.Trace(r.unregister(s))
}

func (r *Registry) GetServices(attr gxregistry.ServiceAttr) ([]gxregistry.Service, error) {
	svc := gxregistry.Service{Attr: &attr}
	path := svc.Path(r.options.Root)
	children, err := r.client.GetChildren(path)
	if err != nil {
		return nil, jerrors.Annotatef(err, "zkClient.GetChildren(path:%s)", path)
	}
	if len(children) == 0 {
		return nil, gxregistry.ErrorRegistryNotFound
	}

	serviceArray := []gxregistry.Service{}
	var node gxregistry.Node
	for _, name := range children {
		node.ID = name
		zkPath := svc.NodePath(r.options.Root, node)

		childData, err := r.client.Get(zkPath)
		fmt.Println("get zkpath:", zkPath, " children:", childData, ", error:", err)
		if err != nil {
			log.Warn("gxzookeeper.Get(name:%s) = error:%s", zkPath, jerrors.ErrorStack(err))
			continue
		}

		sn, err := gxregistry.DecodeService(childData)
		fmt.Println("decode data, sn:", sn, ", err:", err)
		if err != nil {
			log.Warn("gxregistry.DecodeService(data:%#v) = error:%s", childData, jerrors.ErrorStack(err))
			continue
		}
		if attr.Filter(*sn.Attr) {
			for _, node := range sn.Nodes {
				var service gxregistry.Service
				service.Attr = sn.Attr
				service.Nodes = append(service.Nodes, node)
				serviceArray = append(serviceArray, service)
			}
		}
	}

	return serviceArray, nil
}

func (r *Registry) Watch(opts ...gxregistry.WatchOption) (gxregistry.Watcher, error) {
	return nil, nil
}

func (r *Registry) String() string {
	return "zookeeper registry"
}

func (r *Registry) Close() error {
	r.Lock()
	defer r.Unlock()
	if r.client != nil {
		close(r.done)
		r.client.ZkConn().Close()
		r.wg.Wait()
		r.client = nil
	}

	return nil
}
<|endoftext|>


<commit_before>package schema

import (
	"fmt"
	"regexp"
	"strconv"
)

// CastInt casts an integer value (passed-in as unicode string) against a field. Returns an
// error if the value can not be converted to integer.
func castInt(bareNumber bool, value string, c Constraints) (int64, error) {
	v := value
	if !bareNumber {
		var err error
		v, err = stripIntegerFromString(v)
		if err != nil {
			return 0, err
		}
	}
	returned, err := strconv.ParseInt(v, 10, 64)
	if err != nil {
		return 0, err
	}
	if c.Maximum != "" {
		max, err := strconv.ParseInt(c.Maximum, 10, 64)
		if err != nil {
			return 0, fmt.Errorf("invalid maximum integer: %v", c.Maximum)
		}
		if returned > max {
			return 0, fmt.Errorf("constraint check error: integer:%d > maximum:%d", returned, max)
		}
	}
	if c.Minimum != "" {
		min, err := strconv.ParseInt(c.Minimum, 10, 64)
		if err != nil {
			return 0, fmt.Errorf("invalid minimum integer: %v", c.Minimum)
		}
		if returned < min {
			return 0, fmt.Errorf("constraint check error: integer:%d > minimum:%d", returned, min)
		}
	}
	return returned, nil
}

var bareIntegerRegexp = regexp.MustCompile(`((^[0-9]+)|([0-9]+$))`)

func stripIntegerFromString(v string) (string, error) {
	matches := bareIntegerRegexp.FindStringSubmatch(v)
	if matches == nil {
		return "", fmt.Errorf("invalid integer to strip:%s", v)
	}
	return matches[1], nil
}
<commit_msg>Small fix on error message for minimum integer<commit_after>package schema

import (
	"fmt"
	"regexp"
	"strconv"
)

// CastInt casts an integer value (passed-in as unicode string) against a field. Returns an
// error if the value can not be converted to integer.
func castInt(bareNumber bool, value string, c Constraints) (int64, error) {
	v := value
	if !bareNumber {
		var err error
		v, err = stripIntegerFromString(v)
		if err != nil {
			return 0, err
		}
	}
	returned, err := strconv.ParseInt(v, 10, 64)
	if err != nil {
		return 0, err
	}
	if c.Maximum != "" {
		max, err := strconv.ParseInt(c.Maximum, 10, 64)
		if err != nil {
			return 0, fmt.Errorf("invalid maximum integer: %v", c.Maximum)
		}
		if returned > max {
			return 0, fmt.Errorf("constraint check error: integer:%d > maximum:%d", returned, max)
		}
	}
	if c.Minimum != "" {
		min, err := strconv.ParseInt(c.Minimum, 10, 64)
		if err != nil {
			return 0, fmt.Errorf("invalid minimum integer: %v", c.Minimum)
		}
		if returned < min {
			return 0, fmt.Errorf("constraint check error: integer:%d < minimum:%d", returned, min)
		}
	}
	return returned, nil
}

var bareIntegerRegexp = regexp.MustCompile(`((^[0-9]+)|([0-9]+$))`)

func stripIntegerFromString(v string) (string, error) {
	matches := bareIntegerRegexp.FindStringSubmatch(v)
	if matches == nil {
		return "", fmt.Errorf("invalid integer to strip:%s", v)
	}
	return matches[1], nil
}
<|endoftext|>


<commit_before>package run

import (
	"gopkg.in/workanator/go-floc.v2"
	"gopkg.in/workanator/go-floc.v2/errors"
)

func handleResult(ctrl floc.Control, err error, where string) error {
	if err != nil {
		ctrl.Fail(nil, err)
		return errors.NewErrLocation(err, where)
	}

	return nil
}
<commit_msg>Wrap error into ErrLocation prior to fail<commit_after>package run

import (
	"gopkg.in/workanator/go-floc.v2"
	"gopkg.in/workanator/go-floc.v2/errors"
)

func handleResult(ctrl floc.Control, err error, where string) error {
	if err != nil {
		locationErr := errors.NewErrLocation(err, where)
		ctrl.Fail(nil, locationErr)

		return locationErr
	}

	return nil
}
<|endoftext|>


<commit_before>// 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 gofish

import (
	"encoding/json"

	"github.com/stmcginnis/gofish/school/common"
	"github.com/stmcginnis/gofish/school/redfish"
	"github.com/stmcginnis/gofish/school/swordfish"
)

// Service represents the service root of a Redfish enabled device.
type Service struct {
	common.Entity
	Version            string `json:"ServiceVersion"`
	UUID               string `json:"UUID"`
	chassis            string
	managers           string
	taskService        string
	sessionService     string
	storageServices    string
	storageSystems     string
	accountService     string
	eventService       string
	registries         string
	systems            string
	compositionService string
}

// UnmarshalJSON unmarshals a Service object from the raw JSON.
func (s *Service) UnmarshalJSON(b []byte) error {
	type temp Service
	type linkReference struct {
		Chassis            common.Link
		Managers           common.Link
		TaskService        common.Link
		SessionService     common.Link
		StorageServices    common.Link
		StorageSystems     common.Link
		AccountService     common.Link
		EventService       common.Link
		Registries         common.Link
		Systems            common.Link
		CompositionService common.Link
	}
	var t struct {
		temp
		Links linkReference
	}

	err := json.Unmarshal(b, &t)
	if err != nil {
		return err
	}

	*s = Service(t.temp)

	// Extract the links to other entities for later
	s.chassis = string(t.Links.Chassis)
	s.managers = string(t.Links.Managers)
	s.taskService = string(t.Links.TaskService)
	s.sessionService = string(t.Links.SessionService)
	s.storageServices = string(t.Links.StorageServices)
	s.storageSystems = string(t.Links.StorageSystems)
	s.accountService = string(t.Links.AccountService)
	s.eventService = string(t.Links.EventService)
	s.registries = string(t.Links.Registries)
	s.systems = string(t.Links.Systems)
	s.compositionService = string(t.Links.CompositionService)

	return nil
}

// ServiceRoot gets the root service of the Redfish service.
func ServiceRoot(c common.Client) (*Service, error) {

	resp, err := c.Get(common.DefaultServiceRoot)
	defer resp.Body.Close()

	var service Service
	err = json.NewDecoder(resp.Body).Decode(&service)
	if err != nil {
		return nil, err
	}
	service.SetClient(c)
	return &service, nil
}

// Chassis gets the chassis instances managed by this service.
func (s *Service) Chassis() ([]*redfish.Chassis, error) {
	return redfish.ListReferencedChassis(s.Client, s.chassis)
}

// Managers gets the manager instances of this service.
func (s *Service) Managers() ([]*redfish.Manager, error) {
	return redfish.ListReferencedManagers(s.Client, s.managers)
}

// StorageSystems gets the storage system instances managed by this service.
func (s *Service) StorageSystems() ([]*swordfish.StorageSystem, error) {
	return swordfish.ListReferencedStorageSystems(s.Client, s.storageSystems)
}

// StorageServices gets the Swordfish storage services
func (s *Service) StorageServices() ([]*swordfish.StorageService, error) {
	return swordfish.ListReferencedStorageServices(s.Client, s.storageServices)
}

// Tasks gets the system's tasks
func (s *Service) Tasks() ([]*redfish.Task, error) {
	return redfish.ListReferencedTasks(s.Client, s.taskService)
}

// Sessions gets the system's active sessions
func (s *Service) Sessions() ([]*redfish.Session, error) {
	return redfish.ListReferencedSessions(s.Client, s.sessionService)
}

// AccountService gets the Redfish AccountService
func (s *Service) AccountService() (*redfish.AccountService, error) {
	return redfish.GetAccountService(s.Client, s.accountService)
}

// EventService gets the Redfish EventService
func (s *Service) EventService() (*redfish.EventService, error) {
	return redfish.GetEventService(s.Client, s.eventService)
}

// Systems get the system instances from the service
func (s *Service) Systems() ([]*redfish.ComputerSystem, error) {
	return redfish.ListReferencedComputerSystems(s.Client, s.systems)
}

// CompositionService gets the composition service instance
func (s *Service) CompositionService() (*redfish.CompositionService, error) {
	return redfish.GetCompositionService(s.Client, s.compositionService)
}
<commit_msg>Fix the UnmarshalJSON, for some reason with the old structure it wasn't able to unpack against real hardware<commit_after>// 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 gofish

import (
	"encoding/json"

	"github.com/stmcginnis/gofish/school/common"
	"github.com/stmcginnis/gofish/school/redfish"
	"github.com/stmcginnis/gofish/school/swordfish"
)

// Service represents the service root of a Redfish enabled device.
type Service struct {
	common.Entity
	Version            string `json:"ServiceVersion"`
	UUID               string `json:"UUID"`
	chassis            string
	managers           string
	taskService        string
	sessionService     string
	storageServices    string
	storageSystems     string
	accountService     string
	eventService       string
	registries         string
	systems            string
	compositionService string
}

// UnmarshalJSON unmarshals a Service object from the raw JSON.
func (s *Service) UnmarshalJSON(b []byte) error {
	type temp Service
	var t struct {
		temp
		// Link references
		Chassis            common.Link
		Managers           common.Link
		TaskService        common.Link
		SessionService     common.Link
		StorageServices    common.Link
		StorageSystems     common.Link
		AccountService     common.Link
		EventService       common.Link
		Registries         common.Link
		Systems            common.Link
		CompositionService common.Link
	}

	err := json.Unmarshal(b, &t)
	if err != nil {
		return err
	}

	*s = Service(t.temp)

	// Extract the links to other entities for later
	s.chassis = string(t.Chassis)
	s.managers = string(t.Managers)
	s.taskService = string(t.TaskService)
	s.sessionService = string(t.SessionService)
	s.storageServices = string(t.StorageServices)
	s.storageSystems = string(t.StorageSystems)
	s.accountService = string(t.AccountService)
	s.eventService = string(t.EventService)
	s.registries = string(t.Registries)
	s.systems = string(t.Systems)
	s.compositionService = string(t.CompositionService)

	return nil
}

// ServiceRoot gets the root service of the Redfish service.
func ServiceRoot(c common.Client) (*Service, error) {
	resp, err := c.Get(common.DefaultServiceRoot)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var service Service
	err = json.NewDecoder(resp.Body).Decode(&service)
	if err != nil {
		return nil, err
	}

	service.SetClient(c)
	return &service, nil
}

// Chassis gets the chassis instances managed by this service.
func (s *Service) Chassis() ([]*redfish.Chassis, error) {
	return redfish.ListReferencedChassis(s.Client, s.chassis)
}

// Managers gets the manager instances of this service.
func (s *Service) Managers() ([]*redfish.Manager, error) {
	return redfish.ListReferencedManagers(s.Client, s.managers)
}

// StorageSystems gets the storage system instances managed by this service.
func (s *Service) StorageSystems() ([]*swordfish.StorageSystem, error) {
	return swordfish.ListReferencedStorageSystems(s.Client, s.storageSystems)
}

// StorageServices gets the Swordfish storage services
func (s *Service) StorageServices() ([]*swordfish.StorageService, error) {
	return swordfish.ListReferencedStorageServices(s.Client, s.storageServices)
}

// Tasks gets the system's tasks
func (s *Service) Tasks() ([]*redfish.Task, error) {
	return redfish.ListReferencedTasks(s.Client, s.taskService)
}

// Sessions gets the system's active sessions
func (s *Service) Sessions() ([]*redfish.Session, error) {
	return redfish.ListReferencedSessions(s.Client, s.sessionService)
}

// AccountService gets the Redfish AccountService
func (s *Service) AccountService() (*redfish.AccountService, error) {
	return redfish.GetAccountService(s.Client, s.accountService)
}

// EventService gets the Redfish EventService
func (s *Service) EventService() (*redfish.EventService, error) {
	return redfish.GetEventService(s.Client, s.eventService)
}

// Systems get the system instances from the service
func (s *Service) Systems() ([]*redfish.ComputerSystem, error) {
	return redfish.ListReferencedComputerSystems(s.Client, s.systems)
}

// CompositionService gets the composition service instance
func (s *Service) CompositionService() (*redfish.CompositionService, error) {
	return redfish.GetCompositionService(s.Client, s.compositionService)
}
<|endoftext|>


<commit_before>package goinsta

// Account is personal account object
type Account struct {
	inst *Instagram
}

// NewAccount creates new account structure
func NewAccount(inst *Instagram) (*Account, error) {
	account := &Account{
		inst: inst,
	}
	return account, nil
}
<commit_msg>Defined account object<commit_after>package goinsta

// Account is personal account object
type Account struct {
	inst *Instagram

	// Activity is recent activity
	Activity *Activity
	// Tray is your disponible friend's stories
	Tray *Tray

	User
	//Birthday -> what the hell is ?
	PhoneNumber             string           `json:"phone_number"`
	HDProfilePicVersions    []ImageCandidate `json:"hd_profile_pic_versions"`
	Gender                  int              `json:"gender"`
	ShowConversionEditEntry bool             `json:"show_conversion_edit_entry"`
	ExternalLynxURL         string           `json:"external_lynx_url"`
	Biography               string           `json:"biography"`
	HDProfilePicURLInfo     ImageCandidate   `json:"hd_profile_pic_url_info"`
	Email                   string           `json:"email"`
	ExternalURL             string           `json:"external_url"`
}

// NewAccount creates new account structure
func NewAccount(inst *Instagram) (*Account, error) {
	account := &Account{
		inst: inst,
	}
	return account, nil
}
<|endoftext|>


<commit_before>package jsapi

import (
	"github.com/ant0ine/go-json-rest/rest"
	"google.golang.org/appengine"
	"google.golang.org/appengine/user"
	"log"
	"net/http"
)

const PATH_PREFIX = "/jsapi"

func init() {
	api := rest.NewApi()
	api.Use(
		&LoggedInMiddleware{},
		&rest.RecoverMiddleware{
			EnableResponseStackTrace: true,
		},
		&rest.JsonIndentMiddleware{},
		&rest.ContentTypeCheckerMiddleware{},
	)
	router, err := rest.MakeRouter(
		rest.Get("/#path", func(w rest.ResponseWriter, r *rest.Request) {
			path := r.PathParam("path")
			ctx := appengine.NewContext(r.Request)
			u := user.Current(ctx)
			url, _ := user.LogoutURL(ctx, PATH_PREFIX+r.URL.Path)
			w.WriteJson(map[string]interface{}{
				"user":      u,
				"LogoutUrl": url,
				"path":      path,
			})
		}),
	)
	if err != nil {
		log.Fatal(err)
	}
	api.SetApp(router)
	http.Handle("/", http.StripPrefix(PATH_PREFIX, api.MakeHandler()))
}
<commit_msg>made skeleton for the supported API routes, all of which just panic, excepting `/current_user`<commit_after>package jsapi

import (
	"github.com/ant0ine/go-json-rest/rest"
	"google.golang.org/appengine"
	"google.golang.org/appengine/user"
	"log"
	"net/http"
	"strings"
)

const PATH_PREFIX = "/jsapi"

func init() {
	api := rest.NewApi()
	api.Use(
		&LoggedInMiddleware{},
		&rest.RecoverMiddleware{
			EnableResponseStackTrace: true,
		},
		&rest.JsonIndentMiddleware{},
		&rest.ContentTypeCheckerMiddleware{},
	)
	router, err := rest.MakeRouter(
		rest.Get(   "/current_user",    getCurrentUser),
		rest.Get(   "/events",          getEvents),
		rest.Post(  "/events",          postEvents),
		rest.Get(   "/events/:id",      getEvent),
		rest.Patch( "/events/:id",      patchEvent),
		rest.Delete("/events/:id",      deleteEvent),
		rest.Get(   "/tags",            getTags),
		rest.Get(   "/tagsets",         getTagsets),
	)
	if err != nil {
		log.Fatal(err)
	}
	api.SetApp(router)
	http.Handle("/", http.StripPrefix(PATH_PREFIX, api.MakeHandler()))
}

func getTags(w rest.ResponseWriter, r *rest.Request) {
	panic("not implemented")
}

func getTagsets(w rest.ResponseWriter, r *rest.Request) {
	panic("not implemented")
}

func deleteEvent(w rest.ResponseWriter, r *rest.Request) {
	panic("not implemented")
}

func patchEvent(w rest.ResponseWriter, r *rest.Request) {
	panic("not implemented")
}

func getEvent(w rest.ResponseWriter, r *rest.Request) {
	panic("not implemented")
}

func postEvents(w rest.ResponseWriter, r *rest.Request) {
	panic("not implemented")
}

func getEvents(w rest.ResponseWriter, r *rest.Request) {
	panic("not implemented")
}

func getCurrentUser(w rest.ResponseWriter, r *rest.Request) {
	ctx := appengine.NewContext(r.Request)
	u := user.Current(ctx)
	logoutUrl, _ := user.LogoutURL(ctx, r.Referer())
	w.WriteJson(RecordResponse{
		Data: Data{
			Type: "user",
			Id: u.ID,
			Attributes: map[string]interface{}{
				"email": u.Email,
				"name": strings.Split(u.Email, "@")[0],
			},
		},
		Meta: map[string]interface{}{
			"logout_url": logoutUrl,
		},
	})
}
<|endoftext|>


<commit_before>package bid

import (
	"log"

	"github.com/mxmCherry/openrtb"
	"golang.org/x/net/context"

	"github.com/satoshi03/go-dsp-api/common/consts"
	"github.com/satoshi03/go-dsp-api/common/errors"
	"github.com/satoshi03/go-dsp-api/data"
)

func bid(ctx context.Context, br *openrtb.BidRequest) []*data.Ad {
	var selected []*data.Ad
	for _, imp := range br.Imp {
		ad, ok := getAd(ctx, &imp)
		if ok {
			ad.ImpID = imp.ID
			selected = append(selected, &ad)
		}
	}
	return selected
}

func getAd(ctx context.Context, imp *openrtb.Imp) (data.Ad, bool) {
	// Get Index having candidate ad list
	index, err := data.GetIndex(ctx, imp)
	if err != nil {
		// For debug
		log.Println(err)
		return data.Ad{}, false
	}

	// Find valid ad having max score(=ecpm) in index
	for i := range index {
		if err := validate(imp, &index[i]); err == nil {
			// Valid ad was found
			return index[i], true
		} else {
			// For debug
			log.Println(err)
		}
	}

	// No valid ad was found
	return data.Ad{}, false
}

func validate(imp *openrtb.Imp, ad *data.Ad) error {
	// Native Ad is not supported
	if imp.Native != nil {
		return errors.NoSupportError{"native"}
	}
	// Video Ad is not supported
	if imp.Video != nil {
		return errors.NoSupportError{"video"}
	}
	// Check bid currency
	if imp.BidFloorCur != "" && imp.BidFloorCur != consts.DefaultBidCur {
		return errors.InvalidCurError
	}
	// Check bid price greater than bid floor price
	if ad.CalcBidPrice() <= imp.BidFloor {
		return errors.LowPriceError
	}

	return nil
}
<commit_msg>add imp validation<commit_after>package bid

import (
	"log"

	"github.com/mxmCherry/openrtb"
	"golang.org/x/net/context"

	"github.com/satoshi03/go-dsp-api/common/consts"
	"github.com/satoshi03/go-dsp-api/common/errors"
	"github.com/satoshi03/go-dsp-api/data"
)

func bid(ctx context.Context, br *openrtb.BidRequest) []*data.Ad {
	var selected []*data.Ad
	for _, imp := range br.Imp {
		// If imp is invalid, skip it
		if err := validateImp(&imp); err != nil {
			continue
		}
		ad, ok := getAd(ctx, &imp)
		if ok {
			ad.ImpID = imp.ID
			selected = append(selected, &ad)
		}
	}
	return selected
}

func getAd(ctx context.Context, imp *openrtb.Imp) (data.Ad, bool) {
	// Get Index having candidate ad list
	index, err := data.GetIndex(ctx, imp)
	if err != nil {
		// For debug
		log.Println(err)
		return data.Ad{}, false
	}

	// Find valid ad having max score(=ecpm) in index
	for i := range index {
		if err := validateAd(imp, &index[i]); err == nil {
			// Valid ad was found
			return index[i], true
		} else {
			// For debug
			log.Println(err)
		}
	}

	// No valid ad was found
	return data.Ad{}, false
}

func validateImp(imp *openrtb.Imp) error {
	// Native Ad is not supported
	if imp.Native != nil {
		return errors.NoSupportError{"native"}
	}
	// Video Ad is not supported
	if imp.Video != nil {
		return errors.NoSupportError{"video"}
	}
	// Check bid currency
	if imp.BidFloorCur != "" && imp.BidFloorCur != consts.DefaultBidCur {
		return errors.InvalidCurError
	}
	return nil
}

func validateAd(imp *openrtb.Imp, ad *data.Ad) error {
	// Check bid price greater than bid floor price
	if ad.CalcBidPrice() <= imp.BidFloor {
		return errors.LowPriceError
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013, Richard Johnson
Copyright (c) 2014, Kilian Gilonne
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package safebrowsing

import (
	//"fmt"
	"os"
	"testing"
	"time"
	//"bytes"
	"bytes"
	//"encoding/hex"
	"crypto/sha256"
	"io/ioutil"
	"net/http"
	"sync"
	//"strings"
)

type MockReadCloser struct {
	buf *bytes.Buffer
}

func NewMockReadCloser(contents string) (mrc *MockReadCloser) {
	return &MockReadCloser{
		buf: bytes.NewBuffer([]byte(contents)),
	}
}
func (mrc *MockReadCloser) Read(p []byte) (n int, err error) {
	n, err = mrc.buf.Read(p)
	return n, err
}
func (mrc *MockReadCloser) Close() (err error) {
	return nil
}

func NewMockRequest(data string) func(string, string, bool) (*http.Response, error) {
	request := func(string, string, bool) (*http.Response, error) {
		response := &http.Response{
			StatusCode: 200,
			Body:       NewMockReadCloser(data),
		}
		return response, nil
	}
	return request
}

func TestSafeBrowsingLists(t *testing.T) {
	data := "googpub-phish-shavar\ngoog-malware-shavar"
	ss := &SafeBrowsing{
		request: NewMockRequest(data),
		Lists:   make(map[string]*SafeBrowsingList),
		Logger:  new(DefaultLogger),
	}
	err := ss.requestSafeBrowsingLists()
	if err != nil {
		t.Fatal(err)
	}
	if len(ss.Lists) != 2 {
		t.Error("List not processed correctly")
	}
}

func TestRedirectList(t *testing.T) {
	data := `n:1200
i:googpub-phish-shavar
u:cache.google.com/first_redirect_example
u:cache.google.com/first_redirect_example_1
sd:1,2
i:acme-white-shavar
u:cache.google.com/second_redirect_example
u:cache.google.com/second_redirect_example_2
ad:1-2,4-5,7
sd:2-6`
	ss := &SafeBrowsing{
		request: NewMockRequest(data),
		Lists: map[string]*SafeBrowsingList{
			"googpub-phish-shavar": newSafeBrowsingList("googpub-phish-shavar", ""),
			"acme-white-shavar":    newSafeBrowsingList("acme-white-shavar", ""),
		},
		Logger: new(DefaultLogger),
	}
	err, _ := ss.requestRedirectList()
	if err != nil {
		t.Error(err)
	}
	if len(ss.Lists["googpub-phish-shavar"].DataRedirects) != 2 {
		t.Error("Unable to parse redirect list")
	}
	if ss.Lists["googpub-phish-shavar"].DataRedirects[0] != "https://cache.google.com/first_redirect_example" {
		t.Error("Unable to parse redirect list")
	}
	if ss.Lists["acme-white-shavar"].DataRedirects[0] != "https://cache.google.com/second_redirect_example" {
		t.Error("Unable to parse redirect list")
	}
	if len(ss.Lists["googpub-phish-shavar"].DeleteChunks[CHUNK_TYPE_SUB]) != 2 {
		t.Error("Delete chunks not processed")
	}
	if len(ss.Lists["acme-white-shavar"].DeleteChunks[CHUNK_TYPE_ADD]) != 5 {
		t.Error("Delete chunks not processed")
	}
	if len(ss.Lists["acme-white-shavar"].DeleteChunks[CHUNK_TYPE_SUB]) != 5 {
		t.Error("Delete chunks not processed")
	}
	if ss.UpdateDelay != 1200 {
		t.Error("Update delay not parsed")
	}
}

func TestUrlListed(t *testing.T) {

	url := "http://test.com/"
	url = Canonicalize(url)
	urls := GenerateTestCandidates(url)
	url = urls[0]
	hasher := sha256.New()
	hasher.Write([]byte(url))
	hash := hasher.Sum(nil)
	chunkData := []byte("600\n" + "googpub-phish-shavar:32:1\n" + string(hash) + "\n")
	tmpDirName, err := ioutil.TempDir("", "safebrowsing")
	if err != nil {
		t.Error(err)
		return
	}

	ss := &SafeBrowsing{
		LastUpdated: time.Now(),
		DataDir:     tmpDirName,
		Lists: map[string]*SafeBrowsingList{
			"googpub-phish-shavar": &SafeBrowsingList{
				Name:              "googpub-phish-shavar",
				FileName:          tmpDirName + "/googpub-phish-shavar.dat",
				Lookup:            NewTrie(),
				FullHashRequested: NewTrie(),
				FullHashes:        NewTrie(),
				Cache:             make(map[FullHash]*FullHashCache),
				DeleteChunks: map[ChunkData_ChunkType]map[ChunkNum]bool{
					CHUNK_TYPE_ADD: make(map[ChunkNum]bool),
					CHUNK_TYPE_SUB: make(map[ChunkNum]bool),
				},
				Logger: new(DefaultLogger),
				fsLock: new(sync.Mutex),
			},
		},
		Logger:  new(DefaultLogger),
		request: NewMockRequest(string(chunkData)),
	}
	ss.Lists["googpub-phish-shavar"].Lookup.Set(string(hash[:PREFIX_4B_SZ]))

	result, _, err := ss.MightBeListed(url)
	if err != nil {
		t.Error(err)
		return
	}
	if result == "" {
		t.Error("Hash was not found :/")
		return
	}

	result, err = ss.IsListed(url)
	if err != nil {
		t.Error(err)
		return
	}
	if result == "" {
		t.Error("Full hash was not found :/")
		return
	}
	os.RemoveAll(tmpDirName)
}
<commit_msg>small fix for test<commit_after>/*
Copyright (c) 2013, Richard Johnson
Copyright (c) 2014, Kilian Gilonne
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package safebrowsing

import (
	//"fmt"
	"os"
	"testing"
	"time"
	//"bytes"
	"bytes"
	//"encoding/hex"
	"crypto/sha256"
	"io/ioutil"
	"net/http"
	"sync"
	//"strings"
)

type MockReadCloser struct {
	buf *bytes.Buffer
}

func NewMockReadCloser(contents string) (mrc *MockReadCloser) {
	return &MockReadCloser{
		buf: bytes.NewBuffer([]byte(contents)),
	}
}
func (mrc *MockReadCloser) Read(p []byte) (n int, err error) {
	n, err = mrc.buf.Read(p)
	return n, err
}
func (mrc *MockReadCloser) Close() (err error) {
	return nil
}

func NewMockRequest(data string) func(string, string, bool) (*http.Response, error) {
	request := func(string, string, bool) (*http.Response, error) {
		response := &http.Response{
			StatusCode: 200,
			Body:       NewMockReadCloser(data),
		}
		return response, nil
	}
	return request
}

func TestSafeBrowsingLists(t *testing.T) {
	data := "googpub-phish-shavar\ngoog-malware-shavar"
	ss := &SafeBrowsing{
		request: NewMockRequest(data),
		Lists:   make(map[string]*SafeBrowsingList),
		Logger:  new(DefaultLogger),
	}
	err := ss.requestSafeBrowsingLists()
	if err != nil {
		t.Fatal(err)
	}
	if len(ss.Lists) != 2 {
		t.Error("List not processed correctly")
	}
}

func TestRedirectList(t *testing.T) {
	data := `n:1200
i:googpub-phish-shavar
u:cache.google.com/first_redirect_example
u:cache.google.com/first_redirect_example_1
sd:1,2
i:acme-white-shavar
u:cache.google.com/second_redirect_example
u:cache.google.com/second_redirect_example_2
ad:1-2,4-5,7
sd:2-6`
	ss := &SafeBrowsing{
		request: NewMockRequest(data),
		Lists: map[string]*SafeBrowsingList{
			"googpub-phish-shavar": newSafeBrowsingList("googpub-phish-shavar", ""),
			"acme-white-shavar":    newSafeBrowsingList("acme-white-shavar", ""),
		},
		Logger: new(DefaultLogger),
	}
	err, _ := ss.requestRedirectList()
	if err != nil {
		t.Error(err)
	}
	if len(ss.Lists["googpub-phish-shavar"].DataRedirects) != 2 {
		t.Error("Unable to parse redirect list")
	}
	if ss.Lists["googpub-phish-shavar"].DataRedirects[0] != "https://cache.google.com/first_redirect_example" {
		t.Error("Unable to parse redirect list")
	}
	if ss.Lists["acme-white-shavar"].DataRedirects[0] != "https://cache.google.com/second_redirect_example" {
		t.Error("Unable to parse redirect list")
	}
	if len(ss.Lists["googpub-phish-shavar"].DeleteChunks[CHUNK_TYPE_SUB]) != 2 {
		t.Error("Delete chunks not processed")
	}
	if len(ss.Lists["acme-white-shavar"].DeleteChunks[CHUNK_TYPE_ADD]) != 5 {
		t.Error("Delete chunks not processed")
	}
	if len(ss.Lists["acme-white-shavar"].DeleteChunks[CHUNK_TYPE_SUB]) != 5 {
		t.Error("Delete chunks not processed")
	}
	if ss.UpdateDelay != 1200 {
		t.Error("Update delay not parsed")
	}
}

func TestUrlListed(t *testing.T) {

	url := "http://test.com/"
	url = Canonicalize(url)
	urls := GenerateTestCandidates(url)
	url = urls[0]
	hasher := sha256.New()
	hasher.Write([]byte(url))
	hash := hasher.Sum(nil)
	chunkData := []byte("600\n" + "googpub-phish-shavar:32:1\n" + string(hash))
	tmpDirName, err := ioutil.TempDir("", "safebrowsing")
	if err != nil {
		t.Error(err)
		return
	}

	ss := &SafeBrowsing{
		LastUpdated: time.Now(),
		DataDir:     tmpDirName,
		Lists: map[string]*SafeBrowsingList{
			"googpub-phish-shavar": &SafeBrowsingList{
				Name:              "googpub-phish-shavar",
				FileName:          tmpDirName + "/googpub-phish-shavar.dat",
				Lookup:            NewTrie(),
				FullHashRequested: NewTrie(),
				FullHashes:        NewTrie(),
				Cache:             make(map[FullHash]*FullHashCache),
				DeleteChunks: map[ChunkData_ChunkType]map[ChunkNum]bool{
					CHUNK_TYPE_ADD: make(map[ChunkNum]bool),
					CHUNK_TYPE_SUB: make(map[ChunkNum]bool),
				},
				Logger: new(DefaultLogger),
				fsLock: new(sync.Mutex),
			},
		},
		Logger:  new(DefaultLogger),
		request: NewMockRequest(string(chunkData)),
	}
	ss.Lists["googpub-phish-shavar"].Lookup.Set(string(hash[:PREFIX_4B_SZ]))

	result, _, err := ss.MightBeListed(url)
	if err != nil {
		t.Error(err)
		return
	}
	if result == "" {
		t.Error("Hash was not found :/")
		return
	}

	result, err = ss.IsListed(url)
	if err != nil {
		t.Error(err)
		return
	}
	if result == "" {
		t.Error("Full hash was not found :/")
		return
	}
	os.RemoveAll(tmpDirName)
}
<|endoftext|>