<commit_before>package lxd

import (
	"encoding/json"
	"errors"
	"fmt"
	"sync"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
)

// The Operation type represents an ongoing LXD operation (asynchronous processing)
type operation struct {
	api.Operation

	r            *ProtocolLXD
	listener     *EventListener
	handlerReady bool
	handlerLock  sync.Mutex

	chActive chan bool
}

// AddHandler adds a function to be called whenever an event is received
func (op *operation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return nil, err
	}

	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If we're done already, just return
	if op.StatusCode.IsFinal() {
		return nil, nil
	}

	// Wrap the function to filter unwanted messages
	wrapped := func(event api.Event) {
		op.handlerLock.Lock()

		newOp := api.Operation{}
		err := json.Unmarshal(event.Metadata, &newOp)
		if err != nil || newOp.ID != op.ID {
			op.handlerLock.Unlock()
			return
		}
		op.handlerLock.Unlock()

		function(newOp)
	}

	return op.listener.AddHandler([]string{"operation"}, wrapped)
}

// Cancel will request that LXD cancels the operation (if supported)
func (op *operation) Cancel() error {
	return op.r.DeleteOperation(op.ID)
}

// Get returns the API operation struct
func (op *operation) Get() api.Operation {
	return op.Operation
}

// GetWebsocket returns a raw websocket connection from the operation
func (op *operation) GetWebsocket(secret string) (*websocket.Conn, error) {
	return op.r.GetOperationWebsocket(op.ID, secret)
}

// RemoveHandler removes a function to be called whenever an event is received
func (op *operation) RemoveHandler(target *EventTarget) error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If the listener is gone, just return
	if op.listener == nil {
		return nil
	}

	return op.listener.RemoveHandler(target)
}

// Refresh pulls the current version of the operation and updates the struct
func (op *operation) Refresh() error {
	// Get the current version of the operation
	newOp, _, err := op.r.GetOperation(op.ID)
	if err != nil {
		return err
	}

	// Update the operation struct
	op.Operation = *newOp

	return nil
}

// Wait lets you wait until the operation reaches a final state
func (op *operation) Wait() error {
	op.handlerLock.Lock()
	// Check if not done already
	if op.StatusCode.IsFinal() {
		if op.Err != "" {
			op.handlerLock.Unlock()
			return errors.New(op.Err)
		}

		op.handlerLock.Unlock()
		return nil
	}
	op.handlerLock.Unlock()

	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return err
	}

	<-op.chActive

	// We're done, parse the result
	if op.Err != "" {
		return errors.New(op.Err)
	}

	return nil
}

func (op *operation) setupListener() error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// We already have a listener setup
	if op.handlerReady {
		return nil
	}
	op.handlerReady = true

	// Get a new listener
	if op.listener == nil {
		listener, err := op.r.GetEvents()
		if err != nil {
			return err
		}

		op.listener = listener
	}

	// Setup the handler
	chReady := make(chan bool)
	_, err := op.listener.AddHandler([]string{"operation"}, func(event api.Event) {
		<-chReady

		// We don't want concurrency while processing events
		op.handlerLock.Lock()
		defer op.handlerLock.Unlock()

		// Check if we're done already (because of another event)
		if op.listener == nil {
			return
		}

		// Get an operation struct out of this data
		newOp := api.Operation{}
		err := json.Unmarshal(event.Metadata, &newOp)
		if err != nil || newOp.ID != op.ID {
			return
		}

		// Update the struct
		op.Operation = newOp

		// And check if we're done
		if op.StatusCode.IsFinal() {
			op.listener.Disconnect()
			op.listener = nil
			close(op.chActive)
			return
		}
	})
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		return err
	}

	// Monitor event listener
	go func() {
		<-chReady

		// We don't want concurrency while accessing the listener
		op.handlerLock.Lock()

		// Check if we're done already (because of another event)
		listener := op.listener
		if listener == nil {
			op.handlerLock.Unlock()
			return
		}
		op.handlerLock.Unlock()

		// Wait for the listener or operation to be done
		select {
		case <-listener.ctx.Done():
			op.handlerLock.Lock()
			if op.listener != nil {
				op.Err = fmt.Sprintf("%v", listener.err)
				close(op.chActive)
			}
			op.handlerLock.Unlock()
		case <-op.chActive:
			return
		}
	}()

	// And do a manual refresh to avoid races
	err = op.Refresh()
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		return err
	}

	// Check if not done already
	if op.StatusCode.IsFinal() {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		if op.Err != "" {
			return errors.New(op.Err)
		}

		return nil
	}

	// Start processing background updates
	close(chReady)

	return nil
}

// The remoteOperation type represents an ongoing LXD operation between two servers
type remoteOperation struct {
	targetOp Operation

	handlers    []func(api.Operation)
	handlerLock sync.Mutex

	chDone chan bool
	chPost chan bool
	err    error
}

// AddHandler adds a function to be called whenever an event is received
func (op *remoteOperation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	var err error
	var target *EventTarget

	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// Attach to the existing target operation
	if op.targetOp != nil {
		target, err = op.targetOp.AddHandler(function)
		if err != nil {
			return nil, err
		}
	} else {
		// Generate a mock EventTarget
		target = &EventTarget{
			function: func(api.Event) { function(api.Operation{}) },
			types:    []string{"operation"},
		}
	}

	// Add the handler to our list
	op.handlers = append(op.handlers, function)

	return target, nil
}

// CancelTarget attempts to cancel the target operation
func (op *remoteOperation) CancelTarget() error {
	if op.targetOp == nil {
		return fmt.Errorf("No associated target operation")
	}

	return op.targetOp.Cancel()
}

// GetTarget returns the target operation
func (op *remoteOperation) GetTarget() (*api.Operation, error) {
	if op.targetOp == nil {
		return nil, fmt.Errorf("No associated target operation")
	}

	opAPI := op.targetOp.Get()
	return &opAPI, nil
}

// Wait lets you wait until the operation reaches a final state
func (op *remoteOperation) Wait() error {
	<-op.chDone

	if op.chPost != nil {
		<-op.chPost
	}

	return op.err
}
<commit_msg>client/operations: Get error text verbatim in setupListener<commit_after>package lxd

import (
	"encoding/json"
	"errors"
	"fmt"
	"sync"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
)

// The Operation type represents an ongoing LXD operation (asynchronous processing)
type operation struct {
	api.Operation

	r            *ProtocolLXD
	listener     *EventListener
	handlerReady bool
	handlerLock  sync.Mutex

	chActive chan bool
}

// AddHandler adds a function to be called whenever an event is received
func (op *operation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return nil, err
	}

	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If we're done already, just return
	if op.StatusCode.IsFinal() {
		return nil, nil
	}

	// Wrap the function to filter unwanted messages
	wrapped := func(event api.Event) {
		op.handlerLock.Lock()

		newOp := api.Operation{}
		err := json.Unmarshal(event.Metadata, &newOp)
		if err != nil || newOp.ID != op.ID {
			op.handlerLock.Unlock()
			return
		}
		op.handlerLock.Unlock()

		function(newOp)
	}

	return op.listener.AddHandler([]string{"operation"}, wrapped)
}

// Cancel will request that LXD cancels the operation (if supported)
func (op *operation) Cancel() error {
	return op.r.DeleteOperation(op.ID)
}

// Get returns the API operation struct
func (op *operation) Get() api.Operation {
	return op.Operation
}

// GetWebsocket returns a raw websocket connection from the operation
func (op *operation) GetWebsocket(secret string) (*websocket.Conn, error) {
	return op.r.GetOperationWebsocket(op.ID, secret)
}

// RemoveHandler removes a function to be called whenever an event is received
func (op *operation) RemoveHandler(target *EventTarget) error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If the listener is gone, just return
	if op.listener == nil {
		return nil
	}

	return op.listener.RemoveHandler(target)
}

// Refresh pulls the current version of the operation and updates the struct
func (op *operation) Refresh() error {
	// Get the current version of the operation
	newOp, _, err := op.r.GetOperation(op.ID)
	if err != nil {
		return err
	}

	// Update the operation struct
	op.Operation = *newOp

	return nil
}

// Wait lets you wait until the operation reaches a final state
func (op *operation) Wait() error {
	op.handlerLock.Lock()
	// Check if not done already
	if op.StatusCode.IsFinal() {
		if op.Err != "" {
			op.handlerLock.Unlock()
			return errors.New(op.Err)
		}

		op.handlerLock.Unlock()
		return nil
	}
	op.handlerLock.Unlock()

	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return err
	}

	<-op.chActive

	// We're done, parse the result
	if op.Err != "" {
		return errors.New(op.Err)
	}

	return nil
}

func (op *operation) setupListener() error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// We already have a listener setup
	if op.handlerReady {
		return nil
	}
	op.handlerReady = true

	// Get a new listener
	if op.listener == nil {
		listener, err := op.r.GetEvents()
		if err != nil {
			return err
		}

		op.listener = listener
	}

	// Setup the handler
	chReady := make(chan bool)
	_, err := op.listener.AddHandler([]string{"operation"}, func(event api.Event) {
		<-chReady

		// We don't want concurrency while processing events
		op.handlerLock.Lock()
		defer op.handlerLock.Unlock()

		// Check if we're done already (because of another event)
		if op.listener == nil {
			return
		}

		// Get an operation struct out of this data
		newOp := api.Operation{}
		err := json.Unmarshal(event.Metadata, &newOp)
		if err != nil || newOp.ID != op.ID {
			return
		}

		// Update the struct
		op.Operation = newOp

		// And check if we're done
		if op.StatusCode.IsFinal() {
			op.listener.Disconnect()
			op.listener = nil
			close(op.chActive)
			return
		}
	})
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		return err
	}

	// Monitor event listener
	go func() {
		<-chReady

		// We don't want concurrency while accessing the listener
		op.handlerLock.Lock()

		// Check if we're done already (because of another event)
		listener := op.listener
		if listener == nil {
			op.handlerLock.Unlock()
			return
		}
		op.handlerLock.Unlock()

		// Wait for the listener or operation to be done
		select {
		case <-listener.ctx.Done():
			op.handlerLock.Lock()
			if op.listener != nil {
				op.Err = listener.err.Error()
				close(op.chActive)
			}
			op.handlerLock.Unlock()
		case <-op.chActive:
			return
		}
	}()

	// And do a manual refresh to avoid races
	err = op.Refresh()
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		return err
	}

	// Check if not done already
	if op.StatusCode.IsFinal() {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		if op.Err != "" {
			return errors.New(op.Err)
		}

		return nil
	}

	// Start processing background updates
	close(chReady)

	return nil
}

// The remoteOperation type represents an ongoing LXD operation between two servers
type remoteOperation struct {
	targetOp Operation

	handlers    []func(api.Operation)
	handlerLock sync.Mutex

	chDone chan bool
	chPost chan bool
	err    error
}

// AddHandler adds a function to be called whenever an event is received
func (op *remoteOperation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	var err error
	var target *EventTarget

	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// Attach to the existing target operation
	if op.targetOp != nil {
		target, err = op.targetOp.AddHandler(function)
		if err != nil {
			return nil, err
		}
	} else {
		// Generate a mock EventTarget
		target = &EventTarget{
			function: func(api.Event) { function(api.Operation{}) },
			types:    []string{"operation"},
		}
	}

	// Add the handler to our list
	op.handlers = append(op.handlers, function)

	return target, nil
}

// CancelTarget attempts to cancel the target operation
func (op *remoteOperation) CancelTarget() error {
	if op.targetOp == nil {
		return fmt.Errorf("No associated target operation")
	}

	return op.targetOp.Cancel()
}

