<commit_before>package brightbox

import (
	"encoding/json"
	"errors"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"time"
)

type ApiError struct {
	Error            string `json:"error"`
	ErrorDescription string `json:"error_description"`
}

type Resource struct {
	Id string
}

type Connection struct {
	ApiUrl       string
	UserName     string
	UserSecret   string
	AccountId    string
	UserAgent    string
	ClientID     string
	ClientSecret string
	ClientConfig *clientcredentials.Config
	TokenUrl     string
	TokenConfig  *oauth2.Config
	Token        string
	Scopes       []string
	Client       *http.Client
	ctx          context.Context
}

type Server struct {
	Resource
	Name       string
	Status     string
	Locked     bool
	Hostname   string
	Fqdn       string
	CreatedAt  time.Time  `json:"created_at"`
	DeletedAt  string     `json:"deleted_at,omitempty"`
	ServerType ServerType `json:"server_type"`
	CompatabilityMode bool `json:"compatability_mode"`
	Zone       Zone
	Image      Image
	CloudIPs   []CloudIP `json:"cloud_ips"`
	Interfaces []ServerInterface
}

type ServerInterface struct {
	Resource
	MacAddress string `json:"mac_address"`
	IPv4Address string `json:"ipv4_address"`
	IPv6Address string `json:"ipv6_address"`
}

type ServerType struct {
	Resource
	Name     string
	Status   string
	Handle   string
	Cores    int
	Ram      int
	DiskSize int `json:"disk_size"`
}

type Zone struct {
	Resource
	Handle string
}

type Image struct {
	Resource
	Name        string
	Username    string
	Status      string
	Locked      bool
	Description string
	Source      string
	Arch        string
	CreatedAt   time.Time `json:"created_at"`
	Official    bool
	Public      bool
	Owner       string
}

type CloudIP struct {
	Resource
	Status     string
	PublicIP   string
	ReverseDns string
	Name       string
}

func (c *Connection) setDefaults() {
	if c.ApiUrl == "" {
		c.ApiUrl = "https://api.gb1.brightbox.com"
	}
	if c.TokenUrl == "" {
		c.TokenUrl = c.ApiUrl + "/token"
	}
	if c.ClientConfig == nil {
		c.ClientConfig = &clientcredentials.Config{
			ClientID:     c.ClientID,
			ClientSecret: c.ClientSecret,
			TokenURL:     c.TokenUrl,
			Scopes:       c.Scopes,
		}
	}
	if c.TokenConfig == nil {
		c.TokenConfig = &oauth2.Config{}
	}
	c.ctx = oauth2.NoContext
}

func (c *Connection) Connect() error {
	var client *http.Client
	c.setDefaults()
	if c.Token != "" {
		client = oauth2.NewClient(c.ctx, oauth2.StaticTokenSource(&oauth2.Token{AccessToken: c.Token}))
	} else if c.ClientConfig != nil {
		client = c.ClientConfig.Client(c.ctx)
	}
	if client == nil {
		return errors.New("Failed to create oauth2 client")
	}
	c.Client = client
	return nil
}

func DisplayIds(resources interface{}) string {
	val := reflect.ValueOf(resources)
	if val.Kind() == reflect.Slice {
		var ids = make([]string, val.Len())
		for i := 0; i < val.Len(); i++ {
			rval := val.Index(i)
			if rval.Kind() == reflect.Struct && rval.FieldByName("Id").IsValid() {
				ids[i] = rval.FieldByName("Id").String()
			}
		}
		return strings.Join(ids, ",")
	}
	return ""
}

func (c *Connection) api_url(path string) string {
	u, _ := url.Parse(c.ApiUrl)
	v := u.Query()
	if c.AccountId != "" {
		v.Set("account_id", c.AccountId)
	}
	u, _ = u.Parse("/1.0" + path)
	u.RawQuery = v.Encode()
	return u.String()
}

func (c *Connection) MakeApiRequest(method string, path string) (*[]byte, error) {
	var body []byte
	var apierror ApiError
	res, err := c.Client.Get(c.api_url(path))
	if err != nil {
		return nil, err
	}
	body, err = ioutil.ReadAll(res.Body)
	defer res.Body.Close()
	if err != nil {
		return nil, err
	}
	if res.StatusCode == 200 {
		return &body, err
	} else {
		json.Unmarshal(body, &apierror)
		return nil, errors.New(apierror.ErrorDescription)
	}
}

func (c *Connection) Servers() (*[]Server, *[]byte, error) {
	var servers []Server
	var body *[]byte
	body, err := c.MakeApiRequest("get", "/servers")
	if err != nil {
		return nil, body, err
	}
	err = json.Unmarshal(*body, &servers)
	if err != nil {
		return &servers, body, err
	}
	return &servers, body, err
}

func (c *Connection) Server(identifier string) (*Server, *[]byte, error) {
	var server Server
	var body *[]byte
	body, err := c.MakeApiRequest("get", "/servers/"+identifier)
	if err != nil {
		return nil, body, err
	}
	err = json.Unmarshal(*body, &server)
	if err != nil {
		return &server, body, err
	}
	return &server, body, err
}
<commit_msg>Use pointers for time objects in Server<commit_after>package brightbox

import (
	"encoding/json"
	"errors"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"time"
)

type ApiError struct {
	Error            string `json:"error"`
	ErrorDescription string `json:"error_description"`
}

type Resource struct {
	Id string
}

type Connection struct {
	ApiUrl       string
	UserName     string
	UserSecret   string
	AccountId    string
	UserAgent    string
	ClientID     string
	ClientSecret string
	ClientConfig *clientcredentials.Config
	TokenUrl     string
	TokenConfig  *oauth2.Config
	Token        string
	Scopes       []string
	Client       *http.Client
	ctx          context.Context
}

type Server struct {
	Resource
	Name              string
	Status            string
	Locked            bool
	Hostname          string
	Fqdn              string
	CreatedAt         *time.Time `json:"created_at"`
	DeletedAt         *time.Time `json:"deleted_at"`
	ServerType        ServerType `json:"server_type"`
	CompatabilityMode bool       `json:"compatability_mode"`
	Zone              Zone
	Image             Image
	CloudIPs          []CloudIP `json:"cloud_ips"`
	Interfaces        []ServerInterface
}

type ServerInterface struct {
	Resource
	MacAddress  string `json:"mac_address"`
	IPv4Address string `json:"ipv4_address"`
	IPv6Address string `json:"ipv6_address"`
}

type ServerType struct {
	Resource
	Name     string
	Status   string
	Handle   string
	Cores    int
	Ram      int
	DiskSize int `json:"disk_size"`
}

type Zone struct {
	Resource
	Handle string
}

type Image struct {
	Resource
	Name        string
	Username    string
	Status      string
	Locked      bool
	Description string
	Source      string
	Arch        string
	CreatedAt   time.Time `json:"created_at"`
	Official    bool
	Public      bool
	Owner       string
}

type CloudIP struct {
	Resource
	Status     string
	PublicIP   string
	ReverseDns string
	Name       string
}

func (c *Connection) setDefaults() {
	if c.ApiUrl == "" {
		c.ApiUrl = "https://api.gb1.brightbox.com"
	}
	if c.TokenUrl == "" {
		c.TokenUrl = c.ApiUrl + "/token"
	}
	if c.ClientConfig == nil {
		c.ClientConfig = &clientcredentials.Config{
			ClientID:     c.ClientID,
			ClientSecret: c.ClientSecret,
			TokenURL:     c.TokenUrl,
			Scopes:       c.Scopes,
		}
	}
	if c.TokenConfig == nil {
		c.TokenConfig = &oauth2.Config{}
	}
	c.ctx = oauth2.NoContext
}

func (c *Connection) Connect() error {
	var client *http.Client
	c.setDefaults()
	if c.Token != "" {
		client = oauth2.NewClient(c.ctx, oauth2.StaticTokenSource(&oauth2.Token{AccessToken: c.Token}))
	} else if c.ClientConfig != nil {
		client = c.ClientConfig.Client(c.ctx)
	}
	if client == nil {
		return errors.New("Failed to create oauth2 client")
	}
	c.Client = client
	return nil
}

func DisplayIds(resources interface{}) string {
	val := reflect.ValueOf(resources)
	if val.Kind() == reflect.Slice {
		var ids = make([]string, val.Len())
		for i := 0; i < val.Len(); i++ {
			rval := val.Index(i)
			if rval.Kind() == reflect.Struct && rval.FieldByName("Id").IsValid() {
				ids[i] = rval.FieldByName("Id").String()
			}
		}
		return strings.Join(ids, ",")
	}
	return ""
}

func (c *Connection) api_url(path string) string {
	u, _ := url.Parse(c.ApiUrl)
	v := u.Query()
	if c.AccountId != "" {
		v.Set("account_id", c.AccountId)
	}
	u, _ = u.Parse("/1.0" + path)
	u.RawQuery = v.Encode()
	return u.String()
}

func (c *Connection) MakeApiRequest(method string, path string) (*[]byte, error) {
	var body []byte
	var apierror ApiError
	res, err := c.Client.Get(c.api_url(path))
	if err != nil {
		return nil, err
	}
	body, err = ioutil.ReadAll(res.Body)
	defer res.Body.Close()
	if err != nil {
		return nil, err
	}
	if res.StatusCode == 200 {
		return &body, err
	} else {
		json.Unmarshal(body, &apierror)
		return nil, errors.New(apierror.ErrorDescription)
	}
}

func (c *Connection) Servers() (*[]Server, *[]byte, error) {
	var servers []Server
	var body *[]byte
	body, err := c.MakeApiRequest("get", "/servers")
	if err != nil {
		return nil, body, err
	}
	err = json.Unmarshal(*body, &servers)
	if err != nil {
		return &servers, body, err
	}
	return &servers, body, err
}

func (c *Connection) Server(identifier string) (*Server, *[]byte, error) {
	var server Server
	var body *[]byte
	body, err := c.MakeApiRequest("get", "/servers/"+identifier)
	if err != nil {
		return nil, body, err
	}
	err = json.Unmarshal(*body, &server)
	if err != nil {
		return &server, body, err
	}
	return &server, body, err
}
<|endoftext|>


<commit_before>package broker

/*
import (
	"net"
	"testing"

	"github.com/emitter-io/emitter/config"
	"github.com/emitter-io/emitter/network/mqtt"
	"github.com/emitter-io/emitter/security"
	"github.com/stretchr/testify/assert"
)
*/
const testLicense = "zT83oDV0DWY5_JysbSTPTDr8KB0AAAAAAAAAAAAAAAI"

