<commit_before>// Copyright 2015 Bobby Powers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"log"
	"sort"
	"sync"
	"text/template"
	"time"

	"github.com/bpowers/fuse"
	"github.com/bpowers/slack"
	"golang.org/x/net/context"
)

const defaultMsgTmpl = "{{.Timestamp}}\t{{.Username}}\t{{.Text}}\n"

var t = template.Must(template.New("msg").Parse(defaultMsgTmpl))

type msgSlice []slack.Message

func (p msgSlice) Len() int           { return len(p) }
func (p msgSlice) Less(i, j int) bool { return p[i].Timestamp < p[j].Timestamp }
func (p msgSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

type HistoryFn func(id string, params slack.HistoryParameters) (*slack.History, error)

type Session struct {
	// set in SessionInit, immutable after
	history HistoryFn
	id      string
	conn    *FSConn

	sync.Cond
	mu sync.Mutex

	// everything below here must be accessed with Session.L held.

	acks map[int]struct{} // waiting for websocket acks

	// When any of the below are changed, Broadcast is called on
	// cond.

	initialized bool
	formatted   bytes.Buffer
	newestTs    string // most recent timestamp
}

func SessionInit(s *Session, id string, conn *FSConn, history HistoryFn) {
	s.L = &s.mu
	s.history = history
	s.id = id
	s.conn = conn
	s.acks = make(map[int]struct{})
}

func (s *Session) CurrLen() uint64 {
	s.L.Lock()
	defer s.L.Unlock()
	for !s.initialized {
		s.Wait()
	}
	return uint64(s.formatted.Len())
}

func (s *Session) Bytes(offset int64, size int) ([]byte, error) {
	s.L.Lock()
	defer s.L.Unlock()
	for !s.initialized {
		s.Wait()
	}
	if offset != 0 {
		log.Printf("TODO: read w/ offset not implemented yet")
		return nil, fuse.EIO
	}
	bytes := s.formatted.Bytes()
	if len(bytes) > size {
		bytes = bytes[:size]
	}
	return bytes, nil
}

func (s *Session) Write(msg []byte) error {
	msg = bytes.TrimSpace(msg)
	id := s.id
	out := s.conn.ws.NewOutgoingMessage(string(msg), id)

	// record our websocket-message ID so that we know what to do
	// when the server acknowledges receipt
	s.L.Lock()
	s.acks[out.Id] = struct{}{}
	s.L.Unlock()

	err := s.conn.ws.SendMessage(out)
	if err != nil {
		log.Printf("SendMessage: %s", err)
	}

	return nil
}

func (s *Session) Event(evt slack.SlackEvent) bool {
	switch msg := evt.Data.(type) {
	case slack.AckMessage:
		s.L.Lock()
		_, ok := s.acks[msg.ReplyTo]
		delete(s.acks, msg.ReplyTo)
		s.L.Unlock()
		if !ok {
			return false
		}
		if err := s.FetchHistory(msg.Timestamp, true); err != nil {
			log.Printf("'%s'.FetchHistory() 2: %s", s.id, err)
		}
		return true

	case *slack.MessageEvent:
		if msg.ChannelId != s.id {
			log.Printf("error: bad routing on %s for %#v", s.id, msg)
			return false
		}
		s.addMessage((*slack.Message)(msg))
		return true
	}

	return false
}

// must be called with s.L held
func (s *Session) formatMsg(msg *slack.Message) error {
	return t.Execute(&s.formatted, msg)
}

func (s *Session) FetchHistory(oldest string, inclusive bool) error {
	h, err := s.history(s.id, slack.HistoryParameters{
		Oldest:    oldest,
		Count:     1000,
		Inclusive: inclusive,
	})
	if err != nil {
		return fmt.Errorf("GetHistory(%s): %s", s.id, err)
	}

	if h.HasMore {
		log.Printf("TODO: we need to page/fetch more messages")
	}

	sort.Sort(msgSlice(h.Messages))

	s.L.Lock()
	defer s.L.Unlock()

	for _, msg := range h.Messages {
		err := s.formatMsg(&msg)
		if err != nil {
			log.Printf("formatMsg(%#v): %s", msg, err)
		}
	}
	s.newestTs = h.Messages[len(h.Messages)-1].Timestamp
	s.initialized = true

	s.Broadcast()

	return nil
}

func (s *Session) addMessage(msg *slack.Message) error {
	s.L.Lock()
	defer s.L.Unlock()
	// don't add messages from the websocket until after we've
	// initialized history.
	for !s.initialized {
		log.Printf("waiting to init before recording msg %s", msg.Text)
		s.Wait()
	}
	if msg.Timestamp <= s.newestTs {
		log.Printf("dropping WS message %s (%s) because it is too old", msg.Timestamp, msg.Text)
		return nil
	}

	err := s.formatMsg(msg)
	if err != nil {
		log.Printf("formatMsg(%#v): %s", msg, err)
		return nil
	}
	s.newestTs = msg.Timestamp

	s.Broadcast()

	return nil
}

func newSession(parent *DirNode) (INode, error) {
	name := "session"
	n := new(SessionAttrNode)
	if err := n.Node.Init(parent, name, nil); err != nil {
		return nil, fmt.Errorf("node.Init('%s': %s", name, err)
	}
	n.mode = 0444
	return n, nil
}

func (an *SessionAttrNode) Activate() error {
	if an.parent == nil {
		return nil
	}

	return an.parent.addChild(an)
}

func (an *SessionAttrNode) DirentType() fuse.DirentType {
	return fuse.DT_File
}

func (an *SessionAttrNode) IsDir() bool {
	return false
}

type SessionProvider interface {
	CurrLen() uint64
	Bytes(offset int64, size int) ([]byte, error)
}

type SessionWriter interface {
	Write([]byte) error
}

type SessionAttrNode struct {
	Node
	Size int
}

func (an *SessionAttrNode) Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error {
	resp.AttrValid = 200 * time.Millisecond
	an.Attr(&resp.Attr)
	return nil
}

func (an *SessionAttrNode) Attr(a *fuse.Attr) {
	a.Inode = an.ino
	a.Mode = an.mode
	a.Size = an.parent.priv.(SessionProvider).CurrLen()
}

func (an *SessionAttrNode) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	provider := an.parent.priv.(SessionProvider)

	frag, err := provider.Bytes(req.Offset, req.Size)
	if err != nil {
		return fmt.Errorf("GetBytes(%d, %d): %s", req.Offset, req.Size, err)
	}

	an.Size += len(frag)

	resp.Data = frag
	return nil
}

type sessionWriteNode struct {
	AttrNode
}

func newSessionWrite(parent *DirNode) (INode, error) {
	name := "write"
	n := new(sessionWriteNode)
	if err := n.AttrNode.Node.Init(parent, name, nil); err != nil {
		return nil, fmt.Errorf("node.Init('%s': %s", name, err)
	}
	n.Update()
	n.mode = 0222
	return n, nil
}

func (n *sessionWriteNode) Update() {
}

func (n *sessionWriteNode) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
	g, ok := n.parent.priv.(SessionWriter)
	if !ok {
		log.Printf("priv is not SessionWriter")
		return fuse.ENOSYS
	}

	resp.Size = len(req.Data)
	go g.Write(req.Data)

	return nil
}

func (n *sessionWriteNode) Activate() error {
	if n.parent == nil {
		return nil
	}

	return n.parent.addChild(n)
}
<commit_msg>nice formatting<commit_after>// Copyright 2015 Bobby Powers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"log"
	"math"
	"sort"
	"strconv"
	"sync"
	"text/template"
	"time"

	"github.com/bpowers/fuse"
	"github.com/bpowers/slack"
	"golang.org/x/net/context"
)

const defaultMsgTmpl = "{{ts .Timestamp \"Jan 02 15:04:05\"}}\t{{username .}}\t{{.Text}}\n"

type msgSlice []slack.Message