// GetTarget returns the target operation
func (op *remoteOperation) GetTarget() (*api.Operation, error) {
	if op.targetOp == nil {
		return nil, fmt.Errorf("No associated target operation")
	}

	opAPI := op.targetOp.Get()
	return &opAPI, nil
}

// Wait lets you wait until the operation reaches a final state
func (op *remoteOperation) Wait() error {
	<-op.chDone

	if op.chPost != nil {
		<-op.chPost
	}

	return op.err
}
<|endoftext|>


<commit_before>package wood

import (
	"net/http"

	"github.com/256dpi/fire"

	"github.com/goware/cors"
)

// DefaultProtector constructs a middleware that by default limits the request
// body size to 4Ks and sets a basic CORS configuration.
func DefaultProtector() func(http.Handler) http.Handler {
	return NewProtector("8M", cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedHeaders: []string{"Origin", "Accept", "Content-Type", "Authorization"},
		AllowedMethods: []string{"GET", "POST", "PATCH", "DELETE"},
	})
}

// NewProtector constructs a middleware that implements basic protection measures
// for the passed endpoint. Currently the protector limits the body size
// to a the passed length and automatically handles CORS using the specified
// options.
func NewProtector(maxBody string, corsOptions cors.Options) func(http.Handler) http.Handler {
	c := cors.New(corsOptions)

	return func(next http.Handler) http.Handler {
		return c.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// replace read with a limited reader
			r.Body = http.MaxBytesReader(w, r.Body, int64(fire.DataSize(maxBody)))

			// call next handler
			next.ServeHTTP(w, r)
		}))
	}
}
<commit_msg>corrected docs<commit_after>package wood

import (
	"net/http"

	"github.com/256dpi/fire"

	"github.com/goware/cors"
)

// DefaultProtector constructs a middleware that by default limits the request
// body size to 8M and sets a basic CORS configuration.
func DefaultProtector() func(http.Handler) http.Handler {
	return NewProtector("8M", cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedHeaders: []string{"Origin", "Accept", "Content-Type", "Authorization"},
		AllowedMethods: []string{"GET", "POST", "PATCH", "DELETE"},
	})
}

// NewProtector constructs a middleware that implements basic protection measures
// for the passed endpoint. Currently the protector limits the body size
// to a the passed length and automatically handles CORS using the specified
// options.
func NewProtector(maxBody string, corsOptions cors.Options) func(http.Handler) http.Handler {
	c := cors.New(corsOptions)

	return func(next http.Handler) http.Handler {
		return c.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// replace read with a limited reader
			r.Body = http.MaxBytesReader(w, r.Body, int64(fire.DataSize(maxBody)))

			// call next handler
			next.ServeHTTP(w, r)
		}))
	}
}
<|endoftext|>


<commit_before>package wordnik

type WordOfTheDay struct {
	Id          int64
	ParentId    string
	Category    string
	CreatedBy   string
	CreatedAt   string
	HtmlExtra   string
	Word        string
	Definitions []SimpleDefinition
	Examples    []SimpleExample
	Note        string
	PublishDate string
}

type ContentProvider struct {
	Id   int64
	Name string
}

type SimpleDefinition struct {
	Test         string
	Source       string
	Note         string
	PartOfSpeech string
}

type SimpleExample struct {
	Id    int64
	Title string
	Text  string
	Url   string
}
<commit_msg>Small typo in the Word response (Test -> Text)<commit_after>package wordnik

type WordOfTheDay struct {
	Id          int64
	ParentId    string
	Category    string
	CreatedBy   string
	CreatedAt   string
	HtmlExtra   string
	Word        string
	Definitions []SimpleDefinition
	Examples    []SimpleExample
	Note        string
	PublishDate string
}

type ContentProvider struct {
	Id   int64
	Name string
}

type SimpleDefinition struct {
	Text         string
	Source       string
	Note         string
	PartOfSpeech string
}

type SimpleExample struct {
	Id    int64
	Title string
	Text  string
	Url   string
}
<|endoftext|>


<commit_before>package binp

import (
	"errors"
	"fmt"
)

// Parser type. Don't touch the internals.
type Parser struct {
	r   []byte
	off int
}

// Catch a panic into an error.
func Catch(f func()) (err error) {
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			err, ok = r.(error)
			if !ok {
				err = errors.New(fmt.Sprint(r))
			}
		}
	}()
	f()
	return
}

// Create a new parser with the given buffer. Panics on error.
func NewParser(b []byte) *Parser {
	return &Parser{b, 0}
}

// Parse a byte from the buffer.
func (p *Parser) Byte(d *byte) *Parser {
	*d = p.r[p.off]
	p.off++
	return p
}

// Parse a byte from the buffer, synonym for .Byte.
func (p *Parser) B8(d *byte) *Parser {
	*d = p.r[p.off]
	p.off++
	return p
}

// Parse a byte from the buffer, synonym for .Byte.
func (p *Parser) N8(d *byte) *Parser {
	*d = p.r[p.off]
	p.off++
	return p
}

// Parse 4 native endian bytes from the buffer.
func (p *Parser) N32(d *uint32) *Parser {
	*d = NativeEndian.Uint32(p.r[p.off:])
	p.off += 4
	return p
}

// Parse 8 native endian bytes from the buffer.
func (p *Parser) N64(d *uint64) *Parser {
	*d = NativeEndian.Uint64(p.r[p.off:])
	p.off += 8
	return p
}

// Parse 2 native endian bytes from the buffer.
func (p *Parser) N16(d *uint16) *Parser {
	*d = NativeEndian.Uint16(p.r[p.off:])
	p.off += 2
	return p
}

// Parse n bytes from the buffer and copy to a []byte pointer that is allocated.
func (p *Parser) NBytes(n int, d *[]byte) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	*d = make([]byte, n)
	copy(*d, p.r[p.off:])
	p.off += n
	return p
}

// Parse n bytes from the buffer and copy to the supplied []byte.
func (p *Parser) NBytesCopy(n int, d []byte) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	copy(d, p.r[p.off:p.off+n])
	p.off += n
	return p
}

// Parse n bytes from the buffer to a []byte pointer that refers to the parser internal buffer.
func (p *Parser) NBytesPeek(n int, d *[]byte) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	*d = p.r[p.off : p.off+n]
	p.off += n
	return p
}

// Parse a string with a 4 byte native endian length prefix to a []byte pointer.
func (p *Parser) N32Bytes(d *[]byte) *Parser {
	var v uint32
	return p.N32(&v).NBytes(int(v), d)
}

// Ensure the input is aligned possibly skipping bytes.
func (p *Parser) Align(n int) *Parser {
	r := p.off % n
	if r == 0 {
		return p
	}
	p.off += n - r
	return p
}

// Skip bytes.
func (p *Parser) Skip(n int) *Parser {
	p.off += n
	return p
}

// Parse n bytes from the buffer to a string pointer.
func (p *Parser) NString(n int, d *string) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	bs := p.r[p.off : p.off+n]
	*d = string(bs)
	return p
}

// Parse a string with a 4 byte native endian length prefix to a string pointer.
func (p *Parser) N32String(d *string) *Parser {
	var v uint32
	return p.N32(&v).NString(int(v), d)
}

// Parse a string with a 2 byte native endian length prefix to a string pointer.
func (p *Parser) N16String(d *string) *Parser {
	var v uint16
	return p.N16(&v).NString(int(v), d)
}

// Parse a string with a 1 byte length prefix to a string pointer.
func (p *Parser) N8String(d *string) *Parser {
	var v uint8
	return p.Byte(&v).NString(int(v), d)
}

// Parse a null terminated string.
func (p *Parser) String0(d *string) *Parser {
	for i, ch := range p.r[p.off:] {
		if ch == 0 {
			p.NString(i, d)
			p.off++
			return p
		}
	}
	panic("String0: null byte not found")
}

// Check that we are at the end of input.
func (p *Parser) End() {
	if p.off != len(p.r) {
		panic("binparser: overlong packet")
	}
}

// Check that we are at the end of input.
func (p *Parser) AtEnd() bool {
	return p.off == len(p.r)
}

// Peek the rest of input as raw bytes.
func (p *Parser) PeekRest(d *[]byte) *Parser {
	*d = p.r[p.off:]
	return p
}
<commit_msg>Fix for String parsing in last commit<commit_after>package binp

import (
	"errors"
	"fmt"
)

// Parser type. Don't touch the internals.
type Parser struct {
	r   []byte
	off int
}

// Catch a panic into an error.
func Catch(f func()) (err error) {
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			err, ok = r.(error)
			if !ok {
				err = errors.New(fmt.Sprint(r))
			}
		}
	}()
	f()
	return
}

// Create a new parser with the given buffer. Panics on error.
func NewParser(b []byte) *Parser {
	return &Parser{b, 0}
}

// Parse a byte from the buffer.
func (p *Parser) Byte(d *byte) *Parser {
	*d = p.r[p.off]
	p.off++
	return p
}

// Parse a byte from the buffer, synonym for .Byte.
func (p *Parser) B8(d *byte) *Parser {
	*d = p.r[p.off]
	p.off++
	return p
}

// Parse a byte from the buffer, synonym for .Byte.
func (p *Parser) N8(d *byte) *Parser {
	*d = p.r[p.off]
	p.off++
	return p
}

// Parse 4 native endian bytes from the buffer.
func (p *Parser) N32(d *uint32) *Parser {
	*d = NativeEndian.Uint32(p.r[p.off:])
	p.off += 4
	return p
}

// Parse 8 native endian bytes from the buffer.
func (p *Parser) N64(d *uint64) *Parser {
	*d = NativeEndian.Uint64(p.r[p.off:])
	p.off += 8
	return p
}

// Parse 2 native endian bytes from the buffer.
func (p *Parser) N16(d *uint16) *Parser {
	*d = NativeEndian.Uint16(p.r[p.off:])
	p.off += 2
	return p
}

// Parse n bytes from the buffer and copy to a []byte pointer that is allocated.
func (p *Parser) NBytes(n int, d *[]byte) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	*d = make([]byte, n)
	copy(*d, p.r[p.off:])
	p.off += n
	return p
}

// Parse n bytes from the buffer and copy to the supplied []byte.
func (p *Parser) NBytesCopy(n int, d []byte) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	copy(d, p.r[p.off:p.off+n])
	p.off += n
	return p
}

// Parse n bytes from the buffer to a []byte pointer that refers to the parser internal buffer.
func (p *Parser) NBytesPeek(n int, d *[]byte) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	*d = p.r[p.off : p.off+n]
	p.off += n
	return p
}

// Parse a string with a 4 byte native endian length prefix to a []byte pointer.
func (p *Parser) N32Bytes(d *[]byte) *Parser {
	var v uint32
	return p.N32(&v).NBytes(int(v), d)
}

// Ensure the input is aligned possibly skipping bytes.
func (p *Parser) Align(n int) *Parser {
	r := p.off % n
	if r == 0 {
		return p
	}
	p.off += n - r
	return p
}

// Skip bytes.
func (p *Parser) Skip(n int) *Parser {
	p.off += n
	return p
}

// Parse n bytes from the buffer to a string pointer.
func (p *Parser) NString(n int, d *string) *Parser {
	if n > len(p.r[p.off:]) {
		panic("binparser: overflowing length")
	}
	bs := p.r[p.off : p.off+n]
	*d = string(bs)
	p.off += n
	return p
}

// Parse a string with a 4 byte native endian length prefix to a string pointer.
func (p *Parser) N32String(d *string) *Parser {
	var v uint32
	return p.N32(&v).NString(int(v), d)
}

// Parse a string with a 2 byte native endian length prefix to a string pointer.
func (p *Parser) N16String(d *string) *Parser {
	var v uint16
	return p.N16(&v).NString(int(v), d)
}

