<commit_before>package main

import	(
	"os"
	"fmt"
	"crypto/sha512"
	"encoding/hex"
	"hash"
	"path/filepath"
	"flag"
	"net/http"
	"net/url"
	"io/ioutil"
	"log"
	"strconv"
)

type LMVFile struct {
	hash string
	size int64
	name string
}

func CalculateSHA512(str string) string {

	var hasher hash.Hash = sha512.New()

	hasher.Reset()
	hasher.Write([]byte(str))
	return hex.EncodeToString(hasher.Sum(nil))

}

func encode(fp string, token bool) {

	lmv_file := new(LMVFile)

	file, err := os.Open(fp)

    if err != nil {
    	log.Fatal(err)
    }

    defer file.Close()

    stat, err := file.Stat()

    if err != nil {
    	log.Fatal(err)
    }

    bs := make([]byte, stat.Size())
    _, err = file.Read(bs)

    if err != nil {
        log.Fatal(err)
    }

    lmv_file.hash = CalculateSHA512(string(bs))
    lmv_file.size = stat.Size()
    lmv_file.name = filepath.Base(fp)

	if token {

    	upload_address := "http://127.0.0.1:8081/upload"

		fields := make(url.Values)
        fields.Set("name", lmv_file.name)
        fields.Set("hash", lmv_file.hash)
        fields.Set("size", strconv.FormatInt(lmv_file.size, 10))

    	resp, err := http.PostForm(upload_address, fields)

    	if err != nil {
			log.Fatal(err)
		}

		defer resp.Body.Close()

		body, err := ioutil.ReadAll(resp.Body)

		if err != nil {
			log.Fatal(err)
		}

		fmt.Println("'" + lmv_file.name + "'" + " --> " + "'" + string(body) + "'")

	} else {

		os.Create(lmv_file.name + ".lmv")

		full := lmv_file.hash + "\n" + lmv_file.name + "\n" + strconv.FormatInt(lmv_file.size, 10)

		err = ioutil.WriteFile(lmv_file.name + ".lmv", []byte(full), 0644)

		if err != nil {
			log.Fatal(err)
		}

    }

}

func main() {

	token := flag.Bool("token", false, "Use tokens in place of .lmv files")

	flag.Parse()

	if len(os.Args) < 2 {

		fmt.Println("Use lmv -h for usage")

	} else {

		for i := 0; i < len(os.Args[1:]); i++ {

			if _, err := os.Stat(os.Args[i+1]); err == nil {

	    		encode(os.Args[i+1], *token)

			}

	    }

	}
}<commit_msg>Pass []bytes to hashing function, don't convert to string<commit_after>package main

import	(
	"os"
	"fmt"
	"crypto/sha512"
	"encoding/hex"
	"hash"
	"path/filepath"
	"flag"
	"net/http"
	"net/url"
	"io/ioutil"
	"log"
	"strconv"
)

type LMVFile struct {
	hash string
	size int64
	name string
}

func CalculateSHA512(data []byte) string {

	var hasher hash.Hash = sha512.New()

	hasher.Reset()
	hasher.Write(data)
	return hex.EncodeToString(hasher.Sum(nil))

}

func encode(fp string, token bool) {

	lmv_file := new(LMVFile)

	file, err := os.Open(fp)

    if err != nil {
    	log.Fatal(err)
    }

    defer file.Close()

    stat, err := file.Stat()

    if err != nil {
    	log.Fatal(err)
    }

    bs := make([]byte, stat.Size())
    _, err = file.Read(bs)

    if err != nil {
        log.Fatal(err)
    }

    lmv_file.hash = CalculateSHA512(bs)
    lmv_file.size = stat.Size()
    lmv_file.name = filepath.Base(fp)

	if token {

    	upload_address := "http://127.0.0.1:8081/upload"

		fields := make(url.Values)
        fields.Set("name", lmv_file.name)
        fields.Set("hash", lmv_file.hash)
        fields.Set("size", strconv.FormatInt(lmv_file.size, 10))

    	resp, err := http.PostForm(upload_address, fields)

    	if err != nil {
			log.Fatal(err)
		}

		defer resp.Body.Close()

		body, err := ioutil.ReadAll(resp.Body)

		if err != nil {
			log.Fatal(err)
		}

		fmt.Println("'" + lmv_file.name + "'" + " --> " + "'" + string(body) + "'")

	} else {

		os.Create(lmv_file.name + ".lmv")

		full := lmv_file.hash + "\n" + lmv_file.name + "\n" + strconv.FormatInt(lmv_file.size, 10)

		err = ioutil.WriteFile(lmv_file.name + ".lmv", []byte(full), 0644)

		if err != nil {
			log.Fatal(err)
		}

    }

}

func main() {

	token := flag.Bool("token", false, "Use tokens in place of .lmv files")

	flag.Parse()

	if len(os.Args) < 2 {

		fmt.Println("Use lmv -h for usage")

	} else {

		for i := 0; i < len(os.Args[1:]); i++ {

			if _, err := os.Stat(os.Args[i+1]); err == nil {

	    		encode(os.Args[i+1], *token)

			}

	    }

	}
}
<|endoftext|>


<commit_before><commit_msg>Fixing err chan<commit_after><|endoftext|>


<commit_before>package weblog

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024}

func NewWebLogger() *WebLogger {
	ww := NewWebWriter()
	l := log.New(ww, "", log.Lshortfile)
	go ww.Run()

	return &WebLogger{l, ww}
}

type WebLogger struct {
	*log.Logger

	writer *WebWriter
}

func (wl *WebLogger) Handle(w http.ResponseWriter, r *http.Request) {
	wl.writer.Handle(w, r)
}

func NewWebWriter() *WebWriter {
	ww := &WebWriter{register: make(chan *connection),
		unregister:  make(chan *connection),
		connections: make(map[*connection]bool)}
	return ww
}

type WebWriter struct {
	register    chan *connection
	unregister  chan *connection
	connections map[*connection]bool
}

func (ww *WebWriter) Run() {
	for {
		select {
		case c := <-ww.unregister:
			ww.connections[c] = false
			delete(ww.connections, c)
			c.ws.Close()
		case c := <-ww.register:
			ww.connections[c] = true
			fmt.Println("Just registered a client")
		}
	}
}

func (ww *WebWriter) Write(p []byte) (int, error) {
	for conn := range ww.connections {
		conn.send <- p
	}

	return len(p), nil
}

func (ww *WebWriter) Handle(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		return
	}
	c := &connection{send: make(chan []byte, 256), ws: ws}
	ww.register <- c
	defer func() { ww.unregister <- c }()

	c.send <- []byte("Welcome to WebWriter!")
	c.writer()
}

type connection struct {
	send chan []byte
	ws   *websocket.Conn
}

func (c connection) writer() {
	for message := range c.send {
		err := c.ws.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			break
		}
	}
}
<commit_msg>log: WebWriter -> webWriter, minimising public API<commit_after>package weblog

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024}

func NewWebLogger() *WebLogger {
	ww := &webWriter{register: make(chan *connection),
		unregister:  make(chan *connection),
		connections: make(map[*connection]bool)}

	l := log.New(ww, "", log.Lshortfile)
	go ww.Run()

	return &WebLogger{l, ww}
}

type WebLogger struct {
	*log.Logger

	writer *webWriter
}

func (wl *WebLogger) Handle(w http.ResponseWriter, r *http.Request) {
	wl.writer.Handle(w, r)
}

type webWriter struct {
	register    chan *connection
	unregister  chan *connection
	connections map[*connection]bool
}

func (ww *webWriter) Run() {
	for {
		select {
		case c := <-ww.unregister:
			ww.connections[c] = false
			delete(ww.connections, c)
			c.ws.Close()
		case c := <-ww.register:
			ww.connections[c] = true
			fmt.Println("Just registered a client")
		}
	}
}

func (ww *webWriter) Write(p []byte) (int, error) {
	for conn := range ww.connections {
		conn.send <- p
	}

	return len(p), nil
}

func (ww *webWriter) Handle(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		return
	}
	c := &connection{send: make(chan []byte, 256), ws: ws}
	ww.register <- c
	defer func() { ww.unregister <- c }()

	c.send <- []byte("Welcome to the weblog!")
	c.writer()
}

type connection struct {
	send chan []byte
	ws   *websocket.Conn
}

func (c connection) writer() {
	for message := range c.send {
		err := c.ws.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			break
		}
	}
}
<|endoftext|>


<commit_before>package forestdb

import "C"
import "unsafe"

//export LogCallbackInternal
func LogCallbackInternal(errCode C.int, msg *C.char, ctx *C.char) {
	context := (*logContext)(unsafe.Pointer(ctx))
	(*context.callback)(context.name, int(errCode), C.GoString(msg), context.userCtx)
}

//export FatalErrorCallbackInternal
func FatalErrorCallbackInternal() {
	fatalErrorCallback()
}

// Logger interface
type Logger interface {
	// Warnings, logged by default.
	Warnf(format string, v ...interface{})
	// Errors, logged by default.
	Errorf(format string, v ...interface{})
	// Fatal errors. Will not terminate execution.
	Fatalf(format string, v ...interface{})
	// Informational messages.
	Infof(format string, v ...interface{})
	// Timing utility
	Debugf(format string, v ...interface{})
	// Program execution tracing. Not logged by default
	Tracef(format string, v ...interface{})
}

type Dummy struct {
}

func (*Dummy) Fatalf(_ string, _ ...interface{}) {
}

func (*Dummy) Errorf(_ string, _ ...interface{}) {
}

func (*Dummy) Warnf(_ string, _ ...interface{}) {
}

func (*Dummy) Infof(_ string, _ ...interface{}) {
}

func (*Dummy) Debugf(_ string, _ ...interface{}) {
}

func (*Dummy) Tracef(_ string, _ ...interface{}) {
}

// Logger to use
var Log Logger = &Dummy{}
<commit_msg>add implementation of leveled logger<commit_after>package forestdb

import "C"
import (
	"log"
	"unsafe"
)

//export LogCallbackInternal
func LogCallbackInternal(errCode C.int, msg *C.char, ctx *C.char) {
	context := (*logContext)(unsafe.Pointer(ctx))
	(*context.callback)(context.name, int(errCode), C.GoString(msg), context.userCtx)
}

//export FatalErrorCallbackInternal
func FatalErrorCallbackInternal() {
	fatalErrorCallback()
}

// Logger interface
type Logger interface {
	// Warnings, logged by default.
	Warnf(format string, v ...interface{})
	// Errors, logged by default.
	Errorf(format string, v ...interface{})
	// Fatal errors. Will not terminate execution.
	Fatalf(format string, v ...interface{})
	// Informational messages.
	Infof(format string, v ...interface{})
	// Timing utility
	Debugf(format string, v ...interface{})
	// Program execution tracing. Not logged by default
	Tracef(format string, v ...interface{})
}

type Dummy struct {
}

func (*Dummy) Fatalf(_ string, _ ...interface{}) {
}

func (*Dummy) Errorf(_ string, _ ...interface{}) {
}

func (*Dummy) Warnf(_ string, _ ...interface{}) {
}

func (*Dummy) Infof(_ string, _ ...interface{}) {
}

func (*Dummy) Debugf(_ string, _ ...interface{}) {
}

func (*Dummy) Tracef(_ string, _ ...interface{}) {
}

type LogLevel int

const (
	LogFatal LogLevel = iota
	LogError
	LogWarn
	LogInfo
	LogDebug
	LogTrace
)

type LeveledLog struct {
	level LogLevel
}

func NewLeveledLog(level LogLevel) *LeveledLog {
	return &LeveledLog{level: level}
}

func (l *LeveledLog) Fatalf(format string, a ...interface{}) {
	if l.level >= LogFatal {
		log.Fatalf(format, a...)
	}
}

func (l *LeveledLog) Errorf(format string, a ...interface{}) {
	if l.level >= LogError {
		log.Printf(format, a...)
	}
}

func (l *LeveledLog) Warnf(format string, a ...interface{}) {
	if l.level >= LogWarn {
		log.Printf(format, a...)
	}
}

func (l *LeveledLog) Infof(format string, a ...interface{}) {
	if l.level >= LogInfo {
		log.Printf(format, a...)
	}
}

func (l *LeveledLog) Debugf(format string, a ...interface{}) {
	if l.level >= LogDebug {
		log.Printf(format, a...)
	}
}

func (l *LeveledLog) Tracef(format string, a ...interface{}) {
	if l.level >= LogTrace {
		log.Printf(format, a...)
	}
}

// Logger to use
var Log Logger = &Dummy{}
<|endoftext|>


<commit_before>// Copyright 2012-2018, Rolf Veen and contributors.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ogdl

import "os"

// Log is a log store for binary OGDL objects.
//
// All objects are appended to a file, and a position is returned.
//
type Log struct {
	f        *os.File
	autoSync bool
}

// OpenLog opens a log file. If the file doesn't exist, it is created.
func OpenLog(file string) (*Log, error) {

	f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	log := Log{f, true}

	return &log, nil
}