func (p msgSlice) Len() int           { return len(p) }
func (p msgSlice) Less(i, j int) bool { return p[i].Timestamp < p[j].Timestamp }
func (p msgSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

type HistoryFn func(id string, params slack.HistoryParameters) (*slack.History, error)

type Session struct {
	// set in SessionInit, immutable after
	history HistoryFn
	id      string
	conn    *FSConn
	fns     template.FuncMap

	sync.Cond
	mu sync.Mutex

	// everything below here must be accessed with Session.L held.

	acks map[int]struct{} // waiting for websocket acks

	// When any of the below are changed, Broadcast is called on
	// cond.

	initialized bool
	formatted   bytes.Buffer
	newestTs    string // most recent timestamp
}

func SessionInit(s *Session, id string, conn *FSConn, history HistoryFn) {
	s.L = &s.mu
	s.history = history
	s.id = id
	s.conn = conn
	s.acks = make(map[int]struct{})

	s.fns = template.FuncMap{
		"username": func(msg *slack.Message) (string, error) {
			u := s.conn.users.Get(msg.UserId)
			if u == nil {
				return fmt.Sprintf("<unknown|%s>", msg.UserId), nil
			}
			return u.Name, nil
		},
		"ts": func(ts, layout string) (string, error) {
			secs, err := strconv.ParseFloat(ts, 64)
			if err != nil {
				log.Printf("ParseFloat(%s): %s", ts, err)
				return ts, nil
			}
			sec := int64(secs)
			nsec := int64(1000000000 * (secs - math.Floor(secs)))
			t := time.Unix(sec, nsec)
			return t.Format(layout), nil
		},
	}
}

func (s *Session) CurrLen() uint64 {
	s.L.Lock()
	defer s.L.Unlock()
	for !s.initialized {
		s.Wait()
	}
	return uint64(s.formatted.Len())
}

func (s *Session) Bytes(offset int64, size int) ([]byte, error) {
	s.L.Lock()
	defer s.L.Unlock()
	for !s.initialized {
		s.Wait()
	}
	if offset != 0 {
		log.Printf("TODO: read w/ offset not implemented yet")
		return nil, fuse.EIO
	}
	bytes := s.formatted.Bytes()
	if len(bytes) > size {
		bytes = bytes[:size]
	}
	return bytes, nil
}

func (s *Session) Write(msg []byte) error {
	msg = bytes.TrimSpace(msg)
	id := s.id
	out := s.conn.ws.NewOutgoingMessage(string(msg), id)

	// record our websocket-message ID so that we know what to do
	// when the server acknowledges receipt
	s.L.Lock()
	s.acks[out.Id] = struct{}{}
	s.L.Unlock()

	err := s.conn.ws.SendMessage(out)
	if err != nil {
		log.Printf("SendMessage: %s", err)
	}

	return nil
}

func (s *Session) Event(evt slack.SlackEvent) bool {
	switch msg := evt.Data.(type) {
	case slack.AckMessage:
		s.L.Lock()
		_, ok := s.acks[msg.ReplyTo]
		delete(s.acks, msg.ReplyTo)
		s.L.Unlock()
		if !ok {
			return false
		}
		if err := s.FetchHistory(msg.Timestamp, true); err != nil {
			log.Printf("'%s'.FetchHistory() 2: %s", s.id, err)
		}
		return true

	case *slack.MessageEvent:
		if msg.ChannelId != s.id {
			log.Printf("error: bad routing on %s for %#v", s.id, msg)
			return false
		}
		s.addMessage((*slack.Message)(msg))
		return true
	}

	return false
}

// must be called with s.L held
func (s *Session) formatMsg(msg *slack.Message) error {
	t := template.Must(template.New("msg").Funcs(s.fns).Parse(defaultMsgTmpl))
	return t.Execute(&s.formatted, msg)
}

func (s *Session) FetchHistory(oldest string, inclusive bool) error {
	h, err := s.history(s.id, slack.HistoryParameters{
		Oldest:    oldest,
		Count:     1000,
		Inclusive: inclusive,
	})
	if err != nil {
		return fmt.Errorf("GetHistory(%s): %s", s.id, err)
	}

	if h.HasMore {
		log.Printf("TODO: we need to page/fetch more messages")
	}

	sort.Sort(msgSlice(h.Messages))

	s.L.Lock()
	defer s.L.Unlock()

	for _, msg := range h.Messages {
		err := s.formatMsg(&msg)
		if err != nil {
			log.Printf("formatMsg(%#v): %s", msg, err)
		}
	}
	s.newestTs = h.Messages[len(h.Messages)-1].Timestamp
	s.initialized = true

	s.Broadcast()

	return nil
}

func (s *Session) addMessage(msg *slack.Message) error {
	s.L.Lock()
	defer s.L.Unlock()
	// don't add messages from the websocket until after we've
	// initialized history.
	for !s.initialized {
		log.Printf("waiting to init before recording msg %s", msg.Text)
		s.Wait()
	}
	if msg.Timestamp <= s.newestTs {
		log.Printf("dropping WS message %s (%s) because it is too old", msg.Timestamp, msg.Text)
		return nil
	}

	err := s.formatMsg(msg)
	if err != nil {
		log.Printf("formatMsg(%#v): %s", msg, err)
		return nil
	}
	s.newestTs = msg.Timestamp

	s.Broadcast()

	return nil
}

func newSession(parent *DirNode) (INode, error) {
	name := "session"
	n := new(SessionAttrNode)
	if err := n.Node.Init(parent, name, nil); err != nil {
		return nil, fmt.Errorf("node.Init('%s': %s", name, err)
	}
	n.mode = 0444
	return n, nil
}

func (an *SessionAttrNode) Activate() error {
	if an.parent == nil {
		return nil
	}

	return an.parent.addChild(an)
}

func (an *SessionAttrNode) DirentType() fuse.DirentType {
	return fuse.DT_File
}

func (an *SessionAttrNode) IsDir() bool {
	return false
}

type SessionProvider interface {
	CurrLen() uint64
	Bytes(offset int64, size int) ([]byte, error)
}

type SessionWriter interface {
	Write([]byte) error
}

type SessionAttrNode struct {
	Node
	Size int
}

func (an *SessionAttrNode) Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error {
	resp.AttrValid = 200 * time.Millisecond
	an.Attr(&resp.Attr)
	return nil
}

func (an *SessionAttrNode) Attr(a *fuse.Attr) {
	a.Inode = an.ino
	a.Mode = an.mode
	a.Size = an.parent.priv.(SessionProvider).CurrLen()
}

func (an *SessionAttrNode) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	provider := an.parent.priv.(SessionProvider)

	frag, err := provider.Bytes(req.Offset, req.Size)
	if err != nil {
		return fmt.Errorf("GetBytes(%d, %d): %s", req.Offset, req.Size, err)
	}

	an.Size += len(frag)

	resp.Data = frag
	return nil
}

type sessionWriteNode struct {
	AttrNode
}

func newSessionWrite(parent *DirNode) (INode, error) {
	name := "write"
	n := new(sessionWriteNode)
	if err := n.AttrNode.Node.Init(parent, name, nil); err != nil {
		return nil, fmt.Errorf("node.Init('%s': %s", name, err)
	}
	n.Update()
	n.mode = 0222
	return n, nil
}

func (n *sessionWriteNode) Update() {
}

func (n *sessionWriteNode) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
	g, ok := n.parent.priv.(SessionWriter)
	if !ok {
		log.Printf("priv is not SessionWriter")
		return fuse.ENOSYS
	}

	resp.Size = len(req.Data)
	go g.Write(req.Data)

	return nil
}

func (n *sessionWriteNode) Activate() error {
	if n.parent == nil {
		return nil
	}

	return n.parent.addChild(n)
}
<|endoftext|>


<commit_before>// session.go - mixnet session client
// Copyright (C) 2017  Yawning Angel, Ruben Pollan, David Stainton
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Package client provides the Katzenpost midclient
package client

import (
	"errors"
	"fmt"

	"github.com/katzenpost/core/crypto/ecdh"
	"github.com/katzenpost/core/log"
	"github.com/katzenpost/core/sphinx/constants"
	"github.com/katzenpost/minclient"
	"github.com/katzenpost/minclient/block"
	"github.com/op/go-logging"
)

// MessageIDLength is the length of a message ID
const MessageIDLength = 24

// MessageConsumer is an interface used for
// processing received messages
type MessageConsumer interface {
	ReceivedMessage(message []byte)
	ReceivedACK(messageID *[MessageIDLength]byte, message []byte)
}

// Session holds the client session
type Session struct {
	client          *minclient.Client
	queue           chan string
	log             *logging.Logger
	logBackend      *log.Backend
	messageConsumer MessageConsumer
	connected       chan bool
}

// NewSession stablishes a session with provider using key
func (client *Client) NewSession(user, provider string, linkKeyPriv *ecdh.PrivateKey, consumer MessageConsumer) (*Session, error) {
	var err error
	session := new(Session)
	clientCfg := &minclient.ClientConfig{
		User:       user,
		Provider:   provider,
		LinkKey:    linkKeyPriv,
		LogBackend: client.logBackend,
		PKIClient:  client.cfg.PKIClient,
		OnConnFn:   session.onConnection,
		//OnEmptyFn:   session.onEmpty,
		OnMessageFn: session.onMessage,
		OnACKFn:     session.onACK,
	}
	session.connected = make(chan bool, 1)
	session.messageConsumer = consumer
	session.client, err = minclient.New(clientCfg)
	if err != nil {
		return nil, err
	}
	session.log = client.logBackend.GetLogger(fmt.Sprintf("%s@%s_session", user, provider))
	return session, nil
}

// Shutdown the session
func (s *Session) Shutdown() {
	s.client.Shutdown()
}

func (s *Session) WaitForConnection() error {
	isConnected := <-s.connected
	if !isConnected {
		return errors.New("status is not connected even with status change")
	}
	return nil
}

// Send reliably delivers the message to the recipient's queue
// on the destination provider or returns an error
func (s *Session) Send(recipient, provider string, message []byte) (*[MessageIDLength]byte, error) {
	s.log.Debugf("Send")
	return nil, errors.New("Failure: Send is not yet implemented.")
}

// SendUnreliable unreliably sends a message to the recipient's queue
// on the destination provider or returns an error
func (c *Session) SendUnreliable(recipient, provider string, message []byte) error {
	c.log.Debugf("SendUnreliable")
	fragment := [block.BlockCiphertextLength]byte{}
	if len(message) < block.BlockCiphertextLength {
		copy(fragment[:], message)
	} else {
		return errors.New("Failure: fragmentation not yet implemented.")
	}
	return c.client.SendUnreliableCiphertext(recipient, provider, fragment[:])
}

// OnConnection will be called by the minclient api
// upon connecting to the Provider
func (s *Session) onConnection(isConnected bool) {
	s.log.Debugf("OnConnection")
	s.connected <- isConnected
}

// OnMessage will be called by the minclient api
// upon receiving a message
func (s *Session) onMessage(message []byte) error {
	s.log.Debugf("OnMessage")
	s.messageConsumer.ReceivedMessage(message)
	return nil
}

// OnACK is called by the minclient api whe
// we receive an ACK message
func (s *Session) onACK(surbid *[constants.SURBIDLength]byte, message []byte) error {
	s.log.Debugf("OnACK")
	return nil
}
<commit_msg>Teach NewSession to block until connected<commit_after>// session.go - mixnet session client
// Copyright (C) 2017  Yawning Angel, Ruben Pollan, David Stainton
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Package client provides the Katzenpost midclient
package client

import (
	"errors"
	"fmt"

	"github.com/katzenpost/core/crypto/ecdh"
	"github.com/katzenpost/core/log"
	"github.com/katzenpost/core/sphinx/constants"
	"github.com/katzenpost/minclient"
	"github.com/katzenpost/minclient/block"
	"github.com/op/go-logging"
)

// MessageIDLength is the length of a message ID
const MessageIDLength = 24

// MessageConsumer is an interface used for
// processing received messages
type MessageConsumer interface {
	ReceivedMessage(message []byte)
	ReceivedACK(messageID *[MessageIDLength]byte, message []byte)
}

// Session holds the client session
type Session struct {
	client          *minclient.Client
	queue           chan string
	log             *logging.Logger
	logBackend      *log.Backend
	messageConsumer MessageConsumer
	connected       chan bool
}

// NewSession stablishes a session with provider using key.
// This method will block until session is connected to the Provider.
func (client *Client) NewSession(user, provider string, linkKeyPriv *ecdh.PrivateKey, consumer MessageConsumer) (*Session, error) {
	var err error
	session := new(Session)
	clientCfg := &minclient.ClientConfig{
		User:       user,
		Provider:   provider,
		LinkKey:    linkKeyPriv,
		LogBackend: client.logBackend,
		PKIClient:  client.cfg.PKIClient,
		OnConnFn:   session.onConnection,
		//OnEmptyFn:   session.onEmpty,
		OnMessageFn: session.onMessage,
		OnACKFn:     session.onACK,
	}
	session.connected = make(chan bool, 0)
	session.messageConsumer = consumer
	session.log = client.logBackend.GetLogger(fmt.Sprintf("%s@%s_session", user, provider))
	session.client, err = minclient.New(clientCfg)
	if err != nil {
		return nil, err
	}
	err = session.waitForConnection()
	if err != nil {
		return nil, err
	}
	return session, nil
}

// Shutdown the session
func (s *Session) Shutdown() {
	s.client.Shutdown()
}

// waitForConnection blocks until the client is
// connected to the Provider
func (s *Session) waitForConnection() error {
	isConnected := <-s.connected
	if !isConnected {
		return errors.New("status is not connected even with status change")
	}
	return nil
}

// Send reliably delivers the message to the recipient's queue
// on the destination provider or returns an error
func (s *Session) Send(recipient, provider string, message []byte) (*[MessageIDLength]byte, error) {
	s.log.Debugf("Send")
	return nil, errors.New("Failure: Send is not yet implemented.")
}