/*
func TestPubsub(t *testing.T) {
	cfg := config.NewDefault()
	cfg.License = testLicense
	cfg.TCPPort = ":9998"
	cfg.TLSPort = ":9999"
	cfg.Cluster = nil

	// Start the broker asynchronously
	broker, svcErr := NewService(cfg)
	broker.ContractProvider = security.NewSingleContractProvider(broker.License)
	assert.NoError(t, svcErr)
	defer close(broker.Closing)
	go broker.Listen()

	// Create a client
	cli, dialErr := net.Dial("tcp", ":9998")
	assert.NoError(t, dialErr)
	defer cli.Close()

	{ // Connect to the broker
		connect := mqtt.Connect{ClientID: []byte("test")}
		n, err := connect.EncodeTo(cli)
		assert.Equal(t, 14, n)
		assert.NoError(t, err)
	}

	{ // Read connack
		pkt, err := mqtt.DecodePacket(cli)
		assert.NoError(t, err)
		assert.Equal(t, mqtt.TypeOfConnack, pkt.Type())
	}

	{ // Subscribe to a topic
		sub := mqtt.Subscribe{
			Header: &mqtt.StaticHeader{QOS: 0},
			Subscriptions: []mqtt.TopicQOSTuple{
				{Topic: []byte("0Nq8SWbL8qoOKEDqh_ebBepug6cLLlWO/a/b/c/"), Qos: 0},
			},
		}
		_, err := sub.EncodeTo(cli)
		assert.NoError(t, err)
	}

	{ // Read suback
		pkt, err := mqtt.DecodePacket(cli)
		assert.NoError(t, err)
		assert.Equal(t, mqtt.TypeOfSuback, pkt.Type())
	}

	{ // Publish a message
		msg := mqtt.Publish{
			Header:  &mqtt.StaticHeader{QOS: 0},
			Topic:   []byte("0Nq8SWbL8qoOKEDqh_ebBepug6cLLlWO/a/b/c/"),
			Payload: []byte("hello world"),
		}
		_, err := msg.EncodeTo(cli)
		assert.NoError(t, err)
	}

	{ // Read the message back
		pkt, err := mqtt.DecodePacket(cli)
		assert.NoError(t, err)
		assert.Equal(t, mqtt.TypeOfPublish, pkt.Type())
		assert.Equal(t, &mqtt.Publish{
			Header:  &mqtt.StaticHeader{QOS: 0},
			Topic:   []byte("a/b/c/"),
			Payload: []byte("hello world"),
		}, pkt)
	}
}
*/
<commit_msg>test uncommented<commit_after>package broker

import (
	"net"
	"testing"

	"github.com/emitter-io/emitter/config"
	"github.com/emitter-io/emitter/network/mqtt"
	"github.com/emitter-io/emitter/security"
	"github.com/stretchr/testify/assert"
)

const testLicense = "zT83oDV0DWY5_JysbSTPTDr8KB0AAAAAAAAAAAAAAAI"

func TestPubsub(t *testing.T) {
	cfg := config.NewDefault()
	cfg.License = testLicense
	cfg.TCPPort = ":9998"
	cfg.TLSPort = ":9999"
	cfg.Cluster = nil

	// Start the broker asynchronously
	broker, svcErr := NewService(cfg)
	broker.ContractProvider = security.NewSingleContractProvider(broker.License)
	assert.NoError(t, svcErr)
	defer close(broker.Closing)
	go broker.Listen()

	// Create a client
	cli, dialErr := net.Dial("tcp", ":9998")
	assert.NoError(t, dialErr)
	defer cli.Close()

	{ // Connect to the broker
		connect := mqtt.Connect{ClientID: []byte("test")}
		n, err := connect.EncodeTo(cli)
		assert.Equal(t, 14, n)
		assert.NoError(t, err)
	}

	{ // Read connack
		pkt, err := mqtt.DecodePacket(cli)
		assert.NoError(t, err)
		assert.Equal(t, mqtt.TypeOfConnack, pkt.Type())
	}

	{ // Subscribe to a topic
		sub := mqtt.Subscribe{
			Header: &mqtt.StaticHeader{QOS: 0},
			Subscriptions: []mqtt.TopicQOSTuple{
				{Topic: []byte("0Nq8SWbL8qoOKEDqh_ebBepug6cLLlWO/a/b/c/"), Qos: 0},
			},
		}
		_, err := sub.EncodeTo(cli)
		assert.NoError(t, err)
	}

	{ // Read suback
		pkt, err := mqtt.DecodePacket(cli)
		assert.NoError(t, err)
		assert.Equal(t, mqtt.TypeOfSuback, pkt.Type())
	}

	{ // Publish a message
		msg := mqtt.Publish{
			Header:  &mqtt.StaticHeader{QOS: 0},
			Topic:   []byte("0Nq8SWbL8qoOKEDqh_ebBepug6cLLlWO/a/b/c/"),
			Payload: []byte("hello world"),
		}
		_, err := msg.EncodeTo(cli)
		assert.NoError(t, err)
	}

	{ // Read the message back
		pkt, err := mqtt.DecodePacket(cli)
		assert.NoError(t, err)
		assert.Equal(t, mqtt.TypeOfPublish, pkt.Type())
		assert.Equal(t, &mqtt.Publish{
			Header:  &mqtt.StaticHeader{QOS: 0},
			Topic:   []byte("a/b/c/"),
			Payload: []byte("hello world"),
		}, pkt)
	}
}
<|endoftext|>


<commit_before>package handler

import (
	"net/http"
	"io/ioutil"
	"log"
	"errors"
	"encoding/json"
	"strings"
	"github.com/gorilla/mux"
	"github.com/gorilla/context"
	"github.com/spf13/viper"
	"github.com/untoldone/bloomapi/api"
	raven "github.com/getsentry/raven-go"
)

func YourChartFetchHandler (w http.ResponseWriter, req *http.Request) {
	raven.SetHttpContext(raven.NewHttp(req))
	vars := mux.Vars(req)
	yourchartUrl := viper.GetString("yourchartUrl")
	yourchartLabUrl := viper.GetString("yourchartLabUrl")
	id := vars["id"]

	apiKey, ok := context.Get(req, "api_key").(string)

	enabled, err := YourchartEnabled(apiKey)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	upstreamJobId, upstreamLabJobId, err := YourchartAuthorized(apiKey, id)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	if (!ok || !enabled || upstreamJobId == "") {
		api.Render(w, req, 404, map[string]string{
			"name": "Source Not Found",
			"message": "Please contact support@bloomapi.com if this is in error",
		})
		return
	}

	getResp, err := http.Get(yourchartUrl + "/" + upstreamJobId)
	body, err := ioutil.ReadAll(getResp.Body)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	var decoded map[string]interface{}
	decoder := json.NewDecoder(strings.NewReader(string(body)))
	err = decoder.Decode(&decoded)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	api.AddFeature(req, "handler:yourchart:fetch")

	if upstreamLabJobId == "" {
		api.Render(w, req, http.StatusOK, decoded)
		return
	}

	getLabResp, err := http.Get(yourchartLabUrl + "/" + upstreamLabJobId)
	labBody, err := ioutil.ReadAll(getLabResp.Body)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	var labDecoded map[string]interface{}
	labDecoder := json.NewDecoder(strings.NewReader(string(labBody)))
	err = labDecoder.Decode(&labDecoded)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
		return
	}

	state, ok := decoded["state"].(string)
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name": "Source Not Found",
			"message": "Please contact support@bloomapi.com if this is in error",
		})
		return
	}

	if state != "complete" {
		api.Render(w, req, http.StatusOK, decoded)
		return
	}

	labState, ok := labDecoded["state"].(string)
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name": "Source Not Found",
			"message": "Please contact support@bloomapi.com if this is in error",
		})
		return
	}

	if labState != "complete" {
		api.Render(w, req, http.StatusOK, map[string]string{"state": "authenticated"})
		return
	}

	for iOne, patient := range decoded["result"].(map[string]interface{})["patients"].([]interface{}) {
		//name := patient.(map[string]interface{})["name"].(string)
		details := patient.(map[string]interface{})["details"]
		replaced := false

		if labDecoded["result"].(map[string]interface{})["patients"].([]interface{})[0].(map[string]interface{})["test-results"] != nil {
			// New version Jan 25, 2016
			for iTwo, labPatient := range labDecoded["result"].(map[string]interface{})["patients"].([]interface{}) {
				//labName := labPatient.(map[string]interface{})["name"].(string)
				//labDetails := labPatient.(map[string]interface{})["details"]

				if iOne == iTwo {
					if labPatient.(map[string]interface{})["name"] != nil &&
							patient.(map[string]interface{})["name"] != labPatient.(map[string]interface{})["name"] {
						raven.CaptureErrorAndWait(errors.New("multiple patients inproperly matched"), nil)
						api.Render(w, req, http.StatusInternalServerError, "Internal Server Error: multiple patients inproperly matched")
						return
					}

					if details != nil {
						details.(map[string]interface{})["test-results"] = labPatient.(map[string]interface{})["test-results"]
					}

					replaced = true
					break
				}
			}
		} else {
			// Previous version
			details.(map[string]interface{})["test-results"] = labDecoded["result"].(map[string]interface{})["patients"]
			replaced = true
		}

		if !replaced {
			log.Println("Failed to match Epic lab service patient to mobile patient")
			raven.CaptureErrorAndWait(errors.New("Failed to match Epic lab service patient to mobile patient"), nil)
			api.Render(w, req, http.StatusInternalServerError, "Internal Server Error")
			return
		}
	}

	api.Render(w, req, http.StatusOK, decoded)
}<commit_msg>return failed state for internal error yourchart<commit_after>package handler

import (
	"net/http"
	"io/ioutil"
	"log"
	"errors"
	"encoding/json"
	"strings"
	"github.com/gorilla/mux"
	"github.com/gorilla/context"
	"github.com/spf13/viper"
	"github.com/untoldone/bloomapi/api"
	raven "github.com/getsentry/raven-go"
)

