<commit_before>// Copyright 2014 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 plan9obj implements access to Plan 9 a.out object files.
package plan9obj

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"
)

// A FileHeader represents a Plan 9 a.out file header.
type FileHeader struct {
	Magic       uint32
	Bss         uint32
	Entry       uint64
	PtrSize     int
	LoadAddress uint64
	HdrSize     uint64
}

// A File represents an open Plan 9 a.out file.
type File struct {
	FileHeader
	Sections []*Section
	closer   io.Closer
}

// A SectionHeader represents a single Plan 9 a.out section header.
// This structure doesn't exist on-disk, but eases navigation
// through the object file.
type SectionHeader struct {
	Name   string
	Size   uint32
	Offset uint32
}

// A Section represents a single section in a Plan 9 a.out file.
type Section struct {
	SectionHeader

	// Embed ReaderAt for ReadAt method.
	// Do not embed SectionReader directly
	// to avoid having Read and Seek.
	// If a client wants Read and Seek it must use
	// Open() to avoid fighting over the seek offset
	// with other clients.
	io.ReaderAt
	sr *io.SectionReader
}

// Data reads and returns the contents of the Plan 9 a.out section.
func (s *Section) Data() ([]byte, error) {
	dat := make([]byte, s.sr.Size())
	n, err := s.sr.ReadAt(dat, 0)
	if n == len(dat) {
		err = nil
	}
	return dat[0:n], err
}

// Open returns a new ReadSeeker reading the Plan 9 a.out section.
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }

// A Symbol represents an entry in a Plan 9 a.out symbol table section.
type Sym struct {
	Value uint64
	Type  rune
	Name  string
}

/*
 * Plan 9 a.out reader
 */

// formatError is returned by some operations if the data does
// not have the correct format for an object file.
type formatError struct {
	off int
	msg string
	val interface{}
}

func (e *formatError) Error() string {
	msg := e.msg
	if e.val != nil {
		msg += fmt.Sprintf(" '%v'", e.val)
	}
	msg += fmt.Sprintf(" in record at byte %#x", e.off)
	return msg
}

// Open opens the named file using os.Open and prepares it for use as a Plan 9 a.out binary.
func Open(name string) (*File, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	ff, err := NewFile(f)
	if err != nil {
		f.Close()
		return nil, err
	}
	ff.closer = f
	return ff, nil
}

// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() error {
	var err error
	if f.closer != nil {
		err = f.closer.Close()
		f.closer = nil
	}
	return err
}

func parseMagic(magic []byte) (uint32, error) {
	m := binary.BigEndian.Uint32(magic)
	switch m {
	case Magic386, MagicAMD64, MagicARM:
		return m, nil
	}
	return 0, &formatError{0, "bad magic number", magic}
}

// NewFile creates a new File for accessing a Plan 9 binary in an underlying reader.
// The Plan 9 binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, error) {
	sr := io.NewSectionReader(r, 0, 1<<63-1)
	// Read and decode Plan 9 magic
	var magic [4]byte
	if _, err := r.ReadAt(magic[:], 0); err != nil {
		return nil, err
	}
	_, err := parseMagic(magic[:])
	if err != nil {
		return nil, err
	}

	ph := new(prog)
	if err := binary.Read(sr, binary.BigEndian, ph); err != nil {
		return nil, err
	}

	f := &File{FileHeader: FileHeader{
		Magic:       ph.Magic,
		Bss:         ph.Bss,
		Entry:       uint64(ph.Entry),
		PtrSize:     4,
		LoadAddress: 0x1000,
		HdrSize:     4 * 8,
	}}

	if ph.Magic&Magic64 != 0 {
		if err := binary.Read(sr, binary.BigEndian, &f.Entry); err != nil {
			return nil, err
		}
		f.PtrSize = 8
		f.LoadAddress = 0x200000
		f.HdrSize += 8
	}

	var sects = []struct {
		name string
		size uint32
	}{
		{"text", ph.Text},
		{"data", ph.Data},
		{"syms", ph.Syms},
		{"spsz", ph.Spsz},
		{"pcsz", ph.Pcsz},
	}

	f.Sections = make([]*Section, 5)

	off := uint32(f.HdrSize)

	for i, sect := range sects {
		s := new(Section)
		s.SectionHeader = SectionHeader{
			Name:   sect.name,
			Size:   sect.size,
			Offset: off,
		}
		off += sect.size
		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
		s.ReaderAt = s.sr
		f.Sections[i] = s
	}

	return f, nil
}

func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
	var order binary.ByteOrder = binary.BigEndian
	var s sym
	p := data
	for len(p) >= 4 {
		// Symbol type, value.
		if len(p) < ptrsz {
			return &formatError{len(data), "unexpected EOF", nil}
		}
		// fixed-width value
		if ptrsz == 8 {
			s.value = order.Uint64(p[0:8])
			p = p[8:]
		} else {
			s.value = uint64(order.Uint32(p[0:4]))
			p = p[4:]
		}

		var typ byte
		typ = p[0] & 0x7F
		s.typ = typ
		p = p[1:]

		// Name.
		var i int
		var nnul int
		for i = 0; i < len(p); i++ {
			if p[i] == 0 {
				nnul = 1
				break
			}
		}
		switch typ {
		case 'z', 'Z':
			p = p[i+nnul:]
			for i = 0; i+2 <= len(p); i += 2 {
				if p[i] == 0 && p[i+1] == 0 {
					nnul = 2
					break
				}
			}
		}
		if len(p) < i+nnul {
			return &formatError{len(data), "unexpected EOF", nil}
		}
		s.name = p[0:i]
		i += nnul
		p = p[i:]

		fn(s)
	}
	return nil
}

// NewTable decodes the Go symbol table in data,
// returning an in-memory representation.
func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
	var n int
	err := walksymtab(symtab, ptrsz, func(s sym) error {
		n++
		return nil
	})
	if err != nil {
		return nil, err
	}

	fname := make(map[uint16]string)
	syms := make([]Sym, 0, n)
	err = walksymtab(symtab, ptrsz, func(s sym) error {
		n := len(syms)
		syms = syms[0 : n+1]
		ts := &syms[n]
		ts.Type = rune(s.typ)
		ts.Value = s.value
		switch s.typ {
		default:
			ts.Name = string(s.name)
		case 'z', 'Z':
			for i := 0; i < len(s.name); i += 2 {
				eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
				elt, ok := fname[eltIdx]
				if !ok {
					return &formatError{-1, "bad filename code", eltIdx}
				}
				if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
					ts.Name += "/"
				}
				ts.Name += elt
			}
		}
		switch s.typ {
		case 'f':
			fname[uint16(s.value)] = ts.Name
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	return syms, nil
}

// Symbols returns the symbol table for f.
func (f *File) Symbols() ([]Sym, error) {
	symtabSection := f.Section("syms")
	if symtabSection == nil {
		return nil, errors.New("no symbol section")
	}

	symtab, err := symtabSection.Data()
	if err != nil {
		return nil, errors.New("cannot load symbol section")
	}

	return newTable(symtab, f.PtrSize)
}

// Section returns a section with the given name, or nil if no such
// section exists.
func (f *File) Section(name string) *Section {
	for _, s := range f.Sections {
		if s.Name == name {
			return s
		}
	}
	return nil
}
<commit_msg>debug/plan9obj: export ErrNoSymbols<commit_after>// Copyright 2014 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 plan9obj implements access to Plan 9 a.out object files.
package plan9obj

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"
)

// A FileHeader represents a Plan 9 a.out file header.
type FileHeader struct {
	Magic       uint32
	Bss         uint32
	Entry       uint64
	PtrSize     int
	LoadAddress uint64
	HdrSize     uint64
}

// A File represents an open Plan 9 a.out file.
type File struct {
	FileHeader
	Sections []*Section
	closer   io.Closer
}

// A SectionHeader represents a single Plan 9 a.out section header.
// This structure doesn't exist on-disk, but eases navigation
// through the object file.
type SectionHeader struct {
	Name   string
	Size   uint32
	Offset uint32
}

// A Section represents a single section in a Plan 9 a.out file.
type Section struct {
	SectionHeader

	// Embed ReaderAt for ReadAt method.
	// Do not embed SectionReader directly
	// to avoid having Read and Seek.
	// If a client wants Read and Seek it must use
	// Open() to avoid fighting over the seek offset
	// with other clients.
	io.ReaderAt
	sr *io.SectionReader
}

// Data reads and returns the contents of the Plan 9 a.out section.
func (s *Section) Data() ([]byte, error) {
	dat := make([]byte, s.sr.Size())
	n, err := s.sr.ReadAt(dat, 0)
	if n == len(dat) {
		err = nil
	}
	return dat[0:n], err
}

// Open returns a new ReadSeeker reading the Plan 9 a.out section.
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }

// A Symbol represents an entry in a Plan 9 a.out symbol table section.
type Sym struct {
	Value uint64
	Type  rune
	Name  string
}

/*
 * Plan 9 a.out reader
 */

// formatError is returned by some operations if the data does
// not have the correct format for an object file.
type formatError struct {
	off int
	msg string
	val interface{}
}

func (e *formatError) Error() string {
	msg := e.msg
	if e.val != nil {
		msg += fmt.Sprintf(" '%v'", e.val)
	}
	msg += fmt.Sprintf(" in record at byte %#x", e.off)
	return msg
}

// Open opens the named file using os.Open and prepares it for use as a Plan 9 a.out binary.
func Open(name string) (*File, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	ff, err := NewFile(f)
	if err != nil {
		f.Close()
		return nil, err
	}
	ff.closer = f
	return ff, nil
}

// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() error {
	var err error
	if f.closer != nil {
		err = f.closer.Close()
		f.closer = nil
	}
	return err
}

func parseMagic(magic []byte) (uint32, error) {
	m := binary.BigEndian.Uint32(magic)
	switch m {
	case Magic386, MagicAMD64, MagicARM:
		return m, nil
	}
	return 0, &formatError{0, "bad magic number", magic}
}

// NewFile creates a new File for accessing a Plan 9 binary in an underlying reader.
// The Plan 9 binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, error) {
	sr := io.NewSectionReader(r, 0, 1<<63-1)
	// Read and decode Plan 9 magic
	var magic [4]byte
	if _, err := r.ReadAt(magic[:], 0); err != nil {
		return nil, err
	}
	_, err := parseMagic(magic[:])
	if err != nil {
		return nil, err
	}

	ph := new(prog)
	if err := binary.Read(sr, binary.BigEndian, ph); err != nil {
		return nil, err
	}

	f := &File{FileHeader: FileHeader{
		Magic:       ph.Magic,
		Bss:         ph.Bss,
		Entry:       uint64(ph.Entry),
		PtrSize:     4,
		LoadAddress: 0x1000,
		HdrSize:     4 * 8,
	}}

	if ph.Magic&Magic64 != 0 {
		if err := binary.Read(sr, binary.BigEndian, &f.Entry); err != nil {
			return nil, err
		}
		f.PtrSize = 8
		f.LoadAddress = 0x200000
		f.HdrSize += 8
	}

	var sects = []struct {
		name string
		size uint32
	}{
		{"text", ph.Text},
		{"data", ph.Data},
		{"syms", ph.Syms},
		{"spsz", ph.Spsz},
		{"pcsz", ph.Pcsz},
	}

	f.Sections = make([]*Section, 5)

	off := uint32(f.HdrSize)

	for i, sect := range sects {
		s := new(Section)
		s.SectionHeader = SectionHeader{
			Name:   sect.name,
			Size:   sect.size,
			Offset: off,
		}
		off += sect.size
		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
		s.ReaderAt = s.sr
		f.Sections[i] = s
	}

	return f, nil
}