// SendUnreliable unreliably sends a message to the recipient's queue
// on the destination provider or returns an error
func (c *Session) SendUnreliable(recipient, provider string, message []byte) error {
	c.log.Debugf("SendUnreliable")
	fragment := [block.BlockCiphertextLength]byte{}
	if len(message) < block.BlockCiphertextLength {
		copy(fragment[:], message)
	} else {
		return errors.New("Failure: fragmentation not yet implemented.")
	}
	return c.client.SendUnreliableCiphertext(recipient, provider, fragment[:])
}

// OnConnection will be called by the minclient api
// upon connecting to the Provider
func (s *Session) onConnection(isConnected bool) {
	s.log.Debugf("OnConnection")
	s.connected <- isConnected
}

// OnMessage will be called by the minclient api
// upon receiving a message
func (s *Session) onMessage(message []byte) error {
	s.log.Debugf("OnMessage")
	s.messageConsumer.ReceivedMessage(message)
	return nil
}

// OnACK is called by the minclient api whe
// we receive an ACK message
func (s *Session) onACK(surbid *[constants.SURBIDLength]byte, message []byte) error {
	s.log.Debugf("OnACK")
	return nil
}
<|endoftext|>


<commit_before>package main

import "github.com/spf13/cobra"
import "github.com/spf13/viper"
import "fmt"
import "os"
import "net"
import "strconv"

// import "bufio"

func sendToTV(sharpCommand string, sharpParameter string) {

	cmdString := fmt.Sprintf("%4s%-4s\r", sharpCommand, sharpParameter)

	address := viper.GetString("ipaddress")
	port 	  := viper.GetString("port")
	connect_string := fmt.Sprintf("%s:%s",address,port)
	conn, err := net.Dial("tcp", connect_string)

	if err != nil {
		fmt.Println("Error connecting to TV.")
		return
	}

	if viper.GetBool("debug") {
		fmt.Printf("Sending command %v\n", cmdString)
	}

	fmt.Fprintf(conn, cmdString)
	if err != nil {
		fmt.Println("An error occured.")
		fmt.Println(err.Error())
	} else {
		if viper.GetBool("debug") {
			fmt.Printf(">>>> Sent %v\n", cmdString)
		}
	}

	tmp := make([]byte, 256)
	result, err := conn.Read(tmp)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		if viper.GetBool("debug") {
			fmt.Printf(">>>> Received: %s %s\n", tmp, string(result))
		}

	}

}

func main() {

	viper.SetConfigName("config")
	viper.AddConfigPath("$HOME/.sharptv")
	viper.SetDefault("debug", false)
	viper.SetDefault("port", "10002")

	err := viper.ReadInConfig() // Find and read the config file
	if err != nil { // Handle errors reading the config file
    panic(fmt.Errorf("Fatal error config file: %s \n", err))
}

	if viper.GetBool("debug") {
    fmt.Println("debug enabled")
}

	var sharptvCmd = &cobra.Command{
		Use:   "sharptv",
		Short: "sharptv is your command line interface to your television set",
		Long: `sharptv is the main command, used to control your TV

GoSharpTV is a hobbist project by an owner of a Sharp brand TV for other owners
of Sharp brand TVs.  It is implemented in the the Go programming lanugage.

`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("SharpTV command line remote control.")
		},
	}

	var cmdVolume = &cobra.Command{
		Use:   "volume {0..60|up|down}",
		Short: "Set the volume level of the TV.",
		Long: `Adjust the sound volume for the television.

You may find that a lower volume is more pleasant at night.

Examples:

	sharptv volume 0    # Effectively mutes without showing the mute icon
	sharptv volume 25   # Set TV to a little less than half volume.
	sharptv volume 60   # Blast the volume as loud as it will go!
	sharptv volume down # Reduce the volume by owe
    `,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) != 1 {
				cmd.Usage()
				os.Exit(1)
			}

			numerical_argument, err := strconv.Atoi(args[0])
			if err == nil {
				if (numerical_argument > -1 && numerical_argument < 61) {
					fmt.Printf("Setting volume to %v\n", args[0])
					sendToTV("VOLM", args[0])
				} else {
					fmt.Printf("Volume specificed is out of range 0 to 60")
					return
				}
				return
			}

			switch args[0] {

			case "down":
				fmt.Println("Reducing the volume")
				sendToTV("RCKY", "32")

			case "up":
				fmt.Println("Increasing the volume")
				sendToTV("RCKY", "33")

			default:
				cmd.Usage();
			}

		},
	}

	var cmdMute = &cobra.Command{
		Use:   "mute {on|off}",
		Short: "Turn the volume of the TV off or on",
		Long: `Mutes or unmutes the television.  If not subcommand of either "off" or "on" are
    specfified, then the mute will be toggled from it's current state.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch {
			case len(args) > 1:
				cmd.Usage()
			case len(args) == 0:
				fmt.Println("Toggling mute.")
				sendToTV("MUTE", "0000")

			case args[0] == "on":
				fmt.Println("Turning on mute.  This will silence the TV.")
				sendToTV("MUTE", "0001")

			case args[0] == "off":
				fmt.Println("Turning off mute.  This will return TV to the previous volume.")
				sendToTV("MUTE", "0002")

			case args[0] == "status":
				sendToTV("MUTE", "?")

			}
		},
	}

	var cmdPower = &cobra.Command{
		Use:   "power {on|off}",
		Short: "Turn the TV off or on",
		Long: `Powers the TV off or on.  If neither subcommand of either "off" nor "on" are
    specfified, then the power will be toggled from it's current state.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch {
			case len(args) == 0:
				fmt.Println("Toggling Power is not yet implemented.")
			case len(args) > 1:
				cmd.Usage()
			case args[0] == "on":
				fmt.Println("Turning on the TV.")
				sendToTV("POWR", "1")
			case args[0] == "off":
				fmt.Println("Turning off the TV.")
				sendToTV("POWR", "0")
			case args[0] == "status":
				sendToTV("POWR", "?")
			default:
				cmd.Usage()
			}
		},
	}

	var cmdInput = &cobra.Command{
		Use:   "input [TV source input number]",
		Short: "Set the input source",
		Long: `Adjust the input source to be displayed on the TV

    `,
		Run: func(cmd *cobra.Command, args []string) {
			switch {

			case len(args) == 1:
				fmt.Printf("Setting input source to %v\n", args[0])
				sendToTV("IAVD", args[0])

			case len(args) != 1:
				cmd.Usage()
			}
		},
	}
	sharptvCmd.AddCommand(cmdPower)
	sharptvCmd.AddCommand(cmdMute)
	sharptvCmd.AddCommand(cmdInput)
	sharptvCmd.AddCommand(cmdVolume)
		sharptvCmd.Execute()
}
<commit_msg>Configuration file working for ip, port and debug.<commit_after>package main

import "github.com/spf13/cobra"
import "github.com/spf13/viper"
import "fmt"
import "os"
import "net"
import "strconv"

// Flags that are to be added to commands
var ip, port string

func sendToTV(sharpCommand string, sharpParameter string) {

	cmdString := fmt.Sprintf("%4s%-4s\r", sharpCommand, sharpParameter)

	ip = viper.GetString("ip")
	port = viper.GetString("port")

	connect_string := fmt.Sprintf("%s:%s", ip, port)
	if viper.GetBool("debug") {
		fmt.Printf("Connecting to TV at %s\n", connect_string)
	}
	conn, err := net.Dial("tcp", connect_string)

	if err != nil {
		fmt.Println("Error connecting to TV.")
		return
	}

	if viper.GetBool("debug") {
		fmt.Printf("Sending command %v\n", cmdString)
	}

	fmt.Fprintf(conn, cmdString)
	if err != nil {
		fmt.Println("An error occured.")
		fmt.Println(err.Error())
	} else {
		if viper.GetBool("debug") {
			fmt.Printf(">>>> Sent %v\n", cmdString)
		}
	}

	tmp := make([]byte, 256)
	result, err := conn.Read(tmp)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		if viper.GetBool("debug") {
			fmt.Printf(">>>> Received: %s %s\n", tmp, string(result))
		}

	}
}

func main() {

	var sharptvCmd = &cobra.Command{
		Use:   "sharptv",
		Short: "sharptv is your command line interface to your television set",
		Long: `sharptv is the main command, used to control your TV

GoSharpTV is a hobbist project by an owner of a Sharp brand TV for other owners
of Sharp brand TVs.  It is implemented in the the Go programming lanugage.

`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("SharpTV command line remote control.")
		},
	}
	viper.SetConfigName("config")
	viper.AddConfigPath("$HOME/.sharptv")
	viper.SetDefault("debug", false)

	// sharptvCmd.PersistentFlags().StringVarP(&port, "port", "p", "10003", "Port for TV API. Defaults to 10002")
	// viper.BindPFlag("port", sharptvCmd.Flags().Lookup("port"))
	//
	// sharptvCmd.PersistentFlags().StringVar(&ip, "ip", "television ip address", "IP address for TV API.")
	// viper.BindPFlag("ip", sharptvCmd.Flags().Lookup("ip"))

	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	if viper.GetBool("debug") {
		fmt.Println("debug enabled")
	}

	var cmdVolume = &cobra.Command{
		Use:   "volume {0..60|up|down}",
		Short: "Set the volume level of the TV.",
		Long: `Adjust the sound volume for the television.

You may find that a lower volume is more pleasant at night.

Examples:

	sharptv volume 0    # Effectively mutes without showing the mute icon
	sharptv volume 25   # Set TV to a little less than half volume.
	sharptv volume 60   # Blast the volume as loud as it will go!
	sharptv volume down # Reduce the volume by owe
    `,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) != 1 {
				cmd.Usage()
				os.Exit(1)
			}

			numerical_argument, err := strconv.Atoi(args[0])
			if err == nil {
				if numerical_argument > -1 && numerical_argument < 61 {
					fmt.Printf("Setting volume to %v\n", args[0])
					sendToTV("VOLM", args[0])
				} else {
					fmt.Printf("Volume specificed is out of range 0 to 60")
					return
				}
				return
			}

			switch args[0] {

			case "down":
				fmt.Println("Reducing the volume")
				sendToTV("RCKY", "32")

			case "up":
				fmt.Println("Increasing the volume")
				sendToTV("RCKY", "33")

			default:
				cmd.Usage()
			}

		},
	}

	var cmdMute = &cobra.Command{
		Use:   "mute {on|off}",
		Short: "Turn the volume of the TV off or on",
		Long: `Mutes or unmutes the television.  If not subcommand of either "off" or "on" are
    specfified, then the mute will be toggled from it's current state.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch {
			case len(args) > 1:
				cmd.Usage()
			case len(args) == 0:
				fmt.Println("Toggling mute.")
				sendToTV("MUTE", "0000")

			case args[0] == "on":
				fmt.Println("Turning on mute.  This will silence the TV.")
				sendToTV("MUTE", "0001")

			case args[0] == "off":
				fmt.Println("Turning off mute.  This will return TV to the previous volume.")
				sendToTV("MUTE", "0002")

			case args[0] == "status":
				sendToTV("MUTE", "?")

			}
		},
	}

	var cmdPower = &cobra.Command{
		Use:   "power {on|off}",
		Short: "Turn the TV off or on",
		Long: `Powers the TV off or on.  If neither subcommand of either "off" nor "on" are
    specfified, then the power will be toggled from it's current state.`,
		Run: func(cmd *cobra.Command, args []string) {
			switch {
			case len(args) == 0:
				fmt.Println("Toggling Power is not yet implemented.")
			case len(args) > 1:
				cmd.Usage()
			case args[0] == "on":
				fmt.Println("Turning on the TV.")
				sendToTV("POWR", "1")
			case args[0] == "off":
				fmt.Println("Turning off the TV.")
				sendToTV("POWR", "0")
			case args[0] == "status":
				sendToTV("POWR", "?")
			default:
				cmd.Usage()
			}
		},
	}

	var cmdInput = &cobra.Command{
		Use:   "input [TV source input number]",
		Short: "Set the input source",
		Long: `Adjust the input source to be displayed on the TV

    `,
		Run: func(cmd *cobra.Command, args []string) {
			switch {

			case len(args) == 1:
				fmt.Printf("Setting input source to %v\n", args[0])
				sendToTV("IAVD", args[0])

			case len(args) != 1:
				cmd.Usage()
			}
		},
	}

	sharptvCmd.AddCommand(cmdPower)
	sharptvCmd.AddCommand(cmdMute)
	sharptvCmd.AddCommand(cmdInput)
	sharptvCmd.AddCommand(cmdVolume)
	sharptvCmd.Execute()
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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 localdisk registers the "filesystem" blobserver storage type,
storing blobs in a forest of sharded directories at the specified root.