func YourChartFetchHandler (w http.ResponseWriter, req *http.Request) {
	raven.SetHttpContext(raven.NewHttp(req))
	vars := mux.Vars(req)
	yourchartUrl := viper.GetString("yourchartUrl")
	yourchartLabUrl := viper.GetString("yourchartLabUrl")
	id := vars["id"]

	apiKey, ok := context.Get(req, "api_key").(string)

	enabled, err := YourchartEnabled(apiKey)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
		return
	}

	upstreamJobId, upstreamLabJobId, err := YourchartAuthorized(apiKey, id)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
		return
	}

	if (!ok || !enabled || upstreamJobId == "") {
		api.Render(w, req, 404, map[string]string{
			"name": "Source Not Found",
			"message": "Please contact support@bloomapi.com if this is in error",
		})
		return
	}

	getResp, err := http.Get(yourchartUrl + "/" + upstreamJobId)
	body, err := ioutil.ReadAll(getResp.Body)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
		return
	}

	var decoded map[string]interface{}
	decoder := json.NewDecoder(strings.NewReader(string(body)))
	err = decoder.Decode(&decoded)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
		return
	}

	api.AddFeature(req, "handler:yourchart:fetch")

	if upstreamLabJobId == "" {
		api.Render(w, req, http.StatusOK, decoded)
		return
	}

	getLabResp, err := http.Get(yourchartLabUrl + "/" + upstreamLabJobId)
	labBody, err := ioutil.ReadAll(getLabResp.Body)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
		return
	}

	var labDecoded map[string]interface{}
	labDecoder := json.NewDecoder(strings.NewReader(string(labBody)))
	err = labDecoder.Decode(&labDecoded)
	if err != nil {
		log.Println(err)
		raven.CaptureErrorAndWait(err, nil)
		api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
		return
	}

	state, ok := decoded["state"].(string)
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name": "Source Not Found",
			"message": "Please contact support@bloomapi.com if this is in error",
		})
		return
	}

	if state != "complete" {
		api.Render(w, req, http.StatusOK, decoded)
		return
	}

	labState, ok := labDecoded["state"].(string)
	if !ok {
		api.Render(w, req, 404, map[string]string{
			"name": "Source Not Found",
			"message": "Please contact support@bloomapi.com if this is in error",
		})
		return
	}

	if labState != "complete" {
		api.Render(w, req, http.StatusOK, map[string]string{"state": "authenticated"})
		return
	}

	patients := decoded["result"].(map[string]interface{})["patients"].([]interface{})

	for iOne, patient := range patients {
		//name := patient.(map[string]interface{})["name"].(string)
		details := patient.(map[string]interface{})["details"]
		replaced := false

		labPatients := labDecoded["result"].(map[string]interface{})["patients"].([]interface{})
		if len(patients) != len(labPatients) {
			raven.CaptureErrorAndWait(errors.New("number of patients are different"), nil)
			api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
			return
		}

		if labPatients[0].(map[string]interface{})["test-results"] != nil {
			// New version Jan 25, 2016
			for iTwo, labPatient := range labPatients {
				//labName := labPatient.(map[string]interface{})["name"].(string)
				//labDetails := labPatient.(map[string]interface{})["details"]

				if iOne == iTwo {
					if labPatient.(map[string]interface{})["name"] != nil &&
							patient.(map[string]interface{})["name"] != labPatient.(map[string]interface{})["name"] {
						raven.CaptureErrorAndWait(errors.New("multiple patients inproperly matched"), nil)
						api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
						return
					}

					if details != nil {
						details.(map[string]interface{})["test-results"] = labPatient.(map[string]interface{})["test-results"]
					}

					replaced = true
					break
				}
			}
		} else {
			// Previous version
			details.(map[string]interface{})["test-results"] = labDecoded["result"].(map[string]interface{})["patients"]
			replaced = true
		}

		if !replaced {
			log.Println("Failed to match Epic lab service patient to mobile patient")
			raven.CaptureErrorAndWait(errors.New("Failed to match Epic lab service patient to mobile patient"), nil)
			api.Render(w, req, http.StatusOK, map[string]string{"state": "failed", "message":"Interal Error"})
			return
		}
	}

	api.Render(w, req, http.StatusOK, decoded)
}<|endoftext|>


<commit_before>package helperfunctions

import (
	"strconv"
	"strings"
	"unicode"
)

func TrimSpacesFromArray(title *[]string) {
	copy := *title

	for i := 0; i < len(*title); i++ {
		copy[i] = strings.TrimSpace(copy[i])
	}

	*title = copy
}

func TrimSuffixesFromStringSlice(slice *[]string, suffixes ...string) {
	sliceCopy := *slice
	for sliceIndex, _ := range sliceCopy {
		for _, suffix := range suffixes {
			sliceCopy[sliceIndex] = strings.TrimSuffix(sliceCopy[sliceIndex], suffix)
		}
	}
	*slice = sliceCopy
}

func TrimPrefixesFromStringSlice(slice *[]string, prefixes ...string) {
	sliceCopy := *slice
	for sliceIndex, _ := range sliceCopy {
		for _, prefix := range prefixes {
			sliceCopy[sliceIndex] = strings.TrimPrefix(sliceCopy[sliceIndex], prefix)
		}
	}
	*slice = sliceCopy
}

func TrimSuffixesFromWord(word *string, suffixes ...string) {
	for _, suffix := range suffixes {
		copy := *word
		*word = strings.TrimSuffix(copy, suffix)
	}
}

func StartsWithUppercase(str string) bool {

	if str == "" {
		return false
	} else {
		return unicode.IsUpper([]rune(str)[0])
	}

}

func TrimmedStringInSlice(str string, slice []string) bool {

	TrimSuffixesFromWord(&str, ".", ",")

	for _, strInSlice := range slice {
		if str == strInSlice {
			return true
		}
	}
	return false
}

func StringInSlice(str string, slice []string) bool {

	for _, strInSlice := range slice {
		if str == strInSlice {
			return true
		}
	}
	return false
}

func StringInSliceIgnoreCase(str string, slice []string) bool {
	for _, strInSlice := range slice {
		if strings.ToLower(str) == strings.ToLower(strInSlice) {
			return true
		}
	}
	return false
}

func WordIsNumber(word string) bool {
	TrimSuffixesFromWord(&word, ".", ",")
	_, err := strconv.Atoi(word)
	return err == nil
}

func RemoveIndexFromSlice(index int, slice *[]string) {
	sliceCopy := *slice
	sliceCopy = append(sliceCopy[:index], sliceCopy[index+1:]...)
	*slice = sliceCopy
}

func CurrentIndexNotLast(index int, slice []string) bool {
	return index < len(slice)-1
}
<commit_msg>Improved dependability of removeIndexFromSlice<commit_after>package helperfunctions

import (
	"strconv"
	"strings"
	"unicode"
)

func TrimSpacesFromArray(title *[]string) {
	copy := *title

	for i := 0; i < len(*title); i++ {
		copy[i] = strings.TrimSpace(copy[i])
	}

	*title = copy
}

func TrimSuffixesFromStringSlice(slice *[]string, suffixes ...string) {
	sliceCopy := *slice
	for sliceIndex, _ := range sliceCopy {
		for _, suffix := range suffixes {
			sliceCopy[sliceIndex] = strings.TrimSuffix(sliceCopy[sliceIndex], suffix)
		}
	}
	*slice = sliceCopy
}

func TrimPrefixesFromStringSlice(slice *[]string, prefixes ...string) {
	sliceCopy := *slice
	for sliceIndex, _ := range sliceCopy {
		for _, prefix := range prefixes {
			sliceCopy[sliceIndex] = strings.TrimPrefix(sliceCopy[sliceIndex], prefix)
		}
	}
	*slice = sliceCopy
}

func TrimSuffixesFromWord(word *string, suffixes ...string) {
	for _, suffix := range suffixes {
		copy := *word
		*word = strings.TrimSuffix(copy, suffix)
	}
}

func StartsWithUppercase(str string) bool {

	if str == "" {
		return false
	} else {
		return unicode.IsUpper([]rune(str)[0])
	}

}

func TrimmedStringInSlice(str string, slice []string) bool {

	TrimSuffixesFromWord(&str, ".", ",")

	for _, strInSlice := range slice {
		if str == strInSlice {
			return true
		}
	}
	return false
}

func StringInSlice(str string, slice []string) bool {

	for _, strInSlice := range slice {
		if str == strInSlice {
			return true
		}
	}
	return false
}

func StringInSliceIgnoreCase(str string, slice []string) bool {
	for _, strInSlice := range slice {
		if strings.ToLower(str) == strings.ToLower(strInSlice) {
			return true
		}
	}
	return false
}

func WordIsNumber(word string) bool {
	TrimSuffixesFromWord(&word, ".", ",")
	_, err := strconv.Atoi(word)
	return err == nil
}

func RemoveIndexFromSlice(index int, slice *[]string) {
	sliceCopy := *slice
	if len(sliceCopy) > index {
		sliceCopy = append(sliceCopy[:index], sliceCopy[index+1:]...)
	} else {
		sliceCopy = sliceCopy[:index]
	}
	*slice = sliceCopy
}

func CurrentIndexNotLast(index int, slice []string) bool {
	return index < len(slice)-1
}
<|endoftext|>


<commit_before>package images

import (
	"context"
	"encoding/json"
	"time"

	"github.com/containerd/containerd/content"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

// Image provides the model for how containerd views container images.
type Image struct {
	Name                 string
	Labels               map[string]string
	Target               ocispec.Descriptor
	CreatedAt, UpdatedAt time.Time
}

type Store interface {
	Get(ctx context.Context, name string) (Image, error)
	List(ctx context.Context, filters ...string) ([]Image, error)
	Create(ctx context.Context, image Image) (Image, error)

	// Update will replace the data in the store with the provided image. If
	// one or more fieldpaths are provided, only those fields will be updated.
	Update(ctx context.Context, image Image, fieldpaths ...string) (Image, error)

	Delete(ctx context.Context, name string) error
}

// TODO(stevvooe): Many of these functions make strong platform assumptions,
// which are untrue in a lot of cases. More refactoring must be done here to
// make this work in all cases.

// Config resolves the image configuration descriptor.
//
// The caller can then use the descriptor to resolve and process the
// configuration of the image.
func (image *Image) Config(ctx context.Context, provider content.Provider) (ocispec.Descriptor, error) {
	return Config(ctx, provider, image.Target)
}

// RootFS returns the unpacked diffids that make up and images rootfs.
//
// These are used to verify that a set of layers unpacked to the expected
// values.
func (image *Image) RootFS(ctx context.Context, provider content.Provider) ([]digest.Digest, error) {
	desc, err := image.Config(ctx, provider)
	if err != nil {
		return nil, err
	}
	return RootFS(ctx, provider, desc)
}

// Size returns the total size of an image's packed resources.
func (image *Image) Size(ctx context.Context, provider content.Provider) (int64, error) {
	var size int64
	return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
		if desc.Size < 0 {
			return nil, errors.Errorf("invalid size %v in %v (%v)", desc.Size, desc.Digest, desc.MediaType)
		}
		size += desc.Size
		return nil, nil
	}), ChildrenHandler(provider)), image.Target)
}

func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor) (ocispec.Descriptor, error) {
	var configDesc ocispec.Descriptor
	return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
		switch image.MediaType {
		case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
			p, err := content.ReadBlob(ctx, provider, image.Digest)
			if err != nil {
				return nil, err
			}

			var manifest ocispec.Manifest
			if err := json.Unmarshal(p, &manifest); err != nil {
				return nil, err
			}

			configDesc = manifest.Config

			return nil, nil
		default:
			return nil, errors.New("could not resolve config")
		}

	}), image)
}

// RootFS returns the unpacked diffids that make up and images rootfs.
//
// These are used to verify that a set of layers unpacked to the expected
// values.
func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
	p, err := content.ReadBlob(ctx, provider, configDesc.Digest)
	if err != nil {
		return nil, err
	}

	var config ocispec.Image
	if err := json.Unmarshal(p, &config); err != nil {
		return nil, err
	}

	// TODO(stevvooe): Remove this bit when OCI structure uses correct type for
	// rootfs.DiffIDs.
	var diffIDs []digest.Digest
	for _, diffID := range config.RootFS.DiffIDs {
		diffIDs = append(diffIDs, digest.Digest(diffID))
	}

	return diffIDs, nil
}
<commit_msg>images: document config utility function<commit_after>package images