// Close closes a log file
func (log *Log) Close() {
	log.f.Close()
}

// Sync commits the changes to disk (the exact behavior is OS dependent).
func (log *Log) Sync() {
	log.f.Sync()
}

// Add adds an OGDL object to the log. The starting position into the log
// is returned.
func (log *Log) Add(g *Graph) int64 {

	b := g.Binary()

	if b == nil {
		return 0
	}

	i, _ := log.f.Seek(0, 2)

	log.f.Write(b)

	if log.autoSync {
		log.f.Sync()
	}

	return i
}

// AddBinary adds an OGDL binary object to the log. The starting position into
// the log is returned.
func (log *Log) AddBinary(b []byte) int64 {

	i, _ := log.f.Seek(0, 2)
	log.f.Write(b)

	if log.autoSync {
		log.f.Sync()
	}

	return i
}

// Get returns the OGDL object at the position given and the position of the
// next object, or an error.
func (log *Log) Get(i int64) (*Graph, int64, error) {

	/* Position in file */
	_, err := log.f.Seek(i, 0)
	if err != nil {
		return nil, -1, err
	}

	p := newBinParser(log.f)
	g := p.parse()

	if p.n == 0 {
		return g, -1, nil
	}

	return g, i + int64(p.n), err
}

// GetBinary returns the OGDL object at the position given and the position of the
// next object, or an error. The object returned is in binary form, exactly
// as it is stored in the log.
func (log *Log) GetBinary(i int64) ([]byte, int64, error) {

	// Position in file
	_, err := log.f.Seek(i, 0)
	if err != nil {
		return nil, 0, err
	}

	/* Read until EOS of binary OGDL.

	   There should be a Header first.
	*/
	p := newBinParser(log.f)

	if !p.header() {
		return nil, 0, err
	}
	for {
		lev, _, _ /* typ, b*/ := p.line(false)
		if lev == 0 {
			break
		}
	}

	n := p.n

	// Read bytes
	b := make([]byte, n)
	_, err = log.f.ReadAt(b, i)

	return b, int64(n), err
}
<commit_msg>add SetSync<commit_after>// Copyright 2012-2018, Rolf Veen and contributors.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ogdl

import "os"

// Log is a log store for binary OGDL objects.
//
// All objects are appended to a file, and a position is returned.
//
type Log struct {
	f        *os.File
	autoSync bool
}

// OpenLog opens a log file. If the file doesn't exist, it is created.
func OpenLog(file string) (*Log, error) {

	f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	log := Log{f, true}

	return &log, nil
}

// Close closes a log file
func (log *Log) Close() {
	log.f.Close()
}

// Sync commits the changes to disk (the exact behavior is OS dependent).
func (log *Log) Sync() {
	log.f.Sync()
}

// Sync commits the changes to disk (the exact behavior is OS dependent).
func (log *Log) SetSync(sync bool) {
	log.autoSync = sync
}

// Add adds an OGDL object to the log. The starting position into the log
// is returned.
func (log *Log) Add(g *Graph) int64 {

	b := g.Binary()

	if b == nil {
		return 0
	}

	i, _ := log.f.Seek(0, 2)

	log.f.Write(b)

	if log.autoSync {
		log.f.Sync()
	}

	return i
}

// AddBinary adds an OGDL binary object to the log. The starting position into
// the log is returned.
func (log *Log) AddBinary(b []byte) int64 {

	i, _ := log.f.Seek(0, 2)
	log.f.Write(b)

	if log.autoSync {
		log.f.Sync()
	}

	return i
}

// Get returns the OGDL object at the position given and the position of the
// next object, or an error.
func (log *Log) Get(i int64) (*Graph, int64, error) {

	/* Position in file */
	_, err := log.f.Seek(i, 0)
	if err != nil {
		return nil, -1, err
	}

	p := newBinParser(log.f)
	g := p.parse()

	if p.n == 0 {
		return g, -1, nil
	}

	return g, i + int64(p.n), err
}

// GetBinary returns the OGDL object at the position given and the position of the
// next object, or an error. The object returned is in binary form, exactly
// as it is stored in the log.
func (log *Log) GetBinary(i int64) ([]byte, int64, error) {

	// Position in file
	_, err := log.f.Seek(i, 0)
	if err != nil {
		return nil, 0, err
	}

	/* Read until EOS of binary OGDL.

	   There should be a Header first.
	*/
	p := newBinParser(log.f)

	if !p.header() {
		return nil, 0, err
	}
	for {
		lev, _, _ /* typ, b*/ := p.line(false)
		if lev == 0 {
			break
		}
	}

	n := p.n

	// Read bytes
	b := make([]byte, n)
	_, err = log.f.ReadAt(b, i)

	return b, int64(n), err
}
<|endoftext|>


<commit_before>package raft

// A state machine command.
// The Raft consensus module does not care about an actual type of a Command.
// It is up to you to make sure that the other components that the consensus
// module talks to agree on the actual type.
type Command interface{}

// An entry in the Raft Log
type LogEntry struct {
	TermNo
	Command
}

// Log entry index. First index is 1.
type LogIndex uint64

// The Raft Log
// An ordered array of `LogEntry`s with first index 1.
type Log interface {
	// An index of 0 indicates no entries present.
	getIndexOfLastEntry() LogIndex

	// TODO: return values for invalid params or log errors
	getLogEntryAtIndex(LogIndex) LogEntry

	// Get the term of the entry at the given index.
	// Equivalent to getLogEntryAtIndex(...).TermNo but this call allows
	// the Log implementation to not fetch the Command if that's a useful
	// optimization.
	// TODO: return values for invalid params or log errors
	// TODO: 0 for 0 and simplify callers and tests
	getTermAtIndex(LogIndex) TermNo

	// Set the entries after the given index.
	//
	// Theoretically, the Log can just delete all existing entries
	// following the given index and then append the given new
	// entries after that index.
	//
	// However, Raft properties means that the Log can use this logic:
	// - (AppendEntries receiver step 3.) If an existing entry conflicts with
	// a new one (same index but different terms), delete the existing entry
	// and all that follow it (#5.3)
	// - (AppendEntries receiver step 4.) Append any new entries not already
	// in the log
	//
	// I.e. the Log can choose to set only the entries starting from
	// the first index where the terms of the existing entry and the new
	// entry don't match.
	//
	// Note that an index of 0 is valid and implies deleting all entries.
	// A zero length slice and nil both indicate no new entries to be added
	// after deleting.
	//
	// This method is expected to always succeed. All errors should be indicated
	// by panicking, and this will shutdown the consensus module. This includes
	// both invalid parameters from the caller and internal errors in the Log.
	setEntriesAfterIndex(LogIndex, []LogEntry)
}

// Helper method
func getIndexAndTermOfLastEntry(log Log) (LogIndex, TermNo) {
	lastLogIndex := log.getIndexOfLastEntry()
	var lastLogTerm TermNo = 0
	if lastLogIndex > 0 {
		lastLogTerm = log.getTermAtIndex(lastLogIndex)
	}
	return lastLogIndex, lastLogTerm
}
<commit_msg>Edit Log comments on error handling and invalid values<commit_after>package raft

// A state machine command.
// The Raft consensus module does not care about an actual type of a Command.
// It is up to you to make sure that the other components that the consensus
// module talks to agree on the actual type.
type Command interface{}

// An entry in the Raft Log
type LogEntry struct {
	TermNo
	Command
}

// Log entry index. First index is 1.
type LogIndex uint64

// The Raft Log
// An ordered array of `LogEntry`s with first index 1.
//
// All errors should be indicated using panic(). This includes both invalid
// parameters sent by the consensus module and internal errors in the Log.
// Note that such a panic will shutdown the consensus module.
//
type Log interface {
	// An index of 0 indicates no entries present.
	getIndexOfLastEntry() LogIndex

	// An index of 0 is invalid for this call.
	getLogEntryAtIndex(LogIndex) LogEntry

	// Get the term of the entry at the given index.
	// Equivalent to getLogEntryAtIndex(...).TermNo but this call allows
	// the Log implementation to not fetch the Command if that's a useful
	// optimization.
	// An index of 0 is invalid for this call.
	getTermAtIndex(LogIndex) TermNo

	// Set the entries after the given index.
	//
	// Theoretically, the Log can just delete all existing entries
	// following the given index and then append the given new
	// entries after that index.
	//
	// However, Raft properties means that the Log can use this logic:
	// - (AppendEntries receiver step 3.) If an existing entry conflicts with
	// a new one (same index but different terms), delete the existing entry
	// and all that follow it (#5.3)
	// - (AppendEntries receiver step 4.) Append any new entries not already
	// in the log
	//
	// I.e. the Log can choose to set only the entries starting from
	// the first index where the terms of the existing entry and the new
	// entry don't match.
	//
	// An index of 0 is valid and implies deleting all entries.
	//
	// A zero length slice and nil both indicate no new entries to be added
	// after deleting.
	setEntriesAfterIndex(LogIndex, []LogEntry)
}