Example low-level config:

     "/storage/": {
         "handler": "storage-filesystem",
         "handlerArgs": {
            "path": "/var/camlistore/blobs"
          }
     },

*/
package localdisk

import (
	"fmt"
	"io"
	"os"
	"regexp"
	"sync"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/blobserver"
	"camlistore.org/pkg/jsonconfig"
	"camlistore.org/pkg/types"
)

// DiskStorage implements the blobserver.Storage interface using the
// local filesystem.
type DiskStorage struct {
	root string

	// the sub-partition (queue) to write to / read from, or "" for none.
	partition string

	// queue partitions to mirror new blobs into (when partition
	// above is the empty string)
	mirrorPartitions []*DiskStorage

	// dirLockMu must be held for writing when deleting an empty directory
	// and for read when receiving blobs.
	dirLockMu sync.RWMutex
}

// New returns a new local disk storage implementation at the provided
// root directory, which must already exist.
func New(root string) (*DiskStorage, error) {
	// Local disk.
	fi, err := os.Stat(root)
	if os.IsNotExist(err) {
		return nil, fmt.Errorf("Storage root %q doesn't exist", root)
	}
	if err != nil {
		return nil, fmt.Errorf("Failed to stat directory %q: %v", root, err)
	}
	if !fi.IsDir() {
		return nil, fmt.Errorf("Storage root %q exists but is not a directory.", root)
	}
	ds := &DiskStorage{
		root: root,
	}
	if _, _, err := ds.StorageGeneration(); err != nil {
		return nil, fmt.Errorf("Error initialization generation for %q: %v", root, err)
	}
	return ds, nil
}

func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (storage blobserver.Storage, err error) {
	path := config.RequiredString("path")
	if err := config.Validate(); err != nil {
		return nil, err
	}
	return New(path)
}

func init() {
	blobserver.RegisterStorageConstructor("filesystem", blobserver.StorageConstructor(newFromConfig))
}

var validQueueName = regexp.MustCompile(`^[a-zA-Z0-9\-\_]+$`)

func (ds *DiskStorage) tryRemoveDir(dir string) {
	ds.dirLockMu.Lock()
	defer ds.dirLockMu.Unlock()
	os.Remove(dir) // ignore error
}

func (ds *DiskStorage) CreateQueue(name string) (blobserver.Storage, error) {
	if !validQueueName.MatchString(name) {
		return nil, fmt.Errorf("invalid queue name %q", name)
	}
	if ds.partition != "" {
		return nil, fmt.Errorf("can't create queue %q on existing queue %q",
			name, ds.partition)
	}
	q := &DiskStorage{
		root:      ds.root,
		partition: "queue-" + name,
	}
	baseDir := ds.PartitionRoot(q.partition)
	if err := os.MkdirAll(baseDir, 0700); err != nil {
		return nil, fmt.Errorf("failed to create queue base dir: %v", err)
	}

	ds.mirrorPartitions = append(ds.mirrorPartitions, q)
	return q, nil
}

func (ds *DiskStorage) FetchStreaming(blob blob.Ref) (io.ReadCloser, int64, error) {
	return ds.Fetch(blob)
}

func (ds *DiskStorage) Fetch(blob blob.Ref) (types.ReadSeekCloser, int64, error) {
	fileName := ds.blobPath("", blob)
	stat, err := os.Stat(fileName)
	if os.IsNotExist(err) {
		return nil, 0, os.ErrNotExist
	}
	file, err := os.Open(fileName)
	if err != nil {
		if os.IsNotExist(err) {
			err = os.ErrNotExist
		}
		return nil, 0, err
	}
	return file, stat.Size(), nil
}

func (ds *DiskStorage) RemoveBlobs(blobs []blob.Ref) error {
	for _, blob := range blobs {
		fileName := ds.blobPath(ds.partition, blob)
		err := os.Remove(fileName)
		switch {
		case err == nil:
			continue
		case os.IsNotExist(err):
			// deleting already-deleted file; harmless.
			continue
		default:
			return err
		}
	}
	return nil
}
<commit_msg>localdisk: another attempt at fixing Mkdir/Rmdir locking for Issue 177<commit_after>/*
Copyright 2011 Google Inc.

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 localdisk registers the "filesystem" blobserver storage type,
storing blobs in a forest of sharded directories at the specified root.

Example low-level config:

     "/storage/": {
         "handler": "storage-filesystem",
         "handlerArgs": {
            "path": "/var/camlistore/blobs"
          }
     },

*/
package localdisk

import (
	"fmt"
	"io"
	"os"
	"regexp"
	"sync"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/blobserver"
	"camlistore.org/pkg/jsonconfig"
	"camlistore.org/pkg/types"
)

// DiskStorage implements the blobserver.Storage interface using the
// local filesystem.
type DiskStorage struct {
	root string

	// the sub-partition (queue) to write to / read from, or "" for none.
	partition string

	// queue partitions to mirror new blobs into (when partition
	// above is the empty string)
	mirrorPartitions []*DiskStorage

	// dirLockMu must be held for writing when deleting an empty directory
	// and for read when receiving blobs.
	// The same lock is shared between queues created from a parent,
	// since they interact with overlapping sets of directories.
	dirLockMu *sync.RWMutex
}

// New returns a new local disk storage implementation at the provided
// root directory, which must already exist.
func New(root string) (*DiskStorage, error) {
	// Local disk.
	fi, err := os.Stat(root)
	if os.IsNotExist(err) {
		return nil, fmt.Errorf("Storage root %q doesn't exist", root)
	}
	if err != nil {
		return nil, fmt.Errorf("Failed to stat directory %q: %v", root, err)
	}
	if !fi.IsDir() {
		return nil, fmt.Errorf("Storage root %q exists but is not a directory.", root)
	}
	ds := &DiskStorage{
		root:      root,
		dirLockMu: new(sync.RWMutex),
	}
	if _, _, err := ds.StorageGeneration(); err != nil {
		return nil, fmt.Errorf("Error initialization generation for %q: %v", root, err)
	}
	return ds, nil
}

func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (storage blobserver.Storage, err error) {
	path := config.RequiredString("path")
	if err := config.Validate(); err != nil {
		return nil, err
	}
	return New(path)
}

func init() {
	blobserver.RegisterStorageConstructor("filesystem", blobserver.StorageConstructor(newFromConfig))
}

var validQueueName = regexp.MustCompile(`^[a-zA-Z0-9\-\_]+$`)

func (ds *DiskStorage) tryRemoveDir(dir string) {
	ds.dirLockMu.Lock()
	defer ds.dirLockMu.Unlock()
	os.Remove(dir) // ignore error
}

func (ds *DiskStorage) CreateQueue(name string) (blobserver.Storage, error) {
	if !validQueueName.MatchString(name) {
		return nil, fmt.Errorf("invalid queue name %q", name)
	}
	if ds.partition != "" {
		return nil, fmt.Errorf("can't create queue %q on existing queue %q",
			name, ds.partition)
	}
	q := &DiskStorage{
		root:      ds.root,
		partition: "queue-" + name,
		dirLockMu: ds.dirLockMu, // see comment on DiskStorage type
	}
	baseDir := ds.PartitionRoot(q.partition)
	if err := os.MkdirAll(baseDir, 0700); err != nil {
		return nil, fmt.Errorf("failed to create queue base dir: %v", err)
	}

	ds.mirrorPartitions = append(ds.mirrorPartitions, q)
	return q, nil
}

func (ds *DiskStorage) FetchStreaming(blob blob.Ref) (io.ReadCloser, int64, error) {
	return ds.Fetch(blob)
}

func (ds *DiskStorage) Fetch(blob blob.Ref) (types.ReadSeekCloser, int64, error) {
	fileName := ds.blobPath("", blob)
	stat, err := os.Stat(fileName)
	if os.IsNotExist(err) {
		return nil, 0, os.ErrNotExist
	}
	file, err := os.Open(fileName)
	if err != nil {
		if os.IsNotExist(err) {
			err = os.ErrNotExist
		}
		return nil, 0, err
	}
	return file, stat.Size(), nil
}

