<commit_before>package satan

import (
	"fmt"
	"log"
	"os"
	"runtime/debug"
	"sync"
	"time"

	"github.com/localhots/satan/stats"
)

// Satan is the master daemon.
type Satan struct {
	SubscribeFunc SubscribeFunc
	Publisher     Publisher
	DaemonStats   stats.Publisher
	Logger        *log.Logger
	NumWorkers    int

	daemons      []Daemon
	queue        chan *task
	runtimeStats stats.Manager

	wgWorkers       sync.WaitGroup
	wgSystem        sync.WaitGroup
	shutdownWorkers chan struct{}
	shutdownSystem  chan struct{}
}

// Actor is a function that could be executed by daemon workers.
type Actor func()

// SubscribeFunc is a function that is used by daemons to subscribe to messages.
type SubscribeFunc func(consumer, topic string) Streamer

// Streamer is the interface that wraps message consumers. Error handling
// should be provided by the implementation. Feel free to panic.
type Streamer interface {
	Messages() <-chan []byte
	Close()
}

// Publisher is the interface that wraps message publishers. Error handling
// should be provided by the implementation. Feel free to panic.
type Publisher interface {
	Publish(msg []byte)
	Close()
}

type task struct {
	daemon    Daemon
	actor     Actor
	createdAt time.Time
	system    bool
	name      string
}

const (
	DefaultNumWorkers = 100
)

// Summon creates a new instance of Satan.
func Summon() *Satan {
	return &Satan{
		Logger:          log.New(os.Stdout, "[daemons] ", log.LstdFlags),
		NumWorkers:      DefaultNumWorkers,
		queue:           make(chan *task),
		runtimeStats:    stats.NewBasicStats(),
		shutdownWorkers: make(chan struct{}),
		shutdownSystem:  make(chan struct{}),
	}
}

// AddDaemon adds a new daemon.
func (s *Satan) AddDaemon(d Daemon) {
	base := d.base()
	base.self = d
	base.subscribeFunc = s.SubscribeFunc
	base.publisher = s.Publisher
	base.queue = s.queue
	base.logger = s.Logger
	base.shutdown = s.shutdownSystem

	go d.Startup()
	s.daemons = append(s.daemons, d)
}

// StartDaemons starts all registered daemons.
func (s *Satan) StartDaemons() {
	s.Logger.Printf("Starting %d workers", s.NumWorkers)
	for i := 0; i < s.NumWorkers; i++ {
		go s.runWorker()
	}
}

// StopDaemons stops all running daemons.
func (s *Satan) StopDaemons() {
	close(s.shutdownSystem)
	for _, d := range s.daemons {
		d.Shutdown()
	}

	s.wgSystem.Wait()
	close(s.shutdownWorkers)
	s.wgWorkers.Wait()
	close(s.queue)

	fmt.Println(s.runtimeStats.Fetch(stats.Latency))
}

func (s *Satan) runWorker() {
	s.wgWorkers.Add(1)
	defer s.wgWorkers.Done()
	defer func() {
		if err := recover(); err != nil {
			s.Logger.Printf("Worker crashed. Error: %v\n", err)
			debug.PrintStack()
			go s.runWorker() // Restarting worker
		}
	}()

	for {
		select {
		case t := <-s.queue:
			s.processTask(t)
		case <-s.shutdownWorkers:
			return
		}
	}
}

func (s *Satan) processTask(t *task) {
	dur := time.Now().Sub(t.createdAt)
	s.runtimeStats.Add(stats.Latency, dur)

	if t.system {
		s.processSystemTask(t)
	} else {
		s.processGeneralTask(t)
	}
}

func (s *Satan) processSystemTask(t *task) {
	s.wgSystem.Add(1)
	defer s.wgSystem.Done()
	defer func() {
		if err := recover(); err != nil {
			s.Logger.Printf("System task %s recovered from a panic\nError: %v\n", t, err)
			debug.PrintStack()

			t.createdAt = time.Now()
			s.queue <- t // Restarting task
		} else {
			s.Logger.Printf("System task %s has stopped\n", t)
		}
	}()

	s.Logger.Printf("Starting system task %s\n", t)
	t.actor() // <--- ACTION STARTS HERE
}

func (s *Satan) processGeneralTask(t *task) {
	defer func() {
		if err := recover(); err != nil {
			if s.DaemonStats != nil {
				s.DaemonStats.Error(t.daemon.base().String())
			}
			t.daemon.base().handlePanic(err)
			s.Logger.Printf("Daemon %s recovered from a panic\nError: %v\n", t.daemon.base(), err)
			debug.PrintStack()
		}
	}()
	if s.DaemonStats != nil {
		defer func(start time.Time) {
			dur := time.Now().Sub(start)
			s.DaemonStats.Add(t.daemon.base().String(), dur)
		}(time.Now())
	}

	t.actor() // <--- ACTION STARTS HERE
}

func (t *task) String() string {
	if t.name == "" {
		return fmt.Sprintf("[unnamed %s process]", t.daemon)
	}

	return fmt.Sprintf("%s[%s]", t.daemon, t.name)
}
<commit_msg>Fix a rare crash when restarting a system task after shutdown was called<commit_after>package satan

import (
	"fmt"
	"log"
	"os"
	"runtime/debug"
	"sync"
	"time"

	"github.com/localhots/satan/stats"
)

// Satan is the master daemon.
type Satan struct {
	SubscribeFunc SubscribeFunc
	Publisher     Publisher
	DaemonStats   stats.Publisher
	Logger        *log.Logger
	NumWorkers    int

	daemons      []Daemon
	queue        chan *task
	runtimeStats stats.Manager

	wgWorkers       sync.WaitGroup
	wgSystem        sync.WaitGroup
	shutdownWorkers chan struct{}
	shutdownSystem  chan struct{}
}

// Actor is a function that could be executed by daemon workers.
type Actor func()

// SubscribeFunc is a function that is used by daemons to subscribe to messages.
type SubscribeFunc func(consumer, topic string) Streamer

// Streamer is the interface that wraps message consumers. Error handling
// should be provided by the implementation. Feel free to panic.
type Streamer interface {
	Messages() <-chan []byte
	Close()
}

// Publisher is the interface that wraps message publishers. Error handling
// should be provided by the implementation. Feel free to panic.
type Publisher interface {
	Publish(msg []byte)
	Close()
}

type task struct {
	daemon    Daemon
	actor     Actor
	createdAt time.Time
	system    bool
	name      string
}

const (
	DefaultNumWorkers = 100
)

// Summon creates a new instance of Satan.
func Summon() *Satan {
	return &Satan{
		Logger:          log.New(os.Stdout, "[daemons] ", log.LstdFlags),
		NumWorkers:      DefaultNumWorkers,
		queue:           make(chan *task),
		runtimeStats:    stats.NewBasicStats(),
		shutdownWorkers: make(chan struct{}),
		shutdownSystem:  make(chan struct{}),
	}
}

// AddDaemon adds a new daemon.
func (s *Satan) AddDaemon(d Daemon) {
	base := d.base()
	base.self = d
	base.subscribeFunc = s.SubscribeFunc
	base.publisher = s.Publisher
	base.queue = s.queue
	base.logger = s.Logger
	base.shutdown = s.shutdownSystem

	go d.Startup()
	s.daemons = append(s.daemons, d)
}

// StartDaemons starts all registered daemons.
func (s *Satan) StartDaemons() {
	s.Logger.Printf("Starting %d workers", s.NumWorkers)
	for i := 0; i < s.NumWorkers; i++ {
		go s.runWorker()
	}
}

// StopDaemons stops all running daemons.
func (s *Satan) StopDaemons() {
	close(s.shutdownSystem)
	for _, d := range s.daemons {
		d.Shutdown()
	}

	s.wgSystem.Wait()
	close(s.shutdownWorkers)
	s.wgWorkers.Wait()
	close(s.queue)

	fmt.Println(s.runtimeStats.Fetch(stats.Latency))
}

func (s *Satan) runWorker() {
	s.wgWorkers.Add(1)
	defer s.wgWorkers.Done()
	defer func() {
		if err := recover(); err != nil {
			s.Logger.Printf("Worker crashed. Error: %v\n", err)
			debug.PrintStack()
			go s.runWorker() // Restarting worker
		}
	}()

	for {
		select {
		case t := <-s.queue:
			s.processTask(t)
		case <-s.shutdownWorkers:
			return
		}
	}
}

func (s *Satan) processTask(t *task) {
	dur := time.Now().Sub(t.createdAt)
	s.runtimeStats.Add(stats.Latency, dur)

	if t.system {
		s.processSystemTask(t)
	} else {
		s.processGeneralTask(t)
	}
}

func (s *Satan) processSystemTask(t *task) {
	// Abort starting a system task if shutdown was already called. Otherwise
	// incrementing a wait group counter will cause a panic. This should be an
	// extremely rare scenario when a system task crashes and tries to restart
	// after a shutdown call.
	select {
	case <-s.shutdownSystem:
		return
	default:
	}

	s.wgSystem.Add(1)
	defer s.wgSystem.Done()
	defer func() {
		if err := recover(); err != nil {
			s.Logger.Printf("System task %s recovered from a panic\nError: %v\n", t, err)
			debug.PrintStack()

			t.createdAt = time.Now()
			s.queue <- t // Restarting task
		} else {
			s.Logger.Printf("System task %s has stopped\n", t)
		}
	}()

	s.Logger.Printf("Starting system task %s\n", t)
	t.actor() // <--- ACTION STARTS HERE
}

func (s *Satan) processGeneralTask(t *task) {
	defer func() {
		if err := recover(); err != nil {
			if s.DaemonStats != nil {
				s.DaemonStats.Error(t.daemon.base().String())
			}
			t.daemon.base().handlePanic(err)
			s.Logger.Printf("Daemon %s recovered from a panic\nError: %v\n", t.daemon.base(), err)
			debug.PrintStack()
		}
	}()
	if s.DaemonStats != nil {
		defer func(start time.Time) {
			dur := time.Now().Sub(start)
			s.DaemonStats.Add(t.daemon.base().String(), dur)
		}(time.Now())
	}

	t.actor() // <--- ACTION STARTS HERE
}

func (t *task) String() string {
	if t.name == "" {
		return fmt.Sprintf("[unnamed %s process]", t.daemon)
	}

	return fmt.Sprintf("%s[%s]", t.daemon, t.name)
}
<|endoftext|>


<commit_before>// Copyright 2015 The LUCI 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 target

import (
	"flag"
	"fmt"

	"go.chromium.org/luci/common/flag/flagenum"
	"go.chromium.org/luci/common/tsmon/types"
)

var _ flag.Value = (*targetTypeFlag)(nil)

var (
	// NilType is given if a metric was created without the TargetType specified.
	NilType = types.TargetType{}

	DeviceType = (*NetworkDevice)(nil).Type()
	TaskType = (*Task)(nil).Type()
)

var targetTypeEnum = flagenum.Enum{
	DeviceType.Name: DeviceType,
	TaskType.Name:   TaskType,
}

type targetTypeFlag struct {
	flags *Flags
}

func (ttf *targetTypeFlag) String() string {
	return ttf.flags.TargetType.Name
}

func (ttf *targetTypeFlag) Set(v string) error {
	targetType, ok := targetTypeEnum[v]
	if !ok {
		return fmt.Errorf("unknown --ts-mon-target-type '%s'", v)
	}
	ttf.flags.TargetType = targetType.(types.TargetType)
	return nil
}
<commit_msg>[tsmon] check if targetTypeFlag has been set.<commit_after>// Copyright 2015 The LUCI 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 target

import (
	"flag"
	"fmt"

	"go.chromium.org/luci/common/flag/flagenum"
	"go.chromium.org/luci/common/tsmon/types"
)

var _ flag.Value = (*targetTypeFlag)(nil)