// Parse a string with a 1 byte length prefix to a string pointer.
func (p *Parser) N8String(d *string) *Parser {
	var v uint8
	return p.Byte(&v).NString(int(v), d)
}

// Parse a null terminated string.
func (p *Parser) String0(d *string) *Parser {
	for i, ch := range p.r[p.off:] {
		if ch == 0 {
			p.NString(i, d)
			p.off++
			return p
		}
	}
	panic("String0: null byte not found")
}

// Check that we are at the end of input.
func (p *Parser) End() {
	if p.off != len(p.r) {
		panic("binparser: overlong packet")
	}
}

// Check that we are at the end of input.
func (p *Parser) AtEnd() bool {
	return p.off == len(p.r)
}

// Peek the rest of input as raw bytes.
func (p *Parser) PeekRest(d *[]byte) *Parser {
	*d = p.r[p.off:]
	return p
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/pivotalservices/cfops/tileregistry"
)

var (
	VERSION  string
	ExitCode int
	logLevel string
)

func main() {
	app := NewApp()
	app.Run(os.Args)
	os.Exit(ExitCode)
}

// NewApp creates a new cli app
func NewApp() *cli.App {
	app := cli.NewApp()
	app.Version = VERSION
	app.Name = "cfops"
	app.Usage = "Cloud Foundry Operations Tool"
	app.Commands = append(app.Commands, []cli.Command{
		cli.Command{
			Name: "version",
			Action: func(c *cli.Context) {
				cli.ShowVersion(c)
			},
		},
		cli.Command{
			Name: "list-tiles",
			Action: func(c *cli.Context) {
				fmt.Println("Available Tiles:")
				for n, _ := range tileregistry.GetRegistry() {
					fmt.Println(n)
				}
			},
		},
	}...)
	return app
}
<commit_msg>[#107947598] registering all tiles from cfbackup<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	_ "github.com/pivotalservices/cfbackup"
	"github.com/pivotalservices/cfops/tileregistry"
)

var (
	VERSION  string
	ExitCode int
	logLevel string
)

func main() {
	app := NewApp()
	app.Run(os.Args)
	os.Exit(ExitCode)
}

// NewApp creates a new cli app
func NewApp() *cli.App {
	app := cli.NewApp()
	app.Version = VERSION
	app.Name = "cfops"
	app.Usage = "Cloud Foundry Operations Tool"
	app.Commands = append(app.Commands, []cli.Command{
		cli.Command{
			Name: "version",
			Action: func(c *cli.Context) {
				cli.ShowVersion(c)
			},
		},
		cli.Command{
			Name: "list-tiles",
			Action: func(c *cli.Context) {
				fmt.Println("Available Tiles:")
				for n, _ := range tileregistry.GetRegistry() {
					fmt.Println(n)
				}
			},
		},
	}...)
	return app
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker Compose CLI 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

       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 compose

import (
	"context"
	"fmt"
	"os"

	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	"github.com/spf13/cobra"

	"github.com/docker/compose/v2/pkg/api"
)

type buildOptions struct {
	*projectOptions
	composeOptions
	quiet    bool
	pull     bool
	progress string
	args     []string
	noCache  bool
	memory   string
}

func buildCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := buildOptions{
		projectOptions: p,
	}
	cmd := &cobra.Command{
		Use:   "build [SERVICE...]",
		Short: "Build or rebuild services",
		PreRunE: Adapt(func(ctx context.Context, args []string) error {
			if opts.memory != "" {
				fmt.Println("WARNING --memory is ignored as not supported in buildkit.")
			}
			if opts.quiet {
				devnull, err := os.Open(os.DevNull)
				if err != nil {
					return err
				}
				os.Stdout = devnull
			}
			return nil
		}),
		RunE: Adapt(func(ctx context.Context, args []string) error {
			return runBuild(ctx, backend, opts, args)
		}),
		ValidArgsFunction: serviceCompletion(p),
	}
	cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
	cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.")
	cmd.Flags().StringVar(&opts.progress, "progress", "auto", `Set type of progress output ("auto", "plain", "noTty")`)
	cmd.Flags().StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services.")
	cmd.Flags().Bool("parallel", true, "Build images in parallel. DEPRECATED")
	cmd.Flags().MarkHidden("parallel") //nolint:errcheck
	cmd.Flags().Bool("compress", true, "Compress the build context using gzip. DEPRECATED")
	cmd.Flags().MarkHidden("compress") //nolint:errcheck
	cmd.Flags().Bool("force-rm", true, "Always remove intermediate containers. DEPRECATED")
	cmd.Flags().MarkHidden("force-rm") //nolint:errcheck
	cmd.Flags().BoolVar(&opts.noCache, "no-cache", false, "Do not use cache when building the image")
	cmd.Flags().Bool("no-rm", false, "Do not remove intermediate containers after a successful build. DEPRECATED")
	cmd.Flags().MarkHidden("no-rm") //nolint:errcheck
	cmd.Flags().StringVarP(&opts.memory, "memory", "m", "", "Set memory limit for the build container. Not supported on buildkit yet.")
	cmd.Flags().MarkHidden("memory") //nolint:errcheck

	return cmd
}