func (ds *DiskStorage) RemoveBlobs(blobs []blob.Ref) error {
	for _, blob := range blobs {
		fileName := ds.blobPath(ds.partition, blob)
		err := os.Remove(fileName)
		switch {
		case err == nil:
			continue
		case os.IsNotExist(err):
			// deleting already-deleted file; harmless.
			continue
		default:
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package namesgenerator

import (
	"fmt"
	"math/rand"
	"time"
)

type NameChecker interface {
	Exists(name string) bool
}

var (
	left = [...]string{"happy", "jolly", "dreamy", "sad", "angry", "pensive", "focused", "sleepy", "grave", "distracted", "determined", "stoic", "stupefied", "sharp", "agitated", "cocky", "tender", "goofy", "furious", "desperate", "hopeful", "compassionate", "silly", "lonely", "condescending", "naughty", "kickass", "drunk", "boring", "nostalgic", "ecstatic", "insane", "cranky", "mad", "jovial", "sick", "hungry", "thirsty", "elegant", "backstabbing", "clever", "trusting", "loving", "suspicious", "berserk", "high", "romantic", "prickly", "evil"}
	// Docker 0.7.x generates names from notable scientists and hackers.
	//
	// Ada Lovelace invented the first algorithm. http://en.wikipedia.org/wiki/Ada_Lovelace (thanks James Turnbull)
	// Ada Yonath - an Israeli crystallographer, the first woman from the Middle East to win a Nobel prize in the sciences. http://en.wikipedia.org/wiki/Ada_Yonath
	// Adele Goldstine, born Adele Katz, wrote the complete technical description for the first electronic digital computer, ENIAC. http://en.wikipedia.org/wiki/Adele_Goldstine
	// Alan Turing was a founding father of computer science. http://en.wikipedia.org/wiki/Alan_Turing.
	// Albert Einstein invented the general theory of relativity. http://en.wikipedia.org/wiki/Albert_Einstein
	// Ambroise Pare invented modern surgery. http://en.wikipedia.org/wiki/Ambroise_Par%C3%A9
	// Archimedes was a physicist, engineer and mathematician who invented too many things to list them here. http://en.wikipedia.org/wiki/Archimedes
	// Barbara McClintock - a distinguished American cytogeneticist, 1983 Nobel Laureate in Physiology or Medicine for discovering transposons. http://en.wikipedia.org/wiki/Barbara_McClintock
	// Benjamin Franklin is famous for his experiments in electricity and the invention of the lightning rod.
	// Charles Babbage invented the concept of a programmable computer. http://en.wikipedia.org/wiki/Charles_Babbage.
	// Charles Darwin established the principles of natural evolution. http://en.wikipedia.org/wiki/Charles_Darwin.
	// Dennis Ritchie and Ken Thompson created UNIX and the C programming language. http://en.wikipedia.org/wiki/Dennis_Ritchie http://en.wikipedia.org/wiki/Ken_Thompson
	// Douglas Engelbart gave the mother of all demos: http://en.wikipedia.org/wiki/Douglas_Engelbart
	// Elizabeth Blackwell - American doctor and first American woman to receive a medical degree - http://en.wikipedia.org/wiki/Elizabeth_Blackwell
	// Emmett Brown invented time travel. http://en.wikipedia.org/wiki/Emmett_Brown (thanks Brian Goff)
	// Enrico Fermi invented the first nuclear reactor. http://en.wikipedia.org/wiki/Enrico_Fermi.
	// Erna Schneider Hoover revolutionized modern communication by inventing a computerized telephon switching method. http://en.wikipedia.org/wiki/Erna_Schneider_Hoover
	// Euclid invented geometry. http://en.wikipedia.org/wiki/Euclid
	// Françoise Barré-Sinoussi - French virologist and Nobel Prize Laureate in Physiology or Medicine; her work was fundamental in identifying HIV as the cause of AIDS. http://en.wikipedia.org/wiki/Fran%C3%A7oise_Barr%C3%A9-Sinoussi
	// Galileo was a founding father of modern astronomy, and faced politics and obscurantism to establish scientific truth.  http://en.wikipedia.org/wiki/Galileo_Galilei
	// Gertrude Elion - American biochemist, pharmacologist and the 1988 recipient of the Nobel Prize in Medicine - http://en.wikipedia.org/wiki/Gertrude_Elion
	// Grace Hopper developed the first compiler for a computer programming language and  is credited with popularizing the term "debugging" for fixing computer glitches. http://en.wikipedia.org/wiki/Grace_Hopper
	// Henry Poincare made fundamental contributions in several fields of mathematics. http://en.wikipedia.org/wiki/Henri_Poincar%C3%A9
	// Hypatia - Greek Alexandrine Neoplatonist philosopher in Egypt who was one of the earliest mothers of mathematics - http://en.wikipedia.org/wiki/Hypatia
	// Isaac Newton invented classic mechanics and modern optics. http://en.wikipedia.org/wiki/Isaac_Newton
	// Jane Colden - American botanist widely considered the first female American botanist - http://en.wikipedia.org/wiki/Jane_Colden
	// Jane Goodall - British primatologist, ethologist, and anthropologist who is considered to be the world's foremost expert on chimpanzees - http://en.wikipedia.org/wiki/Jane_Goodall
	// Jean Bartik, born Betty Jean Jennings, was one of the original programmers for the ENIAC computer. http://en.wikipedia.org/wiki/Jean_Bartik
	// Jean E. Sammet developed FORMAC, the first widely used computer language for symbolic manipulation of mathematical formulas. http://en.wikipedia.org/wiki/Jean_E._Sammet
	// Johanna Mestorf - German prehistoric archaeologist and first female museum director in Germany - http://en.wikipedia.org/wiki/Johanna_Mestorf
	// John McCarthy invented LISP: http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)
	// June Almeida - Scottish virologist who took the first pictures of the rubella virus - http://en.wikipedia.org/wiki/June_Almeida
	// Karen Spärck Jones came up with the concept of inverse document frequency, which is used in most search engines today. http://en.wikipedia.org/wiki/Karen_Sp%C3%A4rck_Jones
	// Leonardo Da Vinci invented too many things to list here. http://en.wikipedia.org/wiki/Leonardo_da_Vinci.
	// Linus Torvalds invented Linux and Git. http://en.wikipedia.org/wiki/Linus_Torvalds
	// Lise Meitner - Austrian/Swedish physicist who was involved in the discovery of nuclear fission. The element meitnerium is named after her - http://en.wikipedia.org/wiki/Lise_Meitner
	// Louis Pasteur discovered vaccination, fermentation and pasteurization. http://en.wikipedia.org/wiki/Louis_Pasteur.
	// Malcolm McLean invented the modern shipping container: http://en.wikipedia.org/wiki/Malcom_McLean
	// Maria Ardinghelli - Italian translator, mathematician and physicist - http://en.wikipedia.org/wiki/Maria_Ardinghelli
	// Maria Kirch - German astronomer and first woman to discover a comet - http://en.wikipedia.org/wiki/Maria_Margarethe_Kirch
	// Maria Mayer - American theoretical physicist and Nobel laureate in Physics for proposing the nuclear shell model of the atomic nucleus - http://en.wikipedia.org/wiki/Maria_Mayer
	// Marie Curie discovered radioactivity. http://en.wikipedia.org/wiki/Marie_Curie.
	// Marie-Jeanne de Lalande - French astronomer, mathematician and cataloguer of stars - http://en.wikipedia.org/wiki/Marie-Jeanne_de_Lalande
	// Mary Leakey - British paleoanthropologist who discovered the first fossilized Proconsul skull - http://en.wikipedia.org/wiki/Mary_Leakey
	// Muhammad ibn Jābir al-Ḥarrānī al-Battānī was a founding father of astronomy. http://en.wikipedia.org/wiki/Mu%E1%B8%A5ammad_ibn_J%C4%81bir_al-%E1%B8%A4arr%C4%81n%C4%AB_al-Batt%C4%81n%C4%AB
	// Niels Bohr is the father of quantum theory. http://en.wikipedia.org/wiki/Niels_Bohr.
	// Nikola Tesla invented the AC electric system and every gaget ever used by a James Bond villain. http://en.wikipedia.org/wiki/Nikola_Tesla
	// Pierre de Fermat pioneered several aspects of modern mathematics. http://en.wikipedia.org/wiki/Pierre_de_Fermat
	// Rachel Carson - American marine biologist and conservationist, her book Silent Spring and other writings are credited with advancing the global environmental movement. http://en.wikipedia.org/wiki/Rachel_Carson
	// Radia Perlman is a software designer and network engineer and most famous for her invention of the spanning-tree protocol (STP). http://en.wikipedia.org/wiki/Radia_Perlman
	// Richard Feynman was a key contributor to quantum mechanics and particle physics. http://en.wikipedia.org/wiki/Richard_Feynman
	// Rob Pike was a key contributor to Unix, Plan 9, the X graphic system, utf-8, and the Go programming language. http://en.wikipedia.org/wiki/Rob_Pike
	// Rosalind Franklin - British biophysicist and X-ray crystallographer whose research was critical to the understanding of DNA - http://en.wikipedia.org/wiki/Rosalind_Franklin
	// Sophie Kowalevski - Russian mathematician responsible for important original contributions to analysis, differential equations and mechanics - http://en.wikipedia.org/wiki/Sofia_Kovalevskaya
	// Sophie Wilson designed the first Acorn Micro-Computer and the instruction set for ARM processors. http://en.wikipedia.org/wiki/Sophie_Wilson
	// Stephen Hawking pioneered the field of cosmology by combining general relativity and quantum mechanics. http://en.wikipedia.org/wiki/Stephen_Hawking
	// Steve Wozniak invented the Apple I and Apple II. http://en.wikipedia.org/wiki/Steve_Wozniak
	// Werner Heisenberg was a founding father of quantum mechanics. http://en.wikipedia.org/wiki/Werner_Heisenberg
	// William Shockley, Walter Houser Brattain and John Bardeen co-invented the transistor (thanks Brian Goff).
	//	http://en.wikipedia.org/wiki/John_Bardeen
	//	http://en.wikipedia.org/wiki/Walter_Houser_Brattain
	//	http://en.wikipedia.org/wiki/William_Shockley
	right = [...]string{"lovelace", "franklin", "tesla", "einstein", "bohr", "davinci", "pasteur", "nobel", "curie", "darwin", "turing", "ritchie", "torvalds", "pike", "thompson", "wozniak", "galileo", "euclid", "newton", "fermat", "archimedes", "poincare", "heisenberg", "feynman", "hawking", "fermi", "pare", "mccarthy", "engelbart", "babbage", "albattani", "ptolemy", "bell", "wright", "lumiere", "morse", "mclean", "brown", "bardeen", "brattain", "shockley", "goldstine", "hoover", "hopper", "bartik", "sammet", "jones", "perlman", "wilson", "kowalevski", "hypatia", "goodall", "mayer", "elion", "blackwell", "lalande", "kirch", "ardinghelli", "colden", "almeida", "leakey", "meitner", "mestorf", "rosalind", "sinoussi", "carson", "mcmclintock", "yonath"}
)

func GenerateRandomName(checker NameChecker) (string, error) {
	retry := 5
	rand.Seed(time.Now().UnixNano())
	name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
	for checker != nil && checker.Exists(name) && retry > 0 || name == "boring_wozniak" /* Steve Wozniak is not boring */ {
		name = fmt.Sprintf("%s%d", name, rand.Intn(10))
		retry = retry - 1
	}
	if retry == 0 {
		return name, fmt.Errorf("Error generating random name")
	}
	return name, nil
}
<commit_msg>Fix typo in names-generator<commit_after>package namesgenerator

import (
	"fmt"
	"math/rand"
	"time"
)

type NameChecker interface {
	Exists(name string) bool
}

var (
	left = [...]string{"happy", "jolly", "dreamy", "sad", "angry", "pensive", "focused", "sleepy", "grave", "distracted", "determined", "stoic", "stupefied", "sharp", "agitated", "cocky", "tender", "goofy", "furious", "desperate", "hopeful", "compassionate", "silly", "lonely", "condescending", "naughty", "kickass", "drunk", "boring", "nostalgic", "ecstatic", "insane", "cranky", "mad", "jovial", "sick", "hungry", "thirsty", "elegant", "backstabbing", "clever", "trusting", "loving", "suspicious", "berserk", "high", "romantic", "prickly", "evil"}
	// Docker 0.7.x generates names from notable scientists and hackers.
	//
	// Ada Lovelace invented the first algorithm. http://en.wikipedia.org/wiki/Ada_Lovelace (thanks James Turnbull)
	// Ada Yonath - an Israeli crystallographer, the first woman from the Middle East to win a Nobel prize in the sciences. http://en.wikipedia.org/wiki/Ada_Yonath
	// Adele Goldstine, born Adele Katz, wrote the complete technical description for the first electronic digital computer, ENIAC. http://en.wikipedia.org/wiki/Adele_Goldstine
	// Alan Turing was a founding father of computer science. http://en.wikipedia.org/wiki/Alan_Turing.
	// Albert Einstein invented the general theory of relativity. http://en.wikipedia.org/wiki/Albert_Einstein
	// Ambroise Pare invented modern surgery. http://en.wikipedia.org/wiki/Ambroise_Par%C3%A9
	// Archimedes was a physicist, engineer and mathematician who invented too many things to list them here. http://en.wikipedia.org/wiki/Archimedes
	// Barbara McClintock - a distinguished American cytogeneticist, 1983 Nobel Laureate in Physiology or Medicine for discovering transposons. http://en.wikipedia.org/wiki/Barbara_McClintock
	// Benjamin Franklin is famous for his experiments in electricity and the invention of the lightning rod.
	// Charles Babbage invented the concept of a programmable computer. http://en.wikipedia.org/wiki/Charles_Babbage.
	// Charles Darwin established the principles of natural evolution. http://en.wikipedia.org/wiki/Charles_Darwin.
	// Dennis Ritchie and Ken Thompson created UNIX and the C programming language. http://en.wikipedia.org/wiki/Dennis_Ritchie http://en.wikipedia.org/wiki/Ken_Thompson
	// Douglas Engelbart gave the mother of all demos: http://en.wikipedia.org/wiki/Douglas_Engelbart
	// Elizabeth Blackwell - American doctor and first American woman to receive a medical degree - http://en.wikipedia.org/wiki/Elizabeth_Blackwell
	// Emmett Brown invented time travel. http://en.wikipedia.org/wiki/Emmett_Brown (thanks Brian Goff)
	// Enrico Fermi invented the first nuclear reactor. http://en.wikipedia.org/wiki/Enrico_Fermi.
	// Erna Schneider Hoover revolutionized modern communication by inventing a computerized telephon switching method. http://en.wikipedia.org/wiki/Erna_Schneider_Hoover
	// Euclid invented geometry. http://en.wikipedia.org/wiki/Euclid
	// Françoise Barré-Sinoussi - French virologist and Nobel Prize Laureate in Physiology or Medicine; her work was fundamental in identifying HIV as the cause of AIDS. http://en.wikipedia.org/wiki/Fran%C3%A7oise_Barr%C3%A9-Sinoussi
	// Galileo was a founding father of modern astronomy, and faced politics and obscurantism to establish scientific truth.  http://en.wikipedia.org/wiki/Galileo_Galilei
	// Gertrude Elion - American biochemist, pharmacologist and the 1988 recipient of the Nobel Prize in Medicine - http://en.wikipedia.org/wiki/Gertrude_Elion
	// Grace Hopper developed the first compiler for a computer programming language and  is credited with popularizing the term "debugging" for fixing computer glitches. http://en.wikipedia.org/wiki/Grace_Hopper
	// Henry Poincare made fundamental contributions in several fields of mathematics. http://en.wikipedia.org/wiki/Henri_Poincar%C3%A9
	// Hypatia - Greek Alexandrine Neoplatonist philosopher in Egypt who was one of the earliest mothers of mathematics - http://en.wikipedia.org/wiki/Hypatia
	// Isaac Newton invented classic mechanics and modern optics. http://en.wikipedia.org/wiki/Isaac_Newton
	// Jane Colden - American botanist widely considered the first female American botanist - http://en.wikipedia.org/wiki/Jane_Colden
	// Jane Goodall - British primatologist, ethologist, and anthropologist who is considered to be the world's foremost expert on chimpanzees - http://en.wikipedia.org/wiki/Jane_Goodall
	// Jean Bartik, born Betty Jean Jennings, was one of the original programmers for the ENIAC computer. http://en.wikipedia.org/wiki/Jean_Bartik
	// Jean E. Sammet developed FORMAC, the first widely used computer language for symbolic manipulation of mathematical formulas. http://en.wikipedia.org/wiki/Jean_E._Sammet
	// Johanna Mestorf - German prehistoric archaeologist and first female museum director in Germany - http://en.wikipedia.org/wiki/Johanna_Mestorf
	// John McCarthy invented LISP: http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)
	// June Almeida - Scottish virologist who took the first pictures of the rubella virus - http://en.wikipedia.org/wiki/June_Almeida
	// Karen Spärck Jones came up with the concept of inverse document frequency, which is used in most search engines today. http://en.wikipedia.org/wiki/Karen_Sp%C3%A4rck_Jones
	// Leonardo Da Vinci invented too many things to list here. http://en.wikipedia.org/wiki/Leonardo_da_Vinci.
	// Linus Torvalds invented Linux and Git. http://en.wikipedia.org/wiki/Linus_Torvalds
	// Lise Meitner - Austrian/Swedish physicist who was involved in the discovery of nuclear fission. The element meitnerium is named after her - http://en.wikipedia.org/wiki/Lise_Meitner
	// Louis Pasteur discovered vaccination, fermentation and pasteurization. http://en.wikipedia.org/wiki/Louis_Pasteur.
	// Malcolm McLean invented the modern shipping container: http://en.wikipedia.org/wiki/Malcom_McLean
	// Maria Ardinghelli - Italian translator, mathematician and physicist - http://en.wikipedia.org/wiki/Maria_Ardinghelli
	// Maria Kirch - German astronomer and first woman to discover a comet - http://en.wikipedia.org/wiki/Maria_Margarethe_Kirch
	// Maria Mayer - American theoretical physicist and Nobel laureate in Physics for proposing the nuclear shell model of the atomic nucleus - http://en.wikipedia.org/wiki/Maria_Mayer
	// Marie Curie discovered radioactivity. http://en.wikipedia.org/wiki/Marie_Curie.
	// Marie-Jeanne de Lalande - French astronomer, mathematician and cataloguer of stars - http://en.wikipedia.org/wiki/Marie-Jeanne_de_Lalande
	// Mary Leakey - British paleoanthropologist who discovered the first fossilized Proconsul skull - http://en.wikipedia.org/wiki/Mary_Leakey
	// Muhammad ibn Jābir al-Ḥarrānī al-Battānī was a founding father of astronomy. http://en.wikipedia.org/wiki/Mu%E1%B8%A5ammad_ibn_J%C4%81bir_al-%E1%B8%A4arr%C4%81n%C4%AB_al-Batt%C4%81n%C4%AB
	// Niels Bohr is the father of quantum theory. http://en.wikipedia.org/wiki/Niels_Bohr.
	// Nikola Tesla invented the AC electric system and every gaget ever used by a James Bond villain. http://en.wikipedia.org/wiki/Nikola_Tesla
	// Pierre de Fermat pioneered several aspects of modern mathematics. http://en.wikipedia.org/wiki/Pierre_de_Fermat
	// Rachel Carson - American marine biologist and conservationist, her book Silent Spring and other writings are credited with advancing the global environmental movement. http://en.wikipedia.org/wiki/Rachel_Carson
	// Radia Perlman is a software designer and network engineer and most famous for her invention of the spanning-tree protocol (STP). http://en.wikipedia.org/wiki/Radia_Perlman
	// Richard Feynman was a key contributor to quantum mechanics and particle physics. http://en.wikipedia.org/wiki/Richard_Feynman
	// Rob Pike was a key contributor to Unix, Plan 9, the X graphic system, utf-8, and the Go programming language. http://en.wikipedia.org/wiki/Rob_Pike
	// Rosalind Franklin - British biophysicist and X-ray crystallographer whose research was critical to the understanding of DNA - http://en.wikipedia.org/wiki/Rosalind_Franklin
	// Sophie Kowalevski - Russian mathematician responsible for important original contributions to analysis, differential equations and mechanics - http://en.wikipedia.org/wiki/Sofia_Kovalevskaya
	// Sophie Wilson designed the first Acorn Micro-Computer and the instruction set for ARM processors. http://en.wikipedia.org/wiki/Sophie_Wilson
	// Stephen Hawking pioneered the field of cosmology by combining general relativity and quantum mechanics. http://en.wikipedia.org/wiki/Stephen_Hawking
	// Steve Wozniak invented the Apple I and Apple II. http://en.wikipedia.org/wiki/Steve_Wozniak
	// Werner Heisenberg was a founding father of quantum mechanics. http://en.wikipedia.org/wiki/Werner_Heisenberg
	// William Shockley, Walter Houser Brattain and John Bardeen co-invented the transistor (thanks Brian Goff).
	//	http://en.wikipedia.org/wiki/John_Bardeen
	//	http://en.wikipedia.org/wiki/Walter_Houser_Brattain
	//	http://en.wikipedia.org/wiki/William_Shockley
	right = [...]string{"lovelace", "franklin", "tesla", "einstein", "bohr", "davinci", "pasteur", "nobel", "curie", "darwin", "turing", "ritchie", "torvalds", "pike", "thompson", "wozniak", "galileo", "euclid", "newton", "fermat", "archimedes", "poincare", "heisenberg", "feynman", "hawking", "fermi", "pare", "mccarthy", "engelbart", "babbage", "albattani", "ptolemy", "bell", "wright", "lumiere", "morse", "mclean", "brown", "bardeen", "brattain", "shockley", "goldstine", "hoover", "hopper", "bartik", "sammet", "jones", "perlman", "wilson", "kowalevski", "hypatia", "goodall", "mayer", "elion", "blackwell", "lalande", "kirch", "ardinghelli", "colden", "almeida", "leakey", "meitner", "mestorf", "rosalind", "sinoussi", "carson", "mcclintock", "yonath"}
)

func GenerateRandomName(checker NameChecker) (string, error) {
	retry := 5
	rand.Seed(time.Now().UnixNano())
	name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
	for checker != nil && checker.Exists(name) && retry > 0 || name == "boring_wozniak" /* Steve Wozniak is not boring */ {
		name = fmt.Sprintf("%s%d", name, rand.Intn(10))
		retry = retry - 1
	}
	if retry == 0 {
		return name, fmt.Errorf("Error generating random name")
	}
	return name, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Ludovic Fauvet
// Licensed under the MIT license

package filesystem

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	. "github.com/etix/mirrorbits/config"
	"io"
	"os"
)

// Generate a human readable sha1 hash of the given file path
func HashFile(path string) (hashes FileInfo, err error) {
	f, err := os.Open(path)
	if err != nil {
		return
	}
	defer f.Close()

	reader := bufio.NewReader(f)

	if GetConfig().Hashes.SHA1 {
		sha1Hash := sha1.New()
		_, err = io.Copy(sha1Hash, reader)
		if err == nil {
			hashes.Sha1 = hex.EncodeToString(sha1Hash.Sum(nil))
		}
	}
	if GetConfig().Hashes.SHA256 {
		sha256Hash := sha256.New()
		_, err = io.Copy(sha256Hash, reader)
		if err == nil {
			hashes.Sha256 = hex.EncodeToString(sha256Hash.Sum(nil))
		}
	}
	if GetConfig().Hashes.MD5 {
		md5Hash := md5.New()
		_, err = io.Copy(md5Hash, reader)
		if err == nil {
			hashes.Md5 = hex.EncodeToString(md5Hash.Sum(nil))
		}
	}
	return
}
<commit_msg>Fix file hashing using more than one hash method<commit_after>// Copyright (c) 2014-2017 Ludovic Fauvet
// Licensed under the MIT license

package filesystem

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	. "github.com/etix/mirrorbits/config"
	"hash"
	"io"
	"os"
)

// Generate a human readable hash of the given file path
func HashFile(path string) (hashes FileInfo, err error) {
	f, err := os.Open(path)
	if err != nil {
		return
	}
	defer f.Close()

	reader := bufio.NewReader(f)

	var writers []io.Writer

	if GetConfig().Hashes.SHA1 {
		hsha1 := newHasher(sha1.New(), &hashes.Sha1)
		defer hsha1.Close()
		writers = append(writers, hsha1)
	}
	if GetConfig().Hashes.SHA256 {
		hsha256 := newHasher(sha256.New(), &hashes.Sha256)
		defer hsha256.Close()
		writers = append(writers, hsha256)
	}
	if GetConfig().Hashes.MD5 {
		hmd5 := newHasher(md5.New(), &hashes.Md5)
		defer hmd5.Close()
		writers = append(writers, hmd5)
	}

	if len(writers) == 0 {
		return
	}

	w := io.MultiWriter(writers...)

	_, err = io.Copy(w, reader)
	if err != nil {
		return
	}

	return
}

type hasher struct {
	hash.Hash
	output *string
}

func newHasher(hash hash.Hash, output *string) hasher {
	return hasher{
		Hash:   hash,
		output: output,
	}
}

func (h hasher) Close() error {
	*h.output = hex.EncodeToString(h.Sum(nil))
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2019 Jeremy Edwards
//
// 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 filesystem

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/jeremyje/gowebserver/termhook"
)

const fsDirMode = os.FileMode(0777)

type createFsResult struct {
	handler       http.FileSystem
	localFilePath string
	tmpDir        string
	err           error
}

func (r createFsResult) withError(err error) createFsResult {
	r.err = err
	return r
}

func (r createFsResult) withHandler(handler http.FileSystem, err error) createFsResult {
	r.handler = handler
	r.err = err
	return r
}

func createDirectory(path string) error {
	return os.MkdirAll(dirPath(path), fsDirMode)
}

func stageRemoteFile(maybeRemoteFilePath string) createFsResult {
	localFilePath, err := downloadFile(maybeRemoteFilePath)
	if err != nil {
		return createFsResult{err: fmt.Errorf("cannot download file %s, %s", maybeRemoteFilePath, err)}
	}
	tmpDir, err := createTempDirectory()
	if err != nil {
		return createFsResult{err: fmt.Errorf("cannot create temp directory, %s", err)}
	}

	return createFsResult{
		localFilePath: localFilePath,
		tmpDir:        tmpDir,
		err:           nil,
	}
}

func createTempDirectory() (string, error) {
	tmpDir, err := ioutil.TempDir(os.TempDir(), "gowebserver")

	if err != nil {
		return "", fmt.Errorf("cannot create temp directory, %s", err)
	}
	termhook.Add(func() {
		tryDeleteDirectory(tmpDir)
	})
	return tmpDir, nil
}

func tryDeleteDirectory(path string) {
	err := os.RemoveAll(path)
	if err != nil && err != os.ErrNotExist {
		log.Fatalf("cannot delete directory: %s, Error= %v", path, err)
	}
}

func tryDeleteFile(path string) {
	err := os.Remove(path)
	if err != nil && err != os.ErrNotExist {
		log.Fatalf("cannot delete file: %s, Error= %v", path, err)
	}
}

func downloadFile(path string) (string, error) {
	if strings.HasPrefix(strings.ToLower(path), "http") {
		f, err := ioutil.TempFile(os.TempDir(), "gowebserverdl")
		if err != nil {
			return "", err
		}
		defer f.Close()
		resp, err := http.Get(path)
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()
		io.Copy(f, resp.Body)
		return f.Name(), nil
	}
	return path, nil
}

func exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func dirPath(dirPath string) string {
	return strings.TrimRight(dirPath, "/") + "/"
}

func copyFile(reader io.Reader, filePath string) error {
	fsf, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("Cannot create target file %s, %s", filePath, err)
	}
	defer fsf.Close()

	_, err = io.Copy(fsf, reader)
	if err != nil {
		return fmt.Errorf("Cannot copy to target file %s, %s", filePath, err)
	}
	return nil
}
<commit_msg>Fix error handling.<commit_after>// Copyright 2019 Jeremy Edwards
//
// 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 filesystem

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/jeremyje/gowebserver/termhook"
)