var (
	// NilType is given if a metric was created without the TargetType specified.
	NilType = types.TargetType{}

	DeviceType = (*NetworkDevice)(nil).Type()
	TaskType = (*Task)(nil).Type()
)

var targetTypeEnum = flagenum.Enum{
	DeviceType.Name: DeviceType,
	TaskType.Name:   TaskType,
}

type targetTypeFlag struct {
	flags *Flags
}

func (ttf *targetTypeFlag) String() string {
	if ttf.flags != nil {
		return ttf.flags.TargetType.Name
	}
	return DeviceType.Name
}

func (ttf *targetTypeFlag) Set(v string) error {
	targetType, ok := targetTypeEnum[v]
	if !ok {
		return fmt.Errorf("unknown --ts-mon-target-type '%s'", v)
	}
	ttf.flags.TargetType = targetType.(types.TargetType)
	return nil
}
<|endoftext|>


<commit_before>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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
 */

package zlib

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"strconv"
)

type MEIResponse struct {
	ConformityLevel int          `json:"conformity_level"`
	MoreFollows     bool         `json:"more_follows"`
	ObjectCount     int          `json:"object_count"`
	Objects         MEIObjectSet `json:"objects,omitempty"`
}

type MEIObjectSet []MEIObject

func (ms *MEIObjectSet) MarshalJSON() ([]byte, error) {
	enc := make(map[string]string, len(*ms))
	for _, obj := range *ms {
		enc[obj.OID.Name()] = obj.Value
	}
	return json.Marshal(enc)
}

type MEIObject struct {
	OID   MEIObjectID
	Value string
}

type MEIObjectID int

const (
	OIDVendor              MEIObjectID = 0
	OIDProductCode         MEIObjectID = 1
	OIDRevision            MEIObjectID = 2
	OIDVendorURL           MEIObjectID = 3
	OIDProductName         MEIObjectID = 4
	OIDModelName           MEIObjectID = 5
	OIDUserApplicationName MEIObjectID = 6
)

var meiObjectNames = []string{
	"vendor",
	"product_code",
	"revision",
	"vendor_url",
	"product_name",
	"model_name",
	"user_application_name",
}

func (m *MEIObjectID) Name() string {
	oid := int(*m)
	var name string
	if oid >= len(meiObjectNames) || oid < 0 {
		name = "oid." + strconv.Itoa(oid)
	} else {
		name = meiObjectNames[oid]
	}
	return name
}

func (m *MEIObject) MarshalJSON() ([]byte, error) {
	enc := make(map[string]interface{}, 1)
	name := m.OID.Name()
	enc[name] = m.Value
	return json.Marshal(enc)
}

type ExceptionResponse struct {
	ExceptionFunction FunctionCode `json:"exception_function"`
	ExceptionType     byte         `json:"exception_type"`
}

type ModbusEvent struct {
	Length           int                `json:"length"`
	UnitID           int                `json:"unit_id"`
	Function         FunctionCode       `json:"function_code"`
	Response         []byte             `json:"raw_response,omitempty"`
	MEIResponse      *MEIResponse       `json:"mei_response,omitempty"`
	ExceptionReponse *ExceptionResponse `json:"exception_response,omitempty"`
}

func (m *ModbusEvent) IsException() bool {
	return (m.Function&0x80 != 0)
}

func (m *ModbusEvent) ParseSelf() {
	if m.IsException() {
		m.parseException()
	} else {
		m.parseReponse()
	}
}

func (m *ModbusEvent) parseException() {
	exceptionFunction := m.Function & 0x7F
	var exceptionType byte
	if len(m.Response) > 0 {
		exceptionType = m.Response[0]
	}
	res := ExceptionResponse{
		ExceptionFunction: exceptionFunction,
		ExceptionType:     exceptionType,
	}
	m.ExceptionReponse = &res
}

func (m *ModbusEvent) parseReponse() {
	if m.Function != FunctionCodeMEI {
		return
	}
	if len(m.Response) < 6 {
		return
	}
	meiType := m.Response[0]
	if meiType != 0x0E {
		return
	}
	readType := m.Response[1]
	if readType != 1 {
		return
	}
	conformityLevel := m.Response[2]
	moreFollows := (m.Response[3] != 0)
	objectCount := m.Response[5]
	objects := make([]MEIObject, objectCount)
	it := 6
	for idx := range objects {
		n, obj := parseMEIObject(m.Response[it:])
		it += n
		if obj == nil {
			break
		}
		objects[idx] = *obj
	}
	res := MEIResponse{
		ConformityLevel: int(conformityLevel),
		MoreFollows:     moreFollows,
		ObjectCount:     int(objectCount),
		Objects:         objects,
	}
	m.MEIResponse = &res
}

func parseMEIObject(objectBytes []byte) (int, *MEIObject) {
	length := len(objectBytes)
	if length < 2 {
		return length, nil
	}
	oid := objectBytes[0]
	objLen := int(objectBytes[1])
	if length < 2+objLen {
		return length, nil
	}
	s := string(objectBytes[2 : 2+objLen])
	obj := MEIObject{
		OID:   MEIObjectID(oid),
		Value: s,
	}
	return 2 + objLen, &obj
}

type FunctionCode byte
type ExceptionFunctionCode byte
type ExceptionCode byte

type ModbusRequest struct {
	Function FunctionCode
	Data     []byte
}

func (r *ModbusRequest) MarshalBinary() (data []byte, err error) {
	data = make([]byte, 7+1+len(r.Data))
	copy(data[0:4], ModbusHeaderBytes)
	msglen := len(r.Data) + 2 // unit ID and function
	binary.BigEndian.PutUint16(data[4:6], uint16(msglen))
	data[6] = 0
	data[7] = byte(r.Function)
	copy(data[8:], r.Data)
	return
}

type ModbusResponse struct {
	Length   int
	UnitID   int
	Function FunctionCode
	Data     []byte
}

func (c *Conn) ReadMin(res []byte, bytes int) (cnt int, err error) {
	for cnt < bytes {
		var n int
		n, err = c.getUnderlyingConn().Read(res[cnt:])
		cnt += n

		if err != nil && cnt >= len(res) {
			err = fmt.Errorf("modbus: response buffer too small")
		}

		if err != nil {
			return
		}
	}

	return
}

func (c *Conn) GetModbusResponse() (res ModbusResponse, err error) {
	var cnt int
	buf := make([]byte, 1024) // should be more memory than we need
	header := buf[0:7]
	buf = buf[7:]

	cnt, err = c.ReadMin(header, 7)
	if err != nil {
		err = fmt.Errorf("modbus: could not get response: %s", err.Error())
		return
	}

	// first 4 bytes should be known, verify them
	if !bytes.Equal(header[0:4], ModbusHeaderBytes) {
		err = fmt.Errorf("modbus: not a modbus response")
		return
	}

	msglen := int(binary.BigEndian.Uint16(header[4:6]))
	unitID := int(header[6])

	cnt = 0
	if msglen > len(buf) {
		msglen = len(buf)
	}
	// One of the bytes in length counts as part of the header
	for cnt < msglen-1 {
		var n int
		n, err = c.getUnderlyingConn().Read(buf[cnt:])
		cnt += n

		if err != nil && cnt >= len(buf) {
			err = fmt.Errorf("modbus: response buffer too small")
		}

		if err != nil {
			break
		}
	}

	if cnt > len(buf) {
		cnt = len(buf)
	}

	var d []byte
	if cnt > 1 {
		d = buf[1:cnt]
	}

	//TODO this really should be done by a more elegant unmarshaling function
	res = ModbusResponse{
		Length:   msglen,
		UnitID:   unitID,
		Function: FunctionCode(buf[0]),
		Data:     d,
	}

	return
}

type ModbusException struct {
	Function      ExceptionFunctionCode
	ExceptionType ExceptionCode
}

func (e ExceptionFunctionCode) FunctionCode() FunctionCode {
	code := byte(e) & byte(0x79)
	return FunctionCode(code)
}

func (c FunctionCode) ExceptionFunctionCode() ExceptionFunctionCode {
	code := byte(c) | byte(0x80)
	return ExceptionFunctionCode(code)
}

func (c FunctionCode) IsException() bool {
	return (byte(c) & 0x80) == 0x80
}

var ModbusHeaderBytes = []byte{
	0x13, 0x37, // do not matter, will just be verifying they are the same
	0x00, 0x00, // must be 0
}

var ModbusFunctionEncapsulatedInterface = FunctionCode(0x2B)

const (
	FunctionCodeMEI = FunctionCode(0x2B)
)
<commit_msg>Change '.' to '_' in unknown modbus object IDs<commit_after>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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
 */

package zlib

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"strconv"
)

type MEIResponse struct {
	ConformityLevel int          `json:"conformity_level"`
	MoreFollows     bool         `json:"more_follows"`
	ObjectCount     int          `json:"object_count"`
	Objects         MEIObjectSet `json:"objects,omitempty"`
}

type MEIObjectSet []MEIObject

func (ms *MEIObjectSet) MarshalJSON() ([]byte, error) {
	enc := make(map[string]string, len(*ms))
	for _, obj := range *ms {
		enc[obj.OID.Name()] = obj.Value
	}
	return json.Marshal(enc)
}

type MEIObject struct {
	OID   MEIObjectID
	Value string
}

type MEIObjectID int

const (
	OIDVendor              MEIObjectID = 0
	OIDProductCode         MEIObjectID = 1
	OIDRevision            MEIObjectID = 2
	OIDVendorURL           MEIObjectID = 3
	OIDProductName         MEIObjectID = 4
	OIDModelName           MEIObjectID = 5
	OIDUserApplicationName MEIObjectID = 6
)

var meiObjectNames = []string{
	"vendor",
	"product_code",
	"revision",
	"vendor_url",
	"product_name",
	"model_name",
	"user_application_name",
}

func (m *MEIObjectID) Name() string {
	oid := int(*m)
	var name string
	if oid >= len(meiObjectNames) || oid < 0 {
		name = "oid_" + strconv.Itoa(oid)
	} else {
		name = meiObjectNames[oid]
	}
	return name
}

func (m *MEIObject) MarshalJSON() ([]byte, error) {
	enc := make(map[string]interface{}, 1)
	name := m.OID.Name()
	enc[name] = m.Value
	return json.Marshal(enc)
}

type ExceptionResponse struct {
	ExceptionFunction FunctionCode `json:"exception_function"`
	ExceptionType     byte         `json:"exception_type"`
}

type ModbusEvent struct {
	Length           int                `json:"length"`
	UnitID           int                `json:"unit_id"`
	Function         FunctionCode       `json:"function_code"`
	Response         []byte             `json:"raw_response,omitempty"`
	MEIResponse      *MEIResponse       `json:"mei_response,omitempty"`
	ExceptionReponse *ExceptionResponse `json:"exception_response,omitempty"`
}

func (m *ModbusEvent) IsException() bool {
	return (m.Function&0x80 != 0)
}

func (m *ModbusEvent) ParseSelf() {
	if m.IsException() {
		m.parseException()
	} else {
		m.parseReponse()
	}
}

func (m *ModbusEvent) parseException() {
	exceptionFunction := m.Function & 0x7F
	var exceptionType byte
	if len(m.Response) > 0 {
		exceptionType = m.Response[0]
	}
	res := ExceptionResponse{
		ExceptionFunction: exceptionFunction,
		ExceptionType:     exceptionType,
	}
	m.ExceptionReponse = &res
}