// Helper method
func getIndexAndTermOfLastEntry(log Log) (LogIndex, TermNo) {
	lastLogIndex := log.getIndexOfLastEntry()
	var lastLogTerm TermNo = 0
	if lastLogIndex > 0 {
		lastLogTerm = log.getTermAtIndex(lastLogIndex)
	}
	return lastLogIndex, lastLogTerm
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"log"
	"mime"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

// recording pages filtered to access log

var (
	accessLog CSVLog
	tlsLog    CSVLog
)

type CSVLog struct {
	lock sync.Mutex
	file *os.File
	csv  *csv.Writer
}

func (l *CSVLog) Open(filename string) {
	l.lock.Lock()
	defer l.lock.Unlock()
	if l.file != nil && l.file != os.Stdout {
		l.file.Close()
		l.file = nil
	}

	if filename != "" {
		logfile, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
		if err != nil {
			log.Printf("Could not open log file (%s): %s\n Sending access log messages to standard output instead.", filename, err)
		} else {
			l.file = logfile
		}
	}
	if l.file == nil {
		l.file = os.Stdout
	}

	l.csv = csv.NewWriter(l.file)
}

func (l *CSVLog) Log(data []string) {
	l.lock.Lock()
	defer l.lock.Unlock()
	l.csv.Write(data)
	l.csv.Flush()
}

func logAccess(req *http.Request, resp *http.Response, contentLength int, pruned bool, user string, tally map[rule]int, scores map[string]int, rule ACLActionRule, title string, ignored []string) []string {
	conf := getConfig()

	modified := ""
	if pruned {
		modified = "pruned"
	}

	status := 0
	if resp != nil {
		status = resp.StatusCode
	}

	if rule.Action == "" {
		rule.Action = "allow"
	}

	var contentType string
	if resp != nil {
		contentType = resp.Header.Get("Content-Type")
	}
	if ct2, _, err := mime.ParseMediaType(contentType); err == nil {
		contentType = ct2
	}

	var userAgent string
	if conf.LogUserAgent {
		userAgent = req.Header.Get("User-Agent")
	}

	logLine := toStrings(time.Now().Format("2006-01-02 15:04:05.000"), user, rule.Action, req.URL, req.Method, status, contentType, contentLength, modified, listTally(stringTally(tally)), listTally(scores), rule.Conditions(), title, strings.Join(ignored, ","), userAgent, req.Proto, req.Referer(), platform(req.Header.Get("User-Agent")))

	accessLog.Log(logLine)
	return logLine
}

func logTLS(user, serverAddr, serverName string, err error, cachedCert bool) {
	errStr := ""
	if err != nil {
		errStr = err.Error()
	}

	cached := ""
	if cachedCert {
		cached = "cached certificate"
	}

	tlsLog.Log(toStrings(time.Now().Format("2006-01-02 15:04:05.000"), user, serverName, serverAddr, errStr, cached))
}

// toStrings converts its arguments into a slice of strings.
func toStrings(a ...interface{}) []string {
	result := make([]string, len(a))
	for i, x := range a {
		result[i] = fmt.Sprint(x)
	}
	return result
}

// stringTally returns a copy of tally with strings instead of rules as keys.
func stringTally(tally map[rule]int) map[string]int {
	st := make(map[string]int)
	for r, n := range tally {
		st[r.String()] = n
	}
	return st
}

// listTally sorts the tally and formats it as a comma-separated string.
func listTally(tally map[string]int) string {
	b := new(bytes.Buffer)
	for i, rule := range sortedKeys(tally) {
		if i > 0 {
			b.WriteString(", ")
		}
		fmt.Fprint(b, rule, " ", tally[rule])
	}
	return b.String()
}
<commit_msg>Switch to microseconds instead<commit_after>package main

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"log"
	"mime"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

// recording pages filtered to access log

var (
	accessLog CSVLog
	tlsLog    CSVLog
)

type CSVLog struct {
	lock sync.Mutex
	file *os.File
	csv  *csv.Writer
}

func (l *CSVLog) Open(filename string) {
	l.lock.Lock()
	defer l.lock.Unlock()
	if l.file != nil && l.file != os.Stdout {
		l.file.Close()
		l.file = nil
	}

	if filename != "" {
		logfile, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
		if err != nil {
			log.Printf("Could not open log file (%s): %s\n Sending access log messages to standard output instead.", filename, err)
		} else {
			l.file = logfile
		}
	}
	if l.file == nil {
		l.file = os.Stdout
	}

	l.csv = csv.NewWriter(l.file)
}

func (l *CSVLog) Log(data []string) {
	l.lock.Lock()
	defer l.lock.Unlock()
	l.csv.Write(data)
	l.csv.Flush()
}

func logAccess(req *http.Request, resp *http.Response, contentLength int, pruned bool, user string, tally map[rule]int, scores map[string]int, rule ACLActionRule, title string, ignored []string) []string {
	conf := getConfig()

	modified := ""
	if pruned {
		modified = "pruned"
	}

	status := 0
	if resp != nil {
		status = resp.StatusCode
	}

	if rule.Action == "" {
		rule.Action = "allow"
	}

	var contentType string
	if resp != nil {
		contentType = resp.Header.Get("Content-Type")
	}
	if ct2, _, err := mime.ParseMediaType(contentType); err == nil {
		contentType = ct2
	}

	var userAgent string
	if conf.LogUserAgent {
		userAgent = req.Header.Get("User-Agent")
	}

	logLine := toStrings(time.Now().Format("2006-01-02 15:04:05.000000"), user, rule.Action, req.URL, req.Method, status, contentType, contentLength, modified, listTally(stringTally(tally)), listTally(scores), rule.Conditions(), title, strings.Join(ignored, ","), userAgent, req.Proto, req.Referer(), platform(req.Header.Get("User-Agent")))

	accessLog.Log(logLine)
	return logLine
}

func logTLS(user, serverAddr, serverName string, err error, cachedCert bool) {
	errStr := ""
	if err != nil {
		errStr = err.Error()
	}

	cached := ""
	if cachedCert {
		cached = "cached certificate"
	}

	tlsLog.Log(toStrings(time.Now().Format("2006-01-02 15:04:05.000000"), user, serverName, serverAddr, errStr, cached))
}

// toStrings converts its arguments into a slice of strings.
func toStrings(a ...interface{}) []string {
	result := make([]string, len(a))
	for i, x := range a {
		result[i] = fmt.Sprint(x)
	}
	return result
}

// stringTally returns a copy of tally with strings instead of rules as keys.
func stringTally(tally map[rule]int) map[string]int {
	st := make(map[string]int)
	for r, n := range tally {
		st[r.String()] = n
	}
	return st
}

// listTally sorts the tally and formats it as a comma-separated string.
func listTally(tally map[string]int) string {
	b := new(bytes.Buffer)
	for i, rule := range sortedKeys(tally) {
		if i > 0 {
			b.WriteString(", ")
		}
		fmt.Fprint(b, rule, " ", tally[rule])
	}
	return b.String()
}
<|endoftext|>


<commit_before>package lnd

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

	"github.com/btcsuite/btcd/connmgr"
	"github.com/btcsuite/btclog"
	"github.com/jrick/logrotate/rotator"
	"github.com/lightninglabs/neutrino"
	sphinx "github.com/lightningnetwork/lightning-onion"
	"github.com/lightningnetwork/lnd/autopilot"
	"github.com/lightningnetwork/lnd/build"
	"github.com/lightningnetwork/lnd/chainntnfs"
	"github.com/lightningnetwork/lnd/chanbackup"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/channelnotifier"
	"github.com/lightningnetwork/lnd/contractcourt"
	"github.com/lightningnetwork/lnd/discovery"
	"github.com/lightningnetwork/lnd/htlcswitch"
	"github.com/lightningnetwork/lnd/invoices"
	"github.com/lightningnetwork/lnd/lnrpc/autopilotrpc"
	"github.com/lightningnetwork/lnd/lnrpc/chainrpc"
	"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
	"github.com/lightningnetwork/lnd/lnrpc/signrpc"
	"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
	"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
	"github.com/lightningnetwork/lnd/lnwallet"
	"github.com/lightningnetwork/lnd/monitoring"
	"github.com/lightningnetwork/lnd/netann"
	"github.com/lightningnetwork/lnd/routing"
	"github.com/lightningnetwork/lnd/signal"
	"github.com/lightningnetwork/lnd/sweep"
	"github.com/lightningnetwork/lnd/watchtower"
	"github.com/lightningnetwork/lnd/watchtower/wtclient"
)

// Loggers per subsystem.  A single backend logger is created and all subsystem
// loggers created from it will write to the backend.  When adding new
// subsystems, add the subsystem logger variable here and to the
// subsystemLoggers map.
//
// Loggers can not be used before the log rotator has been initialized with a
// log file.  This must be performed early during application startup by
// calling initLogRotator.
var (
	logWriter = &build.LogWriter{}

	// backendLog is the logging backend used to create all subsystem
	// loggers.  The backend must not be used before the log rotator has
	// been initialized, or data races and/or nil pointer dereferences will
	// occur.
	backendLog = btclog.NewBackend(logWriter)

	// logRotator is one of the logging outputs.  It should be closed on
	// application shutdown.
	logRotator *rotator.Rotator

	ltndLog = build.NewSubLogger("LTND", backendLog.Logger)
	lnwlLog = build.NewSubLogger("LNWL", backendLog.Logger)
	peerLog = build.NewSubLogger("PEER", backendLog.Logger)
	discLog = build.NewSubLogger("DISC", backendLog.Logger)
	rpcsLog = build.NewSubLogger("RPCS", backendLog.Logger)
	srvrLog = build.NewSubLogger("SRVR", backendLog.Logger)
	ntfnLog = build.NewSubLogger("NTFN", backendLog.Logger)
	chdbLog = build.NewSubLogger("CHDB", backendLog.Logger)
	fndgLog = build.NewSubLogger("FNDG", backendLog.Logger)
	hswcLog = build.NewSubLogger("HSWC", backendLog.Logger)
	utxnLog = build.NewSubLogger("UTXN", backendLog.Logger)
	brarLog = build.NewSubLogger("BRAR", backendLog.Logger)
	cmgrLog = build.NewSubLogger("CMGR", backendLog.Logger)
	crtrLog = build.NewSubLogger("CRTR", backendLog.Logger)
	btcnLog = build.NewSubLogger("BTCN", backendLog.Logger)
	atplLog = build.NewSubLogger("ATPL", backendLog.Logger)
	cnctLog = build.NewSubLogger("CNCT", backendLog.Logger)
	sphxLog = build.NewSubLogger("SPHX", backendLog.Logger)
	swprLog = build.NewSubLogger("SWPR", backendLog.Logger)
	sgnrLog = build.NewSubLogger("SGNR", backendLog.Logger)
	wlktLog = build.NewSubLogger("WLKT", backendLog.Logger)
	arpcLog = build.NewSubLogger("ARPC", backendLog.Logger)
	invcLog = build.NewSubLogger("INVC", backendLog.Logger)
	nannLog = build.NewSubLogger("NANN", backendLog.Logger)
	wtwrLog = build.NewSubLogger("WTWR", backendLog.Logger)
	ntfrLog = build.NewSubLogger("NTFR", backendLog.Logger)
	irpcLog = build.NewSubLogger("IRPC", backendLog.Logger)
	chnfLog = build.NewSubLogger("CHNF", backendLog.Logger)
	chbuLog = build.NewSubLogger("CHBU", backendLog.Logger)
	promLog = build.NewSubLogger("PROM", backendLog.Logger)
	wtclLog = build.NewSubLogger("WTCL", backendLog.Logger)
)

// Initialize package-global logger variables.
func init() {
	lnwallet.UseLogger(lnwlLog)
	discovery.UseLogger(discLog)
	chainntnfs.UseLogger(ntfnLog)
	channeldb.UseLogger(chdbLog)
	htlcswitch.UseLogger(hswcLog)
	connmgr.UseLogger(cmgrLog)
	routing.UseLogger(crtrLog)
	neutrino.UseLogger(btcnLog)
	autopilot.UseLogger(atplLog)
	contractcourt.UseLogger(cnctLog)
	sphinx.UseLogger(sphxLog)
	signal.UseLogger(ltndLog)
	sweep.UseLogger(swprLog)
	signrpc.UseLogger(sgnrLog)
	walletrpc.UseLogger(wlktLog)
	autopilotrpc.UseLogger(arpcLog)
	invoices.UseLogger(invcLog)
	netann.UseLogger(nannLog)
	watchtower.UseLogger(wtwrLog)
	chainrpc.UseLogger(ntfrLog)
	invoicesrpc.UseLogger(irpcLog)
	channelnotifier.UseLogger(chnfLog)
	chanbackup.UseLogger(chbuLog)
	monitoring.UseLogger(promLog)
	wtclient.UseLogger(wtclLog)

	addSubLogger(routerrpc.Subsystem, routerrpc.UseLogger)
	addSubLogger(wtclientrpc.Subsystem, wtclientrpc.UseLogger)
}

// addSubLogger is a helper method to conveniently register the logger of a sub
// system.
func addSubLogger(subsystem string, useLogger func(btclog.Logger)) {
	logger := build.NewSubLogger(subsystem, backendLog.Logger)
	useLogger(logger)
	subsystemLoggers[subsystem] = logger
}

// subsystemLoggers maps each subsystem identifier to its associated logger.
var subsystemLoggers = map[string]btclog.Logger{
	"LTND": ltndLog,
	"LNWL": lnwlLog,
	"PEER": peerLog,
	"DISC": discLog,
	"RPCS": rpcsLog,
	"SRVR": srvrLog,
	"NTFN": ntfnLog,
	"CHDB": chdbLog,
	"FNDG": fndgLog,
	"HSWC": hswcLog,
	"UTXN": utxnLog,
	"BRAR": brarLog,
	"CMGR": cmgrLog,
	"CRTR": crtrLog,
	"BTCN": btcnLog,
	"ATPL": atplLog,
	"CNCT": cnctLog,
	"SPHX": sphxLog,
	"SWPR": swprLog,
	"SGNR": sgnrLog,
	"WLKT": wlktLog,
	"ARPC": arpcLog,
	"INVC": invcLog,
	"NANN": nannLog,
	"WTWR": wtwrLog,
	"NTFR": ntfnLog,
	"IRPC": irpcLog,
	"CHNF": chnfLog,
	"CHBU": chbuLog,
	"PROM": promLog,
	"WTCL": wtclLog,
}

// initLogRotator initializes the logging rotator to write logs to logFile and
// create roll files in the same directory.  It must be called before the
// package-global log rotator variables are used.
func initLogRotator(logFile string, MaxLogFileSize int, MaxLogFiles int) {
	logDir, _ := filepath.Split(logFile)
	err := os.MkdirAll(logDir, 0700)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create log directory: %v\n", err)
		os.Exit(1)
	}
	r, err := rotator.New(logFile, int64(MaxLogFileSize*1024), false, MaxLogFiles)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create file rotator: %v\n", err)
		os.Exit(1)
	}

	pr, pw := io.Pipe()
	go r.Run(pr)

	logWriter.RotatorPipe = pw
	logRotator = r
}

// setLogLevel sets the logging level for provided subsystem.  Invalid
// subsystems are ignored.  Uninitialized subsystems are dynamically created as
// needed.
func setLogLevel(subsystemID string, logLevel string) {
	// Ignore invalid subsystems.
	logger, ok := subsystemLoggers[subsystemID]
	if !ok {
		return
	}

	// Defaults to info if the log level is invalid.
	level, _ := btclog.LevelFromString(logLevel)
	logger.SetLevel(level)
}

// setLogLevels sets the log level for all subsystem loggers to the passed
// level. It also dynamically creates the subsystem loggers as needed, so it
// can be used to initialize the logging system.
func setLogLevels(logLevel string) {
	// Configure all sub-systems with the new logging level.  Dynamically
	// create loggers as needed.
	for subsystemID := range subsystemLoggers {
		setLogLevel(subsystemID, logLevel)
	}
}

// logClosure is used to provide a closure over expensive logging operations so
// don't have to be performed when the logging level doesn't warrant it.
type logClosure func() string

// String invokes the underlying function and returns the result.
func (c logClosure) String() string {
	return c()
}