func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
	var order binary.ByteOrder = binary.BigEndian
	var s sym
	p := data
	for len(p) >= 4 {
		// Symbol type, value.
		if len(p) < ptrsz {
			return &formatError{len(data), "unexpected EOF", nil}
		}
		// fixed-width value
		if ptrsz == 8 {
			s.value = order.Uint64(p[0:8])
			p = p[8:]
		} else {
			s.value = uint64(order.Uint32(p[0:4]))
			p = p[4:]
		}

		var typ byte
		typ = p[0] & 0x7F
		s.typ = typ
		p = p[1:]

		// Name.
		var i int
		var nnul int
		for i = 0; i < len(p); i++ {
			if p[i] == 0 {
				nnul = 1
				break
			}
		}
		switch typ {
		case 'z', 'Z':
			p = p[i+nnul:]
			for i = 0; i+2 <= len(p); i += 2 {
				if p[i] == 0 && p[i+1] == 0 {
					nnul = 2
					break
				}
			}
		}
		if len(p) < i+nnul {
			return &formatError{len(data), "unexpected EOF", nil}
		}
		s.name = p[0:i]
		i += nnul
		p = p[i:]

		fn(s)
	}
	return nil
}

// NewTable decodes the Go symbol table in data,
// returning an in-memory representation.
func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
	var n int
	err := walksymtab(symtab, ptrsz, func(s sym) error {
		n++
		return nil
	})
	if err != nil {
		return nil, err
	}

	fname := make(map[uint16]string)
	syms := make([]Sym, 0, n)
	err = walksymtab(symtab, ptrsz, func(s sym) error {
		n := len(syms)
		syms = syms[0 : n+1]
		ts := &syms[n]
		ts.Type = rune(s.typ)
		ts.Value = s.value
		switch s.typ {
		default:
			ts.Name = string(s.name)
		case 'z', 'Z':
			for i := 0; i < len(s.name); i += 2 {
				eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
				elt, ok := fname[eltIdx]
				if !ok {
					return &formatError{-1, "bad filename code", eltIdx}
				}
				if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
					ts.Name += "/"
				}
				ts.Name += elt
			}
		}
		switch s.typ {
		case 'f':
			fname[uint16(s.value)] = ts.Name
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	return syms, nil
}

// ErrNoSymbols is returned by File.Symbols if there is no such section
// in the File.
var ErrNoSymbols = errors.New("no symbol section")

// Symbols returns the symbol table for f.
func (f *File) Symbols() ([]Sym, error) {
	symtabSection := f.Section("syms")
	if symtabSection == nil {
		return nil, ErrNoSymbols
	}

	symtab, err := symtabSection.Data()
	if err != nil {
		return nil, errors.New("cannot load symbol section")
	}

	return newTable(symtab, f.PtrSize)
}

// Section returns a section with the given name, or nil if no such
// section exists.
func (f *File) Section(name string) *Section {
	for _, s := range f.Sections {
		if s.Name == name {
			return s
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package sim

import (
	"log"

	"my/itto/verify/packet"
	"my/itto/verify/packet/bats"
	"my/itto/verify/packet/itto"
)

type SimMessage struct {
	Pam     packet.ApplicationMessage
	Session *Session
	sim     Sim
}

func NewSimMessage(sim Sim, pam packet.ApplicationMessage) *SimMessage {
	s := sim.Session(pam.Flow())
	m := &SimMessage{
		Pam:     pam,
		Session: &s,
		sim:     sim,
	}
	return m
}

func (m *SimMessage) IgnoredBySubscriber() bool {
	if m.sim.Subscr() == nil {
		return false
	}
	var oid packet.OptionId
	if m, ok := m.Pam.Layer().(packet.TradeMessage); ok {
		oid, _, _ = m.TradeInfo()
	}
	return oid.Valid() && !m.sim.Subscr().Subscribed(oid)
}

func (m *SimMessage) MessageOperations() []SimOperation {
	var ops []SimOperation
	addOperation := func(origOrderId packet.OrderId, operation SimOperation) {
		opop := operation.getOperation()
		opop.m = m
		opop.sim = m.sim
		opop.origOrderId = origOrderId
		ops = append(ops, operation)
	}
	addOperationReplace := func(origOrderId packet.OrderId, ord order) {
		opRemove := &OperationRemove{}
		opAdd := &OperationAdd{
			// unknown: optionId; maybe unknown: OrderSide.Side
			order:     ord,
			Operation: Operation{sibling: opRemove},
		}
		addOperation(origOrderId, opRemove)
		addOperation(packet.OrderIdUnknown, opAdd)
	}
	switch im := m.Pam.Layer().(type) {
	case *itto.IttoMessageAddOrder:
		var oid packet.OptionId
		if !m.IgnoredBySubscriber() {
			oid = im.OId
		}
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: orderFromItto(oid, im.OrderSide)})
	case *itto.IttoMessageAddQuote:
		var oid packet.OptionId
		if !m.IgnoredBySubscriber() {
			oid = im.OId
		}
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: orderFromItto(oid, im.Bid)})
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: orderFromItto(oid, im.Ask)})
	case *itto.IttoMessageSingleSideExecuted:
		addOperation(im.OrigRefNumD, &OperationUpdate{sizeChange: im.Size})
	case *itto.IttoMessageSingleSideExecutedWithPrice:
		addOperation(im.OrigRefNumD, &OperationUpdate{sizeChange: im.Size})
	case *itto.IttoMessageOrderCancel:
		addOperation(im.OrigRefNumD, &OperationUpdate{sizeChange: im.Size})
	case *itto.IttoMessageSingleSideReplace:
		addOperationReplace(im.OrigRefNumD, orderFromItto(packet.OptionIdUnknown, im.OrderSide))
	case *itto.IttoMessageSingleSideDelete:
		addOperation(im.OrigRefNumD, &OperationRemove{})
	case *itto.IttoMessageSingleSideUpdate:
		addOperationReplace(im.RefNumD, orderFromItto(packet.OptionIdUnknown, im.OrderSide))
	case *itto.IttoMessageQuoteReplace:
		addOperationReplace(im.Bid.OrigRefNumD, orderFromItto(packet.OptionIdUnknown, im.Bid.OrderSide))
		addOperationReplace(im.Ask.OrigRefNumD, orderFromItto(packet.OptionIdUnknown, im.Ask.OrderSide))
	case *itto.IttoMessageQuoteDelete:
		addOperation(im.BidOrigRefNumD, &OperationRemove{})
		addOperation(im.AskOrigRefNumD, &OperationRemove{})
	case *itto.IttoMessageBlockSingleSideDelete:
		for _, r := range im.RefNumDs {
			addOperation(r, &OperationRemove{})
		}
	case *bats.PitchMessageAddOrder:
		var oid packet.OptionId
		if !m.IgnoredBySubscriber() {
			oid = im.Symbol
		}
		ord := order{
			OptionId: oid,
			OrderId:  im.OrderId,
			Side:     im.Side,
			Price:    im.Price,
			Size:     int(im.Size),
		}
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: ord})
	case *bats.PitchMessageDeleteOrder:
		addOperation(im.OrderId, &OperationRemove{})
	case *bats.PitchMessageOrderExecuted:
		addOperation(im.OrderId, &OperationUpdate{sizeChange: int(im.Size)})
	case *bats.PitchMessageOrderExecutedAtPriceSize:
		addOperation(im.OrderId, &OperationUpdate{sizeChange: int(im.Size)})
	case *bats.PitchMessageReduceSize:
		addOperation(im.OrderId, &OperationUpdate{sizeChange: int(im.Size)})
	case *bats.PitchMessageModifyOrder:
		ord := order{
			OrderId: im.OrderId,
			Price:   im.Price,
			Size:    int(im.Size),
		}
		addOperationReplace(im.OrderId, ord)
	case
		*itto.IttoMessageNoii,
		*itto.IttoMessageOptionsTrade,
		*itto.IttoMessageOptionsCrossTrade,
		*itto.IttoMessageOptionDirectory,
		*itto.IttoMessageOptionOpen,
		*itto.IttoMessageOptionTradingAction,
		*bats.PitchMessageTime,
		*bats.PitchMessageSymbolMapping:
		// silently ignore
	default:
		log.Println("unexpected message ", m.Pam.Layer())
	}
	return ops
}

func orderFromItto(oid packet.OptionId, os itto.OrderSide) order {
	return order{
		OptionId: oid,
		OrderId:  os.RefNumD,
		Side:     os.Side,
		Price:    os.Price,
		Size:     os.Size,
	}
}
<commit_msg>sim:SimMessage:trivial: change functions order<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package sim

import (
	"log"

	"my/itto/verify/packet"
	"my/itto/verify/packet/bats"
	"my/itto/verify/packet/itto"
)

type SimMessage struct {
	Pam     packet.ApplicationMessage
	Session *Session
	sim     Sim
}

func NewSimMessage(sim Sim, pam packet.ApplicationMessage) *SimMessage {
	s := sim.Session(pam.Flow())
	m := &SimMessage{
		Pam:     pam,
		Session: &s,
		sim:     sim,
	}
	return m
}

func (m *SimMessage) MessageOperations() []SimOperation {
	var ops []SimOperation
	addOperation := func(origOrderId packet.OrderId, operation SimOperation) {
		opop := operation.getOperation()
		opop.m = m
		opop.sim = m.sim
		opop.origOrderId = origOrderId
		ops = append(ops, operation)
	}
	addOperationReplace := func(origOrderId packet.OrderId, ord order) {
		opRemove := &OperationRemove{}
		opAdd := &OperationAdd{
			// unknown: optionId; maybe unknown: OrderSide.Side
			order:     ord,
			Operation: Operation{sibling: opRemove},
		}
		addOperation(origOrderId, opRemove)
		addOperation(packet.OrderIdUnknown, opAdd)
	}
	switch im := m.Pam.Layer().(type) {
	case *itto.IttoMessageAddOrder:
		var oid packet.OptionId
		if !m.IgnoredBySubscriber() {
			oid = im.OId
		}
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: orderFromItto(oid, im.OrderSide)})
	case *itto.IttoMessageAddQuote:
		var oid packet.OptionId
		if !m.IgnoredBySubscriber() {
			oid = im.OId
		}
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: orderFromItto(oid, im.Bid)})
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: orderFromItto(oid, im.Ask)})
	case *itto.IttoMessageSingleSideExecuted:
		addOperation(im.OrigRefNumD, &OperationUpdate{sizeChange: im.Size})
	case *itto.IttoMessageSingleSideExecutedWithPrice:
		addOperation(im.OrigRefNumD, &OperationUpdate{sizeChange: im.Size})
	case *itto.IttoMessageOrderCancel:
		addOperation(im.OrigRefNumD, &OperationUpdate{sizeChange: im.Size})
	case *itto.IttoMessageSingleSideReplace:
		addOperationReplace(im.OrigRefNumD, orderFromItto(packet.OptionIdUnknown, im.OrderSide))
	case *itto.IttoMessageSingleSideDelete:
		addOperation(im.OrigRefNumD, &OperationRemove{})
	case *itto.IttoMessageSingleSideUpdate:
		addOperationReplace(im.RefNumD, orderFromItto(packet.OptionIdUnknown, im.OrderSide))
	case *itto.IttoMessageQuoteReplace:
		addOperationReplace(im.Bid.OrigRefNumD, orderFromItto(packet.OptionIdUnknown, im.Bid.OrderSide))
		addOperationReplace(im.Ask.OrigRefNumD, orderFromItto(packet.OptionIdUnknown, im.Ask.OrderSide))
	case *itto.IttoMessageQuoteDelete:
		addOperation(im.BidOrigRefNumD, &OperationRemove{})
		addOperation(im.AskOrigRefNumD, &OperationRemove{})
	case *itto.IttoMessageBlockSingleSideDelete:
		for _, r := range im.RefNumDs {
			addOperation(r, &OperationRemove{})
		}
	case *bats.PitchMessageAddOrder:
		var oid packet.OptionId
		if !m.IgnoredBySubscriber() {
			oid = im.Symbol
		}
		ord := order{
			OptionId: oid,
			OrderId:  im.OrderId,
			Side:     im.Side,
			Price:    im.Price,
			Size:     int(im.Size),
		}
		addOperation(packet.OrderIdUnknown, &OperationAdd{order: ord})
	case *bats.PitchMessageDeleteOrder:
		addOperation(im.OrderId, &OperationRemove{})
	case *bats.PitchMessageOrderExecuted:
		addOperation(im.OrderId, &OperationUpdate{sizeChange: int(im.Size)})
	case *bats.PitchMessageOrderExecutedAtPriceSize:
		addOperation(im.OrderId, &OperationUpdate{sizeChange: int(im.Size)})
	case *bats.PitchMessageReduceSize:
		addOperation(im.OrderId, &OperationUpdate{sizeChange: int(im.Size)})
	case *bats.PitchMessageModifyOrder:
		ord := order{
			OrderId: im.OrderId,
			Price:   im.Price,
			Size:    int(im.Size),
		}
		addOperationReplace(im.OrderId, ord)
	case
		*itto.IttoMessageNoii,
		*itto.IttoMessageOptionsTrade,
		*itto.IttoMessageOptionsCrossTrade,
		*itto.IttoMessageOptionDirectory,
		*itto.IttoMessageOptionOpen,
		*itto.IttoMessageOptionTradingAction,
		*bats.PitchMessageTime,
		*bats.PitchMessageSymbolMapping:
		// silently ignore
	default:
		log.Println("unexpected message ", m.Pam.Layer())
	}
	return ops
}
func (m *SimMessage) IgnoredBySubscriber() bool {
	if m.sim.Subscr() == nil {
		return false
	}
	var oid packet.OptionId
	if m, ok := m.Pam.Layer().(packet.TradeMessage); ok {
		oid, _, _ = m.TradeInfo()
	}
	return oid.Valid() && !m.sim.Subscr().Subscribed(oid)
}