func (m *ModbusEvent) parseReponse() {
	if m.Function != FunctionCodeMEI {
		return
	}
	if len(m.Response) < 6 {
		return
	}
	meiType := m.Response[0]
	if meiType != 0x0E {
		return
	}
	readType := m.Response[1]
	if readType != 1 {
		return
	}
	conformityLevel := m.Response[2]
	moreFollows := (m.Response[3] != 0)
	objectCount := m.Response[5]
	objects := make([]MEIObject, objectCount)
	it := 6
	for idx := range objects {
		n, obj := parseMEIObject(m.Response[it:])
		it += n
		if obj == nil {
			break
		}
		objects[idx] = *obj
	}
	res := MEIResponse{
		ConformityLevel: int(conformityLevel),
		MoreFollows:     moreFollows,
		ObjectCount:     int(objectCount),
		Objects:         objects,
	}
	m.MEIResponse = &res
}

func parseMEIObject(objectBytes []byte) (int, *MEIObject) {
	length := len(objectBytes)
	if length < 2 {
		return length, nil
	}
	oid := objectBytes[0]
	objLen := int(objectBytes[1])
	if length < 2+objLen {
		return length, nil
	}
	s := string(objectBytes[2 : 2+objLen])
	obj := MEIObject{
		OID:   MEIObjectID(oid),
		Value: s,
	}
	return 2 + objLen, &obj
}

type FunctionCode byte
type ExceptionFunctionCode byte
type ExceptionCode byte

type ModbusRequest struct {
	Function FunctionCode
	Data     []byte
}

func (r *ModbusRequest) MarshalBinary() (data []byte, err error) {
	data = make([]byte, 7+1+len(r.Data))
	copy(data[0:4], ModbusHeaderBytes)
	msglen := len(r.Data) + 2 // unit ID and function
	binary.BigEndian.PutUint16(data[4:6], uint16(msglen))
	data[6] = 0
	data[7] = byte(r.Function)
	copy(data[8:], r.Data)
	return
}

type ModbusResponse struct {
	Length   int
	UnitID   int
	Function FunctionCode
	Data     []byte
}

func (c *Conn) ReadMin(res []byte, bytes int) (cnt int, err error) {
	for cnt < bytes {
		var n int
		n, err = c.getUnderlyingConn().Read(res[cnt:])
		cnt += n

		if err != nil && cnt >= len(res) {
			err = fmt.Errorf("modbus: response buffer too small")
		}

		if err != nil {
			return
		}
	}

	return
}

func (c *Conn) GetModbusResponse() (res ModbusResponse, err error) {
	var cnt int
	buf := make([]byte, 1024) // should be more memory than we need
	header := buf[0:7]
	buf = buf[7:]

	cnt, err = c.ReadMin(header, 7)
	if err != nil {
		err = fmt.Errorf("modbus: could not get response: %s", err.Error())
		return
	}

	// first 4 bytes should be known, verify them
	if !bytes.Equal(header[0:4], ModbusHeaderBytes) {
		err = fmt.Errorf("modbus: not a modbus response")
		return
	}

	msglen := int(binary.BigEndian.Uint16(header[4:6]))
	unitID := int(header[6])

	cnt = 0
	if msglen > len(buf) {
		msglen = len(buf)
	}
	// One of the bytes in length counts as part of the header
	for cnt < msglen-1 {
		var n int
		n, err = c.getUnderlyingConn().Read(buf[cnt:])
		cnt += n

		if err != nil && cnt >= len(buf) {
			err = fmt.Errorf("modbus: response buffer too small")
		}

		if err != nil {
			break
		}
	}

	if cnt > len(buf) {
		cnt = len(buf)
	}

	var d []byte
	if cnt > 1 {
		d = buf[1:cnt]
	}

	//TODO this really should be done by a more elegant unmarshaling function
	res = ModbusResponse{
		Length:   msglen,
		UnitID:   unitID,
		Function: FunctionCode(buf[0]),
		Data:     d,
	}

	return
}

type ModbusException struct {
	Function      ExceptionFunctionCode
	ExceptionType ExceptionCode
}

func (e ExceptionFunctionCode) FunctionCode() FunctionCode {
	code := byte(e) & byte(0x79)
	return FunctionCode(code)
}

func (c FunctionCode) ExceptionFunctionCode() ExceptionFunctionCode {
	code := byte(c) | byte(0x80)
	return ExceptionFunctionCode(code)
}

func (c FunctionCode) IsException() bool {
	return (byte(c) & 0x80) == 0x80
}

var ModbusHeaderBytes = []byte{
	0x13, 0x37, // do not matter, will just be verifying they are the same
	0x00, 0x00, // must be 0
}

var ModbusFunctionEncapsulatedInterface = FunctionCode(0x2B)

const (
	FunctionCodeMEI = FunctionCode(0x2B)
)
<|endoftext|>


<commit_before>// Package lib contains: actions.go - cleaner.go - commands.go - destroy.go - snapshot.go - sync.go - take.go - uuid.go
//
// Cleaner removes all keys with the flag #deleted at the datacenter indicated
//
package lib

import (
	"fmt"
	"os"
	"strings"

	"github.com/nfrance-conseil/zeplic/config"
	"github.com/hashicorp/consul/api"
)

// Cleaner deletes all KV pairs with #deleted flag in dataset
func Cleaner(RealDataset string) int {
	// Search the dataset
	var datacenter string
	j, _, _ := config.JSON()
	for i := 0; i < j; i++ {
		pieces := config.Extract(i)
		dataset := pieces[2].(string)
		if RealDataset == dataset {
			datacenter = pieces[4].(string)
			break
		} else {
			continue
		}
	}

	var code int
	if datacenter != "" {
		// Resolve hostname
		hostname, err := os.Hostname()
		if err != nil {
			w.Err("[ERROR > lib/cleaner.go:35] it was not possible to resolve the hostname.")
			code = 1
			return code
		}

		// Create a new client
		client, err := api.NewClient(api.DefaultConfig())
		if err != nil {
			w.Err("[ERROR > lib/cleaner.go:43]@[CONSUL] it was not possible to create a new client.")
			code = 1
			return code
		}
		kv := client.KV()

		// KV write options
		q1 := &api.QueryOptions{Datacenter: datacenter}

		// Get KV pairs
		keyfix := fmt.Sprintf("zeplic/%s/", hostname)
		pairs, _, err := kv.List(keyfix, q1)
		if err != nil {
			w.Err("[ERROR > lib/cleaner.go:56]@[CONSUL] it was not possible to get the KV pairs.")
			code = 1
			return code
		}

		for i := 0; i < len(pairs); i++ {
			value := string(pairs[i].Value[:])
			if strings.Contains(value, "#deleted") && strings.Contains(value, RealDataset) {
				key := pairs[i].Key
				pair := fmt.Sprintf("%s:%s", key, value)

				// Destroy KV pairs with #deleted flag
				q2 := &api.WriteOptions{Datacenter: datacenter}
				_, err = kv.Delete(key, q2)
				if err != nil {
					w.Err("[ERROR > lib/cleaner.go:71]@[CONSUL] it was not possible to destroy the KV pair '"+pair+"'.")
					code = 1
				} else {
					w.Info("[INFO]@[CONSUL] the KV pair '"+pair+"' has been destroyed.")
					code = 0
				}
				continue
			} else {
				code = 0
				continue
			}
		}
		return code
	} else {
		w.Err("[ERROR > lib/cleaner.go:24] the dataset '"+RealDataset+"' has not a datacenter configured.")
		code = 1
		return code
	}
}
<commit_msg>Golint cleaner.go<commit_after>// Package lib contains: actions.go - cleaner.go - commands.go - destroy.go - snapshot.go - sync.go - take.go - uuid.go
//
// Cleaner removes all keys with the flag #deleted at the datacenter indicated
//
package lib

import (
	"fmt"
	"os"
	"strings"

	"github.com/nfrance-conseil/zeplic/config"
	"github.com/hashicorp/consul/api"
)