import (
	"context"
	"encoding/json"
	"time"

	"github.com/containerd/containerd/content"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

// Image provides the model for how containerd views container images.
type Image struct {
	Name                 string
	Labels               map[string]string
	Target               ocispec.Descriptor
	CreatedAt, UpdatedAt time.Time
}

type Store interface {
	Get(ctx context.Context, name string) (Image, error)
	List(ctx context.Context, filters ...string) ([]Image, error)
	Create(ctx context.Context, image Image) (Image, error)

	// Update will replace the data in the store with the provided image. If
	// one or more fieldpaths are provided, only those fields will be updated.
	Update(ctx context.Context, image Image, fieldpaths ...string) (Image, error)

	Delete(ctx context.Context, name string) error
}

// TODO(stevvooe): Many of these functions make strong platform assumptions,
// which are untrue in a lot of cases. More refactoring must be done here to
// make this work in all cases.

// Config resolves the image configuration descriptor.
//
// The caller can then use the descriptor to resolve and process the
// configuration of the image.
func (image *Image) Config(ctx context.Context, provider content.Provider) (ocispec.Descriptor, error) {
	return Config(ctx, provider, image.Target)
}

// RootFS returns the unpacked diffids that make up and images rootfs.
//
// These are used to verify that a set of layers unpacked to the expected
// values.
func (image *Image) RootFS(ctx context.Context, provider content.Provider) ([]digest.Digest, error) {
	desc, err := image.Config(ctx, provider)
	if err != nil {
		return nil, err
	}
	return RootFS(ctx, provider, desc)
}

// Size returns the total size of an image's packed resources.
func (image *Image) Size(ctx context.Context, provider content.Provider) (int64, error) {
	var size int64
	return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
		if desc.Size < 0 {
			return nil, errors.Errorf("invalid size %v in %v (%v)", desc.Size, desc.Digest, desc.MediaType)
		}
		size += desc.Size
		return nil, nil
	}), ChildrenHandler(provider)), image.Target)
}

// Config resolves the image configuration descriptor using a content provided
// to resolve child resources on the image.
//
// The caller can then use the descriptor to resolve and process the
// configuration of the image.
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor) (ocispec.Descriptor, error) {
	var configDesc ocispec.Descriptor
	return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
		switch image.MediaType {
		case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
			p, err := content.ReadBlob(ctx, provider, image.Digest)
			if err != nil {
				return nil, err
			}

			var manifest ocispec.Manifest
			if err := json.Unmarshal(p, &manifest); err != nil {
				return nil, err
			}

			configDesc = manifest.Config

			return nil, nil
		default:
			return nil, errors.New("could not resolve config")
		}

	}), image)
}

// RootFS returns the unpacked diffids that make up and images rootfs.
//
// These are used to verify that a set of layers unpacked to the expected
// values.
func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
	p, err := content.ReadBlob(ctx, provider, configDesc.Digest)
	if err != nil {
		return nil, err
	}

	var config ocispec.Image
	if err := json.Unmarshal(p, &config); err != nil {
		return nil, err
	}

	// TODO(stevvooe): Remove this bit when OCI structure uses correct type for
	// rootfs.DiffIDs.
	var diffIDs []digest.Digest
	for _, diffID := range config.RootFS.DiffIDs {
		diffIDs = append(diffIDs, digest.Digest(diffID))
	}

	return diffIDs, nil
}
<|endoftext|>


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

// +build !race

package integration

import (
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"

	"github.com/u-root/u-root/pkg/qemu"
	"github.com/u-root/u-root/pkg/vmtest"
)

// testPkgs returns a slice of tests to run.
func testPkgs(t *testing.T) []string {
	// Packages which do not contain tests (or do not contain tests for the
	// build target) will still compile a test binary which vacuously pass.
	cmd := exec.Command("go", "list",
		"github.com/u-root/u-root/cmds/boot/...",
		"github.com/u-root/u-root/cmds/core/...",
		"github.com/u-root/u-root/cmds/exp/...",
		"github.com/u-root/u-root/pkg/...",
	)
	cmd.Env = append(os.Environ(), "GOARCH="+vmtest.TestArch())
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatal(err)
	}
	pkgs := strings.Fields(strings.TrimSpace(string(out)))

	// TODO: Some tests do not run properly in QEMU at the moment. They are
	// blocklisted. These tests fail for mostly two reasons:
	// 1. either it requires networking (not enabled in the kernel)
	// 2. or it depends on some test files (for example /bin/sleep)
	blocklist := []string{
		"github.com/u-root/u-root/cmds/core/cmp",
		"github.com/u-root/u-root/cmds/core/dd",
		"github.com/u-root/u-root/cmds/core/elvish/eval",
		"github.com/u-root/u-root/cmds/core/elvish/edit/tty",
		"github.com/u-root/u-root/cmds/core/fusermount",
		"github.com/u-root/u-root/cmds/core/wget",
		"github.com/u-root/u-root/cmds/core/which",
		"github.com/u-root/u-root/cmds/exp/rush",
		"github.com/u-root/u-root/cmds/exp/pox",
		"github.com/u-root/u-root/pkg/crypto",
		"github.com/u-root/u-root/pkg/tarutil",
		"github.com/u-root/u-root/pkg/ldd",

		// These have special configuration.
		"github.com/u-root/u-root/pkg/gpio",
		"github.com/u-root/u-root/pkg/mount",
		"github.com/u-root/u-root/pkg/mount/loop",

		// Missing xzcat in VM.
		"github.com/u-root/u-root/cmds/exp/bzimage",
		"github.com/u-root/u-root/pkg/boot/bzimage",

		// No Go compiler in VM.
		"github.com/u-root/u-root/pkg/bb",
		"github.com/u-root/u-root/pkg/uroot",
		"github.com/u-root/u-root/pkg/uroot/builder",

		// ??
		"github.com/u-root/u-root/pkg/tss",
	}
	if vmtest.TestArch() == "arm64" {
		blocklist = append(
			blocklist,
			"github.com/u-root/u-root/pkg/strace",
		)
	}
	for i := 0; i < len(pkgs); i++ {
		for _, b := range blocklist {
			if pkgs[i] == b {
				pkgs = append(pkgs[:i], pkgs[i+1:]...)
			}
		}
	}

	return pkgs
}

// TestGoTest effectively runs "go test ./..." inside a QEMU instance. The
// tests run as root and can do all sorts of things not possible otherwise.
func TestGoTest(t *testing.T) {
	pkgs := testPkgs(t)

	o := &vmtest.Options{
		QEMUOpts: qemu.Options{
			Timeout: 120 * time.Second,
		},
	}
	vmtest.GolangTest(t, pkgs, o)
}
<commit_msg>integrations: bump mem to 5G for gotests<commit_after>// Copyright 2018 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build !race
// +build !race

package integration

import (
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"

	"github.com/u-root/u-root/pkg/qemu"
	"github.com/u-root/u-root/pkg/vmtest"
)

// testPkgs returns a slice of tests to run.
func testPkgs(t *testing.T) []string {
	// Packages which do not contain tests (or do not contain tests for the
	// build target) will still compile a test binary which vacuously pass.
	cmd := exec.Command("go", "list",
		"github.com/u-root/u-root/cmds/boot/...",
		"github.com/u-root/u-root/cmds/core/...",
		"github.com/u-root/u-root/cmds/exp/...",
		"github.com/u-root/u-root/pkg/...",
	)
	cmd.Env = append(os.Environ(), "GOARCH="+vmtest.TestArch())
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatal(err)
	}
	pkgs := strings.Fields(strings.TrimSpace(string(out)))

	// TODO: Some tests do not run properly in QEMU at the moment. They are
	// blocklisted. These tests fail for mostly two reasons:
	// 1. either it requires networking (not enabled in the kernel)
	// 2. or it depends on some test files (for example /bin/sleep)
	blocklist := []string{
		"github.com/u-root/u-root/cmds/core/cmp",
		"github.com/u-root/u-root/cmds/core/dd",
		"github.com/u-root/u-root/cmds/core/elvish/eval",
		"github.com/u-root/u-root/cmds/core/elvish/edit/tty",
		"github.com/u-root/u-root/cmds/core/fusermount",
		"github.com/u-root/u-root/cmds/core/wget",
		"github.com/u-root/u-root/cmds/core/which",
		"github.com/u-root/u-root/cmds/exp/rush",
		"github.com/u-root/u-root/cmds/exp/pox",
		"github.com/u-root/u-root/pkg/crypto",
		"github.com/u-root/u-root/pkg/tarutil",
		"github.com/u-root/u-root/pkg/ldd",

		// These have special configuration.
		"github.com/u-root/u-root/pkg/gpio",
		"github.com/u-root/u-root/pkg/mount",
		"github.com/u-root/u-root/pkg/mount/loop",

		// Missing xzcat in VM.
		"github.com/u-root/u-root/cmds/exp/bzimage",
		"github.com/u-root/u-root/pkg/boot/bzimage",

		// No Go compiler in VM.
		"github.com/u-root/u-root/pkg/bb",
		"github.com/u-root/u-root/pkg/uroot",
		"github.com/u-root/u-root/pkg/uroot/builder",

		// ??
		"github.com/u-root/u-root/pkg/tss",
	}
	if vmtest.TestArch() == "arm64" {
		blocklist = append(
			blocklist,
			"github.com/u-root/u-root/pkg/strace",
		)
	}
	for i := 0; i < len(pkgs); i++ {
		for _, b := range blocklist {
			if pkgs[i] == b {
				pkgs = append(pkgs[:i], pkgs[i+1:]...)
			}
		}
	}

	return pkgs
}

// TestGoTest effectively runs "go test ./..." inside a QEMU instance. The
// tests run as root and can do all sorts of things not possible otherwise.
func TestGoTest(t *testing.T) {
	pkgs := testPkgs(t)

	o := &vmtest.Options{
		QEMUOpts: qemu.Options{
			Timeout: 120 * time.Second,
			Devices: []qemu.Device{
				// Bump this up so that some unit tests can happily
				// and questionably pre-claim large bytes slices.
				//
				// e.g. pkg/mount/gpt/gpt_test.go need to claim 4.29G
				//
				//     disk = make([]byte, 0x100000000)
				qemu.ArbitraryArgs{"-m", "6G"},
			},
		},
	}
	vmtest.GolangTest(t, pkgs, o)
}
<|endoftext|>


<commit_before>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 containermatcher

import (
	"strings"

	"github.com/richardlehane/mscfb"
	"github.com/richardlehane/siegfried/internal/siegreader"
)

type mscfbReader struct {
	rdr   *mscfb.Reader
	entry *mscfb.File
}

func mscfbRdr(b *siegreader.Buffer) (Reader, error) {
	m, err := mscfb.New(siegreader.ReaderFrom(b))
	if err != nil {
		return nil, err
	}
	return &mscfbReader{rdr: m}, nil
}

func (m *mscfbReader) Next() error {
	var err error
	m.entry, err = m.rdr.Next()
	return err
}

func (m *mscfbReader) Name() string {
	if m.entry == nil {
		return ""
	}
	path := append(m.entry.Path, m.entry.Name)
	return strings.Join(path, "/")
}

func (m *mscfbReader) SetSource(b *siegreader.Buffers) (*siegreader.Buffer, error) {
	return b.Get(m.entry)
}

func (m *mscfbReader) Close() {}

func (m *mscfbReader) IsDir() bool {
	if m.entry == nil {
		return false
	}
	return m.entry.FileInfo().IsDir()
}
<commit_msg>add trailing slash to dir names in MSCFB container matcher<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 containermatcher