func orderFromItto(oid packet.OptionId, os itto.OrderSide) order {
	return order{
		OptionId: oid,
		OrderId:  os.RefNumD,
		Side:     os.Side,
		Price:    os.Price,
		Size:     os.Size,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/miekg/dns"
	. "launchpad.net/gocheck"
	"strings"
	"time"
)

func (s *ConfigSuite) TestServing(c *C) {

	Zones := make(Zones)
	setupPgeodnsZone(Zones)
	go configReader("dns", Zones)
	go listenAndServe(":8853", &Zones)

	time.Sleep(100 * time.Millisecond)

	r := exchange(c, "_status.pgeodns.", dns.TypeTXT)
	txt := r.Answer[0].(*dns.RR_TXT).Txt[0]
	if !strings.HasPrefix(txt, "{") {
		c.Log("Unexpected result for _status.pgeodns", txt)
		c.Fail()
	}

	r = exchange(c, "bar.example.com.", dns.TypeA)
	ip := r.Answer[0].(*dns.RR_A).A
	if ip.String() != "192.168.1.2" {
		c.Log("Unexpected result for bar.example.com", ip, "!= 192.168.1.2")
		c.Fail()
	}

	r = exchange(c, "example.com.", dns.TypeSOA)
	soa := r.Answer[0].(*dns.RR_SOA)
	serial := soa.Serial
	if serial != 3 {
		c.Log("Didn't get SOA record with serial=3 for bar.example.com/AAAA")
		c.Fail()
	}
}

func exchange(c *C, name string, dnstype uint16) *dns.Msg {
	msg := new(dns.Msg)
	cli := new(dns.Client)

	msg.SetQuestion(name, dnstype)
	r, err := cli.Exchange(msg, "127.0.0.1:8853")
	if err != nil {
		c.Log("err", err)
		c.Fail()
	}
	return r
}
<commit_msg>Use gocheck methods to have less test code<commit_after>package main

import (
	"github.com/miekg/dns"
	. "launchpad.net/gocheck"
	"strings"
	"time"
)

func (s *ConfigSuite) TestServing(c *C) {

	Zones := make(Zones)
	setupPgeodnsZone(Zones)
	go configReader("dns", Zones)
	go listenAndServe(":8853", &Zones)

	time.Sleep(100 * time.Millisecond)

	r := exchange(c, "_status.pgeodns.", dns.TypeTXT)
	txt := r.Answer[0].(*dns.RR_TXT).Txt[0]
	if !strings.HasPrefix(txt, "{") {
		c.Log("Unexpected result for _status.pgeodns", txt)
		c.Fail()
	}

	r = exchange(c, "bar.example.com.", dns.TypeA)
	ip := r.Answer[0].(*dns.RR_A).A
	c.Check(ip.String(), Equals, "192.168.1.2")

	r = exchange(c, "example.com.", dns.TypeSOA)
	soa := r.Answer[0].(*dns.RR_SOA)
	serial := soa.Serial
	c.Check(int(serial), Equals, 3)

}

func exchange(c *C, name string, dnstype uint16) *dns.Msg {
	msg := new(dns.Msg)
	cli := new(dns.Client)

	msg.SetQuestion(name, dnstype)
	r, err := cli.Exchange(msg, "127.0.0.1:8853")
	if err != nil {
		c.Log("err", err)
		c.Fail()
	}
	return r
}
<|endoftext|>


<commit_before>package binding

import "testing"

func TestBind(t *testing.T) {
	for _, testCase := range formTestCases {
		performFormTest(t, Bind, testCase)
	}
	for _, testCase := range jsonTestCases {
		performJsonTest(t, Bind, testCase)
	}
	for _, testCase := range multipartFormTestCases {
		performMultipartFormTest(t, Bind, testCase)
	}
}
<commit_msg>Bind tests now perform file tests too<commit_after>package binding

import "testing"

func TestBind(t *testing.T) {
	for _, testCase := range formTestCases {
		performFormTest(t, Bind, testCase)
	}
	for _, testCase := range jsonTestCases {
		performJsonTest(t, Bind, testCase)
	}
	for _, testCase := range multipartFormTestCases {
		performMultipartFormTest(t, Bind, testCase)
	}
	for _, testCase := range fileTestCases {
		performFileTest(t, Bind, testCase)
	}
}
<|endoftext|>


<commit_before>// © 2014 Steve McCoy under the MIT license. See LICENSE for details.

package pngplus

import (
	"bytes"
	"encoding/binary"
	"hash/crc32"
	"testing"
)

func TestEncodeBinary(t *testing.T) {
	var w bytes.Buffer
	s := []byte("hello")

	err := EncodeBinary(&w, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	bs := w.Bytes()
	if len(bs) != 4*3 + len(s) {
		t.Fatalf("wrong length for output: %x", bs)
	}

	var n uint32
	err = binary.Read(bytes.NewBuffer(bs), binary.BigEndian, &n)
	if err != nil {
		t.Fatalf("unexpected length read error: %v", err)
	}

	if n != uint32(len(s)) {
		t.Fatalf("wrong chunk length: %d vs. %d", n, len(s))
	}

	g := bs[4:8]
	if bytes.Compare(g, []byte("biNy")) != 0 {
		t.Fatalf("wrong chunk type: %q", g)
	}

	g = bs[8:8+len(s)]
	if bytes.Compare(g, s) != 0 {
		t.Fatalf("wrong chunk content: %q vs. %q", g, s)
	}

	var crc uint32
	err = binary.Read(bytes.NewBuffer(bs[8+len(s):]), binary.BigEndian, &crc)
	if err != nil {
		t.Fatalf("unexpected crc read error: %v", err)
	}

	if crc != crc32.ChecksumIEEE([]byte("iTXthello")) {
		t.Fatalf("wrong crc: %d vs. %d", crc, 666)
	}
}<commit_msg>Simplify biNy test<commit_after>// © 2014 Steve McCoy under the MIT license. See LICENSE for details.

package pngplus

import (
	"bytes"
	"encoding/binary"
	"hash/crc32"
	"testing"
)

func TestEncodeBinary(t *testing.T) {
	var w bytes.Buffer
	s := []byte("hello")

	err := EncodeBinary(&w, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	bs := w.Bytes()

	var n uint32
	err = binary.Read(bytes.NewBuffer(bs), binary.BigEndian, &n)
	if err != nil {
		t.Fatalf("unexpected length read error: %v", err)
	}

	if n != uint32(len(s)) {
		t.Fatalf("wrong chunk length: %d vs. %d", n, len(s))
	}

	content := string(bs[4:len(bs)-4])
	expected := "biNyhello"
	if content != expected {
		t.Fatalf("wrong content: %q vs. %q", content, expected)
	}

	var crc uint32
	err = binary.Read(bytes.NewBuffer(bs[8+len(s):]), binary.BigEndian, &crc)
	if err != nil {
		t.Fatalf("unexpected crc read error: %v", err)
	}

	excrc := crc32.ChecksumIEEE([]byte(expected))
	if crc != excrc {
		t.Fatalf("wrong crc: %d vs. %d", crc, excrc)
	}
}
<|endoftext|>


<commit_before>/**
 * bogosort - Given a scrambled string N and another string M. You must
 * sort N so that it matches M. After it has been sorted, it must output
 * how many iterations it took to complete the sorting.
 *
 * For a bit of fun, the LEAST efficient algorithm wins. Check out the bogo-bogo sort,
 * an algorithm that's designed not to succeed before the heat death of the universe
 * http://www.dangermouse.net/esoteric/bogobogosort.html[2]
 *
 *
 */
package main

import (
		"fmt"
		"strings"
		"math/rand"
		"log"
		"time"
		"os"
)

func main () {
		rand.Seed(time.Now().UTC().UnixNano())

		if len(os.Args) != 3 {
			log.Fatal("Usage: bogo helol hello")
		}

		firstWord := os.Args[1]
		secondWord := os.Args[2]

		bogoSortAndReturnIterations(firstWord, secondWord)
}

func bogoSortAndReturnIterations(scrambled string, unscrambled string) int {
		letters := strings.Split(scrambled, "")

		var iterations int

		for {
			shuffledStringSlice := ShuffleStringSlice(letters)
			word 				:= strings.Join(shuffledStringSlice, "")

			iterations++

			// Compare word to original input
			if word == unscrambled {
				log.Print(fmt.Sprintf("Shuffled word with %d iterations.", iterations))

				break
			} else {
				log.Print(fmt.Sprintf("Iteration #%d: %s", iterations, word))
			}
		}

		return iterations
}

func ShuffleStringSlice (input []string) []string {
	for i := range input {
		j := rand.Intn(i + 1)
		input[i], input[j] = input[j], input[i]
	}

	return input
}

<commit_msg>Fixes formatting<commit_after>/**
 * bogosort - Given a scrambled string N and another string M. You must
 * sort N so that it matches M. After it has been sorted, it must output
 * how many iterations it took to complete the sorting.
 *
 * For a bit of fun, the LEAST efficient algorithm wins. Check out the bogo-bogo sort,
 * an algorithm that's designed not to succeed before the heat death of the universe
 * http://www.dangermouse.net/esoteric/bogobogosort.html[2]
 *
 *
 */
package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"
)

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	if len(os.Args) != 3 {
		log.Fatal("Usage: bogo helol hello")
	}

	firstWord := os.Args[1]
	secondWord := os.Args[2]

	bogoSortAndReturnIterations(firstWord, secondWord)
}

func bogoSortAndReturnIterations(scrambled string, unscrambled string) int {
	letters := strings.Split(scrambled, "")

	var iterations int

	for {
		shuffledStringSlice := ShuffleStringSlice(letters)
		word := strings.Join(shuffledStringSlice, "")

		iterations++

		// Compare word to original input
		if word == unscrambled {
			log.Print(fmt.Sprintf("Shuffled word with %d iterations.", iterations))

			break
		} else {
			log.Print(fmt.Sprintf("Iteration #%d: %s", iterations, word))
		}
	}

	return iterations
}

func ShuffleStringSlice(input []string) []string {
	for i := range input {
		j := rand.Intn(i + 1)
		input[i], input[j] = input[j], input[i]
	}

	return input
}
<|endoftext|>


<commit_before>// Package replicat is a server for n way synchronization of content (rsync for the cloud).
// More information at: http://replic.at
// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/goji/httpauth"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"os"
	"sync"
	"time"
)