func runBuild(ctx context.Context, backend api.Service, opts buildOptions, services []string) error {
	project, err := opts.toProject(services, cli.WithResolvedPaths(true))
	if err != nil {
		return err
	}

	return backend.Build(ctx, project, api.BuildOptions{
		Pull:     opts.pull,
		Progress: opts.progress,
		Args:     types.NewMappingWithEquals(opts.args),
		NoCache:  opts.noCache,
		Quiet:    opts.quiet,
		Services: services,
	})
}
<commit_msg>check supported --progress flag values<commit_after>/*
   Copyright 2020 Docker Compose CLI 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

       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 compose

import (
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	buildx "github.com/docker/buildx/util/progress"
	"github.com/docker/compose/v2/pkg/utils"
	"github.com/spf13/cobra"

	"github.com/docker/compose/v2/pkg/api"
)

type buildOptions struct {
	*projectOptions
	composeOptions
	quiet    bool
	pull     bool
	progress string
	args     []string
	noCache  bool
	memory   string
}

var printerModes = []string{
	buildx.PrinterModeAuto,
	buildx.PrinterModeTty,
	buildx.PrinterModePlain,
	buildx.PrinterModeQuiet,
}

func buildCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := buildOptions{
		projectOptions: p,
	}
	cmd := &cobra.Command{
		Use:   "build [SERVICE...]",
		Short: "Build or rebuild services",
		PreRunE: Adapt(func(ctx context.Context, args []string) error {
			if opts.memory != "" {
				fmt.Println("WARNING --memory is ignored as not supported in buildkit.")
			}
			if opts.quiet {
				devnull, err := os.Open(os.DevNull)
				if err != nil {
					return err
				}
				os.Stdout = devnull
			}
			if !utils.StringContains(printerModes, opts.progress) {
				return fmt.Errorf("unsupported --progress value %q", opts.progress)
			}
			return nil
		}),
		RunE: Adapt(func(ctx context.Context, args []string) error {
			return runBuild(ctx, backend, opts, args)
		}),
		ValidArgsFunction: serviceCompletion(p),
	}
	cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
	cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.")
	cmd.Flags().StringVar(&opts.progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
	cmd.Flags().StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services.")
	cmd.Flags().Bool("parallel", true, "Build images in parallel. DEPRECATED")
	cmd.Flags().MarkHidden("parallel") //nolint:errcheck
	cmd.Flags().Bool("compress", true, "Compress the build context using gzip. DEPRECATED")
	cmd.Flags().MarkHidden("compress") //nolint:errcheck
	cmd.Flags().Bool("force-rm", true, "Always remove intermediate containers. DEPRECATED")
	cmd.Flags().MarkHidden("force-rm") //nolint:errcheck
	cmd.Flags().BoolVar(&opts.noCache, "no-cache", false, "Do not use cache when building the image")
	cmd.Flags().Bool("no-rm", false, "Do not remove intermediate containers after a successful build. DEPRECATED")
	cmd.Flags().MarkHidden("no-rm") //nolint:errcheck
	cmd.Flags().StringVarP(&opts.memory, "memory", "m", "", "Set memory limit for the build container. Not supported on buildkit yet.")
	cmd.Flags().MarkHidden("memory") //nolint:errcheck

	return cmd
}

func runBuild(ctx context.Context, backend api.Service, opts buildOptions, services []string) error {
	project, err := opts.toProject(services, cli.WithResolvedPaths(true))
	if err != nil {
		return err
	}

	return backend.Build(ctx, project, api.BuildOptions{
		Pull:     opts.pull,
		Progress: opts.progress,
		Args:     types.NewMappingWithEquals(opts.args),
		NoCache:  opts.noCache,
		Quiet:    opts.quiet,
		Services: services,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"net"
	"os"
	"path/filepath"

	"github.com/concourse/atc/atccmd"
	"github.com/concourse/flag"
	"github.com/concourse/tsa/tsacmd"
	flags "github.com/jessevdk/go-flags"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"

	"github.com/concourse/bin/bindata"
)

type WebCommand struct {
	*atccmd.RunCommand

	*tsacmd.TSACommand `group:"TSA Configuration" namespace:"tsa"`
}

const cliArtifactsBindata = "cli-artifacts"

func (WebCommand) lessenRequirements(command *flags.Command) {
	// defaults to address from external URL
	command.FindOptionByLongName("tsa-peer-ip").Required = false

	// defaults to atc external URL
	command.FindOptionByLongName("tsa-atc-url").Required = false

	// defaults to atc session signing key
	command.FindOptionByLongName("tsa-session-signing-key").Required = false
}

func (cmd *WebCommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	return <-ifrit.Invoke(sigmon.New(runner)).Wait()
}

func (cmd *WebCommand) Runner(args []string) (ifrit.Runner, error) {
	err := bindata.RestoreAssets(os.TempDir(), cliArtifactsBindata)
	if err == nil {
		cmd.RunCommand.CLIArtifactsDir = flag.Dir(filepath.Join(os.TempDir(), cliArtifactsBindata))
	}

	cmd.populateTSAFlagsFromATCFlags()

	atcRunner, shouldSkipTSA, err := cmd.RunCommand.Runner(args)
	if err != nil {
		return nil, err
	}

	if shouldSkipTSA {
		return atcRunner, nil
	}

	tsaRunner, err := cmd.TSACommand.Runner(args)
	if err != nil {
		return nil, err
	}

	return grouper.NewParallel(os.Interrupt, grouper.Members{
		{Name: "atc", Runner: atcRunner},
		{Name: "tsa", Runner: tsaRunner},
	}), nil
}

func (cmd *WebCommand) populateTSAFlagsFromATCFlags() error {
	cmd.TSACommand.SessionSigningKey = cmd.RunCommand.Auth.AuthFlags.SigningKey

	if cmd.RunCommand.Auth.AuthFlags.SigningKey.PrivateKey == nil &&
		cmd.TSACommand.SessionSigningKey.PrivateKey == nil {
		signingKey, err := rsa.GenerateKey(rand.Reader, 2048)
		if err != nil {
			return fmt.Errorf("failed to generate session signing key: %s", err)
		}

		cmd.RunCommand.Auth.AuthFlags.SigningKey = &flag.PrivateKey{PrivateKey: signingKey}
		cmd.TSACommand.SessionSigningKey = &flag.PrivateKey{PrivateKey: signingKey}
	}

	if len(cmd.TSACommand.ATCURLs) == 0 {
		cmd.TSACommand.ATCURLs = []flag.URL{cmd.RunCommand.PeerURL()}
	}

	host, _, err := net.SplitHostPort(cmd.RunCommand.PeerURL().URL.Host)
	if err != nil {
		return err
	}

	cmd.TSACommand.PeerIP = host

	return nil
}
<commit_msg>change function name, leave field public<commit_after>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"net"
	"os"
	"path/filepath"

	"github.com/concourse/atc/atccmd"
	"github.com/concourse/flag"
	"github.com/concourse/tsa/tsacmd"
	flags "github.com/jessevdk/go-flags"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"

	"github.com/concourse/bin/bindata"
)

type WebCommand struct {
	*atccmd.RunCommand

	*tsacmd.TSACommand `group:"TSA Configuration" namespace:"tsa"`
}

const cliArtifactsBindata = "cli-artifacts"

func (WebCommand) lessenRequirements(command *flags.Command) {
	// defaults to address from external URL
	command.FindOptionByLongName("tsa-peer-ip").Required = false

	// defaults to atc external URL
	command.FindOptionByLongName("tsa-atc-url").Required = false

	// defaults to atc session signing key
	command.FindOptionByLongName("tsa-session-signing-key").Required = false
}

func (cmd *WebCommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	return <-ifrit.Invoke(sigmon.New(runner)).Wait()
}

func (cmd *WebCommand) Runner(args []string) (ifrit.Runner, error) {
	err := bindata.RestoreAssets(os.TempDir(), cliArtifactsBindata)
	if err == nil {
		cmd.RunCommand.CLIArtifactsDir = flag.Dir(filepath.Join(os.TempDir(), cliArtifactsBindata))
	}

	cmd.populateTSAFlagsFromATCFlags()

	atcRunner, shouldSkipTSA, err := cmd.RunCommand.Runner(args)
	if err != nil {
		return nil, err
	}

	if shouldSkipTSA {
		return atcRunner, nil
	}

	tsaRunner, err := cmd.TSACommand.Runner(args)
	if err != nil {
		return nil, err
	}

	return grouper.NewParallel(os.Interrupt, grouper.Members{
		{Name: "atc", Runner: atcRunner},
		{Name: "tsa", Runner: tsaRunner},
	}), nil
}

func (cmd *WebCommand) populateTSAFlagsFromATCFlags() error {
	cmd.TSACommand.SessionSigningKey = cmd.RunCommand.Auth.AuthFlags.SigningKey

	if cmd.RunCommand.Auth.AuthFlags.SigningKey.PrivateKey == nil &&
		cmd.TSACommand.SessionSigningKey.PrivateKey == nil {
		signingKey, err := rsa.GenerateKey(rand.Reader, 2048)
		if err != nil {
			return fmt.Errorf("failed to generate session signing key: %s", err)
		}

		cmd.RunCommand.Auth.AuthFlags.SigningKey = &flag.PrivateKey{PrivateKey: signingKey}
		cmd.TSACommand.SessionSigningKey = &flag.PrivateKey{PrivateKey: signingKey}
	}

	if len(cmd.TSACommand.ATCURLs) == 0 {
		cmd.TSACommand.ATCURLs = []flag.URL{cmd.RunCommand.PeerURLOrDefault()}
	}

	host, _, err := net.SplitHostPort(cmd.RunCommand.PeerURLOrDefault().URL.Host)
	if err != nil {
		return err
	}

	cmd.TSACommand.PeerIP = host

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"net"
	"os"
	"path/filepath"
	"time"

	"github.com/concourse/atc/atccmd"
	"github.com/concourse/tsa/tsacmd"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"

	"github.com/concourse/bin/bindata"
)

type WebCommand struct {
	atccmd.ATCCommand

	TSA struct {
		BindIP   tsacmd.IPFlag `long:"bind-ip"   default:"0.0.0.0" description:"IP address on which to listen for SSH."`
		BindPort uint16        `long:"bind-port" default:"2222"    description:"Port on which to listen for SSH."`

		HostKeyPath        tsacmd.FileFlag `long:"host-key"        required:"true" description:"Key to use for the TSA's ssh server."`
		AuthorizedKeysPath tsacmd.FileFlag `long:"authorized-keys" required:"true" description:"Path to a file containing public keys to authorize for SSH access."`

		HeartbeatInterval time.Duration `long:"heartbeat-interval" default:"30s" description:"interval on which to heartbeat workers to the ATC"`
	} `group:"TSA Configuration" namespace:"tsa"`
}

const cliArtifactsBindata = "cli-artifacts"

func (cmd *WebCommand) Execute(args []string) error {
	err := bindata.RestoreAssets(os.TempDir(), cliArtifactsBindata)
	if err != nil {
		return err
	}

	cmd.ATCCommand.CLIArtifactsDir = atccmd.DirFlag(filepath.Join(os.TempDir(), cliArtifactsBindata))

	tsa := &tsacmd.TSACommand{
		BindIP:   cmd.TSA.BindIP,
		BindPort: cmd.TSA.BindPort,

		HostKeyPath:        cmd.TSA.HostKeyPath,
		AuthorizedKeysPath: cmd.TSA.AuthorizedKeysPath,

		HeartbeatInterval: cmd.TSA.HeartbeatInterval,
	}

	cmd.populateTSAFlagsFromATCFlags(tsa)

	atcRunner, err := cmd.ATCCommand.Runner(args)
	if err != nil {
		return err
	}

	tsaRunner, err := tsa.Runner(args)
	if err != nil {
		return err
	}

	runner := sigmon.New(grouper.NewParallel(os.Interrupt, grouper.Members{
		{"atc", atcRunner},
		{"tsa", tsaRunner},
	}))

	return <-ifrit.Invoke(runner).Wait()
}

func (cmd *WebCommand) populateTSAFlagsFromATCFlags(tsa *tsacmd.TSACommand) error {
	// TODO: flag types package plz
	err := tsa.ATCURL.UnmarshalFlag(cmd.ATCCommand.PeerURL.String())
	if err != nil {
		return err
	}

	tsa.SessionSigningKeyPath = tsacmd.FileFlag(cmd.ATCCommand.SessionSigningKey)

	host, _, err := net.SplitHostPort(cmd.ATCCommand.PeerURL.URL().Host)
	if err != nil {
		return err
	}

	tsa.PeerIP = host

	tsa.Metrics.YellerAPIKey = cmd.ATCCommand.Metrics.YellerAPIKey
	tsa.Metrics.YellerEnvironment = cmd.ATCCommand.Metrics.YellerEnvironment

	return nil
}
<commit_msg>expose tsa team-authorized keys<commit_after>package main

import (
	"net"
	"os"
	"path/filepath"
	"time"

	"github.com/concourse/atc/atccmd"
	"github.com/concourse/tsa/tsacmd"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"

	"github.com/concourse/bin/bindata"
)

type WebCommand struct {
	atccmd.ATCCommand

	TSA struct {
		BindIP   tsacmd.IPFlag `long:"bind-ip"   default:"0.0.0.0" description:"IP address on which to listen for SSH."`
		BindPort uint16        `long:"bind-port" default:"2222"    description:"Port on which to listen for SSH."`

		HostKeyPath            tsacmd.FileFlag        `long:"host-key"             required:"true" description:"Key to use for the TSA's ssh server."`
		AuthorizedKeysPath     tsacmd.FileFlag        `long:"authorized-keys"      required:"true" description:"Path to a file containing public keys to authorize for SSH access."`
		TeamAuthorizedKeysPath []tsacmd.InputPairFlag `long:"team-authorized-keys" value-name:"NAME=PATH" description:"Path to file containing keys to authorize, in SSH authorized_keys format (one public key per line)."`

		HeartbeatInterval time.Duration `long:"heartbeat-interval" default:"30s" description:"interval on which to heartbeat workers to the ATC"`
	} `group:"TSA Configuration" namespace:"tsa"`
}

const cliArtifactsBindata = "cli-artifacts"

func (cmd *WebCommand) Execute(args []string) error {
	err := bindata.RestoreAssets(os.TempDir(), cliArtifactsBindata)
	if err != nil {
		return err
	}

	cmd.ATCCommand.CLIArtifactsDir = atccmd.DirFlag(filepath.Join(os.TempDir(), cliArtifactsBindata))

	tsa := &tsacmd.TSACommand{
		BindIP:   cmd.TSA.BindIP,
		BindPort: cmd.TSA.BindPort,

		HostKeyPath:            cmd.TSA.HostKeyPath,
		AuthorizedKeysPath:     cmd.TSA.AuthorizedKeysPath,
		TeamAuthorizedKeysPath: cmd.TSA.TeamAuthorizedKeysPath,

		HeartbeatInterval: cmd.TSA.HeartbeatInterval,
	}

	cmd.populateTSAFlagsFromATCFlags(tsa)

	atcRunner, err := cmd.ATCCommand.Runner(args)
	if err != nil {
		return err
	}

	tsaRunner, err := tsa.Runner(args)
	if err != nil {
		return err
	}

	runner := sigmon.New(grouper.NewParallel(os.Interrupt, grouper.Members{
		{"atc", atcRunner},
		{"tsa", tsaRunner},
	}))

	return <-ifrit.Invoke(runner).Wait()
}

func (cmd *WebCommand) populateTSAFlagsFromATCFlags(tsa *tsacmd.TSACommand) error {
	// TODO: flag types package plz
	err := tsa.ATCURL.UnmarshalFlag(cmd.ATCCommand.PeerURL.String())
	if err != nil {
		return err
	}

	tsa.SessionSigningKeyPath = tsacmd.FileFlag(cmd.ATCCommand.SessionSigningKey)

	host, _, err := net.SplitHostPort(cmd.ATCCommand.PeerURL.URL().Host)
	if err != nil {
		return err
	}

	tsa.PeerIP = host

	tsa.Metrics.YellerAPIKey = cmd.ATCCommand.Metrics.YellerAPIKey
	tsa.Metrics.YellerEnvironment = cmd.ATCCommand.Metrics.YellerEnvironment

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/spf13/cobra"

	"github.com/antham/doc-hunt/file"
	"github.com/antham/doc-hunt/ui"
	"github.com/antham/doc-hunt/util"
)

var delConfigCmd = &cobra.Command{
	Use:   "del",
	Short: "Delete one or several configuration row",
	Run: func(cmd *cobra.Command, args []string) {
		list, err := file.ListConfig()

		if err != nil {
			ui.Error(err)
			util.ErrorExit()
		}

		if len(*list) == 0 {
			ui.Info("No config added yet")
			util.SuccessExit()
		}

		renderConfig(list)

		configs, err := promptConfigToRemove(list)

		if err != nil {
			ui.Error(err)
			util.ErrorExit()
		}

		err = file.RemoveConfigs(configs)

		if err != nil {
			ui.Error(err)
			util.ErrorExit()
		}

		ui.Success("Config deleted")
		util.SuccessExit()
	},
}

func promptConfigToRemove(configs *[]file.Config) (*[]file.Config, error) {
	ui.Prompt("Choose configurations number to remove, each separated with a comma")

	defer func() {
		if err := rl.Close(); err != nil {
			ui.Error(err)

			util.ErrorExit()
		}
	}()

	line, err := rl.Readline()

	if err != nil {
		return nil, err
	}

	return parseConfigDelArgs(configs, line)
}

func parseConfigDelArgs(configs *[]file.Config, line string) (*[]file.Config, error) {
	results := []file.Config{}

	for _, sel := range strings.Split(line, ",") {
		strings.TrimSpace(sel)
		n, err := strconv.Atoi(sel)

		if err != nil {
			return nil, fmt.Errorf("%s is not a number", sel)
		}

		if n < 0 || n >= len(*configs) {
			return nil, fmt.Errorf("Value %d is out of bounds", n)
		}

		results = append(results, (*configs)[n])
	}

	return &results, nil
}

func init() {
	configCmd.AddCommand(delConfigCmd)
}
<commit_msg>cmd : assign returned value<commit_after>package cmd

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/spf13/cobra"

	"github.com/antham/doc-hunt/file"
	"github.com/antham/doc-hunt/ui"
	"github.com/antham/doc-hunt/util"
)

var delConfigCmd = &cobra.Command{
	Use:   "del",
	Short: "Delete one or several configuration row",
	Run: func(cmd *cobra.Command, args []string) {
		list, err := file.ListConfig()

		if err != nil {
			ui.Error(err)
			util.ErrorExit()
		}

		if len(*list) == 0 {
			ui.Info("No config added yet")
			util.SuccessExit()
		}

		renderConfig(list)

		configs, err := promptConfigToRemove(list)

		if err != nil {
			ui.Error(err)
			util.ErrorExit()
		}

		err = file.RemoveConfigs(configs)

		if err != nil {
			ui.Error(err)
			util.ErrorExit()
		}

		ui.Success("Config deleted")
		util.SuccessExit()
	},
}

func promptConfigToRemove(configs *[]file.Config) (*[]file.Config, error) {
	ui.Prompt("Choose configurations number to remove, each separated with a comma")

	defer func() {
		if err := rl.Close(); err != nil {
			ui.Error(err)

			util.ErrorExit()
		}
	}()

	line, err := rl.Readline()

	if err != nil {
		return nil, err
	}

	return parseConfigDelArgs(configs, line)
}

func parseConfigDelArgs(configs *[]file.Config, line string) (*[]file.Config, error) {
	results := []file.Config{}

	for _, sel := range strings.Split(line, ",") {
		sel = strings.TrimSpace(sel)
		n, err := strconv.Atoi(sel)

		if err != nil {
			return nil, fmt.Errorf("%s is not a number", sel)
		}

		if n < 0 || n >= len(*configs) {
			return nil, fmt.Errorf("Value %d is out of bounds", n)
		}

		results = append(results, (*configs)[n])
	}

	return &results, nil
}

func init() {
	configCmd.AddCommand(delConfigCmd)
}
<|endoftext|>


<commit_before>// Copyright 2019 The Go Authors. 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 (
	"net/http"
	"sort"
	"strings"
)

// addCSP returns a handler that adds the appropriate Content-Security-Policy header
// to the response and then invokes h.
func addCSP(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var ks []string
		for k := range csp {
			ks = append(ks, k)
		}
		sort.Strings(ks)

		var sb strings.Builder
		for _, k := range ks {
			sb.WriteString(k)
			sb.WriteString(" ")
			sb.WriteString(strings.Join(csp[k], " "))
			sb.WriteString("; ")
		}

		w.Header().Set("Content-Security-Policy", sb.String())

		h.ServeHTTP(w, r)
	})
}

const (
	self         = "'self'"
	none         = "'none'"
	unsafeInline = "'unsafe-inline'"
)

var csp = map[string][]string{
	"connect-src": {
		"'self'",
		"https://golang.org",
		"https://play.golang.org", // For running playground snippets on the blog.
		"www.google-analytics.com",
		"stats.g.doubleclick.net",
	},
	"default-src": {
		self,
	},
	"font-src": {
		self,
		"fonts.googleapis.com",
		"fonts.gstatic.com",
		"data:",
	},
	"style-src": {
		self,
		unsafeInline,
		"fonts.googleapis.com",
		"feedback.googleusercontent.com",
		"www.gstatic.com",
		"gstatic.com",
		"tagmanager.google.com",
	},
	"frame-src": {
		self,
		"www.google.com",
		"feedback.googleusercontent.com",
		"www.googletagmanager.com",
		"scone-pa.clients6.google.com",
	},
	"img-src": {
		self,
		"www.google.com",
		"www.google-analytics.com",
		"ssl.gstatic.com",
		"www.gstatic.com",
		"gstatic.com",
		"data: *",
	},
	"object-src": {
		none,
	},
	"script-src": {
		self,
		"'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck='", // Google Tag Manager main snippet
		"'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M='", // Google Tag Manager Preview mode
		"'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo='", // Google Tag Manager Preview mode
		"www.google.com",
		"apis.google.com",
		"www.gstatic.com",
		"gstatic.com",
		"support.google.com",
		"www.googletagmanager.com",
		"www.google-analytics.com",
		"ssl.google-analytics.com",
		"tagmanager.google.com",
	},
	"frame-ancestors": {
		none,
	},
}
<commit_msg>cmd/golangorg: fix Content Security Policy breaks embedded YouTube videos<commit_after>// Copyright 2019 The Go Authors. 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 (
	"net/http"
	"sort"
	"strings"
)

// addCSP returns a handler that adds the appropriate Content-Security-Policy header
// to the response and then invokes h.
func addCSP(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var ks []string
		for k := range csp {
			ks = append(ks, k)
		}
		sort.Strings(ks)

		var sb strings.Builder
		for _, k := range ks {
			sb.WriteString(k)
			sb.WriteString(" ")
			sb.WriteString(strings.Join(csp[k], " "))
			sb.WriteString("; ")
		}

		w.Header().Set("Content-Security-Policy", sb.String())

		h.ServeHTTP(w, r)
	})
}

const (
	self         = "'self'"
	none         = "'none'"
	unsafeInline = "'unsafe-inline'"
)

var csp = map[string][]string{
	"connect-src": {
		"'self'",
		"https://golang.org",
		"https://play.golang.org", // For running playground snippets on the blog.
		"www.google-analytics.com",
		"stats.g.doubleclick.net",
	},
	"default-src": {
		self,
	},
	"font-src": {
		self,
		"fonts.googleapis.com",
		"fonts.gstatic.com",
		"data:",
	},
	"style-src": {
		self,
		unsafeInline,
		"fonts.googleapis.com",
		"feedback.googleusercontent.com",
		"www.gstatic.com",
		"gstatic.com",
		"tagmanager.google.com",
	},
	"frame-src": {
		self,
		"www.google.com",
		"feedback.googleusercontent.com",
		"www.googletagmanager.com",
		"scone-pa.clients6.google.com",
		"www.youtube.com",
	},
	"img-src": {
		self,
		"www.google.com",
		"www.google-analytics.com",
		"ssl.gstatic.com",
		"www.gstatic.com",
		"gstatic.com",
		"data: *",
	},
	"object-src": {
		none,
	},
	"script-src": {
		self,
		"'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck='", // Google Tag Manager main snippet
		"'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M='", // Google Tag Manager Preview mode
		"'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo='", // Google Tag Manager Preview mode
		"www.google.com",
		"apis.google.com",
		"www.gstatic.com",
		"gstatic.com",
		"support.google.com",
		"www.googletagmanager.com",
		"www.google-analytics.com",
		"ssl.google-analytics.com",
		"tagmanager.google.com",
	},
	"frame-ancestors": {
		none,
	},
}
<|endoftext|>


<commit_before>package main

import (
	"expvar"
	"flag"
	"github.com/valyala/fasthttp"
	"github.com/valyala/fasthttp/expvarhandler"
	"log"
	"net"
	"sync/atomic"
)

var (
	expvarAddr = flag.String("expvarAddr", "localhost:8040", "TCP address for exporting httptp metrics. They are exported "+
		"at http://expvarAddr/expvar page")
)

func initExpvarServer() {
	if *expvarAddr == "" {
		return
	}

	log.Printf("exporting stats at http://%s/expvar", *expvarAddr)

	go func() {
		if err := fasthttp.ListenAndServe(*expvarAddr, expvarHandler); err != nil {
			log.Fatalf("error in expvar server: %s", err)
		}
	}()
}

func expvarHandler(ctx *fasthttp.RequestCtx) {
	path := ctx.Path()
	if string(path) == "/expvar" {
		expvarhandler.ExpvarHandler(ctx)
	} else {
		ctx.Error("unsupported path", fasthttp.StatusBadRequest)
	}
}

func newExpvarDial(dial fasthttp.DialFunc) fasthttp.DialFunc {
	return func(addr string) (net.Conn, error) {
		conn, err := dial(addr)
		if err != nil {
			return nil, err
		}
		outConns.Add(1)
		return &expvarConn{Conn: conn}, nil
	}
}

type expvarConn struct {
	net.Conn
	closed uint32
}

func (c *expvarConn) Close() error {
	if atomic.AddUint32(&c.closed, 1) == 0 {
		outConns.Add(-1)
	}
	return c.Conn.Close()
}

var outConns = expvar.NewInt("outConns")
<commit_msg>httptp: added more expvars for -out<commit_after>package main

import (
	"expvar"
	"flag"
	"github.com/valyala/fasthttp"
	"github.com/valyala/fasthttp/expvarhandler"
	"log"
	"net"
	"sync/atomic"
)

var (
	expvarAddr = flag.String("expvarAddr", "localhost:8040", "TCP address for exporting httptp metrics. They are exported "+
		"at http://expvarAddr/expvar page")
)

func initExpvarServer() {
	if *expvarAddr == "" {
		return
	}

	log.Printf("exporting stats at http://%s/expvar", *expvarAddr)

	go func() {
		if err := fasthttp.ListenAndServe(*expvarAddr, expvarHandler); err != nil {
			log.Fatalf("error in expvar server: %s", err)
		}
	}()
}

func expvarHandler(ctx *fasthttp.RequestCtx) {
	path := ctx.Path()
	if string(path) == "/expvar" {
		expvarhandler.ExpvarHandler(ctx)
	} else {
		ctx.Error("unsupported path", fasthttp.StatusBadRequest)
	}
}

func newExpvarDial(dial fasthttp.DialFunc) fasthttp.DialFunc {
	return func(addr string) (net.Conn, error) {
		conn, err := dial(addr)
		if err != nil {
			outDialError.Add(1)
			return nil, err
		}
		outConns.Add(1)
		outDialSuccess.Add(1)
		return &expvarConn{Conn: conn}, nil
	}
}

type expvarConn struct {
	net.Conn
	closed uint32
}

func (c *expvarConn) Close() error {
	if atomic.AddUint32(&c.closed, 1) == 0 {
		outConns.Add(-1)
	}
	return c.Conn.Close()
}

func (c *expvarConn) Write(p []byte) (int, error) {
	n, err := c.Conn.Write(p)
	outBytesSent.Add(int64(n))
	return n, err
}

func (c *expvarConn) Read(p []byte) (int, error) {
	n, err := c.Conn.Read(p)
	outBytesRecv.Add(int64(n))
	return n, err
}

var (
	outConns       = expvar.NewInt("outConns")
	outDialSuccess = expvar.NewInt("outDialSuccess")
	outDialError   = expvar.NewInt("outDialError")
	outBytesSent   = expvar.NewInt("outBytesSent")
	outBytesRecv   = expvar.NewInt("outBytesRecv")
)
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"
	"text/template"

	"github.com/client9/misspell"
)

var (
	defaultWrite *template.Template
	defaultRead  *template.Template
	stdout       *log.Logger // see below in init()
)

const (
	defaultWriteTmpl = `{{ .Filename }}:{{ .Line }} corrected "{{ js .Original }}" to "{{ js .Corrected }}"`
	defaultReadTmpl  = `{{ .Filename }}:{{ .Line }} found "{{ js .Original }}" a misspelling of "{{ js .Corrected }}"`
)

func init() {
	defaultWrite = template.Must(template.New("defaultWrite").Parse(defaultWriteTmpl))
	defaultRead = template.Must(template.New("defaultRead").Parse(defaultReadTmpl))

	// we cant't just write to os.Stdout directly since we have multiple goroutine
	// all writing at the same time causing broken output.  Log is routine safe.
	// we see it so it doesn't use a prefix or include a time stamp.
	stdout = log.New(os.Stdout, "", 0)
}

func worker(writeit bool, debug bool, mode string, files <-chan string, results chan<- int) {
	fails := 0
	for filename := range files {
		isGolang := strings.HasSuffix(filename, ".go")

		// ignore directories
		if f, err := os.Stat(filename); f.IsDir() && err == nil {
			continue
		}

		raw, err := ioutil.ReadFile(filename)
		if err != nil {
			log.Printf("Unable to read %q: %s", filename, err)
			continue
		}
		orig := string(raw)
		var updated string

		// GROSS
		if mode == "go" || (mode == "auto" && isGolang) {
			updated = misspell.ReplaceGo(orig, debug)
		} else if debug {
			updated = misspell.ReplaceDebug(orig)
		} else {
			updated = misspell.Replace(orig)
		}

		updated, changes := misspell.DiffLines(filename, orig, updated)
		if len(changes) == 0 {
			continue
		}
		for _, diff := range changes {
			// output can be done by doing multiple goroutines
			// and can clobber os.Stdout.
			//
			// the log package can be used simultaneously from multiple goroutines
			var output bytes.Buffer
			if writeit {
				defaultWrite.Execute(&output, diff)
			} else {
				defaultRead.Execute(&output, diff)
			}

			// goroutine-safe print to os.Stdout
			stdout.Println(output.String())
		}

		if writeit {
			ioutil.WriteFile(filename, []byte(updated), 0)
		}
	}
	results <- fails
}

func main() {
	workers := flag.Int("j", 0, "Number of workers, 0 = number of CPUs")
	writeit := flag.Bool("w", false, "Overwrite file with corrections (default is just to display)")
	format := flag.String("f", "", "Use Golang template for log message")
	ignores := flag.String("i", "", "Ignore the following corrections, comma separated")
	mode := flag.String("source", "auto", "Source mode: auto=guess, go=golang source, text=plain or markdown-like text")
	debug := flag.Bool("debug", false, "Debug matching, very slow")
	flag.Parse()

	switch *mode {
	case "auto":
	case "go":
	case "text":
	default:
		log.Fatalf("Mode must be one of auto=guess, go=golang source, text=plain or markdown-like text")
	}
	if len(*format) > 0 {
		t, err := template.New("custom").Parse(*format)
		if err != nil {
			log.Fatalf("Unable to compile log format: %s", err)
		}
		defaultWrite = t
		defaultRead = t
	}
	if len(*ignores) > 0 {
		err := misspell.Ignore(strings.Split(*ignores, ","))
		if err != nil {
			log.Fatalf("unable to process ignores: %s", err)
		}
	}
	if *workers < 0 {
		log.Fatalf("-j must >= 0")
	}
	if *workers == 0 {
		*workers = runtime.NumCPU()
	}

	if *debug {
		*workers = 1
	}
	args := flag.Args()

	/*
		if len(args) == 0 {
			rawin, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				panic(err)
			}
			replacer.WriteString(os.Stdout, string(rawin))
			return
		}
	*/
	c := make(chan string, len(args))
	results := make(chan int, *workers)

	for i := 0; i < *workers; i++ {
		go worker(*writeit, *debug, *mode, c, results)
	}

	for _, filename := range args {
		c <- filename
	}
	close(c)

	count := 0
	for i := 0; i < *workers; i++ {
		changed := <-results
		count += changed
	}
	if count != 0 {
		// log.Printf("Got %d", count)
		// error
		os.Exit(1)
	}
}
<commit_msg>interesting bug from pull #14<commit_after>package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"
	"text/template"

	"github.com/client9/misspell"
)