const fsDirMode = os.FileMode(0777)

type createFsResult struct {
	handler       http.FileSystem
	localFilePath string
	tmpDir        string
	err           error
}

func (r createFsResult) withError(err error) createFsResult {
	r.err = err
	return r
}

func (r createFsResult) withHandler(handler http.FileSystem, err error) createFsResult {
	r.handler = handler
	r.err = err
	return r
}

func createDirectory(path string) error {
	return os.MkdirAll(dirPath(path), fsDirMode)
}

func stageRemoteFile(maybeRemoteFilePath string) createFsResult {
	localFilePath, err := downloadFile(maybeRemoteFilePath)
	if err != nil {
		return createFsResult{err: fmt.Errorf("cannot download file %s, %s", maybeRemoteFilePath, err)}
	}
	tmpDir, err := createTempDirectory()
	if err != nil {
		return createFsResult{err: fmt.Errorf("cannot create temp directory, %s", err)}
	}

	return createFsResult{
		localFilePath: localFilePath,
		tmpDir:        tmpDir,
		err:           nil,
	}
}

func createTempDirectory() (string, error) {
	tmpDir, err := ioutil.TempDir(os.TempDir(), "gowebserver")

	if err != nil {
		return "", fmt.Errorf("cannot create temp directory, %s", err)
	}
	termhook.Add(func() {
		tryDeleteDirectory(tmpDir)
	})
	return tmpDir, nil
}