// Cleaner deletes all KV pairs with #deleted flag in dataset
func Cleaner(RealDataset string) int {
	// Search the dataset
	var datacenter string
	j, _, _ := config.JSON()
	for i := 0; i < j; i++ {
		pieces := config.Extract(i)
		dataset := pieces[2].(string)
		if RealDataset == dataset {
			datacenter = pieces[4].(string)
			break
		} else {
			continue
		}
	}

	var code int
	if datacenter != "" {
		// Resolve hostname
		hostname, err := os.Hostname()
		if err != nil {
			w.Err("[ERROR > lib/cleaner.go:35] it was not possible to resolve the hostname.")
			code = 1
			return code
		}

		// Create a new client
		client, err := api.NewClient(api.DefaultConfig())
		if err != nil {
			w.Err("[ERROR > lib/cleaner.go:43]@[CONSUL] it was not possible to create a new client.")
			code = 1
			return code
		}
		kv := client.KV()

		// KV write options
		q1 := &api.QueryOptions{Datacenter: datacenter}

		// Get KV pairs
		keyfix := fmt.Sprintf("zeplic/%s/", hostname)
		pairs, _, err := kv.List(keyfix, q1)
		if err != nil {
			w.Err("[ERROR > lib/cleaner.go:56]@[CONSUL] it was not possible to get the KV pairs.")
			code = 1
			return code
		} else {
			for i := 0; i < len(pairs); i++ {
				value := string(pairs[i].Value[:])
				if strings.Contains(value, "#deleted") && strings.Contains(value, RealDataset) {
					key := pairs[i].Key
					pair := fmt.Sprintf("%s:%s", key, value)

					// Destroy KV pairs with #deleted flag
					q2 := &api.WriteOptions{Datacenter: datacenter}
					_, err = kv.Delete(key, q2)
					if err != nil {
						w.Err("[ERROR > lib/cleaner.go:71]@[CONSUL] it was not possible to destroy the KV pair '"+pair+"'.")
						code = 1
						break
					} else {
						w.Info("[INFO]@[CONSUL] the KV pair '"+pair+"' has been destroyed.")
						code = 0
						continue
					}
				} else {
					code = 0
					continue
				}
			}
			return code
		}
	} else {
		w.Err("[ERROR > lib/cleaner.go:24] the dataset '"+RealDataset+"' has not a datacenter configured.")
		code = 1
		return code
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package flags provides an extensive command line option parser.
// The flags package is similar in functionality to the go builtin flag package
// but provides more options and uses reflection to provide a convenient and
// succinct way of specifying command line options.
//
// Supported features:
//     Options with short names (-v)
//     Options with long names (--verbose)
//     Options with and without arguments (bool v.s. other type)
//     Options with optional arguments and default values
//     Multiple option groups each containing a set of options
//     Generate and print well-formatted help message
//     Passing remaining command line arguments after -- (optional)
//     Ignoring unknown command line options (optional)
//     Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
//     Supports multiple short options -aux
//     Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
//     Supports same option multiple times (can store in slice or last option counts)
//     Supports maps
//     Supports function callbacks
//
// The flags package uses structs, reflection and struct field tags
// to allow users to specify command line options. This results in very simple
// and consise specification of your application options. For example:
//
//     type Options struct {
//         Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
//     }
//
// This specifies one option with a short name -v and a long name --verbose.
// When either -v or --verbose is found on the command line, a 'true' value
// will be appended to the Verbose field. e.g. when specifying -vvv, the
// resulting value of Verbose will be {[true, true, true]}.
//
// Available field tags:
//     short:       the short name of the option (single character)
//     long:        the long name of the option
//     description: the description of the option (optional)
//     optional:    whether an argument of the option is optional (optional)
//     default:     the default argument value if the option occurs without
//                  an argument (optional)
//     base:        a base used to convert strings to integer values (optional)
//
// Either short: or long: must be specified to make the field eligible as an
// option.
package flags
<commit_msg>Added value-name tag to available field tags in package doc<commit_after>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package flags provides an extensive command line option parser.
// The flags package is similar in functionality to the go builtin flag package
// but provides more options and uses reflection to provide a convenient and
// succinct way of specifying command line options.
//
// Supported features:
//     Options with short names (-v)
//     Options with long names (--verbose)
//     Options with and without arguments (bool v.s. other type)
//     Options with optional arguments and default values
//     Multiple option groups each containing a set of options
//     Generate and print well-formatted help message
//     Passing remaining command line arguments after -- (optional)
//     Ignoring unknown command line options (optional)
//     Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
//     Supports multiple short options -aux
//     Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
//     Supports same option multiple times (can store in slice or last option counts)
//     Supports maps
//     Supports function callbacks
//
// The flags package uses structs, reflection and struct field tags
// to allow users to specify command line options. This results in very simple
// and consise specification of your application options. For example:
//
//     type Options struct {
//         Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
//     }
//
// This specifies one option with a short name -v and a long name --verbose.
// When either -v or --verbose is found on the command line, a 'true' value
// will be appended to the Verbose field. e.g. when specifying -vvv, the
// resulting value of Verbose will be {[true, true, true]}.
//
// Available field tags:
//     short:       the short name of the option (single character)
//     long:        the long name of the option
//     description: the description of the option (optional)
//     optional:    whether an argument of the option is optional (optional)
//     default:     the default argument value if the option occurs without
//                  an argument (optional)
//     base:        a base used to convert strings to integer values (optional)
//     value-name:  the name of the argument value (to be shown in the help, optional)
//
// Either short: or long: must be specified to make the field eligible as an
// option.
package flags
<|endoftext|>


<commit_before>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016-2018
	All Rights Reserved
	Documentation http://djthorpe.github.io/gopi/
	For Licensing and Usage information, please see LICENSE.md
*/

package gopi

import "os"

////////////////////////////////////////////////////////////////////////////////
// TYPES

// Font flags
type FontFlags uint16

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

// FontManager for font management
type FontManager interface {
	Driver

	// Open a font face - first face at index 0 is loaded
	OpenFace(path string) (FontFace, error)

	// Open a font face - indexed within file of several faces
	OpenFaceAtIndex(path string, index uint) (FontFace, error)

	// Open font faces at path, checking to see if individual files should
	// be opened through a callback function
	OpenFacesAtPath(path string, callback func(path string, info os.FileInfo) bool) error

	// Destroy a font face
	DestroyFace(FontFace) error

	// Return an array of font families which are loaded
	Families() []string

	// Return faces in a family and/or with a particular set of attributes
	Faces(family string, flags FontFlags) []FontFace
}

// Abstract font face interface
type FontFace interface {

	// Get Face Name (from the filename)
	Name() string

	// Get Face Index
	Index() uint

	// Get Number of faces within the file
	NumFaces() uint

	// Number of glyphs for the face
	NumGlyphs() uint

	// Return name of font family
	Family() string

	// Return style name of font face
	Style() string

	// Return properties for face
	Flags() FontFlags
}

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

const (
	FONT_FLAGS_NONE             FontFlags = 0x0000
	FONT_FLAGS_STYLE_REGULAR    FontFlags = 0x0001
	FONT_FLAGS_STYLE_BOLD       FontFlags = 0x0002
	FONT_FLAGS_STYLE_ITALIC     FontFlags = 0x0004
	FONT_FLAGS_STYLE_BOLDITALIC FontFlags = 0x0006
	FONT_FLAGS_STYLE_ANY        FontFlags = 0x0007
)
<commit_msg>Updated font interface<commit_after>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016-2018
	All Rights Reserved
	Documentation http://djthorpe.github.io/gopi/
	For Licensing and Usage information, please see LICENSE.md
*/

package gopi

import "os"

////////////////////////////////////////////////////////////////////////////////
// TYPES

// Font flags
type FontFlags uint16

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

// FontManager for font management
type FontManager interface {
	Driver

	// Open a font face - first face at index 0 is loaded
	OpenFace(path string) (FontFace, error)

	// Open a font face - indexed within file of several faces
	OpenFaceAtIndex(path string, index uint) (FontFace, error)

	// Open font faces at path, checking to see if individual files should
	// be opened through a callback function
	OpenFacesAtPath(path string, callback func(path string, info os.FileInfo) bool) error

	// Destroy a font face
	DestroyFace(FontFace) error

	// Return an array of font families which are loaded
	Families() []string

	// Return open face for filepath
	FaceForPath(path string) FontFace

	// Return faces in a family and/or with a particular set of attributes
	Faces(family string, flags FontFlags) []FontFace
}

// Abstract font face interface
type FontFace interface {

	// Get Face Name (from the filename)
	Name() string

	// Get Face Index
	Index() uint

	// Get Number of faces within the file
	NumFaces() uint

	// Number of glyphs for the face
	NumGlyphs() uint

	// Return name of font family
	Family() string

	// Return style name of font face
	Style() string

	// Return properties for face
	Flags() FontFlags
}

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

const (
	FONT_FLAGS_NONE             FontFlags = 0x0000
	FONT_FLAGS_STYLE_REGULAR    FontFlags = 0x0001
	FONT_FLAGS_STYLE_BOLD       FontFlags = 0x0002
	FONT_FLAGS_STYLE_ITALIC     FontFlags = 0x0004
	FONT_FLAGS_STYLE_BOLDITALIC FontFlags = 0x0006
	FONT_FLAGS_STYLE_ANY        FontFlags = 0x0007
)
<|endoftext|>


<commit_before>// Package sensu implements simple methods to interact with Sensu API.
package sensu

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

// Sensu struct contains the API details
type Sensu struct {
	Name    string
	Path    string
	URL     string
	Timeout int
	User    string
	Pass    string
}

// New Initialize a new Sensu API
func New(name string, path string, url string, timeout int, username string, password string) *Sensu {
	return &Sensu{name, path, url, timeout, username, password}
}

// Health The health endpoint checks to see if the api can connect to redis and rabbitmq. It takes parameters for minimum consumers and maximum messages and checks rabbitmq.
func (s *Sensu) Health(consumers int, messages int) (map[string]interface{}, error) {
	fmt.Printf("FIXME health args")
	return s.Get(fmt.Sprintf("health/%d/%d", consumers, messages))
}

// Info Will return the Sensu version along with rabbitmq and redis information.
func (s *Sensu) Info() (map[string]interface{}, error) {
	return s.Get("info")
}

// Get ...
func (s *Sensu) Get(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0
	fmt.Printf("DEBUG: Get endpoint = %s", endpoint)
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Sensu.Get Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("Sensu.Get Error calling Sensu API: %q returned: %v", err, err)
	}
	return s.doJSON(res)
}

// GetList Construct an API call and return the list of results
func (s *Sensu) GetList(endpoint string, limit int, offset int) ([]interface{}, error) {

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Sensu.GetList URL Parsing error: %q returned: %v", err, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("Sensu.GetList Error calling Sensu API: %q returned: %v", err, err)
	}
	return s.doJSONArray(res)
}

func (s *Sensu) doHTTP(req *http.Request) ([]byte, error) {

	if s.User != "" && s.Pass != "" {
		req.SetBasicAuth(s.User, s.Pass)
	}

	client := http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("HTTP request returned: %v", err)
	}
	if res.StatusCode >= 400 {
		return nil, fmt.Errorf("Error calling API at %s: %s", s.URL, res.Status)
	}

	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("Parsing response body returned: %v", err)
	}
	return body, nil
}

// doJsonArray Unmarshall JSON expecting an array
func (s *Sensu) doJSONArray(body []byte) ([]interface{}, error) {
	var results []interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}
	return results, nil
}

// doJsonArray Unmarshall JSON expecting a map
func (s *Sensu) doJSON(body []byte) (map[string]interface{}, error) {
	var results map[string]interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}
	return results, nil
}

// Post to endpoint
func (s *Sensu) Post(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Sensu.Post Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("Sensu.GetList Error calling Sensu API: %q returned: %v", err, err)
	}
	return s.doJSON(res)
}

// PostPayload to endpoint
func (s *Sensu) PostPayload(endpoint string, payload string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("POST", url, strings.NewReader(payload))
	if err != nil {
		return nil, fmt.Errorf("Sensu.PostPayload Parsing error: %q returned: %v", err, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("Sensu.GetList Error calling Sensu API: %q returned: %v", err, err)
	}
	return s.doJSON(res)
}

// Delete resource
func (s *Sensu) Delete(endpoint string) (map[string]interface{}, error) {
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Sensu.Delete Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("Sensu.Delete Error calling Sensu API: %q returned: %v", err, err)
	}
	return s.doJSON(res)
}
<commit_msg>Simplify error messages<commit_after>// Package sensu implements simple methods to interact with Sensu API.
package sensu

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

// Sensu struct contains the API details
type Sensu struct {
	Name    string
	Path    string
	URL     string
	Timeout int
	User    string
	Pass    string
}

// New Initialize a new Sensu API
func New(name string, path string, url string, timeout int, username string, password string) *Sensu {
	return &Sensu{name, path, url, timeout, username, password}
}

// Health The health endpoint checks to see if the api can connect to redis and rabbitmq. It takes parameters for minimum consumers and maximum messages and checks rabbitmq.
func (s *Sensu) Health(consumers int, messages int) (map[string]interface{}, error) {
	fmt.Printf("FIXME health args")
	return s.Get(fmt.Sprintf("health/%d/%d", consumers, messages))
}

// Info Will return the Sensu version along with rabbitmq and redis information.
func (s *Sensu) Info() (map[string]interface{}, error) {
	return s.Get("info")
}

// Get ...
func (s *Sensu) Get(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0
	fmt.Printf("DEBUG: Get endpoint = %s", endpoint)
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// GetList Construct an API call and return the list of results
func (s *Sensu) GetList(endpoint string, limit int, offset int) ([]interface{}, error) {

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("URL Parsing error: %q returned: %v", url, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSONArray(res)
}

func (s *Sensu) doHTTP(req *http.Request) ([]byte, error) {

	if s.User != "" && s.Pass != "" {
		req.SetBasicAuth(s.User, s.Pass)
	}

	client := http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("%v", err)
	}
	if res.StatusCode >= 400 {
		return nil, fmt.Errorf("%v", res.Status)
	}

	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("Parsing response body returned: %v", err)
	}
	return body, nil
}

// doJsonArray Unmarshall JSON expecting an array
func (s *Sensu) doJSONArray(body []byte) ([]interface{}, error) {
	var results []interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}
	return results, nil
}

// doJsonArray Unmarshall JSON expecting a map
func (s *Sensu) doJSON(body []byte) (map[string]interface{}, error) {
	var results map[string]interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}
	return results, nil
}