// ReplicatServer is a structure that contains the definition of the servers in a cluster. Each node has a name and this
// node (as determined by globalSettings.name at the moment) also has a StorageTracker interface.
type ReplicatServer struct {
	ClusterKey    string
	Name          string
	Address       string
	Status        string
	CurrentState  DirTreeMap
	PreviousState DirTreeMap
	Lock          sync.Mutex
	storage       StorageTracker
}

// GetStatus - get the current status of the server
func (server *ReplicatServer) GetStatus() string {
	return server.Status
}

// SetStatus - set the current status of the server
func (server *ReplicatServer) SetStatus(status string) {
	// adding an inline check to make sure the server is valid
	// if the server is being shut down or at the end of a unit test)
	// the assignment can crash without this check
	if server != nil {
		server.Status = status
		sendConfigToServer()
	}
}

const (
	// REPLICAT_STATUS_INITIAL_SCAN - The server is scanning its local storage
	REPLICAT_STATUS_INITIAL_SCAN = "Initial Scan"
	// REPLICAT_STATUS_JOINING_CLUSTER - The server has started to join the cluster and get up to date
	REPLICAT_STATUS_JOINING_CLUSTER = "Joining Cluster"
	// REPLICAT_STATUS_ONLINE - The server is up to date and part of the cluster
	REPLICAT_STATUS_ONLINE = "Online"
)

var serverMap = make(map[string]*ReplicatServer)
var serverMapLock sync.RWMutex

var lastConfigPing = time.Now()