var (
	defaultWrite *template.Template
	defaultRead  *template.Template
	stdout       *log.Logger // see below in init()
)

const (
	defaultWriteTmpl = `{{ .Filename }}:{{ .Line }} corrected "{{ js .Original }}" to "{{ js .Corrected }}"`
	defaultReadTmpl  = `{{ .Filename }}:{{ .Line }} found "{{ js .Original }}" a misspelling of "{{ js .Corrected }}"`
)

func init() {
	defaultWrite = template.Must(template.New("defaultWrite").Parse(defaultWriteTmpl))
	defaultRead = template.Must(template.New("defaultRead").Parse(defaultReadTmpl))

	// we cant't just write to os.Stdout directly since we have multiple goroutine
	// all writing at the same time causing broken output.  Log is routine safe.
	// we see it so it doesn't use a prefix or include a time stamp.
	stdout = log.New(os.Stdout, "", 0)
}

func worker(writeit bool, debug bool, mode string, files <-chan string, results chan<- int) {
	fails := 0
	for filename := range files {
		isGolang := strings.HasSuffix(filename, ".go")

		// ignore directories
		if f, err := os.Stat(filename); err != nil || f.IsDir() {
			continue
		}

		raw, err := ioutil.ReadFile(filename)
		if err != nil {
			log.Printf("Unable to read %q: %s", filename, err)
			continue
		}
		orig := string(raw)
		var updated string

		// GROSS
		if mode == "go" || (mode == "auto" && isGolang) {
			updated = misspell.ReplaceGo(orig, debug)
		} else if debug {
			updated = misspell.ReplaceDebug(orig)
		} else {
			updated = misspell.Replace(orig)
		}

		updated, changes := misspell.DiffLines(filename, orig, updated)
		if len(changes) == 0 {
			continue
		}
		for _, diff := range changes {
			// output can be done by doing multiple goroutines
			// and can clobber os.Stdout.
			//
			// the log package can be used simultaneously from multiple goroutines
			var output bytes.Buffer
			if writeit {
				defaultWrite.Execute(&output, diff)
			} else {
				defaultRead.Execute(&output, diff)
			}

			// goroutine-safe print to os.Stdout
			stdout.Println(output.String())
		}

		if writeit {
			ioutil.WriteFile(filename, []byte(updated), 0)
		}
	}
	results <- fails
}