import (
	"strings"

	"github.com/richardlehane/mscfb"
	"github.com/richardlehane/siegfried/internal/siegreader"
)

type mscfbReader struct {
	rdr   *mscfb.Reader
	entry *mscfb.File
}

func mscfbRdr(b *siegreader.Buffer) (Reader, error) {
	m, err := mscfb.New(siegreader.ReaderFrom(b))
	if err != nil {
		return nil, err
	}
	return &mscfbReader{rdr: m}, nil
}

func (m *mscfbReader) Next() error {
	var err error
	m.entry, err = m.rdr.Next()
	return err
}

func (m *mscfbReader) Name() string {
	if m.entry == nil {
		return ""
	}
	path := append(m.entry.Path, m.entry.Name)
	if m.entry.FileInfo().IsDir() {
		return strings.Join(path, "/") + "/" // add a trailing slash if a directory
	}
	return strings.Join(path, "/")
}

func (m *mscfbReader) SetSource(b *siegreader.Buffers) (*siegreader.Buffer, error) {
	return b.Get(m.entry)
}

func (m *mscfbReader) Close() {}

func (m *mscfbReader) IsDir() bool {
	if m.entry == nil {
		return false
	}
	return m.entry.FileInfo().IsDir()
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 database

import (
	"context"
	"fmt"
	"log"
	"os"
	"testing"

	"github.com/golang-migrate/migrate/v4"
	"github.com/google/exposure-notifications-server/internal/serverenv"

	// imported to register the postgres migration driver
	_ "github.com/golang-migrate/migrate/v4/database/postgres"
	// imported to register the "file" source migration driver
	_ "github.com/golang-migrate/migrate/v4/source/file"
	// imported to register the "postgres" database driver for migrate
)

var testDB *DB

func TestMain(m *testing.M) {
	ctx := context.Background()

	if os.Getenv("DB_USER") != "" {
		var err error
		testDB, err = createTestDB(ctx)
		if err != nil {
			log.Fatalf("creating test DB: %v", err)
		}
	}
	os.Exit(m.Run())
}

// openTestDB connects to the Postgres server specified by the DB_XXX environment
// variables, creates an empty test database on it, and returns a *DB connected
// to that database.
func createTestDB(ctx context.Context) (*DB, error) {
	const testDBName = "exposure-server-test"

	// Connect to the default database to create the test database.
	env := serverenv.New(ctx)
	env.Set("DB_DBNAME", "postgres")
	db, err := NewFromEnv(ctx, env)
	if err != nil {
		return nil, err
	}
	if err := db.createDatabase(ctx, testDBName); err != nil {
		return nil, err
	}
	db.Close(ctx)

	// Connect to the test database and create its schema by applying all migrations.
	env.Set("DB_DBNAME", testDBName)
	db, err = NewFromEnv(ctx, env)
	if err != nil {
		return nil, err
	}
	const source = "file://../../migrations"
	uri, err := dbURI(ctx, configs, env)
	if err != nil {
		return nil, err
	}
	m, err := migrate.New(source, uri)
	if err != nil {
		return nil, err
	}
	if err := m.Up(); err != nil && err != migrate.ErrNoChange {
		_, _ = m.Close()
		return nil, err
	}
	srcErr, dbErr := m.Close()
	if srcErr != nil {
		return nil, srcErr
	}
	if dbErr != nil {
		return nil, dbErr
	}
	return db, nil
}

func (db *DB) createDatabase(ctx context.Context, name string) error {
	conn, err := db.pool.Acquire(ctx)
	if err != nil {
		return err
	}
	defer conn.Release()

	if _, err := conn.Exec(ctx, fmt.Sprintf(`DROP DATABASE IF EXISTS %q`, name)); err != nil {
		return err
	}
	_, err = conn.Exec(ctx, fmt.Sprintf(`CREATE DATABASE %q`, name))
	return err
}

func resetTestDB(t *testing.T) {
	ctx := context.Background()
	conn, err := testDB.pool.Acquire(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Release()

	_, err = conn.Exec(ctx, `
		TRUNCATE FederationQuery, FederationSync, Exposure, ExportConfig, ExportBatch,
				 ExportFile, APIConfig
	`)
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>internal/database: add test for DB time behavior (#77)<commit_after>// Copyright 2020 Google LLC
//
// 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 database

import (
	"context"
	"fmt"
	"log"
	"os"
	"testing"
	"time"

	"github.com/golang-migrate/migrate/v4"
	"github.com/google/exposure-notifications-server/internal/serverenv"
	"github.com/jackc/pgx/v4/pgxpool"

	// imported to register the postgres migration driver
	_ "github.com/golang-migrate/migrate/v4/database/postgres"
	// imported to register the "file" source migration driver
	_ "github.com/golang-migrate/migrate/v4/source/file"
	// imported to register the "postgres" database driver for migrate
)

var testDB *DB

func TestMain(m *testing.M) {
	ctx := context.Background()

	if os.Getenv("DB_USER") != "" {
		var err error
		testDB, err = createTestDB(ctx)
		if err != nil {
			log.Fatalf("creating test DB: %v", err)
		}
	}
	os.Exit(m.Run())
}

// openTestDB connects to the Postgres server specified by the DB_XXX environment
// variables, creates an empty test database on it, and returns a *DB connected
// to that database.
func createTestDB(ctx context.Context) (*DB, error) {
	const testDBName = "exposure-server-test"

	// Connect to the default database to create the test database.
	env := serverenv.New(ctx)
	env.Set("DB_DBNAME", "postgres")
	db, err := NewFromEnv(ctx, env)
	if err != nil {
		return nil, err
	}
	if err := db.createDatabase(ctx, testDBName); err != nil {
		return nil, err
	}
	db.Close(ctx)

	// Connect to the test database and create its schema by applying all migrations.
	env.Set("DB_DBNAME", testDBName)
	db, err = NewFromEnv(ctx, env)
	if err != nil {
		return nil, err
	}
	const source = "file://../../migrations"
	uri, err := dbURI(ctx, configs, env)
	if err != nil {
		return nil, err
	}
	m, err := migrate.New(source, uri)
	if err != nil {
		return nil, err
	}
	if err := m.Up(); err != nil && err != migrate.ErrNoChange {
		_, _ = m.Close()
		return nil, err
	}
	srcErr, dbErr := m.Close()
	if srcErr != nil {
		return nil, srcErr
	}
	if dbErr != nil {
		return nil, dbErr
	}
	return db, nil
}

func (db *DB) createDatabase(ctx context.Context, name string) error {
	conn, err := db.pool.Acquire(ctx)
	if err != nil {
		return err
	}
	defer conn.Release()

	if _, err := conn.Exec(ctx, fmt.Sprintf(`DROP DATABASE IF EXISTS %q`, name)); err != nil {
		return err
	}
	_, err = conn.Exec(ctx, fmt.Sprintf(`CREATE DATABASE %q`, name))
	return err
}

func TestTimestampTypes(t *testing.T) {
	// Demonstrate that the TIMESTAMP type does not preserve non-UTC times, but
	// the TIMESTAMPTZ type does.
	//
	// The reason is that TIMESTAMP stores only the calendar time values (year,
	// month, day, hour, minute, second, microsecond), while TIMESTAMPTZ also
	// records the timezone, giving a location-independent point in time.
	if testDB == nil {
		t.Skip("no test DB")
	}
	ctx := context.Background()
	conn, err := testDB.pool.Acquire(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Release()

	mustExec(t, conn, `CREATE TABLE timestamps (no_tz TIMESTAMP, tz TIMESTAMPTZ)`)

	local := time.Now()                      // timezone is always the local one, not UTC
	local = local.Truncate(time.Microsecond) // Postgres time resolution is microseconds.
	if name, _ := local.Zone(); name == "UTC" {
		t.Fatalf("time.Now returned %s, which is UTC", local)
	}
	// Insert the same time into the DB as both a TIMESTAMP and a TIMESTAMPTZ (aka
	// TIMESTAMP WITH TIME ZONE).
	mustExec(t, conn, `INSERT INTO timestamps (no_tz, tz) VALUES ($1, $2)`, local, local)
	// Read the times back.
	var gotNoTZ, gotWithTZ time.Time
	if err := conn.QueryRow(ctx, `SELECT no_tz, tz FROM timestamps`).Scan(&gotNoTZ, &gotWithTZ); err != nil {
		t.Fatal(err)
	}
	// The TIMESTAMPTZ column is the same time.
	if !local.Equal(gotWithTZ) {
		t.Fatal("TIMESTAMPTZ is not the same time")
	}

	// The TIMESTAMP column is NOT the same time.
	if local.Equal(gotNoTZ) {
		t.Fatal("TIMESTAMP is the same time")
	}
}

func mustExec(t *testing.T, conn *pgxpool.Conn, stmt string, args ...interface{}) {
	_, err := conn.Exec(context.Background(), stmt, args...)
	if err != nil {
		t.Fatalf("executing %s: %v", stmt, err)
	}
}

func resetTestDB(t *testing.T) {
	ctx := context.Background()
	conn, err := testDB.pool.Acquire(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Release()

	_, err = conn.Exec(ctx, `
		TRUNCATE FederationQuery, FederationSync, Exposure, ExportConfig, ExportBatch,
				 ExportFile, APIConfig
	`)
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package storage

import (
	"bytes"
	"crypto/rand"
	"encoding/gob"
	"fmt"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"

	"github.com/brocaar/loraserver/api/gw"
	"github.com/brocaar/loraserver/internal/common"
	"github.com/brocaar/lorawan"
)

const (
	devAddrKeyTempl       = "lora:ns:devaddr:%s" // contains a set of DevEUIs using this DevAddr
	deviceSessionKeyTempl = "lora:ns:device:%s"  // contains the session of a DevEUI
)

const UplinkHistorySize = 20

// RXWindow defines the RX window option.
type RXWindow int8

// Available RX window options.
const (
	RX1 = iota
	RX2
)

// UplinkHistory contains the meta-data of an uplink transmission.
type UplinkHistory struct {
	FCnt         uint32
	MaxSNR       float64
	GatewayCount int
}

// DeviceSession defines a device-session.
type DeviceSession struct {
	// profile ids
	DeviceProfileID  string
	ServiceProfileID string
	RoutingProfileID string

	// session data
	DevAddr  lorawan.DevAddr
	DevEUI   lorawan.EUI64
	JoinEUI  lorawan.EUI64 // TODO: remove?
	NwkSKey  lorawan.AES128Key
	FCntUp   uint32
	FCntDown uint32

	// Only used by ABP activation
	SkipFCntValidation bool

	RXWindow     RXWindow
	RXDelay      uint8
	RX1DROffset  uint8
	RX2DR        uint8
	RX2Frequency int

	// TXPowerIndex which the node is using. The possible values are defined
	// by the lorawan/band package and are region specific. By default it is
	// assumed that the node is using TXPower 0. This value is controlled by
	// the ADR engine.
	TXPowerIndex int

	// DR defines the (last known) data-rate at which the node is operating.
	// This value is controlled by the ADR engine.
	DR int

	// MaxSupportedTXPowerIndex defines the maximum supported tx-power index
	// by the node, or 0 when not set.
	MaxSupportedTXPowerIndex int

	// MaxSupportedDR defines the maximum supported DR index by the node,
	// or 0 when not set.
	MaxSupportedDR int

	// NbTrans defines the number of transmissions for each unconfirmed uplink
	// frame. In case of 0, the default value is used.
	// This value is controlled by the ADR engine.
	NbTrans uint8

	EnabledChannels    []int           // channels that are activated on the node
	ChannelFrequencies []int           // frequency of each channel
	UplinkHistory      []UplinkHistory // contains the last 20 transmissions
	LastRXInfoSet      []gw.RXInfo     // sorted set (best at index 0)

	// LastDevStatusRequest contains the timestamp when the last device-status
	// request was made.
	LastDevStatusRequested time.Time

	// LastDevStatusBattery contains the last received battery status.
	LastDevStatusBattery uint8

	// LastDevStatusMargin contains the last received margin status.
	LastDevStatusMargin int8
}

// AppendUplinkHistory appends an UplinkHistory item and makes sure the list
// never exceeds 20 records. In case more records are present, only the most
// recent ones will be preserved. In case of a re-transmission, the record with
// the best MaxSNR is stored.
func (s *DeviceSession) AppendUplinkHistory(up UplinkHistory) {
	if count := len(s.UplinkHistory); count > 0 {
		// ignore re-transmissions we don't know the source of the
		// re-transmission (it might be a replay-attack)
		if s.UplinkHistory[count-1].FCnt == up.FCnt {
			return
		}
	}

	s.UplinkHistory = append(s.UplinkHistory, up)
	if count := len(s.UplinkHistory); count > UplinkHistorySize {
		s.UplinkHistory = s.UplinkHistory[count-UplinkHistorySize : count]
	}
}

// GetPacketLossPercentage returns the percentage of packet-loss over the
// records stored in UplinkHistory.
// Note it returns 0 when the uplink history table hasn't been filled yet
// to avoid reporting 33% for example when one of the first three uplinks
// was lost.
func (s DeviceSession) GetPacketLossPercentage() float64 {
	if len(s.UplinkHistory) < UplinkHistorySize {
		return 0
	}

	var lostPackets uint32
	var previousFCnt uint32

	for i, uh := range s.UplinkHistory {
		if i == 0 {
			previousFCnt = uh.FCnt
			continue
		}
		lostPackets += uh.FCnt - previousFCnt - 1 // there is always an expected difference of 1
		previousFCnt = uh.FCnt
	}

	return float64(lostPackets) / float64(len(s.UplinkHistory)) * 100
}

// GetRandomDevAddr returns a random free DevAddr. Note that the 7 MSB will be
// set to the NwkID (based on the configured NetID).
func GetRandomDevAddr(p *redis.Pool, netID lorawan.NetID) (lorawan.DevAddr, error) {
	var d lorawan.DevAddr
	b := make([]byte, len(d))
	if _, err := rand.Read(b); err != nil {
		return d, errors.Wrap(err, "read random bytes error")
	}
	copy(d[:], b)
	d[0] = d[0] & 1                    // zero out 7 msb
	d[0] = d[0] ^ (netID.NwkID() << 1) // set 7 msb to NwkID

	return d, nil
}

// ValidateAndGetFullFCntUp validates if the given fCntUp is valid
// and returns the full 32 bit frame-counter.
// Note that the LoRaWAN packet only contains the 16 LSB, so in order
// to validate the MIC, the full 32 bit frame-counter needs to be set.
// After a succesful validation of the FCntUp and the MIC, don't forget
// to synchronize the Node FCntUp with the packet FCnt.
func ValidateAndGetFullFCntUp(s DeviceSession, fCntUp uint32) (uint32, bool) {
	// we need to compare the difference of the 16 LSB
	gap := uint32(uint16(fCntUp) - uint16(s.FCntUp%65536))
	if gap < common.Band.MaxFCntGap {
		return s.FCntUp + gap, true
	}
	return 0, false
}

// SaveDeviceSession saves the device-session. In case it doesn't exist yet
// it will be created.
func SaveDeviceSession(p *redis.Pool, s DeviceSession) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(s); err != nil {
		return errors.Wrap(err, "gob encode error")
	}

	c := p.Get()
	defer c.Close()
	exp := int64(common.NodeSessionTTL) / int64(time.Millisecond)

	c.Send("MULTI")
	c.Send("PSETEX", fmt.Sprintf(deviceSessionKeyTempl, s.DevEUI), exp, buf.Bytes())
	c.Send("SADD", fmt.Sprintf(devAddrKeyTempl, s.DevAddr), s.DevEUI[:])
	c.Send("PEXPIRE", fmt.Sprintf(devAddrKeyTempl, s.DevAddr), exp)

	if _, err := c.Do("EXEC"); err != nil {
		return errors.Wrap(err, "exec error")
	}

	log.WithFields(log.Fields{
		"dev_eui":  s.DevEUI,
		"dev_addr": s.DevAddr,
	}).Info("device-session saved")

	return nil
}

// GetDeviceSession returns the device-session for the given DevEUI.
func GetDeviceSession(p *redis.Pool, devEUI lorawan.EUI64) (DeviceSession, error) {
	var s DeviceSession

	c := p.Get()
	defer c.Close()

	val, err := redis.Bytes(c.Do("GET", fmt.Sprintf(deviceSessionKeyTempl, devEUI)))
	if err != nil {
		if err == redis.ErrNil {
			return s, ErrDoesNotExist
		}
		return s, errors.Wrap(err, "get error")
	}

	err = gob.NewDecoder(bytes.NewReader(val)).Decode(&s)
	if err != nil {
		return s, errors.Wrap(err, "gob decode error")
	}

	return s, nil
}

// DeleteDeviceSession deletes the device-session matching the given DevEUI.
func DeleteDeviceSession(p *redis.Pool, devEUI lorawan.EUI64) error {
	c := p.Get()
	defer c.Close()

	val, err := redis.Int(c.Do("DEL", fmt.Sprintf(deviceSessionKeyTempl, devEUI)))
	if err != nil {
		return errors.Wrap(err, "delete error")
	}
	if val == 0 {
		return ErrDoesNotExist
	}
	log.WithField("dev_eui", devEUI).Info("device-session deleted")
	return nil
}

// GetDeviceSessionsForDevAddr returns a slice of device-sessions using the
// given DevAddr. When no device-session is using the given DevAddr, this returns
// an empty slice.
func GetDeviceSessionsForDevAddr(p *redis.Pool, devAddr lorawan.DevAddr) ([]DeviceSession, error) {
	var items []DeviceSession

	c := p.Get()
	defer c.Close()

	devEUIs, err := redis.ByteSlices(c.Do("SMEMBERS", fmt.Sprintf(devAddrKeyTempl, devAddr)))
	if err != nil {
		if err == redis.ErrNil {
			return items, nil
		}
		return nil, errors.Wrap(err, "get members error")
	}

	for _, b := range devEUIs {
		var devEUI lorawan.EUI64
		copy(devEUI[:], b)

		s, err := GetDeviceSession(p, devEUI)
		if err != nil {
			// TODO: in case not found, remove the DevEUI from the list
			log.WithFields(log.Fields{
				"dev_addr": devAddr,
				"dev_eui":  devEUI,
			}).Warningf("get device-sessions for dev_addr error: %s", err)
		}
		items = append(items, s)
	}

	return items, nil
}

// GetDeviceSessionForPHYPayload returns the device-session matching the given
// PHYPayload. This will fetch all device-sessions associated with the used
// DevAddr and based on FCnt and MIC decide which one to use.
func GetDeviceSessionForPHYPayload(p *redis.Pool, phy lorawan.PHYPayload) (DeviceSession, error) {
	macPL, ok := phy.MACPayload.(*lorawan.MACPayload)
	if !ok {
		return DeviceSession{}, fmt.Errorf("expected *lorawan.MACPayload, got: %T", phy.MACPayload)
	}
	originalFCnt := macPL.FHDR.FCnt

	sessions, err := GetDeviceSessionsForDevAddr(p, macPL.FHDR.DevAddr)
	if err != nil {
		return DeviceSession{}, err
	}

	for _, s := range sessions {
		// reset to the original FCnt
		macPL.FHDR.FCnt = originalFCnt
		// get full FCnt
		fullFCnt, ok := ValidateAndGetFullFCntUp(s, macPL.FHDR.FCnt)
		if !ok {
			// If RelaxFCnt is turned on, just trust the uplink FCnt
			// this is insecure, but has been requested by many people for
			// debugging purposes.
			// Note that we do not reset the FCntDown as this would reset the
			// downlink frame-counter on a re-transmit, which is not what we
			// want.
			if s.SkipFCntValidation {
				fullFCnt = macPL.FHDR.FCnt
				s.FCntUp = macPL.FHDR.FCnt

				// validate if the mic is valid given the FCnt reset
				micOK, err := phy.ValidateMIC(s.NwkSKey)
				if err != nil {
					return DeviceSession{}, errors.Wrap(err, "validate mic error")
				}

				if micOK {
					// we need to update the NodeSession
					if err := SaveDeviceSession(p, s); err != nil {
						return DeviceSession{}, err
					}
					log.WithFields(log.Fields{
						"dev_addr": macPL.FHDR.DevAddr,
						"dev_eui":  s.DevEUI,
					}).Warning("frame counters reset")
					return s, nil
				}
			}
			// try the next node-session
			continue
		}

		// the FCnt is valid, validate the MIC
		macPL.FHDR.FCnt = fullFCnt
		micOK, err := phy.ValidateMIC(s.NwkSKey)
		if err != nil {
			return DeviceSession{}, errors.Wrap(err, "validate mic error")
		}
		if micOK {
			return s, nil
		}
	}

	return DeviceSession{}, ErrDoesNotExistOrFCntOrMICInvalid
}

// DeviceSessionExists returns a bool indicating if a device session exist.
func DeviceSessionExists(p *redis.Pool, devEUI lorawan.EUI64) (bool, error) {
	c := p.Get()
	defer c.Close()

	r, err := redis.Int(c.Do("EXISTS", fmt.Sprintf(deviceSessionKeyTempl, devEUI)))
	if err != nil {
		return false, errors.Wrap(err, "get exists error")
	}
	if r == 1 {
		return true, nil
	}
	return false, nil
}
<commit_msg>Reset UplinkHistory on framecounter reset (skip fcnt mode).<commit_after>package storage

import (
	"bytes"
	"crypto/rand"
	"encoding/gob"
	"fmt"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"

	"github.com/brocaar/loraserver/api/gw"
	"github.com/brocaar/loraserver/internal/common"
	"github.com/brocaar/lorawan"
)

const (
	devAddrKeyTempl       = "lora:ns:devaddr:%s" // contains a set of DevEUIs using this DevAddr
	deviceSessionKeyTempl = "lora:ns:device:%s"  // contains the session of a DevEUI
)

const UplinkHistorySize = 20

// RXWindow defines the RX window option.
type RXWindow int8

// Available RX window options.
const (
	RX1 = iota
	RX2
)

// UplinkHistory contains the meta-data of an uplink transmission.
type UplinkHistory struct {
	FCnt         uint32
	MaxSNR       float64
	GatewayCount int
}

// DeviceSession defines a device-session.
type DeviceSession struct {
	// profile ids
	DeviceProfileID  string
	ServiceProfileID string
	RoutingProfileID string

	// session data
	DevAddr  lorawan.DevAddr
	DevEUI   lorawan.EUI64
	JoinEUI  lorawan.EUI64 // TODO: remove?
	NwkSKey  lorawan.AES128Key
	FCntUp   uint32
	FCntDown uint32

	// Only used by ABP activation
	SkipFCntValidation bool

	RXWindow     RXWindow
	RXDelay      uint8
	RX1DROffset  uint8
	RX2DR        uint8
	RX2Frequency int

	// TXPowerIndex which the node is using. The possible values are defined
	// by the lorawan/band package and are region specific. By default it is
	// assumed that the node is using TXPower 0. This value is controlled by
	// the ADR engine.
	TXPowerIndex int

	// DR defines the (last known) data-rate at which the node is operating.
	// This value is controlled by the ADR engine.
	DR int

	// MaxSupportedTXPowerIndex defines the maximum supported tx-power index
	// by the node, or 0 when not set.
	MaxSupportedTXPowerIndex int

	// MaxSupportedDR defines the maximum supported DR index by the node,
	// or 0 when not set.
	MaxSupportedDR int

	// NbTrans defines the number of transmissions for each unconfirmed uplink
	// frame. In case of 0, the default value is used.
	// This value is controlled by the ADR engine.
	NbTrans uint8

	EnabledChannels    []int           // channels that are activated on the node
	ChannelFrequencies []int           // frequency of each channel
	UplinkHistory      []UplinkHistory // contains the last 20 transmissions
	LastRXInfoSet      []gw.RXInfo     // sorted set (best at index 0)

	// LastDevStatusRequest contains the timestamp when the last device-status
	// request was made.
	LastDevStatusRequested time.Time

	// LastDevStatusBattery contains the last received battery status.
	LastDevStatusBattery uint8

	// LastDevStatusMargin contains the last received margin status.
	LastDevStatusMargin int8
}

// AppendUplinkHistory appends an UplinkHistory item and makes sure the list
// never exceeds 20 records. In case more records are present, only the most
// recent ones will be preserved. In case of a re-transmission, the record with
// the best MaxSNR is stored.
func (s *DeviceSession) AppendUplinkHistory(up UplinkHistory) {
	if count := len(s.UplinkHistory); count > 0 {
		// ignore re-transmissions we don't know the source of the
		// re-transmission (it might be a replay-attack)
		if s.UplinkHistory[count-1].FCnt == up.FCnt {
			return
		}
	}

	s.UplinkHistory = append(s.UplinkHistory, up)
	if count := len(s.UplinkHistory); count > UplinkHistorySize {
		s.UplinkHistory = s.UplinkHistory[count-UplinkHistorySize : count]
	}
}

// GetPacketLossPercentage returns the percentage of packet-loss over the
// records stored in UplinkHistory.
// Note it returns 0 when the uplink history table hasn't been filled yet
// to avoid reporting 33% for example when one of the first three uplinks
// was lost.
func (s DeviceSession) GetPacketLossPercentage() float64 {
	if len(s.UplinkHistory) < UplinkHistorySize {
		return 0
	}

	var lostPackets uint32
	var previousFCnt uint32

	for i, uh := range s.UplinkHistory {
		if i == 0 {
			previousFCnt = uh.FCnt
			continue
		}
		lostPackets += uh.FCnt - previousFCnt - 1 // there is always an expected difference of 1
		previousFCnt = uh.FCnt
	}

	return float64(lostPackets) / float64(len(s.UplinkHistory)) * 100
}

// GetRandomDevAddr returns a random free DevAddr. Note that the 7 MSB will be
// set to the NwkID (based on the configured NetID).
func GetRandomDevAddr(p *redis.Pool, netID lorawan.NetID) (lorawan.DevAddr, error) {
	var d lorawan.DevAddr
	b := make([]byte, len(d))
	if _, err := rand.Read(b); err != nil {
		return d, errors.Wrap(err, "read random bytes error")
	}
	copy(d[:], b)
	d[0] = d[0] & 1                    // zero out 7 msb
	d[0] = d[0] ^ (netID.NwkID() << 1) // set 7 msb to NwkID

	return d, nil
}

// ValidateAndGetFullFCntUp validates if the given fCntUp is valid
// and returns the full 32 bit frame-counter.
// Note that the LoRaWAN packet only contains the 16 LSB, so in order
// to validate the MIC, the full 32 bit frame-counter needs to be set.
// After a succesful validation of the FCntUp and the MIC, don't forget
// to synchronize the Node FCntUp with the packet FCnt.
func ValidateAndGetFullFCntUp(s DeviceSession, fCntUp uint32) (uint32, bool) {
	// we need to compare the difference of the 16 LSB
	gap := uint32(uint16(fCntUp) - uint16(s.FCntUp%65536))
	if gap < common.Band.MaxFCntGap {
		return s.FCntUp + gap, true
	}
	return 0, false
}

// SaveDeviceSession saves the device-session. In case it doesn't exist yet
// it will be created.
func SaveDeviceSession(p *redis.Pool, s DeviceSession) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(s); err != nil {
		return errors.Wrap(err, "gob encode error")
	}

	c := p.Get()
	defer c.Close()
	exp := int64(common.NodeSessionTTL) / int64(time.Millisecond)

	c.Send("MULTI")
	c.Send("PSETEX", fmt.Sprintf(deviceSessionKeyTempl, s.DevEUI), exp, buf.Bytes())
	c.Send("SADD", fmt.Sprintf(devAddrKeyTempl, s.DevAddr), s.DevEUI[:])
	c.Send("PEXPIRE", fmt.Sprintf(devAddrKeyTempl, s.DevAddr), exp)

	if _, err := c.Do("EXEC"); err != nil {
		return errors.Wrap(err, "exec error")
	}

	log.WithFields(log.Fields{
		"dev_eui":  s.DevEUI,
		"dev_addr": s.DevAddr,
	}).Info("device-session saved")

	return nil
}

// GetDeviceSession returns the device-session for the given DevEUI.
func GetDeviceSession(p *redis.Pool, devEUI lorawan.EUI64) (DeviceSession, error) {
	var s DeviceSession

	c := p.Get()
	defer c.Close()

	val, err := redis.Bytes(c.Do("GET", fmt.Sprintf(deviceSessionKeyTempl, devEUI)))
	if err != nil {
		if err == redis.ErrNil {
			return s, ErrDoesNotExist
		}
		return s, errors.Wrap(err, "get error")
	}

	err = gob.NewDecoder(bytes.NewReader(val)).Decode(&s)
	if err != nil {
		return s, errors.Wrap(err, "gob decode error")
	}

	return s, nil
}

// DeleteDeviceSession deletes the device-session matching the given DevEUI.
func DeleteDeviceSession(p *redis.Pool, devEUI lorawan.EUI64) error {
	c := p.Get()
	defer c.Close()

	val, err := redis.Int(c.Do("DEL", fmt.Sprintf(deviceSessionKeyTempl, devEUI)))
	if err != nil {
		return errors.Wrap(err, "delete error")
	}
	if val == 0 {
		return ErrDoesNotExist
	}
	log.WithField("dev_eui", devEUI).Info("device-session deleted")
	return nil
}

// GetDeviceSessionsForDevAddr returns a slice of device-sessions using the
// given DevAddr. When no device-session is using the given DevAddr, this returns
// an empty slice.
func GetDeviceSessionsForDevAddr(p *redis.Pool, devAddr lorawan.DevAddr) ([]DeviceSession, error) {
	var items []DeviceSession

	c := p.Get()
	defer c.Close()

	devEUIs, err := redis.ByteSlices(c.Do("SMEMBERS", fmt.Sprintf(devAddrKeyTempl, devAddr)))
	if err != nil {
		if err == redis.ErrNil {
			return items, nil
		}
		return nil, errors.Wrap(err, "get members error")
	}

	for _, b := range devEUIs {
		var devEUI lorawan.EUI64
		copy(devEUI[:], b)

		s, err := GetDeviceSession(p, devEUI)
		if err != nil {
			// TODO: in case not found, remove the DevEUI from the list
			log.WithFields(log.Fields{
				"dev_addr": devAddr,
				"dev_eui":  devEUI,
			}).Warningf("get device-sessions for dev_addr error: %s", err)
		}
		items = append(items, s)
	}

	return items, nil
}

// GetDeviceSessionForPHYPayload returns the device-session matching the given
// PHYPayload. This will fetch all device-sessions associated with the used
// DevAddr and based on FCnt and MIC decide which one to use.
func GetDeviceSessionForPHYPayload(p *redis.Pool, phy lorawan.PHYPayload) (DeviceSession, error) {
	macPL, ok := phy.MACPayload.(*lorawan.MACPayload)
	if !ok {
		return DeviceSession{}, fmt.Errorf("expected *lorawan.MACPayload, got: %T", phy.MACPayload)
	}
	originalFCnt := macPL.FHDR.FCnt

	sessions, err := GetDeviceSessionsForDevAddr(p, macPL.FHDR.DevAddr)
	if err != nil {
		return DeviceSession{}, err
	}

	for _, s := range sessions {
		// reset to the original FCnt
		macPL.FHDR.FCnt = originalFCnt
		// get full FCnt
		fullFCnt, ok := ValidateAndGetFullFCntUp(s, macPL.FHDR.FCnt)
		if !ok {
			// If RelaxFCnt is turned on, just trust the uplink FCnt
			// this is insecure, but has been requested by many people for
			// debugging purposes.
			// Note that we do not reset the FCntDown as this would reset the
			// downlink frame-counter on a re-transmit, which is not what we
			// want.
			if s.SkipFCntValidation {
				fullFCnt = macPL.FHDR.FCnt
				s.FCntUp = macPL.FHDR.FCnt
				s.UplinkHistory = []UplinkHistory{}

				// validate if the mic is valid given the FCnt reset
				micOK, err := phy.ValidateMIC(s.NwkSKey)
				if err != nil {
					return DeviceSession{}, errors.Wrap(err, "validate mic error")
				}

				if micOK {
					// we need to update the NodeSession
					if err := SaveDeviceSession(p, s); err != nil {
						return DeviceSession{}, err
					}
					log.WithFields(log.Fields{
						"dev_addr": macPL.FHDR.DevAddr,
						"dev_eui":  s.DevEUI,
					}).Warning("frame counters reset")
					return s, nil
				}
			}
			// try the next node-session
			continue
		}

		// the FCnt is valid, validate the MIC
		macPL.FHDR.FCnt = fullFCnt
		micOK, err := phy.ValidateMIC(s.NwkSKey)
		if err != nil {
			return DeviceSession{}, errors.Wrap(err, "validate mic error")
		}
		if micOK {
			return s, nil
		}
	}

	return DeviceSession{}, ErrDoesNotExistOrFCntOrMICInvalid
}

// DeviceSessionExists returns a bool indicating if a device session exist.
func DeviceSessionExists(p *redis.Pool, devEUI lorawan.EUI64) (bool, error) {
	c := p.Get()
	defer c.Close()

	r, err := redis.Int(c.Do("EXISTS", fmt.Sprintf(deviceSessionKeyTempl, devEUI)))
	if err != nil {
		return false, errors.Wrap(err, "get exists error")
	}
	if r == 1 {
		return true, nil
	}
	return false, nil
}
<|endoftext|>


<commit_before>package monit

import (
	"encoding/xml"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strings"

	"code.google.com/p/go-charset/charset"
	_ "code.google.com/p/go-charset/data" // translations between char sets

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshhttp "github.com/cloudfoundry/bosh-utils/http"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
)

type httpClient struct {
	startClient     boshhttp.Client
	stopClient      boshhttp.Client
	unmonitorClient boshhttp.Client
	statusClient    boshhttp.Client
	host            string
	username        string
	password        string
	logger          boshlog.Logger
}

// NewHTTPClient creates a new monit client
//
// status & start use the shortClient
// unmonitor & stop use the longClient
func NewHTTPClient(
	host, username, password string,
	shortClient boshhttp.Client,
	longClient boshhttp.Client,
	logger boshlog.Logger,
) Client {
	return httpClient{
		host:            host,
		username:        username,
		password:        password,
		startClient:     shortClient,
		stopClient:      longClient,
		unmonitorClient: longClient,
		statusClient:    shortClient,
		logger:          logger,
	}
}

func (c httpClient) ServicesInGroup(name string) (services []string, err error) {
	status, err := c.status()
	if err != nil {
		return nil, bosherr.WrapError(err, "Getting status from Monit")
	}

	serviceGroup, found := status.ServiceGroups.Get(name)
	if !found {
		return []string{}, nil
	}

	return serviceGroup.Services, nil
}

func (c httpClient) StartService(serviceName string) error {
	response, err := c.makeRequest(c.startClient, c.monitURL(serviceName), "POST", "action=start")
	if err != nil {
		return bosherr.WrapError(err, "Sending start request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit start POST response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return bosherr.WrapErrorf(err, "Starting Monit service %s", serviceName)
	}

	return nil
}

func (c httpClient) StopService(serviceName string) error {
	response, err := c.makeRequest(c.stopClient, c.monitURL(serviceName), "POST", "action=stop")
	if err != nil {
		return bosherr.WrapError(err, "Sending stop request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit stop POST response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return bosherr.WrapErrorf(err, "Stopping Monit service %s", serviceName)
	}

	return nil
}

func (c httpClient) UnmonitorService(serviceName string) error {
	response, err := c.makeRequest(c.unmonitorClient, c.monitURL(serviceName), "POST", "action=unmonitor")
	if err != nil {
		return bosherr.WrapError(err, "Sending unmonitor request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit unmonitor POST response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return bosherr.WrapErrorf(err, "Unmonitoring Monit service %s", serviceName)
	}

	return nil
}

func (c httpClient) Status() (Status, error) {
	return c.status()
}

func (c httpClient) status() (status, error) {
	c.logger.Debug("http-client", "status function called")
	url := c.monitURL("/_status2")
	url.RawQuery = "format=xml"

	response, err := c.makeRequest(c.statusClient, url, "GET", "")
	if err != nil {
		return status{}, bosherr.WrapError(err, "Sending status request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit status GET response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return status{}, bosherr.WrapError(err, "Getting monit status")
	}

	decoder := xml.NewDecoder(response.Body)
	decoder.CharsetReader = charset.NewReader

	var st status

	err = decoder.Decode(&st)
	if err != nil {
		return status{}, bosherr.WrapError(err, "Unmarshalling Monit status")
	}

	return st, nil
}

func (c httpClient) monitURL(thing string) url.URL {
	return url.URL{
		Scheme: "http",
		Host:   c.host,
		Path:   path.Join("/", thing),
	}
}

func (c httpClient) validateResponse(response *http.Response) error {
	if response.StatusCode == http.StatusOK {
		return nil
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return bosherr.WrapError(err, "Reading body of failed Monit response")
	}

	c.logger.Debug("http-client", "Request failed with %s: %s", response.Status, string(body))

	return bosherr.Errorf("Request failed with %s: %s", response.Status, string(body))
}

func (c httpClient) makeRequest(client boshhttp.Client, target url.URL, method, requestBody string) (*http.Response, error) {
	c.logger.Debug("http-client", "Monit request: url='%s' body='%s'", target.String(), requestBody)

	request, err := http.NewRequest(method, target.String(), strings.NewReader(requestBody))
	if err != nil {
		return nil, err
	}

	request.SetBasicAuth(c.username, c.password)

	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	return client.Do(request)
}
<commit_msg>Remove reference to defunct google code import<commit_after>package monit

import (
	"encoding/xml"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/paulrosania/go-charset/charset"
	_ "github.com/paulrosania/go-charset/data" // translations between char sets

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshhttp "github.com/cloudfoundry/bosh-utils/http"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
)

type httpClient struct {
	startClient     boshhttp.Client
	stopClient      boshhttp.Client
	unmonitorClient boshhttp.Client
	statusClient    boshhttp.Client
	host            string
	username        string
	password        string
	logger          boshlog.Logger
}

// NewHTTPClient creates a new monit client
//
// status & start use the shortClient
// unmonitor & stop use the longClient
func NewHTTPClient(
	host, username, password string,
	shortClient boshhttp.Client,
	longClient boshhttp.Client,
	logger boshlog.Logger,
) Client {
	return httpClient{
		host:            host,
		username:        username,
		password:        password,
		startClient:     shortClient,
		stopClient:      longClient,
		unmonitorClient: longClient,
		statusClient:    shortClient,
		logger:          logger,
	}
}

func (c httpClient) ServicesInGroup(name string) (services []string, err error) {
	status, err := c.status()
	if err != nil {
		return nil, bosherr.WrapError(err, "Getting status from Monit")
	}

	serviceGroup, found := status.ServiceGroups.Get(name)
	if !found {
		return []string{}, nil
	}

	return serviceGroup.Services, nil
}

func (c httpClient) StartService(serviceName string) error {
	response, err := c.makeRequest(c.startClient, c.monitURL(serviceName), "POST", "action=start")
	if err != nil {
		return bosherr.WrapError(err, "Sending start request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit start POST response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return bosherr.WrapErrorf(err, "Starting Monit service %s", serviceName)
	}

	return nil
}

func (c httpClient) StopService(serviceName string) error {
	response, err := c.makeRequest(c.stopClient, c.monitURL(serviceName), "POST", "action=stop")
	if err != nil {
		return bosherr.WrapError(err, "Sending stop request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit stop POST response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return bosherr.WrapErrorf(err, "Stopping Monit service %s", serviceName)
	}

	return nil
}

func (c httpClient) UnmonitorService(serviceName string) error {
	response, err := c.makeRequest(c.unmonitorClient, c.monitURL(serviceName), "POST", "action=unmonitor")
	if err != nil {
		return bosherr.WrapError(err, "Sending unmonitor request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit unmonitor POST response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return bosherr.WrapErrorf(err, "Unmonitoring Monit service %s", serviceName)
	}

	return nil
}

func (c httpClient) Status() (Status, error) {
	return c.status()
}

func (c httpClient) status() (status, error) {
	c.logger.Debug("http-client", "status function called")
	url := c.monitURL("/_status2")
	url.RawQuery = "format=xml"

	response, err := c.makeRequest(c.statusClient, url, "GET", "")
	if err != nil {
		return status{}, bosherr.WrapError(err, "Sending status request to monit")
	}

	defer func() {
		if err := response.Body.Close(); err != nil {
			c.logger.Warn("http-client", "Failed to close monit status GET response body: %s", err.Error())
		}
	}()

	err = c.validateResponse(response)
	if err != nil {
		return status{}, bosherr.WrapError(err, "Getting monit status")
	}

	decoder := xml.NewDecoder(response.Body)
	decoder.CharsetReader = charset.NewReader

	var st status

	err = decoder.Decode(&st)
	if err != nil {
		return status{}, bosherr.WrapError(err, "Unmarshalling Monit status")
	}

	return st, nil
}

func (c httpClient) monitURL(thing string) url.URL {
	return url.URL{
		Scheme: "http",
		Host:   c.host,
		Path:   path.Join("/", thing),
	}
}

func (c httpClient) validateResponse(response *http.Response) error {
	if response.StatusCode == http.StatusOK {
		return nil
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return bosherr.WrapError(err, "Reading body of failed Monit response")
	}

	c.logger.Debug("http-client", "Request failed with %s: %s", response.Status, string(body))

	return bosherr.Errorf("Request failed with %s: %s", response.Status, string(body))
}

func (c httpClient) makeRequest(client boshhttp.Client, target url.URL, method, requestBody string) (*http.Response, error) {
	c.logger.Debug("http-client", "Monit request: url='%s' body='%s'", target.String(), requestBody)

	request, err := http.NewRequest(method, target.String(), strings.NewReader(requestBody))
	if err != nil {
		return nil, err
	}

	request.SetBasicAuth(c.username, c.password)

	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	return client.Do(request)
}
<|endoftext|>


<commit_before>package memory

import (
	"fmt"
	"github.com/pierrre/imageserver"
	lru_impl "github.com/pierrre/imageserver/cache/memory/lru"
)

type MemoryCache struct {
	lru *lru_impl.LRUCache
}

func New(capacity uint64) *MemoryCache {
	return &MemoryCache{
		lru: lru_impl.NewLRUCache(capacity),
	}
}

func (cache *MemoryCache) Get(key string, parameters imageserver.Parameters) (image *imageserver.Image, err error) {
	value, ok := cache.lru.Get(key)
	if !ok {
		err = fmt.Errorf("Not found")
		return
	}
	item := value.(*item)
	image = item.image
	return
}

func (cache *MemoryCache) Set(key string, image *imageserver.Image, parameters imageserver.Parameters) error {
	item := &item{
		image: image,
	}
	cache.lru.Set(key, item)
	return nil
}

type item struct {
	image *imageserver.Image
}

func (item *item) Size() int {
	return len(item.image.Data)
}
<commit_msg>Clean MemoryCache<commit_after>package memory

import (
	"fmt"
	"github.com/pierrre/imageserver"
	lru_impl "github.com/pierrre/imageserver/cache/memory/lru"
)

type MemoryCache struct {
	lru *lru_impl.LRUCache
}

func New(capacity uint64) *MemoryCache {
	return &MemoryCache{
		lru: lru_impl.NewLRUCache(capacity),
	}
}

func (cache *MemoryCache) Get(key string, parameters imageserver.Parameters) (image *imageserver.Image, err error) {
	value, ok := cache.lru.Get(key)
	if !ok {
		err = fmt.Errorf("Not found")
		return
	}
	item := value.(*item)
	image = item.image
	return
}

func (cache *MemoryCache) Set(key string, image *imageserver.Image, parameters imageserver.Parameters) (err error) {
	item := &item{
		image: image,
	}
	cache.lru.Set(key, item)
	return
}

type item struct {
	image *imageserver.Image
}

func (item *item) Size() int {
	return len(item.image.Data)
}
<|endoftext|>