// Post to endpoint
func (s *Sensu) Post(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", url, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// PostPayload to endpoint
func (s *Sensu) PostPayload(endpoint string, payload string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("POST", url, strings.NewReader(payload))
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", url, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// Delete resource
func (s *Sensu) Delete(endpoint string) (map[string]interface{}, error) {
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}
<|endoftext|>


<commit_before>// This app is intented to be go-port of the defunckt's gist library in Ruby
// Currently, uploading single and multiple files are available.
// You can also create secret gists, and both anonymous and user gists.
//
// Author: Viyat Bhalodia
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

//Defines the app version
const VERSION = "v0.1.0"

//#TODO: A list of clipboard commands with copy and paste support.
//This is intended for adding the gist URLs directly to the user clipboard,
//so that manual copying is not needed.
const (
	xclip   = "xclip -o"
	xsel    = "xsel -o"
	pbcopy  = "pbpaste"
	putclip = "getclip"
)

// Defines different constants used
// GIT_IO_URL is the Github's URL shortner
// API v3 is the current version of GitHub API
const (
	GITHUB_API_URL = "https://api.github.com/"
	GIT_IO_URL     = "http://git.io"
	GHE_BASE_PATH  = "/api/v3"
)

//User agent defines a custom agent (required by GitHub)
//`token` stores the GITHUB_TOKEN from the env variables
var (
	USER_AGENT = "gist/#" + VERSION //Github requires this, else rejects API request
	token      = os.Getenv("GITHUB_TOKEN")
)

// Variables used in `Gist` struct
var (
	publicFlag  bool
	description string
	anonymous   bool
	responseObj map[string]interface{}
)

//The top-level struct for a gist file
type GistFile struct {
	Content string `json:"content"`
}

//The required structure for POST data for API purposes
type Gist struct {
	Description string              `json:"description"`
	publicFile  bool                `json:"public"`
	GistFile    map[string]GistFile `json:"files"`
}

//This function loads the GITHUB_TOKEN from a '$HOME/.gist' file
//from the user's home directory.
func loadTokenFromFile() (token string) {
	//get the tokenfile
	file := os.Getenv("$HOME") + "/.gist"
	github_token, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatal(err)
	}
	return string(github_token)
}

//Defines basic usage when program is run with the help flag
func usage() {
	fmt.Fprintf(os.Stderr, "usage: gist [-p] [-d] [-u] example.go\n")
	flag.PrintDefaults()
	os.Exit(2)
}

//The main function parses the CLI args. It also checks the files, and
//loads them into an array.
//Then the files are separated into GistFile structs and collectively
//the files are saved in `files` field in the Gist struct.
//A request is then made to the GitHub api - it depends on whether it is
//anonymous gist or not.
//The response recieved is parsed and the Gist URL is printed to STDOUT.
func main() {
	flag.BoolVar(&publicFlag, "p", true, "Set to false for private gist.")
	flag.BoolVar(&anonymous, "u", true, "Set false if gist should be not anonymous")
	flag.StringVar(&description, "d", "This is a gist", "Description for gist.")
	flag.Usage = usage
	flag.Parse()

	files_list := flag.Args()
	if len(files_list) == 0 {
		log.Fatal("Error: No files specified.")
	}

	//fmt.Println(files_list)
	//fmt.Println(token)

	files := map[string]GistFile{}

	for _, filename := range files_list {
		fmt.Println("Checking file:", filename)
		content, err := ioutil.ReadFile(filename)
		if err != nil {
			log.Fatal("File Error: ", err)
		}
		files[filename] = GistFile{string(content)}
	}

	if description == "" {
		description = strings.Join(files_list, ", ")
	}

	//create a gist from the files array
	gist := Gist{
		description,
		publicFlag,
		files,
	}

	pfile, err := json.Marshal(gist)
	if err != nil {
		log.Fatal("Cannot marshal json: ", err)
	}

	//Check if JSON marshalling succeeds
	fmt.Println("OK")

	b := bytes.NewBuffer(pfile)
	fmt.Println("Uploading...")

	//Separate uploading methods depending on whether the gist is anonymous or not
	if anonymous == true {
		response, err := http.Post("https://api.github.com/gists", "application/json", b)
		if err != nil {
			log.Fatal("HTTP error: ", err)
		}

		err = json.NewDecoder(response.Body).Decode(&responseObj)
		if err != nil {
			log.Fatal("Response JSON error: ", err)
		}

		fmt.Println("--- Gist URL ---")
		fmt.Println(responseObj["html_url"])
	} else {
		req, err := http.NewRequest("POST", "https://api.github.com/gists", b)
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Accept", "application/json")
		req.SetBasicAuth(token, "x-oauth-basic")

		client := http.Client{}
		response, err := client.Do(req)
		if err != nil {
			log.Fatal("HTTP error: ", err)
		}
		err = json.NewDecoder(response.Body).Decode(&responseObj)
		if err != nil {
			log.Fatal("Response JSON error: ", err)
		}

		fmt.Println("--- Gist URL ---")
		fmt.Println(responseObj["html_url"])
	}
}
<commit_msg>Small refactor to API request code, to remove some duplication.<commit_after>// This app is intented to be go-port of the defunckt's gist library in Ruby
// Currently, uploading single and multiple files are available.
// You can also create secret gists, and both anonymous and user gists.
//
// Author: Viyat Bhalodia
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

//Defines the app version
const VERSION = "v0.1.0"

//#TODO: A list of clipboard commands with copy and paste support.
//This is intended for adding the gist URLs directly to the user clipboard,
//so that manual copying is not needed.
const (
	xclip   = "xclip -o"
	xsel    = "xsel -o"
	pbcopy  = "pbpaste"
	putclip = "getclip"
)

// Defines different constants used
// GIT_IO_URL is the Github's URL shortner
// API v3 is the current version of GitHub API
const (
	GITHUB_API_URL = "https://api.github.com/"
	GIT_IO_URL     = "http://git.io"
	GHE_BASE_PATH  = "/api/v3"
)

//User agent defines a custom agent (required by GitHub)
//`token` stores the GITHUB_TOKEN from the env variables
var (
	USER_AGENT = "gist/#" + VERSION //Github requires this, else rejects API request
	token      = os.Getenv("GITHUB_TOKEN")
)

// Variables used in `Gist` struct
var (
	publicFlag  bool
	description string
	anonymous   bool
	responseObj map[string]interface{}
)

//The top-level struct for a gist file
type GistFile struct {
	Content string `json:"content"`
}

//The required structure for POST data for API purposes
type Gist struct {
	Description string              `json:"description"`
	publicFile  bool                `json:"public"`
	GistFile    map[string]GistFile `json:"files"`
}

//This function loads the GITHUB_TOKEN from a '$HOME/.gist' file
//from the user's home directory.
func loadTokenFromFile() (token string) {
	//get the tokenfile
	file := os.Getenv("$HOME") + "/.gist"
	github_token, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatal(err)
	}
	return string(github_token)
}

//Defines basic usage when program is run with the help flag
func usage() {
	fmt.Fprintf(os.Stderr, "usage: gist [-p] [-d] [-u] example.go\n")
	flag.PrintDefaults()
	os.Exit(2)
}

//The main function parses the CLI args. It also checks the files, and
//loads them into an array.
//Then the files are separated into GistFile structs and collectively
//the files are saved in `files` field in the Gist struct.
//A request is then made to the GitHub api - it depends on whether it is
//anonymous gist or not.
//The response recieved is parsed and the Gist URL is printed to STDOUT.
func main() {
	flag.BoolVar(&publicFlag, "p", true, "Set to false for private gist.")
	flag.BoolVar(&anonymous, "u", true, "Set false if gist should be not anonymous")
	flag.StringVar(&description, "d", "This is a gist", "Description for gist.")
	flag.Usage = usage
	flag.Parse()

	files_list := flag.Args()
	if len(files_list) == 0 {
		log.Fatal("Error: No files specified.")
	}

	//fmt.Println(files_list)
	//fmt.Println(token)

	files := map[string]GistFile{}

	for _, filename := range files_list {
		fmt.Println("Checking file:", filename)
		content, err := ioutil.ReadFile(filename)
		if err != nil {
			log.Fatal("File Error: ", err)
		}
		files[filename] = GistFile{string(content)}
	}

	if description == "" {
		description = strings.Join(files_list, ", ")
	}

	//create a gist from the files array
	gist := Gist{
		description,
		publicFlag,
		files,
	}

	pfile, err := json.Marshal(gist)
	if err != nil {
		log.Fatal("Cannot marshal json: ", err)
	}

	//Check if JSON marshalling succeeds
	fmt.Println("OK")

	b := bytes.NewBuffer(pfile)
	fmt.Println("Uploading...")

	// Send request to API

	req, err := http.NewRequest("POST", "https://api.github.com/gists", b)

	if !anonymous {
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Accept", "application/json")
		req.SetBasicAuth(token, "x-oauth-basic")
	}

	client := http.Client{}
	response, err := client.Do(req)
	if err != nil {
		log.Fatal("HTTP error: ", err)
	}
	err = json.NewDecoder(response.Body).Decode(&responseObj)
	if err != nil {
		log.Fatal("Response JSON error: ", err)
	}

	fmt.Println("--- Gist URL ---")
	fmt.Println(responseObj["html_url"])
}
<|endoftext|>


<commit_before>// Copyright 2011 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 build gathers information about Go packages.
//
// Go Path
//
// The Go path is a list of directory trees containing Go source code.
// It is consulted to resolve imports that cannot be found in the standard
// Go tree.  The default path is the value of the GOPATH environment
// variable, interpreted as a path list appropriate to the operating system
// (on Unix, the variable is a colon-separated string;
// on Windows, a semicolon-separated string;
// on Plan 9, a list).
//
// Each directory listed in the Go path must have a prescribed structure:
//
// The src/ directory holds source code.  The path below 'src' determines
// the import path or executable name.
//
// The pkg/ directory holds installed package objects.
// As in the Go tree, each target operating system and
// architecture pair has its own subdirectory of pkg
// (pkg/GOOS_GOARCH).
//
// If DIR is a directory listed in the Go path, a package with
// source in DIR/src/foo/bar can be imported as "foo/bar" and
// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a"
// (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a").
//
// The bin/ directory holds compiled commands.
// Each command is named for its source directory, but only
// using the final element, not the entire path.  That is, the
// command with source in DIR/src/foo/quux is installed into
// DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
// so that you can add DIR/bin to your PATH to get at the
// installed commands.
//
// Here's an example directory layout:
//
//	GOPATH=/home/user/gocode
//
//	/home/user/gocode/
//	    src/
//	        foo/
//	            bar/               (go code in package bar)
//	                x.go
//	            quux/              (go code in package main)
//	                y.go
//	    bin/
//	        quux                   (installed command)
//	    pkg/
//	        linux_amd64/
//	            foo/
//	                bar.a          (installed package object)
//
// Build Constraints
//
// A build constraint is a line comment beginning with the directive +build
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
// only by blank lines and other line comments.
//
// A build constraint is evaluated as the OR of space-separated options;
// each option evaluates as the AND of its comma-separated terms;
// and each term is an alphanumeric word or, preceded by !, its negation.
// That is, the build constraint:
//
//	// +build linux,386 darwin,!cgo
//
// corresponds to the boolean formula:
//
//	(linux AND 386) OR (darwin AND (NOT cgo))
//
// During a particular build, the following words are satisfied:
//
//	- the target operating system, as spelled by runtime.GOOS
//	- the target architecture, as spelled by runtime.GOARCH
//	- "cgo", if ctxt.CgoEnabled is true
//	- any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
// system and architecture values, then the file is considered to have an implicit
// build constraint requiring those terms.
//
// To keep a file from being considered for the build:
//
//	// +build ignore
//
// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
//
// To build a file only when using cgo, and only on Linux and OS X:
//
//	// +build linux,cgo darwin,cgo
//
// Such a file is usually paired with another file implementing the
// default functionality for other systems, which in this case would
// carry the constraint:
//
//	// +build !linux,!darwin !cgo
//
// Naming a file dns_windows.go will cause it to be included only when
// building the package for Windows; similarly, math_386.s will be included
// only when building the package for 32-bit x86.
//
package build
<commit_msg>go/build: document the behavior of multiple build constraints.<commit_after>// Copyright 2011 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 build gathers information about Go packages.
//
// Go Path
//
// The Go path is a list of directory trees containing Go source code.
// It is consulted to resolve imports that cannot be found in the standard
// Go tree.  The default path is the value of the GOPATH environment
// variable, interpreted as a path list appropriate to the operating system
// (on Unix, the variable is a colon-separated string;
// on Windows, a semicolon-separated string;
// on Plan 9, a list).
//
// Each directory listed in the Go path must have a prescribed structure:
//
// The src/ directory holds source code.  The path below 'src' determines
// the import path or executable name.
//
// The pkg/ directory holds installed package objects.
// As in the Go tree, each target operating system and
// architecture pair has its own subdirectory of pkg
// (pkg/GOOS_GOARCH).
//
// If DIR is a directory listed in the Go path, a package with
// source in DIR/src/foo/bar can be imported as "foo/bar" and
// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a"
// (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a").
//
// The bin/ directory holds compiled commands.
// Each command is named for its source directory, but only
// using the final element, not the entire path.  That is, the
// command with source in DIR/src/foo/quux is installed into
// DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
// so that you can add DIR/bin to your PATH to get at the
// installed commands.
//
// Here's an example directory layout:
//
//	GOPATH=/home/user/gocode
//
//	/home/user/gocode/
//	    src/
//	        foo/
//	            bar/               (go code in package bar)
//	                x.go
//	            quux/              (go code in package main)
//	                y.go
//	    bin/
//	        quux                   (installed command)
//	    pkg/
//	        linux_amd64/
//	            foo/
//	                bar.a          (installed package object)
//
// Build Constraints
//
// A build constraint is a line comment beginning with the directive +build
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
// only by blank lines and other line comments.
//
// A build constraint is evaluated as the OR of space-separated options;
// each option evaluates as the AND of its comma-separated terms;
// and each term is an alphanumeric word or, preceded by !, its negation.
// That is, the build constraint:
//
//	// +build linux,386 darwin,!cgo
//
// corresponds to the boolean formula:
//
//	(linux AND 386) OR (darwin AND (NOT cgo))
//
// A file may have multiple build constraints. The overall constraint is the AND
// of the individual constraints. That is, the build constraints:
//
//	// +build linux darwin
//	// +build 386
//
// corresponds to the boolean formula:
//
//	(linux OR darwin) AND 386
//
// During a particular build, the following words are satisfied:
//
//	- the target operating system, as spelled by runtime.GOOS
//	- the target architecture, as spelled by runtime.GOARCH
//	- "cgo", if ctxt.CgoEnabled is true
//	- any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
// system and architecture values, then the file is considered to have an implicit
// build constraint requiring those terms.
//
// To keep a file from being considered for the build:
//
//	// +build ignore
//
// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
//
// To build a file only when using cgo, and only on Linux and OS X:
//
//	// +build linux,cgo darwin,cgo
//
// Such a file is usually paired with another file implementing the
// default functionality for other systems, which in this case would
// carry the constraint:
//
//	// +build !linux,!darwin !cgo
//
// Naming a file dns_windows.go will cause it to be included only when
// building the package for Windows; similarly, math_386.s will be included
// only when building the package for 32-bit x86.
//
package build
<|endoftext|>