func main() {
	workers := flag.Int("j", 0, "Number of workers, 0 = number of CPUs")
	writeit := flag.Bool("w", false, "Overwrite file with corrections (default is just to display)")
	format := flag.String("f", "", "Use Golang template for log message")
	ignores := flag.String("i", "", "Ignore the following corrections, comma separated")
	mode := flag.String("source", "auto", "Source mode: auto=guess, go=golang source, text=plain or markdown-like text")
	debug := flag.Bool("debug", false, "Debug matching, very slow")
	flag.Parse()

	switch *mode {
	case "auto":
	case "go":
	case "text":
	default:
		log.Fatalf("Mode must be one of auto=guess, go=golang source, text=plain or markdown-like text")
	}
	if len(*format) > 0 {
		t, err := template.New("custom").Parse(*format)
		if err != nil {
			log.Fatalf("Unable to compile log format: %s", err)
		}
		defaultWrite = t
		defaultRead = t
	}
	if len(*ignores) > 0 {
		err := misspell.Ignore(strings.Split(*ignores, ","))
		if err != nil {
			log.Fatalf("unable to process ignores: %s", err)
		}
	}
	if *workers < 0 {
		log.Fatalf("-j must >= 0")
	}
	if *workers == 0 {
		*workers = runtime.NumCPU()
	}

	if *debug {
		*workers = 1
	}
	args := flag.Args()

	/*
		if len(args) == 0 {
			rawin, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				panic(err)
			}
			replacer.WriteString(os.Stdout, string(rawin))
			return
		}
	*/
	c := make(chan string, len(args))
	results := make(chan int, *workers)

	for i := 0; i < *workers; i++ {
		go worker(*writeit, *debug, *mode, c, results)
	}

	for _, filename := range args {
		c <- filename
	}
	close(c)

	count := 0
	for i := 0; i < *workers; i++ {
		changed := <-results
		count += changed
	}
	if count != 0 {
		// log.Printf("Got %d", count)
		// error
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package tui

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"github.com/charmbracelet/bubbles/textinput"
	tea "github.com/charmbracelet/bubbletea"

	"nimona.io/pkg/blob"
	"nimona.io/pkg/config"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/daemon"
	"nimona.io/pkg/filesharing"
	"nimona.io/pkg/hyperspace/resolver"
	"nimona.io/pkg/localpeer"
	"nimona.io/pkg/network"
	"nimona.io/pkg/object"
	"nimona.io/pkg/objectmanager"
	"nimona.io/pkg/objectstore"
)

const (
	OutgoingTransferRequestSent     = "TransferRequestSent"
	OutgoingTransferFileSent        = "OutgoingTransferFileSent"
	OutgoingTransferAccepted        = "OutgoingTransferAccepted"
	OutgoingTransferRejected        = "OutgoingTransferRejected"
	IncomingTransferRequestReceived = "IncomingTransferRequestReceived"
	IncomingTransferFileReceived    = "IncomingTransferFileReceived"
	IncomingTransferAccepted        = "IncomingTransferAccepted"
	IncomingTransferRejected        = "IncomingTransferRejected"
)

type (
	Config struct {
		ReceivedFolder string `envconfig:"RECEIVED_FOLDER" default:"received_files"`
	}
	comboConf struct {
		hconf *Config
		nconf *config.Config
	}
	transferWrap struct {
		transfer *filesharing.Transfer
		status   string
		updated  time.Time
	}
	hermod struct {
		textInput textinput.Model
		result    string

		config *comboConf

		network       network.Network
		local         localpeer.LocalPeer
		objectmanager objectmanager.ObjectManager
		blobmanager   blob.Manager
		objectstore   objectstore.Store
		resolver      resolver.Resolver
		fsh           filesharing.Filesharer
		transfers     map[string]*transferWrap
	}
	transferMsg struct {
		trf *filesharing.Transfer
	}
	fileReceivedMsg struct {
		nonce string
	}
)

func NewHermod() hermod {
	her := &hermod{}

	ctx := context.New(
		context.WithCorrelationID("nimona"),
	)

	// init config
	cfg := &Config{}

	d, err := daemon.New(
		ctx,
		daemon.WithConfigOptions(
			config.WithDefaultPath("~/.nimona-hermod"),
			config.WithExtraConfig("HERMOD", cfg),
		),
	)
	if err != nil {
		panic(err)
	}

	local := d.LocalPeer()
	man := d.ObjectManager()
	nnet := d.Network()
	res := d.Resolver()
	str := d.ObjectStore()
	nconf := d.Config()

	cconf := &comboConf{
		hconf: cfg,
		nconf: &nconf,
	}

	// init textinput
	ti := textinput.NewModel()
	ti.Focus()

	fsh := filesharing.New(
		man,
		nnet,
		cfg.ReceivedFolder,
	)

	her.network = nnet
	her.config = cconf
	her.local = local
	her.textInput = ti
	her.config = cconf
	her.resolver = res
	her.objectstore = str
	her.objectmanager = man
	her.fsh = fsh
	her.blobmanager = blob.NewManager(ctx, blob.WithObjectManager(man))
	her.transfers = make(map[string]*transferWrap)

	go func() {
		transfers, err := her.fsh.Listen(ctx)
		if err != nil {
			fmt.Println("failed to listen: ", err)
			os.Exit(-1)
		}

		for transfer := range transfers {
			her.Update(transferMsg{
				trf: transfer,
			})
		}
	}()

	go func() {
		sub := nnet.Subscribe()
		for {
			env, err := sub.Next()
			if err != nil {
				fmt.Println("Failed to get object: ", err)
				return
			}
			switch env.Payload.Type {
			case filesharing.TransferDoneType:
				req := &filesharing.TransferDone{}

				if err := object.Unmarshal(env.Payload, req); err != nil {
					fmt.Println("Failed to get object: ", err)
					continue
				}

				her.transfers[req.Nonce].status = OutgoingTransferFileSent

			case filesharing.TransferResponseType:
				req := &filesharing.TransferResponse{}

				if err := object.Unmarshal(env.Payload, req); err != nil {
					fmt.Println("Failed to get object: ", err)
					continue
				}

				if !req.Accepted {
					her.transfers[req.Nonce].status = OutgoingTransferRejected
				}
				her.transfers[req.Nonce].status = OutgoingTransferAccepted
			}
		}
	}()

	return *her
}

func (h hermod) Init() tea.Cmd {
	return textinput.Blink
}

func (h hermod) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	var cmd tea.Cmd

	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "ctrl+c":
			return h, tea.Quit
		case "enter":
			return h.execute()
		}
	case transferMsg:
		return h.handleTransferMsg(msg)
	case fileReceivedMsg:
		return h.handleFileReceivedMsg(msg)
	}

	h.textInput, cmd = h.textInput.Update(msg)

	return h, cmd
}