// newLogClosure returns a new closure over a function that returns a string
// which itself provides a Stringer interface so that it can be used with the
// logging system.
func newLogClosure(c func() string) logClosure {
	return logClosure(c)
}
<commit_msg>log: correct NTFR -> ntfrLog mapping<commit_after>package lnd

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

	"github.com/btcsuite/btcd/connmgr"
	"github.com/btcsuite/btclog"
	"github.com/jrick/logrotate/rotator"
	"github.com/lightninglabs/neutrino"
	sphinx "github.com/lightningnetwork/lightning-onion"
	"github.com/lightningnetwork/lnd/autopilot"
	"github.com/lightningnetwork/lnd/build"
	"github.com/lightningnetwork/lnd/chainntnfs"
	"github.com/lightningnetwork/lnd/chanbackup"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/channelnotifier"
	"github.com/lightningnetwork/lnd/contractcourt"
	"github.com/lightningnetwork/lnd/discovery"
	"github.com/lightningnetwork/lnd/htlcswitch"
	"github.com/lightningnetwork/lnd/invoices"
	"github.com/lightningnetwork/lnd/lnrpc/autopilotrpc"
	"github.com/lightningnetwork/lnd/lnrpc/chainrpc"
	"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
	"github.com/lightningnetwork/lnd/lnrpc/signrpc"
	"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
	"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
	"github.com/lightningnetwork/lnd/lnwallet"
	"github.com/lightningnetwork/lnd/monitoring"
	"github.com/lightningnetwork/lnd/netann"
	"github.com/lightningnetwork/lnd/routing"
	"github.com/lightningnetwork/lnd/signal"
	"github.com/lightningnetwork/lnd/sweep"
	"github.com/lightningnetwork/lnd/watchtower"
	"github.com/lightningnetwork/lnd/watchtower/wtclient"
)

// Loggers per subsystem.  A single backend logger is created and all subsystem
// loggers created from it will write to the backend.  When adding new
// subsystems, add the subsystem logger variable here and to the
// subsystemLoggers map.
//
// Loggers can not be used before the log rotator has been initialized with a
// log file.  This must be performed early during application startup by
// calling initLogRotator.
var (
	logWriter = &build.LogWriter{}

	// backendLog is the logging backend used to create all subsystem
	// loggers.  The backend must not be used before the log rotator has
	// been initialized, or data races and/or nil pointer dereferences will
	// occur.
	backendLog = btclog.NewBackend(logWriter)

	// logRotator is one of the logging outputs.  It should be closed on
	// application shutdown.
	logRotator *rotator.Rotator

	ltndLog = build.NewSubLogger("LTND", backendLog.Logger)
	lnwlLog = build.NewSubLogger("LNWL", backendLog.Logger)
	peerLog = build.NewSubLogger("PEER", backendLog.Logger)
	discLog = build.NewSubLogger("DISC", backendLog.Logger)
	rpcsLog = build.NewSubLogger("RPCS", backendLog.Logger)
	srvrLog = build.NewSubLogger("SRVR", backendLog.Logger)
	ntfnLog = build.NewSubLogger("NTFN", backendLog.Logger)
	chdbLog = build.NewSubLogger("CHDB", backendLog.Logger)
	fndgLog = build.NewSubLogger("FNDG", backendLog.Logger)
	hswcLog = build.NewSubLogger("HSWC", backendLog.Logger)
	utxnLog = build.NewSubLogger("UTXN", backendLog.Logger)
	brarLog = build.NewSubLogger("BRAR", backendLog.Logger)
	cmgrLog = build.NewSubLogger("CMGR", backendLog.Logger)
	crtrLog = build.NewSubLogger("CRTR", backendLog.Logger)
	btcnLog = build.NewSubLogger("BTCN", backendLog.Logger)
	atplLog = build.NewSubLogger("ATPL", backendLog.Logger)
	cnctLog = build.NewSubLogger("CNCT", backendLog.Logger)
	sphxLog = build.NewSubLogger("SPHX", backendLog.Logger)
	swprLog = build.NewSubLogger("SWPR", backendLog.Logger)
	sgnrLog = build.NewSubLogger("SGNR", backendLog.Logger)
	wlktLog = build.NewSubLogger("WLKT", backendLog.Logger)
	arpcLog = build.NewSubLogger("ARPC", backendLog.Logger)
	invcLog = build.NewSubLogger("INVC", backendLog.Logger)
	nannLog = build.NewSubLogger("NANN", backendLog.Logger)
	wtwrLog = build.NewSubLogger("WTWR", backendLog.Logger)
	ntfrLog = build.NewSubLogger("NTFR", backendLog.Logger)
	irpcLog = build.NewSubLogger("IRPC", backendLog.Logger)
	chnfLog = build.NewSubLogger("CHNF", backendLog.Logger)
	chbuLog = build.NewSubLogger("CHBU", backendLog.Logger)
	promLog = build.NewSubLogger("PROM", backendLog.Logger)
	wtclLog = build.NewSubLogger("WTCL", backendLog.Logger)
)

// Initialize package-global logger variables.
func init() {
	lnwallet.UseLogger(lnwlLog)
	discovery.UseLogger(discLog)
	chainntnfs.UseLogger(ntfnLog)
	channeldb.UseLogger(chdbLog)
	htlcswitch.UseLogger(hswcLog)
	connmgr.UseLogger(cmgrLog)
	routing.UseLogger(crtrLog)
	neutrino.UseLogger(btcnLog)
	autopilot.UseLogger(atplLog)
	contractcourt.UseLogger(cnctLog)
	sphinx.UseLogger(sphxLog)
	signal.UseLogger(ltndLog)
	sweep.UseLogger(swprLog)
	signrpc.UseLogger(sgnrLog)
	walletrpc.UseLogger(wlktLog)
	autopilotrpc.UseLogger(arpcLog)
	invoices.UseLogger(invcLog)
	netann.UseLogger(nannLog)
	watchtower.UseLogger(wtwrLog)
	chainrpc.UseLogger(ntfrLog)
	invoicesrpc.UseLogger(irpcLog)
	channelnotifier.UseLogger(chnfLog)
	chanbackup.UseLogger(chbuLog)
	monitoring.UseLogger(promLog)
	wtclient.UseLogger(wtclLog)

	addSubLogger(routerrpc.Subsystem, routerrpc.UseLogger)
	addSubLogger(wtclientrpc.Subsystem, wtclientrpc.UseLogger)
}

// addSubLogger is a helper method to conveniently register the logger of a sub
// system.
func addSubLogger(subsystem string, useLogger func(btclog.Logger)) {
	logger := build.NewSubLogger(subsystem, backendLog.Logger)
	useLogger(logger)
	subsystemLoggers[subsystem] = logger
}

// subsystemLoggers maps each subsystem identifier to its associated logger.
var subsystemLoggers = map[string]btclog.Logger{
	"LTND": ltndLog,
	"LNWL": lnwlLog,
	"PEER": peerLog,
	"DISC": discLog,
	"RPCS": rpcsLog,
	"SRVR": srvrLog,
	"NTFN": ntfnLog,
	"CHDB": chdbLog,
	"FNDG": fndgLog,
	"HSWC": hswcLog,
	"UTXN": utxnLog,
	"BRAR": brarLog,
	"CMGR": cmgrLog,
	"CRTR": crtrLog,
	"BTCN": btcnLog,
	"ATPL": atplLog,
	"CNCT": cnctLog,
	"SPHX": sphxLog,
	"SWPR": swprLog,
	"SGNR": sgnrLog,
	"WLKT": wlktLog,
	"ARPC": arpcLog,
	"INVC": invcLog,
	"NANN": nannLog,
	"WTWR": wtwrLog,
	"NTFR": ntfrLog,
	"IRPC": irpcLog,
	"CHNF": chnfLog,
	"CHBU": chbuLog,
	"PROM": promLog,
	"WTCL": wtclLog,
}

// initLogRotator initializes the logging rotator to write logs to logFile and
// create roll files in the same directory.  It must be called before the
// package-global log rotator variables are used.
func initLogRotator(logFile string, MaxLogFileSize int, MaxLogFiles int) {
	logDir, _ := filepath.Split(logFile)
	err := os.MkdirAll(logDir, 0700)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create log directory: %v\n", err)
		os.Exit(1)
	}
	r, err := rotator.New(logFile, int64(MaxLogFileSize*1024), false, MaxLogFiles)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create file rotator: %v\n", err)
		os.Exit(1)
	}

	pr, pw := io.Pipe()
	go r.Run(pr)

	logWriter.RotatorPipe = pw
	logRotator = r
}

// setLogLevel sets the logging level for provided subsystem.  Invalid
// subsystems are ignored.  Uninitialized subsystems are dynamically created as
// needed.
func setLogLevel(subsystemID string, logLevel string) {
	// Ignore invalid subsystems.
	logger, ok := subsystemLoggers[subsystemID]
	if !ok {
		return
	}

	// Defaults to info if the log level is invalid.
	level, _ := btclog.LevelFromString(logLevel)
	logger.SetLevel(level)
}

// setLogLevels sets the log level for all subsystem loggers to the passed
// level. It also dynamically creates the subsystem loggers as needed, so it
// can be used to initialize the logging system.
func setLogLevels(logLevel string) {
	// Configure all sub-systems with the new logging level.  Dynamically
	// create loggers as needed.
	for subsystemID := range subsystemLoggers {
		setLogLevel(subsystemID, logLevel)
	}
}

// logClosure is used to provide a closure over expensive logging operations so
// don't have to be performed when the logging level doesn't warrant it.
type logClosure func() string

// String invokes the underlying function and returns the result.
func (c logClosure) String() string {
	return c()
}

// newLogClosure returns a new closure over a function that returns a string
// which itself provides a Stringer interface so that it can be used with the
// logging system.
func newLogClosure(c func() string) logClosure {
	return logClosure(c)
}
<|endoftext|>


<commit_before>package main

type raynode struct {
	Cost int
}

type rayMap map[position]raynode

func (g *game) bestParent(rm rayMap, from, pos position) (position, int) {
	p := pos.Parents(from)
	b := p[0]
	if len(p) > 1 && rm[p[1]].Cost+g.losCost(p[1]) < rm[b].Cost+g.losCost(b) {
		b = p[1]
	}
	return b, rm[b].Cost + g.losCost(b)
}

func (g *game) losCost(pos position) int {
	if g.Player.Pos == pos {
		return 0
	}
	c := g.Dungeon.Cell(pos)
	if c.T == WallCell {
		return g.LosRange()
	}
	if _, ok := g.Clouds[pos]; ok {
		return g.LosRange()
	}
	if _, ok := g.Doors[pos]; ok {
		if pos != g.Player.Pos {
			mons := g.MonsterAt(pos)
			if !mons.Exists() {
				return g.LosRange()
			}
		}
	}
	if _, ok := g.Fungus[pos]; ok {
		return g.LosRange() - 1
	}
	return 1
}

func (g *game) buildRayMap(from position, distance int) rayMap {
	rm := rayMap{}
	rm[from] = raynode{Cost: 0}
	for d := 1; d <= distance; d++ {
		for x := -d + from.X; x <= d+from.X; x++ {
			for _, pos := range []position{{x, from.Y + d}, {x, from.Y - d}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = raynode{Cost: c}
			}
		}
		for y := -d + 1 + from.Y; y <= d-1+from.Y; y++ {
			for _, pos := range []position{{from.X + d, y}, {from.X - d, y}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = raynode{Cost: c}
			}
		}
	}
	return rm
}

func (g *game) LosRange() int {
	losRange := 6
	if g.Player.Armour == ShinyPlates {
		losRange++
	}
	if g.Player.Aptitudes[AptStealthyLOS] {
		losRange -= 2
	}
	if g.Player.Armour == HarmonistRobe {
		losRange -= 1
	}
	if g.Player.Weapon == Frundis {
		losRange -= 1
	}
	if g.Player.HasStatus(StatusShadows) {
		losRange = 1
	}
	if losRange < 1 {
		losRange = 1
	}
	return losRange
}

func (g *game) StopAuto() {
	if g.Autoexploring && !g.AutoHalt {
		g.Print("You stop exploring.")
	} else if g.AutoDir != NoDir {
		g.Print("You stop.")
	} else if g.AutoTarget != InvalidPos {
		g.Print("You stop.")
	}
	g.AutoHalt = true
	g.AutoDir = NoDir
	g.AutoTarget = InvalidPos
	if g.Resting {
		g.Stats.RestInterrupt++
		g.Resting = false
		g.Print("You could not sleep.")
	}
}

func (g *game) ComputeLOS() {
	m := map[position]bool{}
	losRange := g.LosRange()
	g.Player.Rays = g.buildRayMap(g.Player.Pos, losRange)
	for pos, n := range g.Player.Rays {
		if n.Cost < g.LosRange() {
			m[pos] = true
			g.SeePosition(pos)
		}
	}
	g.Player.LOS = m
	for _, mons := range g.Monsters {
		if mons.Exists() && g.Player.LOS[mons.Pos] {
			if mons.Seen {
				g.StopAuto()
				continue
			}
			mons.Seen = true
			g.Printf("You see %s (%v).", mons.Kind.Indefinite(false), mons.State)
			if mons.Kind.Dangerousness() > 10 {
				g.StoryPrint(mons.Kind.SeenStoryText())
			}
			g.StopAuto()
		}
	}
}