<commit_before>// Copyright 2011 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 http provides HTTP client and server implementations.

Get, Head, Post, and PostForm make HTTP requests:

	resp, err := http.Get("http://example.com/")
	...
	resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
	...
	resp, err := http.PostForm("http://example.com/form",
 		url.Values{"key": {"Value"}, "id": {"123"}})

The client must close the response body when finished with it:

	resp, err := http.Get("http://example.com/")
	if err != nil {
		// handle error
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	// ...

For control over HTTP client headers, redirect policy, and other
settings, create a Client:

	client := &http.Client{
		CheckRedirect: redirectPolicyFunc,
	}

	resp, err := client.Get("http://example.com")
	// ...

	req, err := http.NewRequest("GET", "http://example.com", nil)
	// ...
	req.Header.Add("If-None-Match", `W/"wyzzy"`)
	resp, err := client.Do(req)
	// ...

For control over proxies, TLS configuration, keep-alives,
compression, and other settings, create a Transport:

	tr := &http.Transport{
		TLSClientConfig:    &tls.Config{RootCAs: pool},
		DisableCompression: true,
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get("https://example.com")

Clients and Transports are safe for concurrent use by multiple
goroutines and for efficiency should only be created once and re-used.

ListenAndServe starts an HTTP server with a given address and handler.
The handler is usually nil, which means to use DefaultServeMux.
Handle and HandleFunc add handlers to DefaultServeMux:

	http.Handle("/foo", fooHandler)

	http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.RawPath))
	})

	log.Fatal(http.ListenAndServe(":8080", nil))

More control over the server's behavior is available by creating a
custom Server:

	s := &http.Server{
		Addr:           ":8080",
		Handler:        myHandler,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Fatal(s.ListenAndServe())
*/
package http
<commit_msg>net/http: remove an errant space<commit_after>// Copyright 2011 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 http provides HTTP client and server implementations.

Get, Head, Post, and PostForm make HTTP requests:

	resp, err := http.Get("http://example.com/")
	...
	resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
	...
	resp, err := http.PostForm("http://example.com/form",
		url.Values{"key": {"Value"}, "id": {"123"}})

The client must close the response body when finished with it:

	resp, err := http.Get("http://example.com/")
	if err != nil {
		// handle error
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	// ...

For control over HTTP client headers, redirect policy, and other
settings, create a Client:

	client := &http.Client{
		CheckRedirect: redirectPolicyFunc,
	}

	resp, err := client.Get("http://example.com")
	// ...

	req, err := http.NewRequest("GET", "http://example.com", nil)
	// ...
	req.Header.Add("If-None-Match", `W/"wyzzy"`)
	resp, err := client.Do(req)
	// ...

For control over proxies, TLS configuration, keep-alives,
compression, and other settings, create a Transport:

	tr := &http.Transport{
		TLSClientConfig:    &tls.Config{RootCAs: pool},
		DisableCompression: true,
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get("https://example.com")

Clients and Transports are safe for concurrent use by multiple
goroutines and for efficiency should only be created once and re-used.

ListenAndServe starts an HTTP server with a given address and handler.
The handler is usually nil, which means to use DefaultServeMux.
Handle and HandleFunc add handlers to DefaultServeMux:

	http.Handle("/foo", fooHandler)

	http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.RawPath))
	})

	log.Fatal(http.ListenAndServe(":8080", nil))

More control over the server's behavior is available by creating a
custom Server:

	s := &http.Server{
		Addr:           ":8080",
		Handler:        myHandler,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Fatal(s.ListenAndServe())
*/
package http
<|endoftext|>


<commit_before>// Copyright 2009 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.

// Binary to decimal floating point conversion.
// Algorithm:
//   1) store mantissa in multiprecision decimal
//   2) shift decimal by exponent
//   3) read digits out & format

package strconv

import "math"

// TODO: move elsewhere?
type floatInfo struct {
	mantbits uint
	expbits  uint
	bias     int
}

var float32info = floatInfo{23, 8, -127}
var float64info = floatInfo{52, 11, -1023}

// FormatFloat converts the floating-point number f to a string,
// according to the format fmt and precision prec.  It rounds the
// result assuming that the original was obtained from a floating-point
// value of bitSize bits (32 for float32, 64 for float64).
//
// The format fmt is one of
// 'b' (-ddddp±ddd, a binary exponent),
// 'e' (-d.dddde±dd, a decimal exponent),
// 'E' (-d.ddddE±dd, a decimal exponent),
// 'f' (-ddd.dddd, no exponent),
// 'g' ('e' for large exponents, 'f' otherwise), or
// 'G' ('E' for large exponents, 'f' otherwise).
//
// The precision prec controls the number of digits
// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
// For 'g' and 'G' it is the total number of digits.
// The special precision -1 uses the smallest number of digits
// necessary such that ParseFloat will return f exactly.
func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
	return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
}

// AppendFloat appends the string form of the floating-point number f,
// as generated by FormatFloat, to dst and returns the extended buffer.
func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte {
	return genericFtoa(dst, f, fmt, prec, bitSize)
}

func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
	var bits uint64
	var flt *floatInfo
	switch bitSize {
	case 32:
		bits = uint64(math.Float32bits(float32(val)))
		flt = &float32info
	case 64:
		bits = math.Float64bits(val)
		flt = &float64info
	default:
		panic("strconv: illegal AppendFloat/FormatFloat bitSize")
	}

	neg := bits>>(flt.expbits+flt.mantbits) != 0
	exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
	mant := bits & (uint64(1)<<flt.mantbits - 1)

	switch exp {
	case 1<<flt.expbits - 1:
		// Inf, NaN
		var s string
		switch {
		case mant != 0:
			s = "NaN"
		case neg:
			s = "-Inf"
		default:
			s = "+Inf"
		}
		return append(dst, s...)

	case 0:
		// denormalized
		exp++

	default:
		// add implicit top bit
		mant |= uint64(1) << flt.mantbits
	}
	exp += flt.bias

	// Pick off easy binary format.
	if fmt == 'b' {
		return fmtB(dst, neg, mant, exp, flt)
	}

	// Create exact decimal representation.
	// The shift is exp - flt.mantbits because mant is a 1-bit integer
	// followed by a flt.mantbits fraction, and we are treating it as
	// a 1+flt.mantbits-bit integer.
	d := new(decimal)
	d.Assign(mant)
	d.Shift(exp - int(flt.mantbits))

	// Round appropriately.
	// Negative precision means "only as much as needed to be exact."
	shortest := false
	if prec < 0 {
		shortest = true
		roundShortest(d, mant, exp, flt)
		switch fmt {
		case 'e', 'E':
			prec = d.nd - 1
		case 'f':
			prec = max(d.nd-d.dp, 0)
		case 'g', 'G':
			prec = d.nd
		}
	} else {
		switch fmt {
		case 'e', 'E':
			d.Round(prec + 1)
		case 'f':
			d.Round(d.dp + prec)
		case 'g', 'G':
			if prec == 0 {
				prec = 1
			}
			d.Round(prec)
		}
	}

	switch fmt {
	case 'e', 'E':
		return fmtE(dst, neg, d, prec, fmt)
	case 'f':
		return fmtF(dst, neg, d, prec)
	case 'g', 'G':
		// trailing fractional zeros in 'e' form will be trimmed.
		eprec := prec
		if eprec > d.nd && d.nd >= d.dp {
			eprec = d.nd
		}
		// %e is used if the exponent from the conversion
		// is less than -4 or greater than or equal to the precision.
		// if precision was the shortest possible, use precision 6 for this decision.
		if shortest {
			eprec = 6
		}
		exp := d.dp - 1
		if exp < -4 || exp >= eprec {
			if prec > d.nd {
				prec = d.nd
			}
			return fmtE(dst, neg, d, prec-1, fmt+'e'-'g')
		}
		if prec > d.dp {
			prec = d.nd
		}
		return fmtF(dst, neg, d, max(prec-d.dp, 0))
	}

	// unknown format
	return append(dst, '%', fmt)
}

// Round d (= mant * 2^exp) to the shortest number of digits
// that will let the original floating point value be precisely
// reconstructed.  Size is original floating point size (64 or 32).
func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
	// If mantissa is zero, the number is zero; stop now.
	if mant == 0 {
		d.nd = 0
		return
	}

	// TODO(rsc): Unless exp == minexp, if the number of digits in d
	// is less than 17, it seems likely that it would be
	// the shortest possible number already.  So maybe we can
	// bail out without doing the extra multiprecision math here.

	// Compute upper and lower such that any decimal number
	// between upper and lower (possibly inclusive)
	// will round to the original floating point number.

	// d = mant << (exp - mantbits)
	// Next highest floating point number is mant+1 << exp-mantbits.
	// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
	upper := new(decimal)
	upper.Assign(mant*2 + 1)
	upper.Shift(exp - int(flt.mantbits) - 1)

	// d = mant << (exp - mantbits)
	// Next lowest floating point number is mant-1 << exp-mantbits,
	// unless mant-1 drops the significant bit and exp is not the minimum exp,
	// in which case the next lowest is mant*2-1 << exp-mantbits-1.
	// Either way, call it mantlo << explo-mantbits.
	// Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
	minexp := flt.bias + 1 // minimum possible exponent
	var mantlo uint64
	var explo int
	if mant > 1<<flt.mantbits || exp == minexp {
		mantlo = mant - 1
		explo = exp
	} else {
		mantlo = mant*2 - 1
		explo = exp - 1
	}
	lower := new(decimal)
	lower.Assign(mantlo*2 + 1)
	lower.Shift(explo - int(flt.mantbits) - 1)

	// The upper and lower bounds are possible outputs only if
	// the original mantissa is even, so that IEEE round-to-even
	// would round to the original mantissa and not the neighbors.
	inclusive := mant%2 == 0

	// Now we can figure out the minimum number of digits required.
	// Walk along until d has distinguished itself from upper and lower.
	for i := 0; i < d.nd; i++ {
		var l, m, u byte // lower, middle, upper digits
		if i < lower.nd {
			l = lower.d[i]
		} else {
			l = '0'
		}
		m = d.d[i]
		if i < upper.nd {
			u = upper.d[i]
		} else {
			u = '0'
		}

		// Okay to round down (truncate) if lower has a different digit
		// or if lower is inclusive and is exactly the result of rounding down.
		okdown := l != m || (inclusive && l == m && i+1 == lower.nd)

		// Okay to round up if upper has a different digit and
		// either upper is inclusive or upper is bigger than the result of rounding up.
		okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)

		// If it's okay to do either, then round to the nearest one.
		// If it's okay to do only one, do it.
		switch {
		case okdown && okup:
			d.Round(i + 1)
			return
		case okdown:
			d.RoundDown(i + 1)
			return
		case okup:
			d.RoundUp(i + 1)
			return
		}
	}
}