func (h *hermod) handleFileReceivedMsg(
	msg fileReceivedMsg,
) (
	tea.Model, tea.Cmd,
) {
	var cmd tea.Cmd
	h.transfers[msg.nonce].status = IncomingTransferFileReceived
	return h, cmd
}

func (h *hermod) handleTransferMsg(
	msg transferMsg,
) (
	tea.Model,
	tea.Cmd,
) {
	var cmd tea.Cmd
	h.transfers[msg.trf.Request.Nonce] = &transferWrap{
		status:   IncomingTransferRequestReceived,
		transfer: msg.trf,
		updated:  time.Now(),
	}
	return h, cmd
}

func (h hermod) View() string {
	tpl := "%s\n%s\n"
	if len(h.transfers) > 0 {
		tpl += "Transfers:\n"

		transfers := []*transferWrap{}

		for _, trw := range h.transfers {
			transfers = append(transfers, trw)
		}

		sort.SliceStable(transfers, func(i, j int) bool {
			return transfers[i].updated.Unix() > transfers[j].updated.Unix()
		})

		for _, tr := range transfers {
			tpl += fmt.Sprintf(
				"-> Peer: %s File: %s ID: %s Status: %s\n", // TODO arrow based on direction?
				tr.transfer.Peer.String(),
				tr.transfer.Request.File.Name,
				tr.transfer.Request.Nonce,
				tr.status, // TODO convert status to string
			)
		}

	}

	v := fmt.Sprintf(
		tpl,
		h.textInput.View(),
		h.result,
	)
	return v
}

func (h *hermod) execute() (tea.Model, tea.Cmd) {
	h.textInput.Blur()

	fullCommand := h.textInput.Value()

	fc := strings.Split(fullCommand, " ")
	command := fc[0]
	params := []string{}

	for _, p := range fc[1:] {
		np := strings.Trim(p, " ")
		if np != "" {
			params = append(params, np)
		}
	}

	switch command {
	case "help":
		r := "* Send file: `send <file> <peer>`\n"
		r += "* Request offered file: `request <hash>`\n"
		r += "* Show local peer info: `local`\n"
		r += "* Quit: `quit`\n"
		h.result = r
	case "send":
		if len(params) < 2 {
			h.result = "usage: send <file> <peer>"
			break
		}
		h.result = fmt.Sprintf("%d", len(params))
		file := strings.Join(params[:len(params)-1], " ")
		recipient := crypto.PublicKey{}
		err := recipient.UnmarshalString(params[len(params)-1])
		if err != nil {
			h.result = "invalid recipient key"
		}
		h.result = fmt.Sprintf(
			"Sending file %s to %s ...",
			file,
			recipient.String(),
		)
		h.sendFile(file, recipient)
	case "local":
		h.result = fmt.Sprintf(
			"public_key: %s\naddresses: %s\n",
			h.network.GetConnectionInfo().PublicKey,
			h.network.GetConnectionInfo().Addresses,
		)
	case "request":
		if len(params) != 1 {
			h.result = "usage: request <hash>"
			break
		}
		h.result = fmt.Sprintf(
			"Requesting transfer: %s ...",
			params,
		)
		h.requestFile(params[0])
	case "quit":
		return h, tea.Quit
	default:
		h.result = ""
	}

	h.textInput.Reset()
	h.textInput.Focus()

	return h, nil
}

func (h *hermod) sendFile(
	file string,
	peerKey crypto.PublicKey,
) {
	ctx := context.Background()
	filename := filepath.Base(file)
	bl, err := h.blobmanager.ImportFromFile(ctx, file)
	if err != nil {
		h.result = err.Error()
		return
	}

	fr := &filesharing.File{
		Name:   filename,
		Chunks: bl.Chunks,
	}
	nonce, err := h.fsh.RequestTransfer(
		ctx,
		fr,
		peerKey,
	)
	h.transfers[nonce] = &transferWrap{
		status: OutgoingTransferRequestSent,
		transfer: &filesharing.Transfer{
			Request: filesharing.TransferRequest{
				Nonce: nonce,
				File:  *fr,
			},
			Peer: peerKey,
		},
		updated: time.Now(),
	}
	if err != nil {
		h.result = err.Error()
		return
	}
}

func (h *hermod) requestFile(
	nonce string,
) {
	trf := h.transfers[nonce]
	_, err := h.fsh.RequestFile(context.Background(), trf.transfer)
	if err != nil {
		h.result = err.Error()
		return
	}
	h.Update(fileReceivedMsg{
		nonce: trf.transfer.Request.Nonce,
	})
}
<commit_msg>chore(apps): update to remove local peer<commit_after>package tui

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"github.com/charmbracelet/bubbles/textinput"
	tea "github.com/charmbracelet/bubbletea"

	"nimona.io/pkg/blob"
	"nimona.io/pkg/config"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/daemon"
	"nimona.io/pkg/filesharing"
	"nimona.io/pkg/hyperspace/resolver"
	"nimona.io/pkg/network"
	"nimona.io/pkg/object"
	"nimona.io/pkg/objectmanager"
	"nimona.io/pkg/objectstore"
)

const (
	OutgoingTransferRequestSent     = "TransferRequestSent"
	OutgoingTransferFileSent        = "OutgoingTransferFileSent"
	OutgoingTransferAccepted        = "OutgoingTransferAccepted"
	OutgoingTransferRejected        = "OutgoingTransferRejected"
	IncomingTransferRequestReceived = "IncomingTransferRequestReceived"
	IncomingTransferFileReceived    = "IncomingTransferFileReceived"
	IncomingTransferAccepted        = "IncomingTransferAccepted"
	IncomingTransferRejected        = "IncomingTransferRejected"
)

type (
	Config struct {
		ReceivedFolder string `envconfig:"RECEIVED_FOLDER" default:"received_files"`
	}
	comboConf struct {
		hconf *Config
		nconf *config.Config
	}
	transferWrap struct {
		transfer *filesharing.Transfer
		status   string
		updated  time.Time
	}
	hermod struct {
		textInput textinput.Model
		result    string

		config *comboConf

		network       network.Network
		objectmanager objectmanager.ObjectManager
		blobmanager   blob.Manager
		objectstore   objectstore.Store
		resolver      resolver.Resolver
		fsh           filesharing.Filesharer
		transfers     map[string]*transferWrap
	}
	transferMsg struct {
		trf *filesharing.Transfer
	}
	fileReceivedMsg struct {
		nonce string
	}
)

func NewHermod() hermod {
	her := &hermod{}

	ctx := context.New(
		context.WithCorrelationID("nimona"),
	)

	// init config
	cfg := &Config{}

	d, err := daemon.New(
		ctx,
		daemon.WithConfigOptions(
			config.WithDefaultPath("~/.nimona-hermod"),
			config.WithExtraConfig("HERMOD", cfg),
		),
	)
	if err != nil {
		panic(err)
	}

	man := d.ObjectManager()
	nnet := d.Network()
	res := d.Resolver()
	str := d.ObjectStore()
	nconf := d.Config()

	cconf := &comboConf{
		hconf: cfg,
		nconf: &nconf,
	}

	// init textinput
	ti := textinput.NewModel()
	ti.Focus()

	fsh := filesharing.New(
		man,
		nnet,
		cfg.ReceivedFolder,
	)

	her.network = nnet
	her.config = cconf
	her.textInput = ti
	her.config = cconf
	her.resolver = res
	her.objectstore = str
	her.objectmanager = man
	her.fsh = fsh
	her.blobmanager = blob.NewManager(ctx, blob.WithObjectManager(man))
	her.transfers = make(map[string]*transferWrap)

	go func() {
		transfers, err := her.fsh.Listen(ctx)
		if err != nil {
			fmt.Println("failed to listen: ", err)
			os.Exit(-1)
		}

		for transfer := range transfers {
			her.Update(transferMsg{
				trf: transfer,
			})
		}
	}()

	go func() {
		sub := nnet.Subscribe()
		for {
			env, err := sub.Next()
			if err != nil {
				fmt.Println("Failed to get object: ", err)
				return
			}
			switch env.Payload.Type {
			case filesharing.TransferDoneType:
				req := &filesharing.TransferDone{}

				if err := object.Unmarshal(env.Payload, req); err != nil {
					fmt.Println("Failed to get object: ", err)
					continue
				}

				her.transfers[req.Nonce].status = OutgoingTransferFileSent

			case filesharing.TransferResponseType:
				req := &filesharing.TransferResponse{}

				if err := object.Unmarshal(env.Payload, req); err != nil {
					fmt.Println("Failed to get object: ", err)
					continue
				}

				if !req.Accepted {
					her.transfers[req.Nonce].status = OutgoingTransferRejected
				}
				her.transfers[req.Nonce].status = OutgoingTransferAccepted
			}
		}
	}()

	return *her
}

func (h hermod) Init() tea.Cmd {
	return textinput.Blink
}

func (h hermod) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	var cmd tea.Cmd

	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "ctrl+c":
			return h, tea.Quit
		case "enter":
			return h.execute()
		}
	case transferMsg:
		return h.handleTransferMsg(msg)
	case fileReceivedMsg:
		return h.handleFileReceivedMsg(msg)
	}

	h.textInput, cmd = h.textInput.Update(msg)

	return h, cmd
}

func (h *hermod) handleFileReceivedMsg(
	msg fileReceivedMsg,
) (
	tea.Model, tea.Cmd,
) {
	var cmd tea.Cmd
	h.transfers[msg.nonce].status = IncomingTransferFileReceived
	return h, cmd
}

func (h *hermod) handleTransferMsg(
	msg transferMsg,
) (
	tea.Model,
	tea.Cmd,
) {
	var cmd tea.Cmd
	h.transfers[msg.trf.Request.Nonce] = &transferWrap{
		status:   IncomingTransferRequestReceived,
		transfer: msg.trf,
		updated:  time.Now(),
	}
	return h, cmd
}

func (h hermod) View() string {
	tpl := "%s\n%s\n"
	if len(h.transfers) > 0 {
		tpl += "Transfers:\n"

		transfers := []*transferWrap{}

		for _, trw := range h.transfers {
			transfers = append(transfers, trw)
		}

		sort.SliceStable(transfers, func(i, j int) bool {
			return transfers[i].updated.Unix() > transfers[j].updated.Unix()
		})

		for _, tr := range transfers {
			tpl += fmt.Sprintf(
				"-> Peer: %s File: %s ID: %s Status: %s\n", // TODO arrow based on direction?
				tr.transfer.Peer.String(),
				tr.transfer.Request.File.Name,
				tr.transfer.Request.Nonce,
				tr.status, // TODO convert status to string
			)
		}

	}

	v := fmt.Sprintf(
		tpl,
		h.textInput.View(),
		h.result,
	)
	return v
}