func (g *game) SeePosition(pos position) {
	if !g.Dungeon.Cell(pos).Explored {
		see := "see"
		if c, ok := g.Collectables[pos]; ok {
			if c.Quantity > 1 {
				g.Printf("You %s %d %s.", see, c.Quantity, c.Consumable.Plural())
			} else {
				g.Printf("You %s %s.", see, Indefinite(c.Consumable.String(), false))
			}
			g.StopAuto()
		} else if _, ok := g.Stairs[pos]; ok {
			g.Printf("You %s stairs.", see)
			g.StopAuto()
		} else if eq, ok := g.Equipables[pos]; ok {
			g.Printf("You %s %s.", see, Indefinite(eq.String(), false))
			g.StopAuto()
		} else if rd, ok := g.Rods[pos]; ok {
			g.Printf("You %s %s.", see, Indefinite(rd.String(), false))
			g.StopAuto()
		} else if stn, ok := g.MagicalStones[pos]; ok {
			g.Printf("You %s %s.", see, Indefinite(stn.String(), false))
			g.StopAuto()
		}
		g.FunAction()
		g.Dungeon.SetExplored(pos)
		g.DijkstraMapRebuild = true
	} else {
		if g.WrongWall[pos] {
			g.Printf("There is no longer a wall there.")
			g.StopAuto()
			g.DijkstraMapRebuild = true
		}
		if cld, ok := g.Clouds[pos]; ok && cld == CloudFire && (g.WrongDoor[pos] || g.WrongFoliage[pos]) {
			g.Printf("There are flames there.")
			g.StopAuto()
			g.DijkstraMapRebuild = true
		}
	}
	if g.WrongWall[pos] {
		delete(g.WrongWall, pos)
		if g.Dungeon.Cell(pos).T == FreeCell {
			delete(g.TemporalWalls, pos)
		}
	}
	if _, ok := g.WrongDoor[pos]; ok {
		delete(g.WrongDoor, pos)
	}
	if _, ok := g.WrongFoliage[pos]; ok {
		delete(g.WrongFoliage, pos)
	}
	if _, ok := g.DreamingMonster[pos]; ok {
		delete(g.DreamingMonster, pos)
	}
}

func (g *game) ComputeExclusion(pos position, toggle bool) {
	exclusionRange := g.LosRange()
	g.ExclusionsMap[pos] = toggle
	for d := 1; d <= exclusionRange; d++ {
		for x := -d + pos.X; x <= d+pos.X; x++ {
			for _, pos := range []position{{x, pos.Y + d}, {x, pos.Y - d}} {
				if !pos.valid() {
					continue
				}
				g.ExclusionsMap[pos] = toggle
			}
		}
		for y := -d + 1 + pos.Y; y <= d-1+pos.Y; y++ {
			for _, pos := range []position{{pos.X + d, y}, {pos.X - d, y}} {
				if !pos.valid() {
					continue
				}
				g.ExclusionsMap[pos] = toggle
			}
		}
	}
}

func (g *game) Ray(pos position) []position {
	if !g.Player.LOS[pos] {
		return nil
	}
	ray := []position{}
	for pos != g.Player.Pos {
		ray = append(ray, pos)
		pos, _ = g.bestParent(g.Player.Rays, g.Player.Pos, pos)
	}
	return ray
}

func (g *game) ComputeRayHighlight(pos position) {
	g.Highlight = map[position]bool{}
	ray := g.Ray(pos)
	for _, p := range ray {
		g.Highlight[p] = true
	}
}

func (g *game) ComputeNoise() {
	dij := &noisePath{game: g}
	rg := g.LosRange() + 2
	if rg <= 5 {
		rg++
	}
	if g.Player.Aptitudes[AptHear] {
		rg++
	}
	nm := Dijkstra(dij, []position{g.Player.Pos}, rg)
	count := 0
	noise := map[position]bool{}
	rmax := 3
	if g.Player.Aptitudes[AptHear] {
		rmax--
	}
	for pos := range nm {
		if g.Player.LOS[pos] {
			continue
		}
		mons := g.MonsterAt(pos)
		if mons.Exists() && mons.State != Resting && RandInt(rmax) == 0 {
			switch mons.Kind {
			case MonsMirrorSpecter, MonsGiantBee, MonsSatowalgaPlant:
				// no footsteps
			default:
				noise[pos] = true
				g.Print("You hear footsteps.")
				count++
			}
		}
	}
	if count > 0 {
		g.StopAuto()
	}
	g.Noise = noise
}
<commit_msg>now winged monsters do not produce footstep noise but wing flapping<commit_after>package main

type raynode struct {
	Cost int
}

type rayMap map[position]raynode

func (g *game) bestParent(rm rayMap, from, pos position) (position, int) {
	p := pos.Parents(from)
	b := p[0]
	if len(p) > 1 && rm[p[1]].Cost+g.losCost(p[1]) < rm[b].Cost+g.losCost(b) {
		b = p[1]
	}
	return b, rm[b].Cost + g.losCost(b)
}

func (g *game) losCost(pos position) int {
	if g.Player.Pos == pos {
		return 0
	}
	c := g.Dungeon.Cell(pos)
	if c.T == WallCell {
		return g.LosRange()
	}
	if _, ok := g.Clouds[pos]; ok {
		return g.LosRange()
	}
	if _, ok := g.Doors[pos]; ok {
		if pos != g.Player.Pos {
			mons := g.MonsterAt(pos)
			if !mons.Exists() {
				return g.LosRange()
			}
		}
	}
	if _, ok := g.Fungus[pos]; ok {
		return g.LosRange() - 1
	}
	return 1
}

func (g *game) buildRayMap(from position, distance int) rayMap {
	rm := rayMap{}
	rm[from] = raynode{Cost: 0}
	for d := 1; d <= distance; d++ {
		for x := -d + from.X; x <= d+from.X; x++ {
			for _, pos := range []position{{x, from.Y + d}, {x, from.Y - d}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = raynode{Cost: c}
			}
		}
		for y := -d + 1 + from.Y; y <= d-1+from.Y; y++ {
			for _, pos := range []position{{from.X + d, y}, {from.X - d, y}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = raynode{Cost: c}
			}
		}
	}
	return rm
}

func (g *game) LosRange() int {
	losRange := 6
	if g.Player.Armour == ShinyPlates {
		losRange++
	}
	if g.Player.Aptitudes[AptStealthyLOS] {
		losRange -= 2
	}
	if g.Player.Armour == HarmonistRobe {
		losRange -= 1
	}
	if g.Player.Weapon == Frundis {
		losRange -= 1
	}
	if g.Player.HasStatus(StatusShadows) {
		losRange = 1
	}
	if losRange < 1 {
		losRange = 1
	}
	return losRange
}

func (g *game) StopAuto() {
	if g.Autoexploring && !g.AutoHalt {
		g.Print("You stop exploring.")
	} else if g.AutoDir != NoDir {
		g.Print("You stop.")
	} else if g.AutoTarget != InvalidPos {
		g.Print("You stop.")
	}
	g.AutoHalt = true
	g.AutoDir = NoDir
	g.AutoTarget = InvalidPos
	if g.Resting {
		g.Stats.RestInterrupt++
		g.Resting = false
		g.Print("You could not sleep.")
	}
}

func (g *game) ComputeLOS() {
	m := map[position]bool{}
	losRange := g.LosRange()
	g.Player.Rays = g.buildRayMap(g.Player.Pos, losRange)
	for pos, n := range g.Player.Rays {
		if n.Cost < g.LosRange() {
			m[pos] = true
			g.SeePosition(pos)
		}
	}
	g.Player.LOS = m
	for _, mons := range g.Monsters {
		if mons.Exists() && g.Player.LOS[mons.Pos] {
			if mons.Seen {
				g.StopAuto()
				continue
			}
			mons.Seen = true
			g.Printf("You see %s (%v).", mons.Kind.Indefinite(false), mons.State)
			if mons.Kind.Dangerousness() > 10 {
				g.StoryPrint(mons.Kind.SeenStoryText())
			}
			g.StopAuto()
		}
	}
}

func (g *game) SeePosition(pos position) {
	if !g.Dungeon.Cell(pos).Explored {
		see := "see"
		if c, ok := g.Collectables[pos]; ok {
			if c.Quantity > 1 {
				g.Printf("You %s %d %s.", see, c.Quantity, c.Consumable.Plural())
			} else {
				g.Printf("You %s %s.", see, Indefinite(c.Consumable.String(), false))
			}
			g.StopAuto()
		} else if _, ok := g.Stairs[pos]; ok {
			g.Printf("You %s stairs.", see)
			g.StopAuto()
		} else if eq, ok := g.Equipables[pos]; ok {
			g.Printf("You %s %s.", see, Indefinite(eq.String(), false))
			g.StopAuto()
		} else if rd, ok := g.Rods[pos]; ok {
			g.Printf("You %s %s.", see, Indefinite(rd.String(), false))
			g.StopAuto()
		} else if stn, ok := g.MagicalStones[pos]; ok {
			g.Printf("You %s %s.", see, Indefinite(stn.String(), false))
			g.StopAuto()
		}
		g.FunAction()
		g.Dungeon.SetExplored(pos)
		g.DijkstraMapRebuild = true
	} else {
		if g.WrongWall[pos] {
			g.Printf("There is no longer a wall there.")
			g.StopAuto()
			g.DijkstraMapRebuild = true
		}
		if cld, ok := g.Clouds[pos]; ok && cld == CloudFire && (g.WrongDoor[pos] || g.WrongFoliage[pos]) {
			g.Printf("There are flames there.")
			g.StopAuto()
			g.DijkstraMapRebuild = true
		}
	}
	if g.WrongWall[pos] {
		delete(g.WrongWall, pos)
		if g.Dungeon.Cell(pos).T == FreeCell {
			delete(g.TemporalWalls, pos)
		}
	}
	if _, ok := g.WrongDoor[pos]; ok {
		delete(g.WrongDoor, pos)
	}
	if _, ok := g.WrongFoliage[pos]; ok {
		delete(g.WrongFoliage, pos)
	}
	if _, ok := g.DreamingMonster[pos]; ok {
		delete(g.DreamingMonster, pos)
	}
}

func (g *game) ComputeExclusion(pos position, toggle bool) {
	exclusionRange := g.LosRange()
	g.ExclusionsMap[pos] = toggle
	for d := 1; d <= exclusionRange; d++ {
		for x := -d + pos.X; x <= d+pos.X; x++ {
			for _, pos := range []position{{x, pos.Y + d}, {x, pos.Y - d}} {
				if !pos.valid() {
					continue
				}
				g.ExclusionsMap[pos] = toggle
			}
		}
		for y := -d + 1 + pos.Y; y <= d-1+pos.Y; y++ {
			for _, pos := range []position{{pos.X + d, y}, {pos.X - d, y}} {
				if !pos.valid() {
					continue
				}
				g.ExclusionsMap[pos] = toggle
			}
		}
	}
}

func (g *game) Ray(pos position) []position {
	if !g.Player.LOS[pos] {
		return nil
	}
	ray := []position{}
	for pos != g.Player.Pos {
		ray = append(ray, pos)
		pos, _ = g.bestParent(g.Player.Rays, g.Player.Pos, pos)
	}
	return ray
}

func (g *game) ComputeRayHighlight(pos position) {
	g.Highlight = map[position]bool{}
	ray := g.Ray(pos)
	for _, p := range ray {
		g.Highlight[p] = true
	}
}

func (g *game) ComputeNoise() {
	dij := &noisePath{game: g}
	rg := g.LosRange() + 2
	if rg <= 5 {
		rg++
	}
	if g.Player.Aptitudes[AptHear] {
		rg++
	}
	nm := Dijkstra(dij, []position{g.Player.Pos}, rg)
	count := 0
	noise := map[position]bool{}
	rmax := 3
	if g.Player.Aptitudes[AptHear] {
		rmax--
	}
	for pos := range nm {
		if g.Player.LOS[pos] {
			continue
		}
		mons := g.MonsterAt(pos)
		if mons.Exists() && mons.State != Resting && RandInt(rmax) == 0 {
			switch mons.Kind {
			case MonsMirrorSpecter, MonsSatowalgaPlant:
				// no footsteps
			case MonsTinyHarpy, MonsWingedMilfid, MonsGiantBee:
				noise[pos] = true
				g.Print("You hear the flapping of wings.")
				count++
			default:
				noise[pos] = true
				g.Print("You hear footsteps.")
				count++
			}
		}
	}
	if count > 0 {
		g.StopAuto()
	}
	g.Noise = noise
}
<|endoftext|>


<commit_before>package gorivets

import (
	"container/list"
	"strconv"
)

type (
	Lru struct {
		list     *list.List
		elements map[interface{}]*list.Element
		size     int64
		maxSize  int64
		callback Callback
	}

	element struct {
		key  interface{}
		val  interface{}
		size int64
	}

	Callback func(k, v interface{})
)