// BootstrapAndServe - Start the server
func BootstrapAndServe(address string) {
	//trackerTestDual()
	//trackerTestSmallFileInSubfolder()
	//trackerTestEmptyDirectoryMovesInOutAround()
	//trackerTestFileChangeTrackerAddFolders()
	//trackerTestSmallFileCreationAndRename()
	//trackerTestSmallFileCreationAndUpdate()
	//trackerTestSmallFileMovesInOutAround()
	//trackerTestDirectoryCreation()
	//trackerTestNestedDirectoryCreation()
	//trackerTestDirectoryStorage()
	//trackerTestFileChangeTrackerAutoCreateFolderAndCleanup()
	//trackerTestNestedFastDirectoryCreation()

	// testing code to enable debugger use
	http.Handle("/event/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(eventHandler)))
	http.Handle("/tree/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(folderTreeHandler)))
	http.Handle("/config/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(configHandler)))
	http.Handle("/upload/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(uploadHandler)))

	lsnr, err := net.Listen("tcp4", address)
	if err != nil {
		panic(fmt.Sprintf("Error listening: %v\nAddress: %s\n", err, address))
	}
	fmt.Println("Listening on:", lsnr.Addr().String())

	logOnlyHandler := LogOnlyChangeHandler{}
	tracker := FilesystemTracker{}
	fmt.Printf("Looking up settings for node: %s\n", globalSettings.Name)

	directory := globalSettings.Directory

	fmt.Printf("GlobalSettings directory retrieved for this node: %s\n", directory)
	server := &ReplicatServer{Name: globalSettings.Name, ClusterKey: globalSettings.ClusterKey, Address: lsnr.Addr().String(), storage: &tracker, Status: REPLICAT_STATUS_INITIAL_SCAN}
	serverMap[globalSettings.Name] = server
	tracker.init(directory, server)

	go func(tracker StorageTracker) {
		for true {
			tracker.GetStatistics()
			time.Sleep(30 * time.Second)
		}
	}(&tracker)

	var c ChangeHandler
	c = &logOnlyHandler
	tracker.watchDirectory(&c)

	go func(listener net.Listener) {
		err = http.Serve(listener, nil)
		if err != nil {
			panic(err)
		}
	}(lsnr)

	fmt.Println("Starting config update processor")
	go configUpdateProcessor(configUpdateChannel)
	go keepConfigCurrent()

	if globalSettings.ManagerAddress != "" {
		fmt.Printf("about to send config to server (%s)\nOur address is: (%s)", globalSettings.ManagerAddress, lsnr.Addr())
	}
}

const (
	managerOverdueSeconds = 30
	managerCheckSleepTime = 45
)

func keepConfigCurrent() {
	for {
		if time.Since(lastConfigPing) > managerOverdueSeconds*time.Second {
			log.Printf("Manager Contact Overdue, attempting to contact: %s\n", globalSettings.ManagerAddress)
			sendConfigToServer()
		} else {
			fmt.Println("No Update Required")
		}
		time.Sleep(time.Duration(rand.Intn(10)-5+managerCheckSleepTime) * time.Second)
	}
}

func sendConfigToServer() {
	// This field will be empty during testing
	if globalSettings.ManagerAddress == "" {
		return
	}

	url := "http://" + globalSettings.ManagerAddress + "/config/"
	fmt.Printf("Manager location: %s\n", url)

	jsonStr, _ := json.Marshal(serverMap[globalSettings.Name])
	fmt.Printf("jsonStr: %s\n", jsonStr)

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

	data := []byte(globalSettings.ManagerCredentials)
	authHash := base64.StdEncoding.EncodeToString(data)
	req.Header.Add("Authorization", "Basic "+authHash)

	client := &http.Client{}
	_, err = client.Do(req)
	if err != nil {
		log.Fatalf("Alert, going down in flames: %s\n", err)
		panic(err)
	}
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseMultipartForm(32 << 20)
		file, handler, err := r.FormFile("uploadfile")
		if err != nil {
			fmt.Println(err)
			return
		}
		defer file.Close()
		fmt.Fprint(w, handler.Header)

		hash := []byte(r.Form.Get("HASH"))

		storage := serverMap[globalSettings.Name].storage
		local, _ := storage.getEntryJSON(handler.Filename)

		if !bytes.Equal(hash, local.Hash) {
			fullPath := globalSettings.Directory + "/" + handler.Filename
			f, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0666)

			if err != nil {
				fmt.Println(err)
				return
			}

			bytesWritten, err := io.Copy(f, file)
			if err != nil {
				log.Printf("Error copying file: %s, error(%#v)\n", handler.Filename, err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("500 - Error copying file"))
				f.Close()
				return
			}
			fmt.Printf("Wrote out (%s) bytes (%d)\n", handler.Filename, bytesWritten)
			f.Close()

			// Get the old entry
			entryString := r.Form.Get("entryJSON")
			if entryString != "" {
				var entry EntryJSON
				err := json.Unmarshal([]byte(entryString), &entry)
				if err != nil {
					log.Fatalf("Error copying file (Entry handling): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}

				err = os.Chtimes(fullPath, time.Now(), entry.ModTime)
				if err != nil {
					log.Fatalf("Error copying file (Changing times): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}
			}

		}
	}
}

var configUpdateChannel = make(chan *map[string]*ReplicatServer, 100)

func configHandler(_ http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "POST":
		lastConfigPing = time.Now()
		fmt.Println("configHandler: 3")
		decoder := json.NewDecoder(r.Body)
		fmt.Println("configHandler: 4")
		var newServerMap map[string]*ReplicatServer
		err := decoder.Decode(&newServerMap)
		fmt.Println("configHandler: 5")
		if err != nil {
			fmt.Println(err)
		}

		fmt.Println("configHandler: 6")
		configUpdateChannel <- &newServerMap
		fmt.Println("configHandler: 8")
	}
}

func configUpdateProcessor(c chan *map[string]*ReplicatServer) {
	for {
		newServerMap := <-c
		serverMapLock.Lock()

		sendData := false

		// find any nodes that have been deleted
		for name, serverData := range serverMap {
			newServerData, exists := (*newServerMap)[name]
			if !exists {
				fmt.Printf("No longer found config for: %s deleting\n", name)
				delete(serverMap, name)
				continue
			}

			if serverData.Address != newServerData.Address || serverData.Name != newServerData.Name || serverData.ClusterKey != newServerData.ClusterKey || serverData.Status != serverData.Status {
				fmt.Printf("Server data is changed. Replacing.\nold: %v\nnew: %v\n", &serverData, &newServerData)
				if serverData.Status != REPLICAT_STATUS_JOINING_CLUSTER && newServerData.Status == REPLICAT_STATUS_JOINING_CLUSTER {
					fmt.Printf("Decided to send data to: %s\n", serverData.Name)
					sendData = true
				}
				serverMap[name] = newServerData
				fmt.Println("Server data replaced with new server data")
			}
		}

		// find any new nodes
		for name, newServerData := range *newServerMap {
			_, exists := serverMap[name]
			if !exists {
				fmt.Printf("New server configuration for %s: %v\n", name, newServerData)

				// If this server map is for ourselves, build a list of folder if needed and notify others
				if name == globalSettings.Name {
					listOfFileInfo, err := scanDirectoryContents()
					if err != nil {
						log.Fatal(err)
					}
					newServerData.CurrentState = listOfFileInfo
					// Tell all of our friends that we exist and our current state for them to compare against.
					go func(tree DirTreeMap) {
						sendFolderTree(tree)
					}(listOfFileInfo)
				} else {
					fmt.Printf("New Node Decided to send data to: %s\n", name)
					sendData = true
				}

				fmt.Printf("New server configuration provided. Copying: %s\n", name)
				serverMap[name] = newServerData
			}
		}

		if sendData {
			server := serverMap[globalSettings.Name]
			fmt.Println("about to send existing files")
			server.storage.SendCatalog()
			fmt.Println("done sending existing files")
		}

		serverMapLock.Unlock()
	}
}
<commit_msg>clean up cluster config processing. Add support for config to be returned by call to server. This allows replicat to communicate through a firewall to webcat<commit_after>// Package replicat is a server for n way synchronization of content (rsync for the cloud).
// More information at: http://replic.at
// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/goji/httpauth"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"os"
	"sync"
	"time"
)

// ReplicatServer is a structure that contains the definition of the servers in a cluster. Each node has a name and this
// node (as determined by globalSettings.name at the moment) also has a StorageTracker interface.
type ReplicatServer struct {
	ClusterKey    string
	Name          string
	Address       string
	Status        string
	CurrentState  DirTreeMap
	PreviousState DirTreeMap
	Lock          sync.Mutex
	storage       StorageTracker
}

// GetStatus - get the current status of the server
func (server *ReplicatServer) GetStatus() string {
	return server.Status
}

// SetStatus - set the current status of the server
func (server *ReplicatServer) SetStatus(status string) {
	// adding an inline check to make sure the server is valid
	// if the server is being shut down or at the end of a unit test)
	// the assignment can crash without this check
	if server != nil {
		server.Status = status
		sendConfigToServer()
	}
}

const (
	// REPLICAT_STATUS_INITIAL_SCAN - The server is scanning its local storage
	REPLICAT_STATUS_INITIAL_SCAN = "Initial Scan"
	// REPLICAT_STATUS_JOINING_CLUSTER - The server has started to join the cluster and get up to date
	REPLICAT_STATUS_JOINING_CLUSTER = "Joining Cluster"
	// REPLICAT_STATUS_ONLINE - The server is up to date and part of the cluster
	REPLICAT_STATUS_ONLINE = "Online"
)

var serverMap = make(map[string]*ReplicatServer)
var serverMapLock sync.RWMutex

var lastConfigPing = time.Now()

// BootstrapAndServe - Start the server
func BootstrapAndServe(address string) {
	//trackerTestDual()
	//trackerTestSmallFileInSubfolder()
	//trackerTestEmptyDirectoryMovesInOutAround()
	//trackerTestFileChangeTrackerAddFolders()
	//trackerTestSmallFileCreationAndRename()
	//trackerTestSmallFileCreationAndUpdate()
	//trackerTestSmallFileMovesInOutAround()
	//trackerTestDirectoryCreation()
	//trackerTestNestedDirectoryCreation()
	//trackerTestDirectoryStorage()
	//trackerTestFileChangeTrackerAutoCreateFolderAndCleanup()
	//trackerTestNestedFastDirectoryCreation()

	// testing code to enable debugger use
	http.Handle("/event/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(eventHandler)))
	http.Handle("/tree/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(folderTreeHandler)))
	http.Handle("/config/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(configHandler)))
	http.Handle("/upload/", httpauth.SimpleBasicAuth("replicat", "isthecat")(http.HandlerFunc(uploadHandler)))

	lsnr, err := net.Listen("tcp4", address)
	if err != nil {
		panic(fmt.Sprintf("Error listening: %v\nAddress: %s\n", err, address))
	}
	fmt.Println("Listening on:", lsnr.Addr().String())

	logOnlyHandler := LogOnlyChangeHandler{}
	tracker := FilesystemTracker{}
	fmt.Printf("Looking up settings for node: %s\n", globalSettings.Name)

	directory := globalSettings.Directory

	fmt.Printf("GlobalSettings directory retrieved for this node: %s\n", directory)
	server := &ReplicatServer{Name: globalSettings.Name, ClusterKey: globalSettings.ClusterKey, Address: lsnr.Addr().String(), storage: &tracker, Status: REPLICAT_STATUS_INITIAL_SCAN}
	serverMap[globalSettings.Name] = server
	tracker.init(directory, server)

	go func(tracker StorageTracker) {
		for true {
			tracker.GetStatistics()
			time.Sleep(30 * time.Second)
		}
	}(&tracker)

	var c ChangeHandler
	c = &logOnlyHandler
	tracker.watchDirectory(&c)

	go func(listener net.Listener) {
		err = http.Serve(listener, nil)
		if err != nil {
			panic(err)
		}
	}(lsnr)

	fmt.Println("Starting config update processor")
	go configUpdateProcessor(configUpdateChannel)

	if globalSettings.ManagerAddress != "" {
		fmt.Printf("about to send config to server (%s)\nOur address is: (%s)\n", globalSettings.ManagerAddress, lsnr.Addr())
	}

	// we need something to keep us running.
	keepConfigCurrent()
}

const (
	managerOverdueSeconds = 30
	managerCheckSleepTime = 45
)

func keepConfigCurrent() {
	for {
		if time.Since(lastConfigPing) > managerOverdueSeconds*time.Second {
			log.Printf("Manager Contact Overdue, attempting to contact: %s\n", globalSettings.ManagerAddress)
			sendConfigToServer()
		} else {
			fmt.Println("No Update Required")
		}
		time.Sleep(time.Duration(rand.Intn(10)-5+managerCheckSleepTime) * time.Second)
	}
}

func sendConfigToServer() {
	// This field will be empty during testing
	if globalSettings.ManagerAddress == "" {
		return
	}

	url := "http://" + globalSettings.ManagerAddress + "/config/"
	fmt.Printf("Manager location: %s\n", url)

	jsonStr, _ := json.Marshal(serverMap[globalSettings.Name])
	fmt.Printf("jsonStr: %s\n", jsonStr)

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

	data := []byte(globalSettings.ManagerCredentials)
	authHash := base64.StdEncoding.EncodeToString(data)
	req.Header.Add("Authorization", "Basic "+authHash)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("Unable to reach server. Data could be lost: %s\n", err)
	}

	newServerMap, err := extractServerMapFromConfig(resp.Body)
	if err != nil {
		fmt.Printf("Config update failed due to error: %s\n", err)
		return
	}
	configUpdateChannel <- newServerMap

}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseMultipartForm(32 << 20)
		file, handler, err := r.FormFile("uploadfile")
		if err != nil {
			fmt.Println(err)
			return
		}
		defer file.Close()
		fmt.Fprint(w, handler.Header)

		hash := []byte(r.Form.Get("HASH"))

		storage := serverMap[globalSettings.Name].storage
		local, _ := storage.getEntryJSON(handler.Filename)

		if !bytes.Equal(hash, local.Hash) {
			fullPath := globalSettings.Directory + "/" + handler.Filename
			f, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0666)

			if err != nil {
				fmt.Println(err)
				return
			}

			bytesWritten, err := io.Copy(f, file)
			if err != nil {
				log.Printf("Error copying file: %s, error(%#v)\n", handler.Filename, err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("500 - Error copying file"))
				f.Close()
				return
			}
			fmt.Printf("Wrote out (%s) bytes (%d)\n", handler.Filename, bytesWritten)
			f.Close()

			// Get the old entry
			entryString := r.Form.Get("entryJSON")
			if entryString != "" {
				var entry EntryJSON
				err := json.Unmarshal([]byte(entryString), &entry)
				if err != nil {
					log.Fatalf("Error copying file (Entry handling): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}

				err = os.Chtimes(fullPath, time.Now(), entry.ModTime)
				if err != nil {
					log.Fatalf("Error copying file (Changing times): %s, error(%#v)\n", handler.Filename, err)
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte("500 - Error copying file"))
					return
				}
			}

		}
	}
}

var configUpdateChannel = make(chan *map[string]*ReplicatServer, 100)

func configHandler(_ http.ResponseWriter, r *http.Request) {
	newServerMap, err := extractServerMapFromConfig(r.Body)
	if err != nil {
		fmt.Printf("Config update failed due to error: %s\n", err)
		return
	}
	configUpdateChannel <- newServerMap
}

func extractServerMapFromConfig(sourceReader io.Reader) (newServerMap *map[string]*ReplicatServer, err error) {
	decoder := json.NewDecoder(sourceReader)
	err = decoder.Decode(&newServerMap)
	return
}

func configUpdateProcessor(c chan *map[string]*ReplicatServer) {
	for {
		newServerMap := <-c
		serverMapLock.Lock()

		lastConfigPing = time.Now()
		sendData := false

		// find any nodes that have been deleted and update ones that have changed
		for name, serverData := range serverMap {
			newServerData, exists := (*newServerMap)[name]
			if !exists {
				fmt.Printf("No longer found config for: %s deleting\n", name)
				delete(serverMap, name)
				continue
			}

			if serverData.Address != newServerData.Address || serverData.Name != newServerData.Name || serverData.ClusterKey != newServerData.ClusterKey || serverData.Status != serverData.Status {
				fmt.Printf("Server data is changed. Replacing.\nold: %v\nnew: %v\n", &serverData, &newServerData)
				if serverData.Status != REPLICAT_STATUS_JOINING_CLUSTER && newServerData.Status == REPLICAT_STATUS_JOINING_CLUSTER {
					fmt.Printf("Decided to send data to: %s\n", serverData.Name)
					sendData = true
				}
				serverMap[name] = newServerData
				fmt.Println("Server data replaced with new server data")
			}
		}

		// find any new nodes
		for name, newServerData := range *newServerMap {
			_, exists := serverMap[name]
			if !exists {
				fmt.Printf("New server configuration for %s: %v\n", name, newServerData)

				// If this server map is for ourselves, build a list of folder if needed and notify others
				if name == globalSettings.Name {
					listOfFileInfo, err := scanDirectoryContents()
					if err != nil {
						log.Fatal(err)
					}
					newServerData.CurrentState = listOfFileInfo
					// Tell all of our friends that we exist and our current state for them to compare against.
					go func(tree DirTreeMap) {
						sendFolderTree(tree)
					}(listOfFileInfo)
				} else {
					fmt.Printf("New Node Decided to send data to: %s\n", name)
					sendData = true
				}

				fmt.Printf("New server configuration provided. Copying: %s\n", name)
				serverMap[name] = newServerData
			}
		}

		if sendData {
			server := serverMap[globalSettings.Name]
			fmt.Println("about to send existing files")
			server.storage.SendCatalog()
			fmt.Println("done sending existing files")
		}

		serverMapLock.Unlock()
	}
}
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"github.com/itsankoff/gotcha/common"
	"log"
	"net/http"
	"strconv"
	"time"
)

type WebSocketServer struct {
	upgrader     websocket.Upgrader
	connections  map[*common.User]*websocket.Conn
	connected    chan<- *common.User
	disconnected chan<- *common.User
}

func NewWebSocket() WebSocketServer {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin:     func(r *http.Request) bool { return true },
	}

	return WebSocketServer{
		upgrader:    upgrader,
		connections: make(map[*common.User]*websocket.Conn),
	}
}

func (wss *WebSocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("New http connection. Try to upgrade to WebSocket")
	conn, err := wss.upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Failed to upgrade to WebSocket", err)
		fmt.Fprintf(w, "failed")
	}

	wss.addConnection(conn)
}

func (wss *WebSocketServer) addConnection(conn *websocket.Conn) {
	now := time.Now().Unix()
	id := strconv.FormatInt(now, 10)
	user := common.NewUser(id)

	wss.connections[user] = conn
	go wss.inputHandler(user, conn)
	go wss.outputHandler(user, conn)
	go wss.closeHandler(user, conn)

	wss.connected <- user
	log.Println("Add connections", user.Id)
}

func (wss *WebSocketServer) removeConnection(conn *websocket.Conn) {
	for user, c := range wss.connections {
		if c == conn {
			if wss.disconnected != nil {
				wss.disconnected <- user
			}

			close(user.In)
			close(user.Out)
			conn.Close()
			delete(wss.connections, user)

			log.Println("Remove connection", user.Id)
			break
		}
	}
}

func (wss *WebSocketServer) inputHandler(user *common.User, conn *websocket.Conn) {
	log.Println("Start websocket input handler for", user.Id)
	for {
		msgType, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println("Connection read error", err.Error())
			wss.removeConnection(conn)
			return
		}

		message, err := wss.decodeMessage(user, msg, msgType)
		log.Println("Message from ws", user.Id)
		if err != nil {
			log.Println("Failed to decode message", msgType, msg)
			wss.removeConnection(conn)
			return
		}

		user.In <- message
	}
}

func (wss *WebSocketServer) outputHandler(user *common.User, conn *websocket.Conn) {
	log.Println("Start websocket output handler for", user.Id)
	for {
		select {
		case msg := <-user.Out:
			if msg == nil {
				log.Printf("Nil message in output channel for %s. Stop output handler", user.Id)
				return
			}

			log.Println("Message in output channel for", user.Id)
			message, msgType := wss.encodeMessage(user, msg)
			if err := conn.WriteMessage(msgType, message); err != nil {
				log.Println("Connection write error", err.Error())
				wss.removeConnection(conn)
				return
			}
		}
	}
}

func (wss *WebSocketServer) closeHandler(user *common.User, conn *websocket.Conn) {
	log.Println("Start close handler for", user.Id)
	select {
	case <-user.Done:
		log.Println("Done channel closed for user", user.Id)
		wss.removeConnection(conn)
	}
}

func (wss *WebSocketServer) Start(host string, done <-chan interface{}) {
	subPath := "/websocket"
	http.Handle(subPath, wss)
	defer func() {
		http.Handle(subPath, nil)
	}()

	log.Println("Listen on:", host+subPath)
	log.Fatal(http.ListenAndServe(host, nil))
}

func (wss *WebSocketServer) OnUserConnected(handler chan<- *common.User) {
	wss.connected = handler
}