func tryDeleteDirectory(path string) {
	if !exists(path) {
		return
	}
	err := os.RemoveAll(path)
	if err != nil && err != os.ErrNotExist {
		log.Printf("cannot delete directory: %s, Error= %v", path, err)
	}
}

func tryDeleteFile(path string) {
	if !exists(path) {
		return
	}
	err := os.Remove(path)
	if err != nil && err != os.ErrNotExist {
		log.Printf("cannot delete file: %s, Error= %v", path, err)
	}
}

func downloadFile(path string) (string, error) {
	if strings.HasPrefix(strings.ToLower(path), "http") {
		f, err := ioutil.TempFile(os.TempDir(), "gowebserverdl")
		if err != nil {
			return "", err
		}
		defer f.Close()
		resp, err := http.Get(path)
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()
		io.Copy(f, resp.Body)
		return f.Name(), nil
	}
	return path, nil
}

func exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func dirPath(dirPath string) string {
	return strings.TrimRight(dirPath, "/") + "/"
}

func copyFile(reader io.Reader, filePath string) error {
	fsf, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("Cannot create target file %s, %s", filePath, err)
	}
	defer fsf.Close()

	_, err = io.Copy(fsf, reader)
	if err != nil {
		return fmt.Errorf("Cannot copy to target file %s, %s", filePath, err)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 filters

import (
	"regexp"

	"github.com/skydive-project/skydive/common"
)

type Getter interface {
	GetField(field string) (interface{}, error)
	GetFieldInt64(field string) (int64, error)
	GetFieldString(field string) (string, error)
}

func (f *Filter) Eval(g Getter) bool {
	if f.BoolFilter != nil {
		return f.BoolFilter.Eval(g)
	}
	if f.TermStringFilter != nil {
		return f.TermStringFilter.Eval(g)
	}
	if f.TermInt64Filter != nil {
		return f.TermInt64Filter.Eval(g)
	}
	if f.GtInt64Filter != nil {
		return f.GtInt64Filter.Eval(g)
	}
	if f.LtInt64Filter != nil {
		return f.LtInt64Filter.Eval(g)
	}
	if f.GteInt64Filter != nil {
		return f.GteInt64Filter.Eval(g)
	}
	if f.LteInt64Filter != nil {
		return f.LteInt64Filter.Eval(g)
	}
	if f.RegexFilter != nil {
		return f.RegexFilter.Eval(g)
	}
	if f.NullFilter != nil {
		return f.NullFilter.Eval(g)
	}
	if f.InInt64Filter != nil {
		return f.InInt64Filter.Eval(g)
	}
	if f.InStringFilter != nil {
		return f.InStringFilter.Eval(g)
	}

	return true
}

func (b *BoolFilter) Eval(g Getter) bool {
	for _, filter := range b.Filters {
		result := filter.Eval(g)
		if b.Op == BoolFilterOp_NOT && !result {
			return true
		}
		if b.Op == BoolFilterOp_AND && !result {
			return false
		} else if b.Op == BoolFilterOp_OR && result {
			return true
		}
	}
	return b.Op == BoolFilterOp_AND || len(b.Filters) == 0
}

func (r *GtInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field > r.Value {
		return true
	}
	return false
}

func (r *LtInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field < r.Value {
		return true
	}
	return false
}

func (r *GteInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field >= r.Value {
		return true
	}
	return false
}

func (r *LteInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field <= r.Value {
		return true
	}
	return false
}

func (t *TermStringFilter) Eval(g Getter) bool {
	field, err := g.GetFieldString(t.Key)
	if err != nil {
		return false
	}

	return field == t.Value
}

func (t *TermInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(t.Key)
	if err != nil {
		return false
	}

	return field == t.Value
}

func (r *RegexFilter) Eval(g Getter) bool {
	field, err := g.GetFieldString(r.Key)
	if err != nil {
		return false
	}
	// TODO: don't compile regex here
	re := regexp.MustCompile(r.Value)
	return re.MatchString(field)
}

func (n *NullFilter) Eval(g Getter) bool {
	if _, err := g.GetFieldString(n.Key); err == nil {
		return false
	}
	if _, err := g.GetFieldInt64(n.Key); err == nil {
		return false
	}
	return true
}

func (i *InInt64Filter) Eval(g Getter) bool {
	field, err := g.GetField(i.Key)
	if err != nil {
		return false
	}
	switch field := field.(type) {
	case []interface{}:
		for _, intf := range field {
			if v, err := common.ToInt64(intf); err == nil && v == i.Value {
				return true
			}
		}
	case []int64:
		for _, v := range field {
			if v == i.Value {
				return true
			}
		}
	}
	return false
}

func (i *InStringFilter) Eval(g Getter) bool {
	field, err := g.GetField(i.Key)
	if err != nil {
		return false
	}
	switch field := field.(type) {
	case []interface{}:
		for _, intf := range field {
			if s, ok := intf.(string); ok && s == i.Value {
				return true
			}
		}
	case []string:
		for _, s := range field {
			if s == i.Value {
				return true
			}
		}
	}
	return false
}

func NewBoolFilter(op BoolFilterOp, filters ...*Filter) *Filter {
	boolFilter := &BoolFilter{
		Op:      op,
		Filters: []*Filter{},
	}

	for _, filter := range filters {
		if filter != nil {
			boolFilter.Filters = append(boolFilter.Filters, filter)
		}
	}

	return &Filter{BoolFilter: boolFilter}
}

func NewAndFilter(filters ...*Filter) *Filter {
	return NewBoolFilter(BoolFilterOp_AND, filters...)
}

func NewOrFilter(filters ...*Filter) *Filter {
	return NewBoolFilter(BoolFilterOp_OR, filters...)
}

func NewNotFilter(filter *Filter) *Filter {
	return NewBoolFilter(BoolFilterOp_NOT, filter)
}

func NewGtInt64Filter(key string, value int64) *Filter {
	return &Filter{GtInt64Filter: &GtInt64Filter{Key: key, Value: value}}
}

func NewGteInt64Filter(key string, value int64) *Filter {
	return &Filter{GteInt64Filter: &GteInt64Filter{Key: key, Value: value}}
}

func NewLtInt64Filter(key string, value int64) *Filter {
	return &Filter{LtInt64Filter: &LtInt64Filter{Key: key, Value: value}}
}

func NewLteInt64Filter(key string, value int64) *Filter {
	return &Filter{LteInt64Filter: &LteInt64Filter{Key: key, Value: value}}
}

func NewTermInt64Filter(key string, value int64) *Filter {
	return &Filter{TermInt64Filter: &TermInt64Filter{Key: key, Value: value}}
}

func NewTermStringFilter(key string, value string) *Filter {
	return &Filter{TermStringFilter: &TermStringFilter{Key: key, Value: value}}
}

func NewInInt64Filter(key string, value int64) *Filter {
	return &Filter{InInt64Filter: &InInt64Filter{Key: key, Value: value}}
}

func NewInStringFilter(key string, value string) *Filter {
	return &Filter{InStringFilter: &InStringFilter{Key: key, Value: value}}
}

func NewNullFilter(key string) *Filter {
	return &Filter{NullFilter: &NullFilter{Key: key}}
}

func NewFilterForIds(uuids []string, attrs ...string) *Filter {
	terms := make([]*Filter, len(uuids)*len(attrs))
	for i, uuid := range uuids {
		for j, attr := range attrs {
			terms[i*len(attrs)+j] = NewTermStringFilter(attr, uuid)
		}
	}
	return NewOrFilter(terms...)
}

// NewFilterActiveIn returns a filter that returns elements that were active
// in the given time range.
func NewFilterActiveIn(fr Range, prefix string) *Filter {
	return NewAndFilter(
		NewLteInt64Filter(prefix+"Start", fr.To),
		NewGteInt64Filter(prefix+"Last", fr.From),
	)
}

// NewFilterIncludedIn returns a filter that returns elements that include in
// the time range.
func NewFilterIncludedIn(fr Range, prefix string) *Filter {
	return NewAndFilter(
		NewGteInt64Filter(prefix+"Start", fr.From),
		NewLteInt64Filter(prefix+"Last", fr.To),
	)
}
<commit_msg>filters: use a lru cache for compiled regular expressions<commit_after>/*
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 filters

import (
	"regexp"
	"time"

	"github.com/pmylund/go-cache"

	"github.com/skydive-project/skydive/common"
)

var regexpCache *cache.Cache

type Getter interface {
	GetField(field string) (interface{}, error)
	GetFieldInt64(field string) (int64, error)
	GetFieldString(field string) (string, error)
}

func (f *Filter) Eval(g Getter) bool {
	if f.BoolFilter != nil {
		return f.BoolFilter.Eval(g)
	}
	if f.TermStringFilter != nil {
		return f.TermStringFilter.Eval(g)
	}
	if f.TermInt64Filter != nil {
		return f.TermInt64Filter.Eval(g)
	}
	if f.GtInt64Filter != nil {
		return f.GtInt64Filter.Eval(g)
	}
	if f.LtInt64Filter != nil {
		return f.LtInt64Filter.Eval(g)
	}
	if f.GteInt64Filter != nil {
		return f.GteInt64Filter.Eval(g)
	}
	if f.LteInt64Filter != nil {
		return f.LteInt64Filter.Eval(g)
	}
	if f.RegexFilter != nil {
		return f.RegexFilter.Eval(g)
	}
	if f.NullFilter != nil {
		return f.NullFilter.Eval(g)
	}
	if f.InInt64Filter != nil {
		return f.InInt64Filter.Eval(g)
	}
	if f.InStringFilter != nil {
		return f.InStringFilter.Eval(g)
	}

	return true
}

func (b *BoolFilter) Eval(g Getter) bool {
	for _, filter := range b.Filters {
		result := filter.Eval(g)
		if b.Op == BoolFilterOp_NOT && !result {
			return true
		}
		if b.Op == BoolFilterOp_AND && !result {
			return false
		} else if b.Op == BoolFilterOp_OR && result {
			return true
		}
	}
	return b.Op == BoolFilterOp_AND || len(b.Filters) == 0
}

func (r *GtInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field > r.Value {
		return true
	}
	return false
}

func (r *LtInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field < r.Value {
		return true
	}
	return false
}

func (r *GteInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field >= r.Value {
		return true
	}
	return false
}

func (r *LteInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(r.Key)
	if err != nil {
		return false
	}

	if field <= r.Value {
		return true
	}
	return false
}

func (t *TermStringFilter) Eval(g Getter) bool {
	field, err := g.GetFieldString(t.Key)
	if err != nil {
		return false
	}

	return field == t.Value
}

func (t *TermInt64Filter) Eval(g Getter) bool {
	field, err := g.GetFieldInt64(t.Key)
	if err != nil {
		return false
	}

	return field == t.Value
}

func (r *RegexFilter) Eval(g Getter) bool {
	field, err := g.GetFieldString(r.Key)
	if err != nil {
		return false
	}
	re, found := regexpCache.Get(r.Value)
	if !found {
		re = regexp.MustCompile(r.Value)
		regexpCache.Set(r.Value, re, cache.DefaultExpiration)
	}
	return re.(*regexp.Regexp).MatchString(field)
}

func (n *NullFilter) Eval(g Getter) bool {
	if _, err := g.GetFieldString(n.Key); err == nil {
		return false
	}
	if _, err := g.GetFieldInt64(n.Key); err == nil {
		return false
	}
	return true
}

func (i *InInt64Filter) Eval(g Getter) bool {
	field, err := g.GetField(i.Key)
	if err != nil {
		return false
	}
	switch field := field.(type) {
	case []interface{}:
		for _, intf := range field {
			if v, err := common.ToInt64(intf); err == nil && v == i.Value {
				return true
			}
		}
	case []int64:
		for _, v := range field {
			if v == i.Value {
				return true
			}
		}
	}
	return false
}

func (i *InStringFilter) Eval(g Getter) bool {
	field, err := g.GetField(i.Key)
	if err != nil {
		return false
	}
	switch field := field.(type) {
	case []interface{}:
		for _, intf := range field {
			if s, ok := intf.(string); ok && s == i.Value {
				return true
			}
		}
	case []string:
		for _, s := range field {
			if s == i.Value {
				return true
			}
		}
	}
	return false
}

func NewBoolFilter(op BoolFilterOp, filters ...*Filter) *Filter {
	boolFilter := &BoolFilter{
		Op:      op,
		Filters: []*Filter{},
	}

	for _, filter := range filters {
		if filter != nil {
			boolFilter.Filters = append(boolFilter.Filters, filter)
		}
	}

	return &Filter{BoolFilter: boolFilter}
}

func NewAndFilter(filters ...*Filter) *Filter {
	return NewBoolFilter(BoolFilterOp_AND, filters...)
}

func NewOrFilter(filters ...*Filter) *Filter {
	return NewBoolFilter(BoolFilterOp_OR, filters...)
}

func NewNotFilter(filter *Filter) *Filter {
	return NewBoolFilter(BoolFilterOp_NOT, filter)
}

func NewGtInt64Filter(key string, value int64) *Filter {
	return &Filter{GtInt64Filter: &GtInt64Filter{Key: key, Value: value}}
}

func NewGteInt64Filter(key string, value int64) *Filter {
	return &Filter{GteInt64Filter: &GteInt64Filter{Key: key, Value: value}}
}

func NewLtInt64Filter(key string, value int64) *Filter {
	return &Filter{LtInt64Filter: &LtInt64Filter{Key: key, Value: value}}
}

func NewLteInt64Filter(key string, value int64) *Filter {
	return &Filter{LteInt64Filter: &LteInt64Filter{Key: key, Value: value}}
}

func NewTermInt64Filter(key string, value int64) *Filter {
	return &Filter{TermInt64Filter: &TermInt64Filter{Key: key, Value: value}}
}

func NewTermStringFilter(key string, value string) *Filter {
	return &Filter{TermStringFilter: &TermStringFilter{Key: key, Value: value}}
}

func NewInInt64Filter(key string, value int64) *Filter {
	return &Filter{InInt64Filter: &InInt64Filter{Key: key, Value: value}}
}

func NewInStringFilter(key string, value string) *Filter {
	return &Filter{InStringFilter: &InStringFilter{Key: key, Value: value}}
}

func NewNullFilter(key string) *Filter {
	return &Filter{NullFilter: &NullFilter{Key: key}}
}

func NewFilterForIds(uuids []string, attrs ...string) *Filter {
	terms := make([]*Filter, len(uuids)*len(attrs))
	for i, uuid := range uuids {
		for j, attr := range attrs {
			terms[i*len(attrs)+j] = NewTermStringFilter(attr, uuid)
		}
	}
	return NewOrFilter(terms...)
}

// NewFilterActiveIn returns a filter that returns elements that were active
// in the given time range.
func NewFilterActiveIn(fr Range, prefix string) *Filter {
	return NewAndFilter(
		NewLteInt64Filter(prefix+"Start", fr.To),
		NewGteInt64Filter(prefix+"Last", fr.From),
	)
}

// NewFilterIncludedIn returns a filter that returns elements that include in
// the time range.
func NewFilterIncludedIn(fr Range, prefix string) *Filter {
	return NewAndFilter(
		NewGteInt64Filter(prefix+"Start", fr.From),
		NewLteInt64Filter(prefix+"Last", fr.To),
	)
}

func init() {
	regexpCache = cache.New(5*time.Minute, 10*time.Minute)
}
<|endoftext|>