func NewLRU(maxSize int64, callback Callback) *Lru {
	if maxSize < 1 {
		panic("LRU size=" + strconv.FormatInt(maxSize, 10) + " should be positive.")
	}
	l := new(Lru)
	l.list = list.New()
	l.elements = make(map[interface{}]*list.Element)
	l.size = 0
	l.maxSize = maxSize
	l.callback = callback
	return l
}

func (lru *Lru) Add(k, v interface{}, size int64) {
	lru.Delete(k)
	e := &element{key: k, val: v, size: size}
	el := lru.list.PushBack(e)
	lru.elements[k] = el
	lru.size += size
	for lru.size > lru.maxSize && lru.deleteLast() {

	}
}

func (lru *Lru) Get(k interface{}) (interface{}, bool) {
	if e, ok := lru.elements[k]; ok {
		lru.list.MoveToBack(e)
		return e.Value.(*element).val, true
	}
	return nil, false
}

func (lru *Lru) Delete(k interface{}) interface{} {
	return lru.DeleteWithCallback(k, true)
}

func (lru *Lru) DeleteWithCallback(k interface{}, callback bool) interface{} {
	el, ok := lru.elements[k]
	if !ok {
		return nil
	}
	delete(lru.elements, k)
	e := lru.list.Remove(el).(*element)
	lru.size -= e.size
	if callback && lru.callback != nil {
		lru.callback(e.key, e.val)
	}
	return e.val
}

// Clear the cache. This method will not invoke callbacks for the deleted
// elements
func (lru *Lru) Clear() {
	lru.list.Init()
	lru.elements = make(map[interface{}]*list.Element)
	lru.size = 0
}

func (lru *Lru) Len() int {
	return len(lru.elements)
}

func (lru *Lru) Size() int64 {
	return lru.size
}

func (lru *Lru) deleteLast() bool {
	el := lru.list.Front()
	if el == nil {
		return false
	}
	e := el.Value.(*element)
	lru.Delete(e.key)
	return true
}
<commit_msg>rename callback type<commit_after>package gorivets

import (
	"container/list"
	"strconv"
)

type (
	Lru struct {
		list     *list.List
		elements map[interface{}]*list.Element
		size     int64
		maxSize  int64
		callback LruCallback
	}

	element struct {
		key  interface{}
		val  interface{}
		size int64
	}

	LruCallback func(k, v interface{})
)

func NewLRU(maxSize int64, callback LruCallback) *Lru {
	if maxSize < 1 {
		panic("LRU size=" + strconv.FormatInt(maxSize, 10) + " should be positive.")
	}
	l := new(Lru)
	l.list = list.New()
	l.elements = make(map[interface{}]*list.Element)
	l.size = 0
	l.maxSize = maxSize
	l.callback = callback
	return l
}

func (lru *Lru) Add(k, v interface{}, size int64) {
	lru.Delete(k)
	e := &element{key: k, val: v, size: size}
	el := lru.list.PushBack(e)
	lru.elements[k] = el
	lru.size += size
	for lru.size > lru.maxSize && lru.deleteLast() {

	}
}

func (lru *Lru) Get(k interface{}) (interface{}, bool) {
	if e, ok := lru.elements[k]; ok {
		lru.list.MoveToBack(e)
		return e.Value.(*element).val, true
	}
	return nil, false
}

func (lru *Lru) Delete(k interface{}) interface{} {
	return lru.DeleteWithCallback(k, true)
}

func (lru *Lru) DeleteWithCallback(k interface{}, callback bool) interface{} {
	el, ok := lru.elements[k]
	if !ok {
		return nil
	}
	delete(lru.elements, k)
	e := lru.list.Remove(el).(*element)
	lru.size -= e.size
	if callback && lru.callback != nil {
		lru.callback(e.key, e.val)
	}
	return e.val
}

// Clear the cache. This method will not invoke callbacks for the deleted
// elements
func (lru *Lru) Clear() {
	lru.list.Init()
	lru.elements = make(map[interface{}]*list.Element)
	lru.size = 0
}

func (lru *Lru) Len() int {
	return len(lru.elements)
}

func (lru *Lru) Size() int64 {
	return lru.size
}

func (lru *Lru) deleteLast() bool {
	el := lru.list.Front()
	if el == nil {
		return false
	}
	e := el.Value.(*element)
	lru.Delete(e.key)
	return true
}
<|endoftext|>


<commit_before>/*
 * lxc.go: Go bindings for lxc
 *
 * Copyright © 2013, S.Çağlar Onur
 *
 * Authors:
 * S.Çağlar Onur <caglar@10ur.org>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

//Go (golang) Bindings for LXC (Linux Containers)
//
//This package implements Go bindings for the LXC C API.
package lxc

// #cgo linux LDFLAGS: -llxc -lutil
// #include <lxc/lxc.h>
// #include <lxc/lxccontainer.h>
// #include "lxc.h"
import "C"

import (
	"strings"
	"syscall"
	"unsafe"
)

const (
	// Timeout
	WAIT_FOREVER int = iota
	DONT_WAIT

	LXC_NETWORK_KEY = "lxc.network"
)

func makeArgs(args []string) []*C.char {
	ret := make([]*C.char, len(args))
	for i, s := range args {
		ret[i] = C.CString(s)
	}
	return ret
}

func freeArgs(cArgs []*C.char) {
	for _, s := range cArgs {
		C.free(unsafe.Pointer(s))
	}
}

type Container struct {
	container *C.struct_lxc_container
}

func (lxc *Container) Error() string {
	return C.GoString(lxc.container.error_string)
}

func (lxc *Container) GetError() error {
	return syscall.Errno(int(lxc.container.error_num))
}

func NewContainer(name string) Container {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))
	return Container{C.lxc_container_new(cname, nil)}
}

// Returns LXC version
func GetVersion() string {
	return C.GoString(C.lxc_get_version())
}

func GetDefaultConfigPath() string {
	return C.GoString(C.lxc_get_default_config_path())
}

// Returns container's name
func (lxc *Container) GetName() string {
	return C.GoString(lxc.container.name)
}

// Returns whether the container is already defined or not
func (lxc *Container) Defined() bool {
	return bool(C.lxc_container_defined(lxc.container))
}

// Returns whether the container is already running or not
func (lxc *Container) Running() bool {
	return bool(C.lxc_container_running(lxc.container))
}

// Returns the container's state
func (lxc *Container) GetState() State {
	return stateMap[C.GoString(C.lxc_container_state(lxc.container))]
}

// Returns the container's PID
func (lxc *Container) GetInitPID() int {
	return int(C.lxc_container_init_pid(lxc.container))
}

// Returns whether the daemonize flag is set
func (lxc *Container) GetDaemonize() bool {
	return bool(lxc.container.daemonize != 0)
}

// Sets the daemonize flag
func (lxc *Container) SetDaemonize() {
	C.lxc_container_want_daemonize(lxc.container)
}

// Freezes the running container
func (lxc *Container) Freeze() bool {
	return bool(C.lxc_container_freeze(lxc.container))
}

// Unfreezes the frozen container
func (lxc *Container) Unfreeze() bool {
	return bool(C.lxc_container_unfreeze(lxc.container))
}

// Creates the container using given template and arguments
func (lxc *Container) Create(template string, args []string) bool {
	ctemplate := C.CString(template)
	defer C.free(unsafe.Pointer(ctemplate))
	if args != nil {
		cargs := makeArgs(args)
		defer freeArgs(cargs)
		return bool(C.lxc_container_create(lxc.container, ctemplate, &cargs[0]))
	}
	return bool(C.lxc_container_create(lxc.container, ctemplate, nil))
}

// Starts the container
func (lxc *Container) Start(useinit bool, args []string) bool {
	cuseinit := 0
	if useinit {
		cuseinit = 1
	}
	if args != nil {
		cargs := makeArgs(args)
		defer freeArgs(cargs)
		return bool(C.lxc_container_start(lxc.container, C.int(cuseinit), &cargs[0]))
	}
	return bool(C.lxc_container_start(lxc.container, C.int(cuseinit), nil))
}

// Stops the container
func (lxc *Container) Stop() bool {
	return bool(C.lxc_container_stop(lxc.container))
}

// Shutdowns the container
func (lxc *Container) Shutdown(timeout int) bool {
	return bool(C.lxc_container_shutdown(lxc.container, C.int(timeout)))
}

// Destroys the container
func (lxc *Container) Destroy() bool {
	return bool(C.lxc_container_destroy(lxc.container))
}

// Waits till the container changes its state or timeouts
func (lxc *Container) Wait(state State, timeout int) bool {
	cstate := C.CString(state.String())
	defer C.free(unsafe.Pointer(cstate))
	return bool(C.lxc_container_wait(lxc.container, cstate, C.int(timeout)))
}

// Returns the container's configuration file's name
func (lxc *Container) GetConfigFileName() string {
	return C.GoString(C.lxc_container_config_file_name(lxc.container))
}

// Returns the value of the given key
func (lxc *Container) GetConfigItem(key string) []string {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	ret := strings.TrimSpace(C.GoString(C.lxc_container_get_config_item(lxc.container, ckey)))
	return strings.Split(ret, "\n")
}

// Sets the value of given key
func (lxc *Container) SetConfigItem(key string, value string) bool {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	cvalue := C.CString(value)
	defer C.free(unsafe.Pointer(cvalue))
	return bool(C.lxc_container_set_config_item(lxc.container, ckey, cvalue))
}

// Returns the value of the given key
func (lxc *Container) GetCgroupItem(key string) []string {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	ret := strings.TrimSpace(C.GoString(C.lxc_container_get_cgroup_item(lxc.container, ckey)))
	return strings.Split(ret, "\n")
}

// Sets the value of given key
func (lxc *Container) SetCgroupItem(key string, value string) bool {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	cvalue := C.CString(value)
	defer C.free(unsafe.Pointer(cvalue))
	return bool(C.lxc_container_set_cgroup_item(lxc.container, ckey, cvalue))
}

// Clears the value of given key
func (lxc *Container) ClearConfigItem(key string) bool {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	return bool(C.lxc_container_clear_config_item(lxc.container, ckey))
}

// Returns the keys
func (lxc *Container) GetKeys(key string) []string {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	ret := strings.TrimSpace(C.GoString(C.lxc_container_get_keys(lxc.container, ckey)))
	return strings.Split(ret, "\n")
}

// Loads the configuration file from given path
func (lxc *Container) LoadConfigFile(path string) bool {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	return bool(C.lxc_container_load_config(lxc.container, cpath))
}

// Saves the configuration file to given path
func (lxc *Container) SaveConfigFile(path string) bool {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	return bool(C.lxc_container_save_config(lxc.container, cpath))
}

func (lxc *Container) GetConfigPath() string {
	return C.GoString(C.lxc_container_get_config_path(lxc.container))
}

func (lxc *Container) SetConfigPath(path string) bool {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	return bool(C.lxc_container_set_config_path(lxc.container, cpath))
}

func (lxc *Container) GetNumberOfNetworkInterfaces() int {
	return len(lxc.GetConfigItem(LXC_NETWORK_KEY))
}
<commit_msg>WAIT_FOREVER is -1 not 0<commit_after>/*
 * lxc.go: Go bindings for lxc
 *
 * Copyright © 2013, S.Çağlar Onur
 *
 * Authors:
 * S.Çağlar Onur <caglar@10ur.org>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

//Go (golang) Bindings for LXC (Linux Containers)
//
//This package implements Go bindings for the LXC C API.
package lxc

// #cgo linux LDFLAGS: -llxc -lutil
// #include <lxc/lxc.h>
// #include <lxc/lxccontainer.h>
// #include "lxc.h"
import "C"

import (
	"strings"
	"syscall"
	"unsafe"
)

const (
	// Timeout
	WAIT_FOREVER int = iota - 1
	DONT_WAIT

	LXC_NETWORK_KEY = "lxc.network"
)

func makeArgs(args []string) []*C.char {
	ret := make([]*C.char, len(args))
	for i, s := range args {
		ret[i] = C.CString(s)
	}
	return ret
}

func freeArgs(cArgs []*C.char) {
	for _, s := range cArgs {
		C.free(unsafe.Pointer(s))
	}
}

type Container struct {
	container *C.struct_lxc_container
}

func (lxc *Container) Error() string {
	return C.GoString(lxc.container.error_string)
}

func (lxc *Container) GetError() error {
	return syscall.Errno(int(lxc.container.error_num))
}

func NewContainer(name string) Container {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))
	return Container{C.lxc_container_new(cname, nil)}
}

// Returns LXC version
func GetVersion() string {
	return C.GoString(C.lxc_get_version())
}

func GetDefaultConfigPath() string {
	return C.GoString(C.lxc_get_default_config_path())
}

// Returns container's name
func (lxc *Container) GetName() string {
	return C.GoString(lxc.container.name)
}

// Returns whether the container is already defined or not
func (lxc *Container) Defined() bool {
	return bool(C.lxc_container_defined(lxc.container))
}

// Returns whether the container is already running or not
func (lxc *Container) Running() bool {
	return bool(C.lxc_container_running(lxc.container))
}

// Returns the container's state
func (lxc *Container) GetState() State {
	return stateMap[C.GoString(C.lxc_container_state(lxc.container))]
}

// Returns the container's PID
func (lxc *Container) GetInitPID() int {
	return int(C.lxc_container_init_pid(lxc.container))
}

// Returns whether the daemonize flag is set
func (lxc *Container) GetDaemonize() bool {
	return bool(lxc.container.daemonize != 0)
}

// Sets the daemonize flag
func (lxc *Container) SetDaemonize() {
	C.lxc_container_want_daemonize(lxc.container)
}

// Freezes the running container
func (lxc *Container) Freeze() bool {
	return bool(C.lxc_container_freeze(lxc.container))
}

// Unfreezes the frozen container
func (lxc *Container) Unfreeze() bool {
	return bool(C.lxc_container_unfreeze(lxc.container))
}

// Creates the container using given template and arguments
func (lxc *Container) Create(template string, args []string) bool {
	ctemplate := C.CString(template)
	defer C.free(unsafe.Pointer(ctemplate))
	if args != nil {
		cargs := makeArgs(args)
		defer freeArgs(cargs)
		return bool(C.lxc_container_create(lxc.container, ctemplate, &cargs[0]))
	}
	return bool(C.lxc_container_create(lxc.container, ctemplate, nil))
}

// Starts the container
func (lxc *Container) Start(useinit bool, args []string) bool {
	cuseinit := 0
	if useinit {
		cuseinit = 1
	}
	if args != nil {
		cargs := makeArgs(args)
		defer freeArgs(cargs)
		return bool(C.lxc_container_start(lxc.container, C.int(cuseinit), &cargs[0]))
	}
	return bool(C.lxc_container_start(lxc.container, C.int(cuseinit), nil))
}

// Stops the container
func (lxc *Container) Stop() bool {
	return bool(C.lxc_container_stop(lxc.container))
}

// Shutdowns the container
func (lxc *Container) Shutdown(timeout int) bool {
	return bool(C.lxc_container_shutdown(lxc.container, C.int(timeout)))
}

// Destroys the container
func (lxc *Container) Destroy() bool {
	return bool(C.lxc_container_destroy(lxc.container))
}

// Waits till the container changes its state or timeouts
func (lxc *Container) Wait(state State, timeout int) bool {
	cstate := C.CString(state.String())
	defer C.free(unsafe.Pointer(cstate))
	return bool(C.lxc_container_wait(lxc.container, cstate, C.int(timeout)))
}

// Returns the container's configuration file's name
func (lxc *Container) GetConfigFileName() string {
	return C.GoString(C.lxc_container_config_file_name(lxc.container))
}

// Returns the value of the given key
func (lxc *Container) GetConfigItem(key string) []string {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	ret := strings.TrimSpace(C.GoString(C.lxc_container_get_config_item(lxc.container, ckey)))
	return strings.Split(ret, "\n")
}

// Sets the value of given key
func (lxc *Container) SetConfigItem(key string, value string) bool {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	cvalue := C.CString(value)
	defer C.free(unsafe.Pointer(cvalue))
	return bool(C.lxc_container_set_config_item(lxc.container, ckey, cvalue))
}

// Returns the value of the given key
func (lxc *Container) GetCgroupItem(key string) []string {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	ret := strings.TrimSpace(C.GoString(C.lxc_container_get_cgroup_item(lxc.container, ckey)))
	return strings.Split(ret, "\n")
}

// Sets the value of given key
func (lxc *Container) SetCgroupItem(key string, value string) bool {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	cvalue := C.CString(value)
	defer C.free(unsafe.Pointer(cvalue))
	return bool(C.lxc_container_set_cgroup_item(lxc.container, ckey, cvalue))
}

// Clears the value of given key
func (lxc *Container) ClearConfigItem(key string) bool {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	return bool(C.lxc_container_clear_config_item(lxc.container, ckey))
}

// Returns the keys
func (lxc *Container) GetKeys(key string) []string {
	ckey := C.CString(key)
	defer C.free(unsafe.Pointer(ckey))
	ret := strings.TrimSpace(C.GoString(C.lxc_container_get_keys(lxc.container, ckey)))
	return strings.Split(ret, "\n")
}

// Loads the configuration file from given path
func (lxc *Container) LoadConfigFile(path string) bool {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	return bool(C.lxc_container_load_config(lxc.container, cpath))
}

// Saves the configuration file to given path
func (lxc *Container) SaveConfigFile(path string) bool {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	return bool(C.lxc_container_save_config(lxc.container, cpath))
}

func (lxc *Container) GetConfigPath() string {
	return C.GoString(C.lxc_container_get_config_path(lxc.container))
}

func (lxc *Container) SetConfigPath(path string) bool {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	return bool(C.lxc_container_set_config_path(lxc.container, cpath))
}

func (lxc *Container) GetNumberOfNetworkInterfaces() int {
	return len(lxc.GetConfigItem(LXC_NETWORK_KEY))
}
<|endoftext|>


<commit_before>// Copyright 2019 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

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

// Package cgozlib wraps the C "zlib" library.
//
// Unlike some other wrappers, this one supports dictionaries.
package cgozlib

/*
#cgo pkg-config: zlib
#include "zlib.h"

typedef struct {
	uInt ndst;
	uInt nsrc;
} advances;

int cgozlib_inflateInit(z_stream* z) {
	return inflateInit(z);
}

int cgozlib_inflateSetDictionary(z_stream* z,
		Bytef* dict_ptr,
		uInt dict_len) {
	return inflateSetDictionary(z, dict_ptr, dict_len);
}

int cgozlib_inflate(z_stream* z,
		advances *a,
		Bytef* next_out,
		uInt avail_out,
		Bytef* next_in,
		uInt avail_in) {
	z->next_out = next_out;
	z->avail_out = avail_out;
	z->next_in = next_in;
	z->avail_in = avail_in;

	int ret = inflate(z, Z_NO_FLUSH);

	a->ndst = avail_out - z->avail_out;
	a->nsrc = avail_in - z->avail_in;

	z->next_out = NULL;
	z->avail_out = 0;
	z->next_in = NULL;
	z->avail_in = 0;

	return ret;
}

int cgozlib_inflateEnd(z_stream* z) {
	return inflateEnd(z);
}
*/
import "C"