// %e: -d.ddddde±dd
func fmtE(dst []byte, neg bool, d *decimal, prec int, fmt byte) []byte {
	// sign
	if neg {
		dst = append(dst, '-')
	}

	// first digit
	ch := byte('0')
	if d.nd != 0 {
		ch = d.d[0]
	}
	dst = append(dst, ch)

	// .moredigits
	if prec > 0 {
		dst = append(dst, '.')
		for i := 1; i <= prec; i++ {
			ch = '0'
			if i < d.nd {
				ch = d.d[i]
			}
			dst = append(dst, ch)
		}
	}

	// e±
	dst = append(dst, fmt)
	exp := d.dp - 1
	if d.nd == 0 { // special case: 0 has exponent 0
		exp = 0
	}
	if exp < 0 {
		ch = '-'
		exp = -exp
	} else {
		ch = '+'
	}
	dst = append(dst, ch)

	// dddd
	var buf [3]byte
	i := len(buf)
	for exp >= 10 {
		i--
		buf[i] = byte(exp%10 + '0')
		exp /= 10
	}
	// exp < 10
	i--
	buf[i] = byte(exp + '0')

	// leading zeroes
	if i > len(buf)-2 {
		i--
		buf[i] = '0'
	}

	return append(dst, buf[i:]...)
}

// %f: -ddddddd.ddddd
func fmtF(dst []byte, neg bool, d *decimal, prec int) []byte {
	// sign
	if neg {
		dst = append(dst, '-')
	}

	// integer, padded with zeros as needed.
	if d.dp > 0 {
		var i int
		for i = 0; i < d.dp && i < d.nd; i++ {
			dst = append(dst, d.d[i])
		}
		for ; i < d.dp; i++ {
			dst = append(dst, '0')
		}
	} else {
		dst = append(dst, '0')
	}

	// fraction
	if prec > 0 {
		dst = append(dst, '.')
		for i := 0; i < prec; i++ {
			ch := byte('0')
			if j := d.dp + i; 0 <= j && j < d.nd {
				ch = d.d[j]
			}
			dst = append(dst, ch)
		}
	}

	return dst
}

// %b: -ddddddddp+ddd
func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
	var buf [50]byte
	w := len(buf)
	exp -= int(flt.mantbits)
	esign := byte('+')
	if exp < 0 {
		esign = '-'
		exp = -exp
	}
	n := 0
	for exp > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(exp%10 + '0')
		exp /= 10
	}
	w--
	buf[w] = esign
	w--
	buf[w] = 'p'
	n = 0
	for mant > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(mant%10 + '0')
		mant /= 10
	}
	if neg {
		w--
		buf[w] = '-'
	}
	return append(dst, buf[w:]...)
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<commit_msg>strconv: implement fast path for rounding already short numbers.<commit_after>// Copyright 2009 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.

// Binary to decimal floating point conversion.
// Algorithm:
//   1) store mantissa in multiprecision decimal
//   2) shift decimal by exponent
//   3) read digits out & format

package strconv

import "math"

// TODO: move elsewhere?
type floatInfo struct {
	mantbits uint
	expbits  uint
	bias     int
}

var float32info = floatInfo{23, 8, -127}
var float64info = floatInfo{52, 11, -1023}

// FormatFloat converts the floating-point number f to a string,
// according to the format fmt and precision prec.  It rounds the
// result assuming that the original was obtained from a floating-point
// value of bitSize bits (32 for float32, 64 for float64).
//
// The format fmt is one of
// 'b' (-ddddp±ddd, a binary exponent),
// 'e' (-d.dddde±dd, a decimal exponent),
// 'E' (-d.ddddE±dd, a decimal exponent),
// 'f' (-ddd.dddd, no exponent),
// 'g' ('e' for large exponents, 'f' otherwise), or
// 'G' ('E' for large exponents, 'f' otherwise).
//
// The precision prec controls the number of digits
// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
// For 'g' and 'G' it is the total number of digits.
// The special precision -1 uses the smallest number of digits
// necessary such that ParseFloat will return f exactly.
func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
	return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
}

// AppendFloat appends the string form of the floating-point number f,
// as generated by FormatFloat, to dst and returns the extended buffer.
func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte {
	return genericFtoa(dst, f, fmt, prec, bitSize)
}

func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
	var bits uint64
	var flt *floatInfo
	switch bitSize {
	case 32:
		bits = uint64(math.Float32bits(float32(val)))
		flt = &float32info
	case 64:
		bits = math.Float64bits(val)
		flt = &float64info
	default:
		panic("strconv: illegal AppendFloat/FormatFloat bitSize")
	}

	neg := bits>>(flt.expbits+flt.mantbits) != 0
	exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
	mant := bits & (uint64(1)<<flt.mantbits - 1)

	switch exp {
	case 1<<flt.expbits - 1:
		// Inf, NaN
		var s string
		switch {
		case mant != 0:
			s = "NaN"
		case neg:
			s = "-Inf"
		default:
			s = "+Inf"
		}
		return append(dst, s...)

	case 0:
		// denormalized
		exp++

	default:
		// add implicit top bit
		mant |= uint64(1) << flt.mantbits
	}
	exp += flt.bias

	// Pick off easy binary format.
	if fmt == 'b' {
		return fmtB(dst, neg, mant, exp, flt)
	}

	// Create exact decimal representation.
	// The shift is exp - flt.mantbits because mant is a 1-bit integer
	// followed by a flt.mantbits fraction, and we are treating it as
	// a 1+flt.mantbits-bit integer.
	d := new(decimal)
	d.Assign(mant)
	d.Shift(exp - int(flt.mantbits))

	// Round appropriately.
	// Negative precision means "only as much as needed to be exact."
	shortest := false
	if prec < 0 {
		shortest = true
		roundShortest(d, mant, exp, flt)
		switch fmt {
		case 'e', 'E':
			prec = d.nd - 1
		case 'f':
			prec = max(d.nd-d.dp, 0)
		case 'g', 'G':
			prec = d.nd
		}
	} else {
		switch fmt {
		case 'e', 'E':
			d.Round(prec + 1)
		case 'f':
			d.Round(d.dp + prec)
		case 'g', 'G':
			if prec == 0 {
				prec = 1
			}
			d.Round(prec)
		}
	}

	switch fmt {
	case 'e', 'E':
		return fmtE(dst, neg, d, prec, fmt)
	case 'f':
		return fmtF(dst, neg, d, prec)
	case 'g', 'G':
		// trailing fractional zeros in 'e' form will be trimmed.
		eprec := prec
		if eprec > d.nd && d.nd >= d.dp {
			eprec = d.nd
		}
		// %e is used if the exponent from the conversion
		// is less than -4 or greater than or equal to the precision.
		// if precision was the shortest possible, use precision 6 for this decision.
		if shortest {
			eprec = 6
		}
		exp := d.dp - 1
		if exp < -4 || exp >= eprec {
			if prec > d.nd {
				prec = d.nd
			}
			return fmtE(dst, neg, d, prec-1, fmt+'e'-'g')
		}
		if prec > d.dp {
			prec = d.nd
		}
		return fmtF(dst, neg, d, max(prec-d.dp, 0))
	}

	// unknown format
	return append(dst, '%', fmt)
}

// Round d (= mant * 2^exp) to the shortest number of digits
// that will let the original floating point value be precisely
// reconstructed.  Size is original floating point size (64 or 32).
func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
	// If mantissa is zero, the number is zero; stop now.
	if mant == 0 {
		d.nd = 0
		return
	}

	// Compute upper and lower such that any decimal number
	// between upper and lower (possibly inclusive)
	// will round to the original floating point number.

	// We may see at once that the number is already shortest.
	//
	// Suppose d is not denormal, so that 2^exp <= d < 10^dp.
	// The closest shorter number is at least 10^(dp-nd) away.
	// The lower/upper bounds computed below are at distance
	// at most 2^(exp-mantbits).
	//
	// So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
	// or equivalently log2(10)*(dp-nd) > exp-mantbits.
	// It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
	minexp := flt.bias + 1 // minimum possible exponent
	if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
		// The number is already shortest.
		return
	}

	// d = mant << (exp - mantbits)
	// Next highest floating point number is mant+1 << exp-mantbits.
	// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
	upper := new(decimal)
	upper.Assign(mant*2 + 1)
	upper.Shift(exp - int(flt.mantbits) - 1)

	// d = mant << (exp - mantbits)
	// Next lowest floating point number is mant-1 << exp-mantbits,
	// unless mant-1 drops the significant bit and exp is not the minimum exp,
	// in which case the next lowest is mant*2-1 << exp-mantbits-1.
	// Either way, call it mantlo << explo-mantbits.
	// Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
	var mantlo uint64
	var explo int
	if mant > 1<<flt.mantbits || exp == minexp {
		mantlo = mant - 1
		explo = exp
	} else {
		mantlo = mant*2 - 1
		explo = exp - 1
	}
	lower := new(decimal)
	lower.Assign(mantlo*2 + 1)
	lower.Shift(explo - int(flt.mantbits) - 1)

	// The upper and lower bounds are possible outputs only if
	// the original mantissa is even, so that IEEE round-to-even
	// would round to the original mantissa and not the neighbors.
	inclusive := mant%2 == 0

	// Now we can figure out the minimum number of digits required.
	// Walk along until d has distinguished itself from upper and lower.
	for i := 0; i < d.nd; i++ {
		var l, m, u byte // lower, middle, upper digits
		if i < lower.nd {
			l = lower.d[i]
		} else {
			l = '0'
		}
		m = d.d[i]
		if i < upper.nd {
			u = upper.d[i]
		} else {
			u = '0'
		}

		// Okay to round down (truncate) if lower has a different digit
		// or if lower is inclusive and is exactly the result of rounding down.
		okdown := l != m || (inclusive && l == m && i+1 == lower.nd)

		// Okay to round up if upper has a different digit and
		// either upper is inclusive or upper is bigger than the result of rounding up.
		okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)

		// If it's okay to do either, then round to the nearest one.
		// If it's okay to do only one, do it.
		switch {
		case okdown && okup:
			d.Round(i + 1)
			return
		case okdown:
			d.RoundDown(i + 1)
			return
		case okup:
			d.RoundUp(i + 1)
			return
		}
	}
}