func (h *hermod) execute() (tea.Model, tea.Cmd) {
	h.textInput.Blur()

	fullCommand := h.textInput.Value()

	fc := strings.Split(fullCommand, " ")
	command := fc[0]
	params := []string{}

	for _, p := range fc[1:] {
		np := strings.Trim(p, " ")
		if np != "" {
			params = append(params, np)
		}
	}

	switch command {
	case "help":
		r := "* Send file: `send <file> <peer>`\n"
		r += "* Request offered file: `request <hash>`\n"
		r += "* Show local peer info: `local`\n"
		r += "* Quit: `quit`\n"
		h.result = r
	case "send":
		if len(params) < 2 {
			h.result = "usage: send <file> <peer>"
			break
		}
		h.result = fmt.Sprintf("%d", len(params))
		file := strings.Join(params[:len(params)-1], " ")
		recipient := crypto.PublicKey{}
		err := recipient.UnmarshalString(params[len(params)-1])
		if err != nil {
			h.result = "invalid recipient key"
		}
		h.result = fmt.Sprintf(
			"Sending file %s to %s ...",
			file,
			recipient.String(),
		)
		h.sendFile(file, recipient)
	case "local":
		h.result = fmt.Sprintf(
			"public_key: %s\naddresses: %s\n",
			h.network.GetConnectionInfo().PublicKey,
			h.network.GetConnectionInfo().Addresses,
		)
	case "request":
		if len(params) != 1 {
			h.result = "usage: request <hash>"
			break
		}
		h.result = fmt.Sprintf(
			"Requesting transfer: %s ...",
			params,
		)
		h.requestFile(params[0])
	case "quit":
		return h, tea.Quit
	default:
		h.result = ""
	}

	h.textInput.Reset()
	h.textInput.Focus()

	return h, nil
}

func (h *hermod) sendFile(
	file string,
	peerKey crypto.PublicKey,
) {
	ctx := context.Background()
	filename := filepath.Base(file)
	bl, err := h.blobmanager.ImportFromFile(ctx, file)
	if err != nil {
		h.result = err.Error()
		return
	}

	fr := &filesharing.File{
		Name:   filename,
		Chunks: bl.Chunks,
	}
	nonce, err := h.fsh.RequestTransfer(
		ctx,
		fr,
		peerKey,
	)
	h.transfers[nonce] = &transferWrap{
		status: OutgoingTransferRequestSent,
		transfer: &filesharing.Transfer{
			Request: filesharing.TransferRequest{
				Nonce: nonce,
				File:  *fr,
			},
			Peer: peerKey,
		},
		updated: time.Now(),
	}
	if err != nil {
		h.result = err.Error()
		return
	}
}

func (h *hermod) requestFile(
	nonce string,
) {
	trf := h.transfers[nonce]
	_, err := h.fsh.RequestFile(context.Background(), trf.transfer)
	if err != nil {
		h.result = err.Error()
		return
	}
	h.Update(fileReceivedMsg{
		nonce: trf.transfer.Request.Nonce,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/cbroglie/mustache"
)

var rootCmd = &cobra.Command{
	Use: "mustache [data] template",
	Example: `  $ mustache data.yml template.mustache
  $ cat data.yml | mustache template.mustache`,
	Args: cobra.RangeArgs(0, 2),
	Run: func(cmd *cobra.Command, args []string) {
		err := run(cmd, args)
		if err != nil {
			fmt.Printf("Error: %s\n", err.Error())
			os.Exit(1)
		}
	},
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}

func run(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		cmd.Usage()
		return nil
	}

	var data interface{}
	var templatePath string
	if len(args) == 1 {
		var err error
		data, err = parseDataFromStdIn()
		if err != nil {
			return err
		}
		templatePath = args[0]
	} else {
		var err error
		data, err = parseDataFromFile(args[0])
		if err != nil {
			return err
		}
		templatePath = args[1]
	}

	output, err := mustache.RenderFile(templatePath, data)
	if err != nil {
		return err
	}

	fmt.Print(output)
	return nil
}

func parseDataFromStdIn() (interface{}, error) {
	b, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return nil, err
	}
	var data interface{}
	if err := yaml.Unmarshal(b, &data); err != nil {
		return nil, err
	}
	return data, nil
}

func parseDataFromFile(filePath string) (interface{}, error) {
	b, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}
	var data interface{}
	if err := yaml.Unmarshal(b, &data); err != nil {
		return nil, err
	}
	return data, nil
}
<commit_msg>add layout feature<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/cbroglie/mustache"
)

var rootCmd = &cobra.Command{
	Use: "mustache [--layout template] [data] template",
	Example: `  $ mustache data.yml template.mustache
  $ cat data.yml | mustache template.mustache
  $ mustache --layout wrapper.mustache data template.mustache`,
	Args: cobra.RangeArgs(0, 2),
	Run: func(cmd *cobra.Command, args []string) {
		err := run(cmd, args)
		if err != nil {
			fmt.Printf("Error: %s\n", err.Error())
			os.Exit(1)
		}
	},
}
var layoutFile string

func main() {
	rootCmd.Flags().StringVar(&layoutFile, "layout", "", "location of layout file")
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}

func run(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		cmd.Usage()
		return nil
	}

	var data interface{}
	var templatePath string
	if len(args) == 1 {
		var err error
		data, err = parseDataFromStdIn()
		if err != nil {
			return err
		}
		templatePath = args[0]
	} else {
		var err error
		data, err = parseDataFromFile(args[0])
		if err != nil {
			return err
		}
		templatePath = args[1]
	}

	var output string
	var err error
	if layoutFile != "" {
		output, err = mustache.RenderFileInLayout(templatePath, layoutFile, data)
	} else {
		output, err = mustache.RenderFile(templatePath, data)
	}
	if err != nil {
		return err
	}
	fmt.Print(output)
	return nil
}

func parseDataFromStdIn() (interface{}, error) {
	b, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return nil, err
	}
	var data interface{}
	if err := yaml.Unmarshal(b, &data); err != nil {
		return nil, err
	}
	return data, nil
}

func parseDataFromFile(filePath string) (interface{}, error) {
	b, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}
	var data interface{}
	if err := yaml.Unmarshal(b, &data); err != nil {
		return nil, err
	}
	return data, nil
}
<|endoftext|>


<commit_before>package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/majestrate/srndv2/lib/config"
	"github.com/majestrate/srndv2/lib/database"
	"github.com/majestrate/srndv2/lib/frontend"
	"github.com/majestrate/srndv2/lib/nntp"
	"github.com/majestrate/srndv2/lib/store"
	"net"
	"time"
)

func main() {
	log.Info("starting up nntpchan...")
	conf, err := config.Ensure("nntpchan.json")
	if err != nil {
		log.Fatal(err)
	}

	if conf.Log == "debug" {
		log.SetLevel(log.DebugLevel)
	}

	fconfig := conf.Frontend
	if fconfig == nil {
		log.Fatal("no frontend configured")
	}

	sconfig := conf.Store

	if sconfig == nil {
		log.Fatal("no article storage configured")
	}

	nconfig := conf.NNTP

	if nconfig == nil {
		log.Fatal("no nntp server configured")
	}

	dconfig := conf.Database

	if dconfig == nil {
		log.Fatal("no database configured")
	}

	db, err := database.FromConfig(dconfig)
	if err != nil {
		log.Fatalf("failed to create dabatase: %s", err.Error())
	}

	fserv, err := frontend.NewHTTPFrontend(fconfig, db)

	if err != nil {
		log.Fatalf("failed to create frontend: %s", err.Error())
	}

	// create nntp server
	nserv := &nntp.Server{
		Config: nconfig,
		Feeds:  conf.Feeds,
		Hooks:  fserv,
	}

	// create article storage
	nserv.Storage, err = store.NewFilesytemStorage(sconfig.Path)
	if err != nil {
		log.Fatal(err)
	}

	// frontent server loop
	go func() {
		for {
			faddr := fconfig.BindAddr
			time.Sleep(time.Second)
			log.Infof("Frontend bind to %s", faddr)
			fl, err := net.Listen("tcp", faddr)
			if err != nil {
				log.Errorf("frontend  net.Listen failed: %s", err.Error())
				continue
			}
			// run frontend
			err = fserv.Serve(fl)
			if err != nil {
				fl.Close()
				log.Errorf("frontend.serve() %s", err.Error())
			}
		}
	}()

	// nntp server loop
	go func() {
		for {
			time.Sleep(time.Second)
			naddr := conf.NNTP.Bind
			log.Infof("Bind nntp server to %s", naddr)
			nl, err := net.Listen("tcp", naddr)
			if err != nil {
				log.Errorf("nntp server net.Listen failed: %s", err.Error())
				continue
			}
			// run nntp
			err = nserv.Serve(nl)
			if err != nil {
				nl.Close()
				log.Errorf("nntpserver.serve() %s", err.Error())
			}
		}
	}()

}
<commit_msg>persist mainloop<commit_after>package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/majestrate/srndv2/lib/config"
	"github.com/majestrate/srndv2/lib/database"
	"github.com/majestrate/srndv2/lib/frontend"
	"github.com/majestrate/srndv2/lib/nntp"
	"github.com/majestrate/srndv2/lib/store"
	"net"
	"time"
)

func main() {
	log.Info("starting up nntpchan...")
	conf, err := config.Ensure("nntpchan.json")
	if err != nil {
		log.Fatal(err)
	}

	if conf.Log == "debug" {
		log.SetLevel(log.DebugLevel)
	}

	fconfig := conf.Frontend
	if fconfig == nil {
		log.Fatal("no frontend configured")
	}

	sconfig := conf.Store

	if sconfig == nil {
		log.Fatal("no article storage configured")
	}

	nconfig := conf.NNTP

	if nconfig == nil {
		log.Fatal("no nntp server configured")
	}

	dconfig := conf.Database

	if dconfig == nil {
		log.Fatal("no database configured")
	}

	db, err := database.FromConfig(dconfig)
	if err != nil {
		log.Fatalf("failed to create dabatase: %s", err.Error())
	}

	fserv, err := frontend.NewHTTPFrontend(fconfig, db)

	if err != nil {
		log.Fatalf("failed to create frontend: %s", err.Error())
	}

	// create nntp server
	nserv := &nntp.Server{
		Config: nconfig,
		Feeds:  conf.Feeds,
		Hooks:  fserv,
	}

	// create article storage
	nserv.Storage, err = store.NewFilesytemStorage(sconfig.Path)
	if err != nil {
		log.Fatal(err)
	}

	// frontent server loop
	go func() {
		for {
			faddr := fconfig.BindAddr
			time.Sleep(time.Second)
			log.Infof("Frontend bind to %s", faddr)
			fl, err := net.Listen("tcp", faddr)
			if err != nil {
				log.Errorf("frontend  net.Listen failed: %s", err.Error())
				continue
			}
			// run frontend
			err = fserv.Serve(fl)
			if err != nil {
				fl.Close()
				log.Errorf("frontend.serve() %s", err.Error())
			}
		}
	}()

	// nntp server loop
	go func() {
		for {
			time.Sleep(time.Second)
			naddr := conf.NNTP.Bind
			log.Infof("Bind nntp server to %s", naddr)
			nl, err := net.Listen("tcp", naddr)
			if err != nil {
				log.Errorf("nntp server net.Listen failed: %s", err.Error())
				continue
			}
			// run nntp
			err = nserv.Serve(nl)
			if err != nil {
				nl.Close()
				log.Errorf("nntpserver.serve() %s", err.Error())
			}
		}
	}()
	for {
		time.Sleep(time.Second)
	}
}
<|endoftext|>