import (
	"errors"
	"io"
	"unsafe"
)

const cgoEnabled = true

var (
	errMissingResetCall = errors.New("cgozlib: missing Reset call")
	errNilIOReader      = errors.New("cgozlib: nil io.Reader")
	errNilReceiver      = errors.New("cgozlib: nil receiver")
)

const (
	errCodeStreamEnd = 1
	errCodeNeedDict  = 2
)

type errCode int32

func (e errCode) Error() string {
	switch e {
	case +1:
		return "cgozlib: Z_STREAM_END"
	case +2:
		return "cgozlib: Z_NEED_DICT"
	case -1:
		return "cgozlib: Z_ERRNO"
	case -2:
		return "cgozlib: Z_STREAM_ERROR"
	case -3:
		return "cgozlib: Z_DATA_ERROR"
	case -4:
		return "cgozlib: Z_MEM_ERROR"
	case -5:
		return "cgozlib: Z_BUF_ERROR"
	case -6:
		return "cgozlib: Z_VERSION_ERROR"
	}
	return "cgozlib: unknown zlib error"
}

// Reader is both a zlib.Resetter and an io.ReadCloser. Call Reset before
// calling Read.
//
// It is analogous to the value returned by zlib.NewReader in the Go standard
// library.
type Reader struct {
	buf  [4096]byte
	i, j uint32
	r    io.Reader
	dict []byte

	readErr error
	zlibErr error

	z C.z_stream
	a C.advances
}

// Reset implements compression.Reader.
func (r *Reader) Reset(reader io.Reader, dictionary []byte) error {
	if r == nil {
		return errNilReceiver
	}
	if reader == nil {
		return errNilIOReader
	}
	if err := r.Close(); err != nil {
		return err
	}

	if e := C.cgozlib_inflateInit(&r.z); e != 0 {
		return errCode(e)
	}

	r.r = reader
	r.dict = dictionary
	if n := len(r.dict); n > 32768 {
		r.dict = r.dict[n-32768:]
	}
	return nil
}

// Close implements compression.Reader.
func (r *Reader) Close() error {
	if r == nil {
		return errNilReceiver
	}
	if r.r == nil {
		return nil
	}
	r.i = 0
	r.j = 0
	r.r = nil
	r.dict = nil
	r.readErr = nil
	r.zlibErr = nil
	if e := C.cgozlib_inflateEnd(&r.z); e != 0 {
		return errCode(e)
	}
	return nil
}

// Read implements compression.Reader.
func (r *Reader) Read(p []byte) (int, error) {
	if r == nil {
		return 0, errNilReceiver
	}
	if r.r == nil {
		return 0, errMissingResetCall
	}

	const maxLen = 1 << 30
	if len(p) > maxLen {
		p = p[:maxLen]
	}

	for numRead := 0; ; {
		if r.zlibErr != nil {
			return numRead, r.zlibErr
		}
		if len(p) == 0 {
			return numRead, nil
		}

		if r.i >= r.j {
			if r.readErr != nil {
				return numRead, r.readErr
			}

			n, err := r.r.Read(r.buf[:])
			if err == io.EOF {
				err = io.ErrUnexpectedEOF
			}
			r.i, r.j, r.readErr = 0, uint32(n), err
			continue
		}

		e := C.cgozlib_inflate(&r.z, &r.a,
			(*C.Bytef)(unsafe.Pointer(&p[0])),
			(C.uInt)(len(p)),
			(*C.Bytef)(unsafe.Pointer(&r.buf[r.i])),
			(C.uInt)(r.j-r.i),
		)

		numRead += int(r.a.ndst)
		p = p[int(r.a.ndst):]

		r.i += uint32(r.a.nsrc)

		if e == 0 {
			continue
		} else if e == errCodeStreamEnd {
			r.zlibErr = io.EOF
		} else if (e == errCodeNeedDict) && (len(r.dict) > 0) {
			e = C.cgozlib_inflateSetDictionary(&r.z,
				(*C.Bytef)(unsafe.Pointer(&r.dict[0])),
				(C.uInt)(len(r.dict)),
			)
			if e == 0 {
				continue
			}
			r.zlibErr = errCode(e)
		} else {
			r.zlibErr = errCode(e)
		}
		return numRead, r.zlibErr
	}
}
<commit_msg>Tweak cgozlib to be consistent with cgozstd<commit_after>// Copyright 2019 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

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

// Package cgozlib wraps the C "zlib" library.
//
// Unlike some other wrappers, this one supports dictionaries.
package cgozlib

/*
#cgo pkg-config: zlib
#include "zlib.h"

typedef struct {
	uInt ndst;
	uInt nsrc;
} advances;

int cgozlib_inflateInit(z_stream* z) {
	return inflateInit(z);
}

int cgozlib_inflateSetDictionary(z_stream* z,
		Bytef* dict_ptr,
		uInt dict_len) {
	return inflateSetDictionary(z, dict_ptr, dict_len);
}

int cgozlib_inflate(z_stream* z,
		advances* a,
		Bytef* next_out,
		uInt avail_out,
		Bytef* next_in,
		uInt avail_in) {
	z->next_out = next_out;
	z->avail_out = avail_out;
	z->next_in = next_in;
	z->avail_in = avail_in;

	int ret = inflate(z, Z_NO_FLUSH);

	a->ndst = avail_out - z->avail_out;
	a->nsrc = avail_in - z->avail_in;

	z->next_out = NULL;
	z->avail_out = 0;
	z->next_in = NULL;
	z->avail_in = 0;

	return ret;
}

int cgozlib_inflateEnd(z_stream* z) {
	return inflateEnd(z);
}
*/
import "C"

import (
	"errors"
	"io"
	"unsafe"
)

const cgoEnabled = true

var (
	errMissingResetCall = errors.New("cgozlib: missing Reset call")
	errNilIOReader      = errors.New("cgozlib: nil io.Reader")
	errNilReceiver      = errors.New("cgozlib: nil receiver")
)

const (
	errCodeStreamEnd = 1
	errCodeNeedDict  = 2
)

type errCode int32

func (e errCode) Error() string {
	switch e {
	case +1:
		return "cgozlib: Z_STREAM_END"
	case +2:
		return "cgozlib: Z_NEED_DICT"
	case -1:
		return "cgozlib: Z_ERRNO"
	case -2:
		return "cgozlib: Z_STREAM_ERROR"
	case -3:
		return "cgozlib: Z_DATA_ERROR"
	case -4:
		return "cgozlib: Z_MEM_ERROR"
	case -5:
		return "cgozlib: Z_BUF_ERROR"
	case -6:
		return "cgozlib: Z_VERSION_ERROR"
	}
	return "cgozlib: unknown zlib error"
}