func (wss *WebSocketServer) OnUserDisconnected(handler chan<- *common.User) {
	wss.disconnected = handler
}

func (wss WebSocketServer) encodeMessage(u *common.User,
	msg *common.Message) ([]byte, int) {
	json, err := msg.Json()
	if err != nil {
		log.Println("Failed to encode message", err)
		return []byte{}, 0
	}

	return json, int(msg.DataType())
}

func (wss WebSocketServer) decodeMessage(u *common.User,
	data []byte,
	dataType int) (*common.Message, error) {
	var packet map[string]interface{}
	err := json.Unmarshal(data, &packet)
	if err != nil {
		return nil, err
	}

	expire_period, exists := packet["expire_period"]
	var expire_date time.Time
	if exists {
		expire_date = time.Now().Add(time.Duration(expire_period.(float64)) * time.Second)
	}

	messageFrom := packet["from"].(string)
	messageTo := packet["to"].(string)
	messageCmdType := packet["cmd_type"].(string)
	messageCmd := packet["cmd"].(string)
	messageDataType := common.DataType(packet["data_type"].(float64))

	message := common.NewMessage(messageFrom, messageTo,
		messageCmdType, messageCmd,
		expire_date,
		messageDataType, packet["data"])
	return &message, nil
}
<commit_msg>Add more detailed logging in wss<commit_after>package server

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"github.com/itsankoff/gotcha/common"
	"log"
	"net/http"
	"strconv"
	"time"
)

type WebSocketServer struct {
	upgrader     websocket.Upgrader
	connections  map[*common.User]*websocket.Conn
	connected    chan<- *common.User
	disconnected chan<- *common.User
}

func NewWebSocket() WebSocketServer {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin:     func(r *http.Request) bool { return true },
	}

	return WebSocketServer{
		upgrader:    upgrader,
		connections: make(map[*common.User]*websocket.Conn),
	}
}

func (wss *WebSocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("New http connection. Try to upgrade to WebSocket")
	conn, err := wss.upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Failed to upgrade to WebSocket", err)
		fmt.Fprintf(w, "failed")
	}

	wss.addConnection(conn)
}

func (wss *WebSocketServer) addConnection(conn *websocket.Conn) {
	now := time.Now().UnixNano()
	id := strconv.FormatInt(now, 10)
	user := common.NewUser(id)

	wss.connections[user] = conn
	log.Println("Add websocket connection", user.Id)

	go wss.inputHandler(user, conn)
	go wss.outputHandler(user, conn)
	go wss.closeHandler(user, conn)
	wss.connected <- user
}

func (wss *WebSocketServer) removeConnection(conn *websocket.Conn) {
	for user, c := range wss.connections {
		if c == conn {
			if wss.disconnected != nil {
				wss.disconnected <- user
			}

			close(user.In)
			close(user.Out)
			conn.Close()
			delete(wss.connections, user)
			log.Println("Remove websocket connection", user.Id)
			break
		}
	}
}

func (wss *WebSocketServer) inputHandler(user *common.User, conn *websocket.Conn) {
	log.Println("Start websocket input handler for", user.Id)
	for {
		msgType, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println("Websocket connection read error", err.Error())
			wss.removeConnection(conn)
			return
		}

		message, err := wss.decodeMessage(user, msg, msgType)
		// 		log.Println("Websocket message", user.Id)
		if err != nil {
			log.Println("Failed to decode message", msgType, msg)
			wss.removeConnection(conn)
			return
		}

		user.In <- message
	}
}

func (wss *WebSocketServer) outputHandler(user *common.User, conn *websocket.Conn) {
	log.Println("Start websocket output handler for", user.Id)
	for {
		select {
		case msg := <-user.Out:
			if msg == nil {
				log.Printf("Nil message in output channel for %s.", user.Id)
				log.Printf("Stop websocket output handler %s", user.Id)
				return
			}

			// 			log.Println("Message in output channel for", user.Id)
			message, msgType := wss.encodeMessage(user, msg)
			if err := conn.WriteMessage(msgType, message); err != nil {
				log.Println("Websocket connection write error", err.Error())
				wss.removeConnection(conn)
				return
			}
		}
	}
}

func (wss *WebSocketServer) closeHandler(user *common.User, conn *websocket.Conn) {
	log.Println("Start websocket close handler for", user.Id)
	select {
	case <-user.Done:
		log.Println("Done channel closed for user", user.Id)
		wss.removeConnection(conn)
	}
}

func (wss *WebSocketServer) Start(host string, done <-chan interface{}) {
	subPath := "/websocket"
	http.Handle(subPath, wss)
	defer func() {
		http.Handle(subPath, nil)
	}()

	log.Println("WebSocket Server Listens on:", host+subPath)
	log.Fatal(http.ListenAndServe(host, nil))
}

func (wss *WebSocketServer) OnUserConnected(handler chan<- *common.User) {
	wss.connected = handler
}

func (wss *WebSocketServer) OnUserDisconnected(handler chan<- *common.User) {
	wss.disconnected = handler
}

func (wss WebSocketServer) encodeMessage(u *common.User,
	msg *common.Message) ([]byte, int) {
	json, err := msg.Json()
	if err != nil {
		log.Println("Failed to encode message", err)
		return []byte{}, 0
	}

	return json, int(msg.DataType())
}

func (wss WebSocketServer) decodeMessage(u *common.User,
	data []byte,
	dataType int) (*common.Message, error) {
	var packet map[string]interface{}
	err := json.Unmarshal(data, &packet)
	if err != nil {
		return nil, err
	}

	expire_period, exists := packet["expire_period"]
	var expire_date time.Time
	if exists {
		expire_date = time.Now().Add(time.Duration(expire_period.(float64)) * time.Second)
	}

	messageFrom := packet["from"].(string)
	messageTo := packet["to"].(string)
	messageCmdType := packet["cmd_type"].(string)
	messageCmd := packet["cmd"].(string)
	messageDataType := common.DataType(packet["data_type"].(float64))

	message := common.NewMessage(messageFrom, messageTo,
		messageCmdType, messageCmd,
		expire_date,
		messageDataType, packet["data"])
	return &message, nil
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/FederationOfFathers/dashboard/bridge"
	"github.com/nlopes/slack"
	"github.com/uber-go/zap"
)

var api *slack.Client
var rtm *slack.RTM
var connection *slack.Info
var connected bool
var token string
var logger = zap.New(zap.NewJSONEncoder()).With(zap.String("module", "bot"))

// LogLevel sets the logging verbosity for the package
var LogLevel = zap.InfoLevel

// SlackConnect gets the whole party stated
func SlackConnect(slackToken string) error {
	bridge.Data.Slack = data
	bridge.SendMessage = SendMessage
	bridge.PostMessage = PostMessage
	data.load()
	api = slack.New(slackToken)
	populateLists()
	if len(data.Users) < 1 {
		return ErrSlackAPIUnresponsive
	}
	token = slackToken
	rtm = api.NewRTM()
	go mindLists()
	go rtm.ManageConnection()
	go func() {
		for {
			if err := mindSlack(); err != nil {
				logger.Error("error Minding slack", zap.Error(err))
				time.Sleep(30 * time.Second)
			}
		}
	}()
	if home := os.Getenv("SERVICE_DIR"); home != "" {
		SendMessage("#-fof-dashboard", "Dev Dashboard starting up...")
	}
	return nil
}

func mindSlack() error {
	for {
		select {
		case msg := <-postMessage:
			_, _, err := rtm.PostMessage(msg.to, msg.text, slack.PostMessageParameters{
				AsUser:      true,
				UnfurlLinks: true,
				UnfurlMedia: true,
			})
			if err != nil {
				logger.Error("rtm.PostMessage failed", zap.Error(err))
			}
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			// Connecting and Disconnecting
			case *slack.ConnectedEvent:
				logger.Debug("slack.ConnectedEvent", zap.Int("count", ev.ConnectionCount))
				connection = ev.Info
				connected = true
			case *slack.DisconnectedEvent:
				connected = false
				logger.Debug("slack.DisconnectedEvent", zap.Bool("intentional", ev.Intentional))

			// Groups
			case *slack.GroupCloseEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupCloseEvent", zap.Bool("handled", true))
			case *slack.GroupJoinedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupJoinedEvent", zap.Bool("handled", true))
			case *slack.GroupLeftEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupLeftEvent", zap.Bool("handled", true))
			case *slack.GroupRenameEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupRenameEvent", zap.Bool("handled", true))

			// Instant Messages
			case *slack.IMCloseEvent:
				logger.Debug("slack.IMCloseEvent", zap.Bool("handled", false))
			case *slack.IMCreatedEvent:
				logger.Debug("slack.IMCreatedEvent", zap.Bool("handled", false))
			case *slack.IMHistoryChangedEvent:
				logger.Debug("slack.IMHistoryChangedEvent", zap.Bool("handled", false))
			case *slack.IMMarkedEvent:
				logger.Debug("slack.IMMarkedEvent", zap.Bool("handled", false))
			case *slack.IMOpenEvent:
				logger.Debug("slack.IMOpenEvent", zap.Bool("handled", false))

			// Channels
			case *slack.ChannelHistoryChangedEvent:
				logger.Debug("slack.ChannelHistoryChangedEvent", zap.Bool("handled", false))
			case *slack.ChannelArchiveEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelArchiveEvent", zap.Bool("handled", true))
			case *slack.ChannelCreatedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelCreatedEvent", zap.Bool("handled", true))
			case *slack.ChannelDeletedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelDeletedEvent", zap.Bool("handled", true))
			case *slack.ChannelInfoEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelInfoEvent", zap.Bool("handled", true))
			case *slack.ChannelJoinedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelJoinedEvent", zap.Bool("handled", true))
			case *slack.ChannelLeftEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelLeftEvent", zap.Bool("handled", true))
			case *slack.ChannelRenameEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelRenameEvent", zap.Bool("handled", true))
			case *slack.ChannelUnarchiveEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelUnarchiveEvent", zap.Bool("handled", true))

			// Users
			case *slack.MessageEvent:
				go func(ev *slack.MessageEvent) {
					switch strings.ToLower(ev.Channel[:1]) {
					case "d":
						if !handleDirectMessage(ev) {
							logger.Info("slack.MessageEvent",
								zap.Bool("handled", false),
								zap.String("type", "direct_message"),
								zap.String("user", ev.Msg.User),
								zap.String("channel", ev.Msg.Channel),
								zap.String("message", ev.Msg.Text),
								zap.String("debug", fmt.Sprintf("%#v", ev)))
						}
					case "g":
						if !handleGroupMessage(ev) {
							logger.Debug("slack.MessageEvent",
								zap.Bool("handled", false),
								zap.String("type", "group_message"),
								zap.String("user", ev.Msg.User),
								zap.String("channel", ev.Msg.Channel),
								zap.String("message", ev.Msg.Text))
						}
					case "c":
						if !handleChannelMessage(ev) {
							logger.Debug("slack.MessageEvent",
								zap.Bool("handled", false),
								zap.String("type", "channel_message"),
								zap.String("user", ev.Msg.User),
								zap.String("channel", ev.Msg.Channel),
								zap.String("message", ev.Msg.Text))
						}
					default:
						logger.Debug("slack.MessageEvent",
							zap.Bool("handled", false),
							zap.String("type", "unknown"),
							zap.String("raw", fmt.Sprintf("%#v", *ev)),
							zap.String("user", ev.Msg.User),
							zap.String("channel", ev.Msg.Channel),
							zap.String("message", ev.Msg.Text))
					}
				}(ev)
			case *slack.PresenceChangeEvent:
				logger.Debug("slack.PresenceChangeEvent",
					zap.Bool("handled", false),
					zap.String("user", ev.User),
					zap.String("type", ev.Type),
					zap.String("presence", ev.Presence))
			case *slack.UserChangeEvent:
				logger.Debug("slack.UserChangeEvent", zap.Bool("handled", false))
			case *slack.UserTypingEvent:
				logger.Debug("slack.UserTypingEvent", zap.Bool("handled", false))
			case *slack.DNDUpdatedEvent:
				logger.Debug("slack.DNDUpdatedEvent", zap.Bool("handled", false))
			case *slack.PrefChangeEvent:
				logger.Debug("slack.PrefChangeEvent", zap.Bool("handled", false))
			case *slack.TeamJoinEvent:
				logger.Debug("slack.TeamJoinEvent", zap.Bool("handled", false))

			// Files
			case *slack.FileCreatedEvent:
				logger.Debug("slack.FileCreatedEvent", zap.Bool("handled", false))
			case *slack.FileDeletedEvent:
				logger.Debug("slack.FileDeletedEvent", zap.Bool("handled", false))
			case *slack.FilePrivateEvent:
				logger.Debug("slack.FilePrivateEvent", zap.Bool("handled", false))
			case *slack.FilePublicEvent:
				logger.Debug("slack.FilePublicEvent", zap.Bool("handled", false))
			case *slack.FileSharedEvent:
				logger.Debug("slack.FileSharedEvent", zap.Bool("handled", false))
			case *slack.FileUnsharedEvent:
				logger.Debug("slack.FileUnsharedEvent", zap.Bool("handled", false))

			// Errors
			case *slack.UnmarshallingErrorEvent:
				return ev
			case *slack.OutgoingErrorEvent:
				return ev
			case *slack.AckErrorEvent:
				return ev
			case *slack.RTMError:
				return ev
			case *slack.InvalidAuthEvent:
				logger.Fatal("Slack got InvalidAuthEvent")
			}
		}
	}
}