// %e: -d.ddddde±dd
func fmtE(dst []byte, neg bool, d *decimal, prec int, fmt byte) []byte {
	// sign
	if neg {
		dst = append(dst, '-')
	}

	// first digit
	ch := byte('0')
	if d.nd != 0 {
		ch = d.d[0]
	}
	dst = append(dst, ch)

	// .moredigits
	if prec > 0 {
		dst = append(dst, '.')
		for i := 1; i <= prec; i++ {
			ch = '0'
			if i < d.nd {
				ch = d.d[i]
			}
			dst = append(dst, ch)
		}
	}

	// e±
	dst = append(dst, fmt)
	exp := d.dp - 1
	if d.nd == 0 { // special case: 0 has exponent 0
		exp = 0
	}
	if exp < 0 {
		ch = '-'
		exp = -exp
	} else {
		ch = '+'
	}
	dst = append(dst, ch)

	// dddd
	var buf [3]byte
	i := len(buf)
	for exp >= 10 {
		i--
		buf[i] = byte(exp%10 + '0')
		exp /= 10
	}
	// exp < 10
	i--
	buf[i] = byte(exp + '0')

	// leading zeroes
	if i > len(buf)-2 {
		i--
		buf[i] = '0'
	}

	return append(dst, buf[i:]...)
}

// %f: -ddddddd.ddddd
func fmtF(dst []byte, neg bool, d *decimal, prec int) []byte {
	// sign
	if neg {
		dst = append(dst, '-')
	}

	// integer, padded with zeros as needed.
	if d.dp > 0 {
		var i int
		for i = 0; i < d.dp && i < d.nd; i++ {
			dst = append(dst, d.d[i])
		}
		for ; i < d.dp; i++ {
			dst = append(dst, '0')
		}
	} else {
		dst = append(dst, '0')
	}

	// fraction
	if prec > 0 {
		dst = append(dst, '.')
		for i := 0; i < prec; i++ {
			ch := byte('0')
			if j := d.dp + i; 0 <= j && j < d.nd {
				ch = d.d[j]
			}
			dst = append(dst, ch)
		}
	}

	return dst
}

// %b: -ddddddddp+ddd
func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
	var buf [50]byte
	w := len(buf)
	exp -= int(flt.mantbits)
	esign := byte('+')
	if exp < 0 {
		esign = '-'
		exp = -exp
	}
	n := 0
	for exp > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(exp%10 + '0')
		exp /= 10
	}
	w--
	buf[w] = esign
	w--
	buf[w] = 'p'
	n = 0
	for mant > 0 || n < 1 {
		n++
		w--
		buf[w] = byte(mant%10 + '0')
		mant /= 10
	}
	if neg {
		w--
		buf[w] = '-'
	}
	return append(dst, buf[w:]...)
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>package medias

import (
	"encoding/json"
	"errors"
	"github.com/mitchellh/mapstructure"
	"io/ioutil"
	"log"
	"github.com/Zenika/MARCEL/backend/commons"
	"os"
	"fmt"
)

const MEDIAS_CONFIG_PATH string = "data"
const MEDIAS_CONFIG_FILENAME string = "medias.config.json"

var mediasConfigFullpath string = fmt.Sprintf("%s%c%s", MEDIAS_CONFIG_PATH, os.PathSeparator, MEDIAS_CONFIG_FILENAME)

//List of Loaded Medias
var Medias []Media

// LoadMedias loads medias configuration from DB and stor it in memory
func LoadMedias() {
	log.Printf("Start Loading Medias from DB.")

	CreateSaveFileIfNotExist(MEDIAS_CONFIG_PATH, MEDIAS_CONFIG_FILENAME)

	//Medias configurations are loaded from a JSON file on the FS.
	content, err := ioutil.ReadFile(mediasConfigFullpath)
	check(err)

	var obj []interface{}
	json.Unmarshal([]byte(content), &obj)

	//Map the json to the Media structure
	for _, b := range obj {
		var media Media
		err = mapstructure.Decode(b.(map[string]interface{}), &media)
		if err != nil {
			panic(err)
		}
		Medias = append(Medias, media)
	}

	log.Print("Medias configurations is loaded...")
}

// GetMedia Return the media with this id
func GetMedia(idMedia string) (*Media, error) {

	log.Println("Getting media with id: ", idMedia)
	for _, media := range Medias {
		if idMedia == media.ID {
			return &media, nil
		}
	}

	return nil, errors.New("NO_MEDIA_FOUND")
}

// CreateMedia Create a new Media, save it into memory and commit
func CreateMedia() (*Media) {

	log.Println("Creating media")
	newMedia := new(Media)
	newMedia.ID = commons.GetUID()

	SaveMedia(newMedia)
	Commit()

	return newMedia
}

// RemoveMedia Remove media from memory and commit
func RemoveMedia(media *Media) {
	log.Println("Removing media")
	i := GetMediaPosition(media)

	if i >= 0 {
		Medias = append(Medias[:i], Medias[i+1:]...)
	}

	Commit()
}

// GetMediaPosition Return position of a media in the list
func GetMediaPosition(media *Media) int {
	for p, m := range Medias {
		if m.ID == media.ID {
			return p
		}
	}
	return -1
}

// SaveMedia Save media information in memory.
func SaveMedia(media *Media) {
	log.Println("Saving media")
	RemoveMedia(media)
	Medias = append(Medias, *media)

	Commit()
}

// Commit Save all medias in DB.
// Here DB is a JSON file
func Commit() {
	content, _ := json.Marshal(Medias)

	err := ioutil.WriteFile(mediasConfigFullpath, content, 0644)

	if err != nil {
		log.Println("Cannot save medias configuration:")
		log.Panic(err)
	}
}

// CreateSaveFileIfNotExist check if the save file for medias exists and create it if not.
func CreateSaveFileIfNotExist(filePath string, fileName string) {

	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		log.Println("Data directory did not exist. Create it.")
		os.Mkdir(filePath, 0755)
	}

	var fullPath string = fmt.Sprintf("%s%c%s", filePath, os.PathSeparator, fileName)
	if _, err := os.Stat(fullPath); os.IsNotExist(err) {
		content := "[\n]"

		f, err := os.Create(fullPath)
		check(err)

		f.WriteString(content)

		log.Println("Medias configuration file created at %v", fullPath)

		f.Close()
	}
}
<commit_msg>[Add] Use of MediasConfiguration as entrypoint<commit_after>package medias

import (
	"encoding/json"
	"errors"
	"github.com/mitchellh/mapstructure"
	"io/ioutil"
	"log"
	"github.com/Zenika/MARCEL/backend/commons"
	"os"
	"fmt"
)

const MEDIAS_CONFIG_PATH string = "data"
const MEDIAS_CONFIG_FILENAME string = "medias.config.json"

var mediasConfigFullpath string = fmt.Sprintf("%s%c%s", MEDIAS_CONFIG_PATH, os.PathSeparator, MEDIAS_CONFIG_FILENAME)

//List of Loaded Medias
//var Medias []Media
var MediasConfig MediasConfiguration

// LoadMedias loads medias configuration from DB and stor it in memory
func LoadMedias() {
	log.Printf("Start Loading Medias from DB.")

	CreateSaveFileIfNotExist(MEDIAS_CONFIG_PATH, MEDIAS_CONFIG_FILENAME)

	//Medias configurations are loaded from a JSON file on the FS.
	content, err := ioutil.ReadFile(mediasConfigFullpath)
	check(err)

	var obj []interface{}
	json.Unmarshal([]byte(content), &obj)

	//Map the json to the MediasConfig structure
	for _, b := range obj {
		var media Media
		err = mapstructure.Decode(b.(map[string]interface{}), &media)
		if err != nil {
			panic(err)
		}
		MediasConfig.Medias = append(MediasConfig.Medias, media)
	}

	log.Print("Medias configurations is loaded...")
}

func GetAll() (*MediasConfiguration) {
	log.Println("Getting global medias config")

}

// GetMedia Return the media with this id
func GetMedia(idMedia string) (*Media, error) {

	log.Println("Getting media with id: ", idMedia)
	for _, media := range MediasConfig.Medias {
		if idMedia == media.ID {
			return &media, nil
		}
	}

	return nil, errors.New("NO_MEDIA_FOUND")
}

// CreateMedia Create a new Media, save it into memory and commit
func CreateMedia() (*Media) {

	log.Println("Creating media")
	newMedia := new(Media)
	newMedia.ID = commons.GetUID()

	SaveMedia(newMedia)
	Commit()

	return newMedia
}

// RemoveMedia Remove media from memory and commit
func RemoveMedia(media *Media) {
	log.Println("Removing media")
	i := GetMediaPosition(media)

	if i >= 0 {
		MediasConfig.Medias = append(MediasConfig.Medias[:i], MediasConfig.Medias[i+1:]...)
	}

	Commit()
}

// GetMediaPosition Return position of a media in the list
func GetMediaPosition(media *Media) int {
	for p, m := range MediasConfig.Medias {
		if m.ID == media.ID {
			return p
		}
	}
	return -1
}

// SaveMedia Save media information in memory.
func SaveMedia(media *Media) {
	log.Println("Saving media")
	RemoveMedia(media)
	MediasConfig.Medias = append(MediasConfig.Medias, *media)

	Commit()
}

// Commit Save all medias in DB.
// Here DB is a JSON file
func Commit() {
	content, _ := json.Marshal(MediasConfig)

	err := ioutil.WriteFile(mediasConfigFullpath, content, 0644)

	if err != nil {
		log.Println("Cannot save medias configuration:")
		log.Panic(err)
	}
}

// CreateSaveFileIfNotExist check if the save file for medias exists and create it if not.
func CreateSaveFileIfNotExist(filePath string, fileName string) {

	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		log.Println("Data directory did not exist. Create it.")
		os.Mkdir(filePath, 0755)
	}

	var fullPath string = fmt.Sprintf("%s%c%s", filePath, os.PathSeparator, fileName)
	if _, err := os.Stat(fullPath); os.IsNotExist(err) {
		content := "[\n]"

		f, err := os.Create(fullPath)
		check(err)

		f.WriteString(content)

		log.Println("Medias configuration file created at %v", fullPath)

		f.Close()
	}
}
<|endoftext|>


<commit_before>package medias

import (
	"net/http"
	"encoding/json"
	"log"
	"github.com/gorilla/mux"
)

func HandleGetMedia(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	idMedia := vars["idMedia"]

	m, err := GetMedia(idMedia)
	if err != nil {
		writeResponseWithError(w, http.StatusNotFound)
		return
	}

	b, err := json.Marshal(*m)
	if err != nil {
		writeResponseWithError(w, http.StatusNotFound)
		return
	}

	w.Write([]byte(b))
}

func HandleGetMedias(w http.ResponseWriter, r *http.Request) {
	b, err := json.Marshal(Medias)
	if err != nil {
		writeResponseWithError(w, http.StatusNotFound)
		return
	}

	w.Write([]byte(b))
}

func writeResponseWithError(w http.ResponseWriter, errorCode int) {
	w.WriteHeader(errorCode)
}

func check(e error) {
	if e != nil {
		log.Fatal(e)
		panic(e)
	}
}
<commit_msg>[Add] HandleCreateMedia<commit_after>package medias

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"log"
	"net/http"
)

func HandleGetMedia(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	idMedia := vars["idMedia"]

	m, err := GetMedia(idMedia)
	if err != nil {
		writeResponseWithError(w, http.StatusNotFound)
		return
	}

	b, err := json.Marshal(*m)
	if err != nil {
		writeResponseWithError(w, http.StatusNotFound)
		return
	}

	w.Write([]byte(b))
}

func HandleGetAll(w http.ResponseWriter, r *http.Request) {
	b, err := json.Marshal(Medias)
	if err != nil {
		writeResponseWithError(w, http.StatusNotFound)
		return
	}

	w.Write([]byte(b))
}

func HandleCreate(w http.ResponseWriter, r *http.Request) {
	//get a new media
	newMedia := CreateMedia()

	//return it to the client
	b, err := json.Marshal(*newMedia)
	if err != nil {
		writeResponseWithError(w, http.StatusNotFound)
		return
	}

	w.Write([]byte(b))
}

func writeResponseWithError(w http.ResponseWriter, errorCode int) {
	w.WriteHeader(errorCode)
}

func check(e error) {
	if e != nil {
		log.Fatal(e)
		panic(e)
	}
}
<|endoftext|>