// Reader is both a zlib.Resetter and an io.ReadCloser. Call Reset before
// calling Read.
//
// It is analogous to the value returned by zlib.NewReader in the Go standard
// library.
type Reader struct {
	buf  [4096]byte
	i, j uint32
	r    io.Reader
	dict []byte

	readErr error
	zlibErr error

	z C.z_stream
	a C.advances
}

// Reset implements compression.Reader.
func (r *Reader) Reset(reader io.Reader, dictionary []byte) error {
	if r == nil {
		return errNilReceiver
	}
	if err := r.Close(); err != nil {
		return err
	}
	if reader == nil {
		return errNilIOReader
	}

	if e := C.cgozlib_inflateInit(&r.z); e != 0 {
		return errCode(e)
	}

	r.r = reader
	r.dict = dictionary
	if n := len(r.dict); n > 32768 {
		r.dict = r.dict[n-32768:]
	}
	return nil
}

// Close implements compression.Reader.
func (r *Reader) Close() error {
	if r == nil {
		return errNilReceiver
	}
	if r.r == nil {
		return nil
	}
	r.i = 0
	r.j = 0
	r.r = nil
	r.dict = nil
	r.readErr = nil
	r.zlibErr = nil
	if e := C.cgozlib_inflateEnd(&r.z); e != 0 {
		return errCode(e)
	}
	return nil
}

// Read implements compression.Reader.
func (r *Reader) Read(p []byte) (int, error) {
	if r == nil {
		return 0, errNilReceiver
	}
	if r.r == nil {
		return 0, errMissingResetCall
	}

	const maxLen = 1 << 30
	if len(p) > maxLen {
		p = p[:maxLen]
	}

	for numRead := 0; ; {
		if r.zlibErr != nil {
			return numRead, r.zlibErr
		}
		if len(p) == 0 {
			return numRead, nil
		}

		if r.i >= r.j {
			if r.readErr != nil {
				return numRead, r.readErr
			}

			n, err := r.r.Read(r.buf[:])
			if err == io.EOF {
				err = io.ErrUnexpectedEOF
			}
			r.i, r.j, r.readErr = 0, uint32(n), err
			continue
		}

		e := C.cgozlib_inflate(&r.z, &r.a,
			(*C.Bytef)(unsafe.Pointer(&p[0])),
			(C.uInt)(len(p)),
			(*C.Bytef)(unsafe.Pointer(&r.buf[r.i])),
			(C.uInt)(r.j-r.i),
		)

		numRead += int(r.a.ndst)
		p = p[int(r.a.ndst):]

		r.i += uint32(r.a.nsrc)

		if e == 0 {
			continue
		} else if e == errCodeStreamEnd {
			r.zlibErr = io.EOF
		} else if (e == errCodeNeedDict) && (len(r.dict) > 0) {
			e = C.cgozlib_inflateSetDictionary(&r.z,
				(*C.Bytef)(unsafe.Pointer(&r.dict[0])),
				(C.uInt)(len(r.dict)),
			)
			if e == 0 {
				continue
			}
			r.zlibErr = errCode(e)
		} else {
			r.zlibErr = errCode(e)
		}
		return numRead, r.zlibErr
	}
}
<|endoftext|>


<commit_before>package discovery

import (
	"context"
	"errors"
	"io"
	"net"
	"sync"
	"time"

	logging "github.com/ipfs/go-log"
	"github.com/libp2p/go-libp2p-host"
	"github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
	"github.com/whyrusleeping/mdns"
)

var log = logging.Logger("mdns")

const ServiceTag = "_ipfs-discovery._udp"

type Service interface {
	io.Closer
	RegisterNotifee(Notifee)
	UnregisterNotifee(Notifee)
}

type Notifee interface {
	HandlePeerFound(pstore.PeerInfo)
}

type mdnsService struct {
	server  *mdns.Server
	service *mdns.MDNSService
	host    host.Host
	tag     string

	lk       sync.Mutex
	notifees []Notifee
	interval time.Duration
}

func getDialableListenAddrs(ph host.Host) ([]*net.TCPAddr, error) {
	var out []*net.TCPAddr
	for _, addr := range ph.Addrs() {
		na, err := manet.ToNetAddr(addr)
		if err != nil {
			continue
		}
		tcp, ok := na.(*net.TCPAddr)
		if ok {
			out = append(out, tcp)
		}
	}
	if len(out) == 0 {
		return nil, errors.New("failed to find good external addr from peerhost")
	}
	return out, nil
}

func NewMdnsService(ctx context.Context, peerhost host.Host, interval time.Duration, serviceTag string) (Service, error) {

	// don't let mdns use logging...
	mdns.DisableLogging = true

	var ipaddrs []net.IP
	port := 4001

	addrs, err := getDialableListenAddrs(peerhost)
	if err != nil {
		log.Warning(err)
	} else {
		port = addrs[0].Port
		for _, a := range addrs {
			ipaddrs = append(ipaddrs, a.IP)
		}
	}

	myid := peerhost.ID().Pretty()

	info := []string{myid}
	if serviceTag == "" {
		serviceTag = ServiceTag
	}
	service, err := mdns.NewMDNSService(myid, serviceTag, "", "", port, ipaddrs, info)
	if err != nil {
		return nil, err
	}

	// Create the mDNS server, defer shutdown
	server, err := mdns.NewServer(&mdns.Config{Zone: service})
	if err != nil {
		return nil, err
	}

	s := &mdnsService{
		server:   server,
		service:  service,
		host:     peerhost,
		interval: interval,
		tag:      serviceTag,
	}

	go s.pollForEntries(ctx)

	return s, nil
}

func (m *mdnsService) Close() error {
	return m.server.Shutdown()
}

func (m *mdnsService) pollForEntries(ctx context.Context) {

	ticker := time.NewTicker(m.interval)
	for {
		//execute mdns query right away at method call and then with every tick
		entriesCh := make(chan *mdns.ServiceEntry, 16)
		go func() {
			for entry := range entriesCh {
				m.handleEntry(entry)
			}
		}()

		log.Debug("starting mdns query")
		qp := &mdns.QueryParam{
			Domain:  "local",
			Entries: entriesCh,
			Service: m.tag,
			Timeout: time.Second * 5,
		}

		err := mdns.Query(qp)
		if err != nil {
			log.Error("mdns lookup error: ", err)
		}
		close(entriesCh)
		log.Debug("mdns query complete")

		select {
		case <-ticker.C:
			continue
		case <-ctx.Done():
			log.Debug("mdns service halting")
			return
		}
	}
}

func (m *mdnsService) handleEntry(e *mdns.ServiceEntry) {
	log.Debugf("Handling MDNS entry: %s:%d %s", e.AddrV4, e.Port, e.Info)
	mpeer, err := peer.IDB58Decode(e.Info)
	if err != nil {
		log.Warning("Error parsing peer ID from mdns entry: ", err)
		return
	}

	if mpeer == m.host.ID() {
		log.Debug("got our own mdns entry, skipping")
		return
	}

	maddr, err := manet.FromNetAddr(&net.TCPAddr{
		IP:   e.AddrV4,
		Port: e.Port,
	})
	if err != nil {
		log.Warning("Error parsing multiaddr from mdns entry: ", err)
		return
	}

	pi := pstore.PeerInfo{
		ID:    mpeer,
		Addrs: []ma.Multiaddr{maddr},
	}

	m.lk.Lock()
	for _, n := range m.notifees {
		go n.HandlePeerFound(pi)
	}
	m.lk.Unlock()
}

func (m *mdnsService) RegisterNotifee(n Notifee) {
	m.lk.Lock()
	m.notifees = append(m.notifees, n)
	m.lk.Unlock()
}

func (m *mdnsService) UnregisterNotifee(n Notifee) {
	m.lk.Lock()
	found := -1
	for i, notif := range m.notifees {
		if notif == n {
			found = i
			break
		}
	}
	if found != -1 {
		m.notifees = append(m.notifees[:found], m.notifees[found+1:]...)
	}
	m.lk.Unlock()
}
<commit_msg>disable mdns logging from init<commit_after>package discovery

import (
	"context"
	"errors"
	"io"
	"net"
	"sync"
	"time"

	logging "github.com/ipfs/go-log"
	"github.com/libp2p/go-libp2p-host"
	"github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
	"github.com/whyrusleeping/mdns"
)

func init() {
	// don't let mdns use logging...
	mdns.DisableLogging = true
}

var log = logging.Logger("mdns")

const ServiceTag = "_ipfs-discovery._udp"

type Service interface {
	io.Closer
	RegisterNotifee(Notifee)
	UnregisterNotifee(Notifee)
}

type Notifee interface {
	HandlePeerFound(pstore.PeerInfo)
}

type mdnsService struct {
	server  *mdns.Server
	service *mdns.MDNSService
	host    host.Host
	tag     string

	lk       sync.Mutex
	notifees []Notifee
	interval time.Duration
}

func getDialableListenAddrs(ph host.Host) ([]*net.TCPAddr, error) {
	var out []*net.TCPAddr
	for _, addr := range ph.Addrs() {
		na, err := manet.ToNetAddr(addr)
		if err != nil {
			continue
		}
		tcp, ok := na.(*net.TCPAddr)
		if ok {
			out = append(out, tcp)
		}
	}
	if len(out) == 0 {
		return nil, errors.New("failed to find good external addr from peerhost")
	}
	return out, nil
}

func NewMdnsService(ctx context.Context, peerhost host.Host, interval time.Duration, serviceTag string) (Service, error) {

	var ipaddrs []net.IP
	port := 4001

	addrs, err := getDialableListenAddrs(peerhost)
	if err != nil {
		log.Warning(err)
	} else {
		port = addrs[0].Port
		for _, a := range addrs {
			ipaddrs = append(ipaddrs, a.IP)
		}
	}

	myid := peerhost.ID().Pretty()

	info := []string{myid}
	if serviceTag == "" {
		serviceTag = ServiceTag
	}
	service, err := mdns.NewMDNSService(myid, serviceTag, "", "", port, ipaddrs, info)
	if err != nil {
		return nil, err
	}

	// Create the mDNS server, defer shutdown
	server, err := mdns.NewServer(&mdns.Config{Zone: service})
	if err != nil {
		return nil, err
	}

	s := &mdnsService{
		server:   server,
		service:  service,
		host:     peerhost,
		interval: interval,
		tag:      serviceTag,
	}

	go s.pollForEntries(ctx)

	return s, nil
}

func (m *mdnsService) Close() error {
	return m.server.Shutdown()
}

func (m *mdnsService) pollForEntries(ctx context.Context) {

	ticker := time.NewTicker(m.interval)
	for {
		//execute mdns query right away at method call and then with every tick
		entriesCh := make(chan *mdns.ServiceEntry, 16)
		go func() {
			for entry := range entriesCh {
				m.handleEntry(entry)
			}
		}()

		log.Debug("starting mdns query")
		qp := &mdns.QueryParam{
			Domain:  "local",
			Entries: entriesCh,
			Service: m.tag,
			Timeout: time.Second * 5,
		}

		err := mdns.Query(qp)
		if err != nil {
			log.Error("mdns lookup error: ", err)
		}
		close(entriesCh)
		log.Debug("mdns query complete")

		select {
		case <-ticker.C:
			continue
		case <-ctx.Done():
			log.Debug("mdns service halting")
			return
		}
	}
}

func (m *mdnsService) handleEntry(e *mdns.ServiceEntry) {
	log.Debugf("Handling MDNS entry: %s:%d %s", e.AddrV4, e.Port, e.Info)
	mpeer, err := peer.IDB58Decode(e.Info)
	if err != nil {
		log.Warning("Error parsing peer ID from mdns entry: ", err)
		return
	}

	if mpeer == m.host.ID() {
		log.Debug("got our own mdns entry, skipping")
		return
	}

	maddr, err := manet.FromNetAddr(&net.TCPAddr{
		IP:   e.AddrV4,
		Port: e.Port,
	})
	if err != nil {
		log.Warning("Error parsing multiaddr from mdns entry: ", err)
		return
	}

	pi := pstore.PeerInfo{
		ID:    mpeer,
		Addrs: []ma.Multiaddr{maddr},
	}

	m.lk.Lock()
	for _, n := range m.notifees {
		go n.HandlePeerFound(pi)
	}
	m.lk.Unlock()
}

func (m *mdnsService) RegisterNotifee(n Notifee) {
	m.lk.Lock()
	m.notifees = append(m.notifees, n)
	m.lk.Unlock()
}

func (m *mdnsService) UnregisterNotifee(n Notifee) {
	m.lk.Lock()
	found := -1
	for i, notif := range m.notifees {
		if notif == n {
			found = i
			break
		}
	}
	if found != -1 {
		m.notifees = append(m.notifees[:found], m.notifees[found+1:]...)
	}
	m.lk.Unlock()
}
<|endoftext|>


<commit_before><commit_msg>fixed type case issue for SRID. #161<commit_after><|endoftext|>


<commit_before><commit_msg>attribute: add Read/Write Uint64 method<commit_after><|endoftext|>