func GroupInvite(groupID, userID string) error {
	_, _, err := api.InviteUserToGroup(groupID, userID)
	return err
}

func ChannelInvite(channelID, userID string) error {
	_, err := api.InviteUserToChannel(channelID, userID)
	return err
}

func GroupKick(groupID, userID string) error {
	return api.KickUserFromGroup(groupID, userID)
}

func ChannelKick(channelID, userID string) error {
	return api.KickUserFromChannel(channelID, userID)
}
<commit_msg>announce production starting up<commit_after>package bot

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/FederationOfFathers/dashboard/bridge"
	"github.com/nlopes/slack"
	"github.com/uber-go/zap"
)

var api *slack.Client
var rtm *slack.RTM
var connection *slack.Info
var connected bool
var token string
var logger = zap.New(zap.NewJSONEncoder()).With(zap.String("module", "bot"))

// LogLevel sets the logging verbosity for the package
var LogLevel = zap.InfoLevel

// SlackConnect gets the whole party stated
func SlackConnect(slackToken string) error {
	bridge.Data.Slack = data
	bridge.SendMessage = SendMessage
	bridge.PostMessage = PostMessage
	data.load()
	api = slack.New(slackToken)
	populateLists()
	if len(data.Users) < 1 {
		return ErrSlackAPIUnresponsive
	}
	token = slackToken
	rtm = api.NewRTM()
	go mindLists()
	go rtm.ManageConnection()
	go func() {
		for {
			if err := mindSlack(); err != nil {
				logger.Error("error Minding slack", zap.Error(err))
				time.Sleep(30 * time.Second)
			}
		}
	}()
	if home := os.Getenv("SERVICE_DIR"); home != "" {
		SendMessage("#-fof-dashboard", "Dev Dashboard starting up...")
	} else {
		SendMessage("#-fof-dashboard", "Production Dashboard starting up...")
	}
	return nil
}

func mindSlack() error {
	for {
		select {
		case msg := <-postMessage:
			_, _, err := rtm.PostMessage(msg.to, msg.text, slack.PostMessageParameters{
				AsUser:      true,
				UnfurlLinks: true,
				UnfurlMedia: true,
			})
			if err != nil {
				logger.Error("rtm.PostMessage failed", zap.Error(err))
			}
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			// Connecting and Disconnecting
			case *slack.ConnectedEvent:
				logger.Debug("slack.ConnectedEvent", zap.Int("count", ev.ConnectionCount))
				connection = ev.Info
				connected = true
			case *slack.DisconnectedEvent:
				connected = false
				logger.Debug("slack.DisconnectedEvent", zap.Bool("intentional", ev.Intentional))

			// Groups
			case *slack.GroupCloseEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupCloseEvent", zap.Bool("handled", true))
			case *slack.GroupJoinedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupJoinedEvent", zap.Bool("handled", true))
			case *slack.GroupLeftEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupLeftEvent", zap.Bool("handled", true))
			case *slack.GroupRenameEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.GroupRenameEvent", zap.Bool("handled", true))

			// Instant Messages
			case *slack.IMCloseEvent:
				logger.Debug("slack.IMCloseEvent", zap.Bool("handled", false))
			case *slack.IMCreatedEvent:
				logger.Debug("slack.IMCreatedEvent", zap.Bool("handled", false))
			case *slack.IMHistoryChangedEvent:
				logger.Debug("slack.IMHistoryChangedEvent", zap.Bool("handled", false))
			case *slack.IMMarkedEvent:
				logger.Debug("slack.IMMarkedEvent", zap.Bool("handled", false))
			case *slack.IMOpenEvent:
				logger.Debug("slack.IMOpenEvent", zap.Bool("handled", false))

			// Channels
			case *slack.ChannelHistoryChangedEvent:
				logger.Debug("slack.ChannelHistoryChangedEvent", zap.Bool("handled", false))
			case *slack.ChannelArchiveEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelArchiveEvent", zap.Bool("handled", true))
			case *slack.ChannelCreatedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelCreatedEvent", zap.Bool("handled", true))
			case *slack.ChannelDeletedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelDeletedEvent", zap.Bool("handled", true))
			case *slack.ChannelInfoEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelInfoEvent", zap.Bool("handled", true))
			case *slack.ChannelJoinedEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelJoinedEvent", zap.Bool("handled", true))
			case *slack.ChannelLeftEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelLeftEvent", zap.Bool("handled", true))
			case *slack.ChannelRenameEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelRenameEvent", zap.Bool("handled", true))
			case *slack.ChannelUnarchiveEvent:
				UpdateRequest <- struct{}{}
				logger.Debug("slack.ChannelUnarchiveEvent", zap.Bool("handled", true))

			// Users
			case *slack.MessageEvent:
				go func(ev *slack.MessageEvent) {
					switch strings.ToLower(ev.Channel[:1]) {
					case "d":
						if !handleDirectMessage(ev) {
							logger.Info("slack.MessageEvent",
								zap.Bool("handled", false),
								zap.String("type", "direct_message"),
								zap.String("user", ev.Msg.User),
								zap.String("channel", ev.Msg.Channel),
								zap.String("message", ev.Msg.Text),
								zap.String("debug", fmt.Sprintf("%#v", ev)))
						}
					case "g":
						if !handleGroupMessage(ev) {
							logger.Debug("slack.MessageEvent",
								zap.Bool("handled", false),
								zap.String("type", "group_message"),
								zap.String("user", ev.Msg.User),
								zap.String("channel", ev.Msg.Channel),
								zap.String("message", ev.Msg.Text))
						}
					case "c":
						if !handleChannelMessage(ev) {
							logger.Debug("slack.MessageEvent",
								zap.Bool("handled", false),
								zap.String("type", "channel_message"),
								zap.String("user", ev.Msg.User),
								zap.String("channel", ev.Msg.Channel),
								zap.String("message", ev.Msg.Text))
						}
					default:
						logger.Debug("slack.MessageEvent",
							zap.Bool("handled", false),
							zap.String("type", "unknown"),
							zap.String("raw", fmt.Sprintf("%#v", *ev)),
							zap.String("user", ev.Msg.User),
							zap.String("channel", ev.Msg.Channel),
							zap.String("message", ev.Msg.Text))
					}
				}(ev)
			case *slack.PresenceChangeEvent:
				logger.Debug("slack.PresenceChangeEvent",
					zap.Bool("handled", false),
					zap.String("user", ev.User),
					zap.String("type", ev.Type),
					zap.String("presence", ev.Presence))
			case *slack.UserChangeEvent:
				logger.Debug("slack.UserChangeEvent", zap.Bool("handled", false))
			case *slack.UserTypingEvent:
				logger.Debug("slack.UserTypingEvent", zap.Bool("handled", false))
			case *slack.DNDUpdatedEvent:
				logger.Debug("slack.DNDUpdatedEvent", zap.Bool("handled", false))
			case *slack.PrefChangeEvent:
				logger.Debug("slack.PrefChangeEvent", zap.Bool("handled", false))
			case *slack.TeamJoinEvent:
				logger.Debug("slack.TeamJoinEvent", zap.Bool("handled", false))

			// Files
			case *slack.FileCreatedEvent:
				logger.Debug("slack.FileCreatedEvent", zap.Bool("handled", false))
			case *slack.FileDeletedEvent:
				logger.Debug("slack.FileDeletedEvent", zap.Bool("handled", false))
			case *slack.FilePrivateEvent:
				logger.Debug("slack.FilePrivateEvent", zap.Bool("handled", false))
			case *slack.FilePublicEvent:
				logger.Debug("slack.FilePublicEvent", zap.Bool("handled", false))
			case *slack.FileSharedEvent:
				logger.Debug("slack.FileSharedEvent", zap.Bool("handled", false))
			case *slack.FileUnsharedEvent:
				logger.Debug("slack.FileUnsharedEvent", zap.Bool("handled", false))

			// Errors
			case *slack.UnmarshallingErrorEvent:
				return ev
			case *slack.OutgoingErrorEvent:
				return ev
			case *slack.AckErrorEvent:
				return ev
			case *slack.RTMError:
				return ev
			case *slack.InvalidAuthEvent:
				logger.Fatal("Slack got InvalidAuthEvent")
			}
		}
	}
}

func GroupInvite(groupID, userID string) error {
	_, _, err := api.InviteUserToGroup(groupID, userID)
	return err
}

func ChannelInvite(channelID, userID string) error {
	_, err := api.InviteUserToChannel(channelID, userID)
	return err
}

func GroupKick(groupID, userID string) error {
	return api.KickUserFromGroup(groupID, userID)
}

func ChannelKick(channelID, userID string) error {
	return api.KickUserFromChannel(channelID, userID)
}
<|endoftext|>


<commit_before>// Copyright 2010 The Walk 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 kernel32

import (
	"syscall"
	"unsafe"
)

import (
	. "walk/winapi"
)

const MAX_PATH = 260

// Error codes
const (
	ERROR_SUCCESS             = 0
	ERROR_FILE_NOT_FOUND      = 2
	ERROR_INVALID_PARAMETER   = 87
	ERROR_INSUFFICIENT_BUFFER = 122
	ERROR_MORE_DATA           = 234
)

// GlobalAlloc flags
const (
	GHND          = 0x0042
	GMEM_FIXED    = 0x0000
	GMEM_MOVEABLE = 0x0002
	GMEM_ZEROINIT = 0x0040
	GPTR          = 0x004
)

var (
	// Library
	lib uintptr

	// Functions
	getLastError           uintptr
	getLogicalDriveStrings uintptr
	getModuleHandle        uintptr
	getThreadLocale        uintptr
	globalAlloc            uintptr
	globalFree             uintptr
	globalLock             uintptr
	globalUnlock           uintptr
	moveMemory             uintptr
	mulDiv                 uintptr
	setLastError           uintptr
)

type (
	ATOM      uint16
	HANDLE    uintptr
	HGLOBAL   HANDLE
	HINSTANCE HANDLE
	LCID      uint
)

func init() {
	// Library
	lib = MustLoadLibrary("kernel32.dll")

	// Functions
	getLastError = MustGetProcAddress(lib, "GetLastError")
	getLogicalDriveStrings = MustGetProcAddress(lib, "GetLogicalDriveStringsW")
	getModuleHandle = MustGetProcAddress(lib, "GetModuleHandleW")
	getThreadLocale = MustGetProcAddress(lib, "GetThreadLocale")
	globalAlloc = MustGetProcAddress(lib, "GlobalAlloc")
	globalFree = MustGetProcAddress(lib, "GlobalFree")
	globalLock = MustGetProcAddress(lib, "GlobalLock")
	globalUnlock = MustGetProcAddress(lib, "GlobalUnlock")
	moveMemory = MustGetProcAddress(lib, "RtlMoveMemory")
	mulDiv = MustGetProcAddress(lib, "MulDiv")
	setLastError = MustGetProcAddress(lib, "SetLastError")
}

func GetLastError() uint {
	ret, _, _ := syscall.Syscall(setLastError, 0,
		0,
		0,
		0)

	return uint(ret)
}

func GetLogicalDriveStrings(nBufferLength uint, lpBuffer *uint16) uint {
	ret, _, _ := syscall.Syscall(getLogicalDriveStrings, 2,
		uintptr(nBufferLength),
		uintptr(unsafe.Pointer(lpBuffer)),
		0)

	return uint(ret)
}

func GetModuleHandle(lpModuleName *uint16) HINSTANCE {
	ret, _, _ := syscall.Syscall(getModuleHandle, 1,
		uintptr(unsafe.Pointer(lpModuleName)),
		0,
		0)

	return HINSTANCE(ret)
}

func GetThreadLocale() LCID {
	ret, _, _ := syscall.Syscall(getThreadLocale, 0,
		0,
		0,
		0)

	return LCID(ret)
}

func GlobalAlloc(uFlags uint, dwBytes uintptr) HGLOBAL {
	ret, _, _ := syscall.Syscall(globalAlloc, 2,
		uintptr(uFlags),
		dwBytes,
		0)

	return HGLOBAL(ret)
}

func GlobalFree(hMem HGLOBAL) HGLOBAL {
	ret, _, _ := syscall.Syscall(globalFree, 1,
		uintptr(hMem),
		0,
		0)

	return HGLOBAL(ret)
}

func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
	ret, _, _ := syscall.Syscall(globalLock, 1,
		uintptr(hMem),
		0,
		0)

	return unsafe.Pointer(ret)
}

func GlobalUnlock(hMem HGLOBAL) bool {
	ret, _, _ := syscall.Syscall(globalUnlock, 1,
		uintptr(hMem),
		0,
		0)

	return ret != 0
}

func MoveMemory(destination, source unsafe.Pointer, length uintptr) {
	syscall.Syscall(moveMemory, 3,
		uintptr(unsafe.Pointer(destination)),
		uintptr(source),
		uintptr(length))
}

func MulDiv(nNumber, nNumerator, nDenominator int) int {
	ret, _, _ := syscall.Syscall(mulDiv, 3,
		uintptr(nNumber),
		uintptr(nNumerator),
		uintptr(nDenominator))

	return int(ret)
}

func SetLastError(dwErrorCode uint) {
	syscall.Syscall(setLastError, 1,
		uintptr(dwErrorCode),
		0,
		0)
}
<commit_msg>Fix GetLastError syscall, thanks Allen Dang<commit_after>// Copyright 2010 The Walk 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 kernel32

import (
	"syscall"
	"unsafe"
)

import (
	. "walk/winapi"
)

const MAX_PATH = 260

// Error codes
const (
	ERROR_SUCCESS             = 0
	ERROR_FILE_NOT_FOUND      = 2
	ERROR_INVALID_PARAMETER   = 87
	ERROR_INSUFFICIENT_BUFFER = 122
	ERROR_MORE_DATA           = 234
)

// GlobalAlloc flags
const (
	GHND          = 0x0042
	GMEM_FIXED    = 0x0000
	GMEM_MOVEABLE = 0x0002
	GMEM_ZEROINIT = 0x0040
	GPTR          = 0x004
)

var (
	// Library
	lib uintptr

	// Functions
	getLastError           uintptr
	getLogicalDriveStrings uintptr
	getModuleHandle        uintptr
	getThreadLocale        uintptr
	globalAlloc            uintptr
	globalFree             uintptr
	globalLock             uintptr
	globalUnlock           uintptr
	moveMemory             uintptr
	mulDiv                 uintptr
	setLastError           uintptr
)

type (
	ATOM      uint16
	HANDLE    uintptr
	HGLOBAL   HANDLE
	HINSTANCE HANDLE
	LCID      uint
)

func init() {
	// Library
	lib = MustLoadLibrary("kernel32.dll")

	// Functions
	getLastError = MustGetProcAddress(lib, "GetLastError")
	getLogicalDriveStrings = MustGetProcAddress(lib, "GetLogicalDriveStringsW")
	getModuleHandle = MustGetProcAddress(lib, "GetModuleHandleW")
	getThreadLocale = MustGetProcAddress(lib, "GetThreadLocale")
	globalAlloc = MustGetProcAddress(lib, "GlobalAlloc")
	globalFree = MustGetProcAddress(lib, "GlobalFree")
	globalLock = MustGetProcAddress(lib, "GlobalLock")
	globalUnlock = MustGetProcAddress(lib, "GlobalUnlock")
	moveMemory = MustGetProcAddress(lib, "RtlMoveMemory")
	mulDiv = MustGetProcAddress(lib, "MulDiv")
	setLastError = MustGetProcAddress(lib, "SetLastError")
}

func GetLastError() uint {
	ret, _, _ := syscall.Syscall(getLastError, 0,
		0,
		0,
		0)

	return uint(ret)
}

func GetLogicalDriveStrings(nBufferLength uint, lpBuffer *uint16) uint {
	ret, _, _ := syscall.Syscall(getLogicalDriveStrings, 2,
		uintptr(nBufferLength),
		uintptr(unsafe.Pointer(lpBuffer)),
		0)

	return uint(ret)
}

func GetModuleHandle(lpModuleName *uint16) HINSTANCE {
	ret, _, _ := syscall.Syscall(getModuleHandle, 1,
		uintptr(unsafe.Pointer(lpModuleName)),
		0,
		0)

	return HINSTANCE(ret)
}

func GetThreadLocale() LCID {
	ret, _, _ := syscall.Syscall(getThreadLocale, 0,
		0,
		0,
		0)

	return LCID(ret)
}

func GlobalAlloc(uFlags uint, dwBytes uintptr) HGLOBAL {
	ret, _, _ := syscall.Syscall(globalAlloc, 2,
		uintptr(uFlags),
		dwBytes,
		0)

	return HGLOBAL(ret)
}

func GlobalFree(hMem HGLOBAL) HGLOBAL {
	ret, _, _ := syscall.Syscall(globalFree, 1,
		uintptr(hMem),
		0,
		0)

	return HGLOBAL(ret)
}

func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
	ret, _, _ := syscall.Syscall(globalLock, 1,
		uintptr(hMem),
		0,
		0)

	return unsafe.Pointer(ret)
}

func GlobalUnlock(hMem HGLOBAL) bool {
	ret, _, _ := syscall.Syscall(globalUnlock, 1,
		uintptr(hMem),
		0,
		0)

	return ret != 0
}

func MoveMemory(destination, source unsafe.Pointer, length uintptr) {
	syscall.Syscall(moveMemory, 3,
		uintptr(unsafe.Pointer(destination)),
		uintptr(source),
		uintptr(length))
}

func MulDiv(nNumber, nNumerator, nDenominator int) int {
	ret, _, _ := syscall.Syscall(mulDiv, 3,
		uintptr(nNumber),
		uintptr(nNumerator),
		uintptr(nDenominator))

	return int(ret)
}

func SetLastError(dwErrorCode uint) {
	syscall.Syscall(setLastError, 1,
		uintptr(dwErrorCode),
		0,
		0)
}
<|endoftext|>


<commit_before>package configurator

import (
	"encoding/json"
	"fmt"
	"github.com/iankronquist/senior-project-experiment/src/monitor"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
)

type Config struct {
	DockerComposeName string   `json:"docker compose name"`
	MonitorName       string   `json:"monitor process name"`
	Containers        []string `json:"container names"`
}

func StartContainers(c Config) error {

	for _, containerName := range c.Containers {
		containerProc := exec.Command(c.DockerComposeName, "up", "-d", containerName)

		fmt.Println(c.DockerComposeName, "up", "-d", containerName)

		// Copy docker-compose stdout/stderr to configurator's
		compose_stderr, err := containerProc.StderrPipe()
		if err != nil {
			panic(err)
		}
		compose_stdout, err := containerProc.StdoutPipe()
		if err != nil {
			panic(err)
		}
		go io.Copy(os.Stdout, compose_stdout)
		go io.Copy(os.Stderr, compose_stderr)

		containerProc.Start()

		err = containerProc.Wait()
		if err != nil {
			fmt.Println(err)
			return err
		}
	}
	fmt.Println("Containers started!")
	return nil
}

func ReadConfig(fileName string) (Config, error) {
	config := Config{}
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		return config, err
	}
	err = json.Unmarshal(data, &config)
	if err != nil {
		return config, err
	}
	return config, nil
}

func StartMonitor(c Config) {
	fmt.Println("adfasdf")
	FSMessages := make(chan string)
	//networkMessages := make(chan string)
	//execMessages := make(chan string)
	fsMonitor := monitor.FSMonitor{MonitorName: c.MonitorName}

	fsMonitor.Start(FSMessages)
	//go fsMonitor.Start(FSMessages)
	/*
		go monitor.StartNetWorkMonitor(networkMessages)
		go monitor.StartExecMonitor(execMessages)
	*/
}
<commit_msg>Configurator launches fs monitor in a go routine<commit_after>package configurator

import (
	"encoding/json"
	"fmt"
	"github.com/iankronquist/senior-project-experiment/src/monitor"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
)

type Config struct {
	DockerComposeName string   `json:"docker compose name"`
	MonitorName       string   `json:"monitor process name"`
	Containers        []string `json:"container names"`
}

func StartContainers(c Config) error {

	for _, containerName := range c.Containers {
		containerProc := exec.Command(c.DockerComposeName, "up", "-d", containerName)

		fmt.Println(c.DockerComposeName, "up", "-d", containerName)

		// Copy docker-compose stdout/stderr to configurator's
		compose_stderr, err := containerProc.StderrPipe()
		if err != nil {
			panic(err)
		}
		compose_stdout, err := containerProc.StdoutPipe()
		if err != nil {
			panic(err)
		}
		go io.Copy(os.Stdout, compose_stdout)
		go io.Copy(os.Stderr, compose_stderr)

		containerProc.Start()

		err = containerProc.Wait()
		if err != nil {
			fmt.Println(err)
			return err
		}
	}
	fmt.Println("Containers started!")
	return nil
}

func ReadConfig(fileName string) (Config, error) {
	config := Config{}
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		return config, err
	}
	err = json.Unmarshal(data, &config)
	if err != nil {
		return config, err
	}
	return config, nil
}

func StartMonitor(c Config) {
	FSMessages := make(chan string)
	//networkMessages := make(chan string)
	//execMessages := make(chan string)
	fsMonitor := monitor.FSMonitor{MonitorName: c.MonitorName}

	go fsMonitor.Start(FSMessages)
	for {
		select {
			case message := <-FSMessages:
				fmt.Println("Message received: ", message)
		}
	}
	/*
		go monitor.StartNetWorkMonitor(networkMessages)
		go monitor.StartExecMonitor(execMessages)
	*/
}
<|endoftext|>