<commit_before>package permission

import (
	"io/ioutil"
	"json"
	"path"
	"os"
)

const (
	FileNameGroups = "groups.json"
	FileNameUsers  = "users.json"
)

var (
	ErrFileGroups = os.NewError("Couldn't find groups.json")
	ErrFileUsers  = os.NewError("Couldn't find users.json")
)

// This is a permission system based on two json files "groups.json" and "users.json".
// It has one world support.
type JsonPermission struct {
	users       map[string]*CachedUser
	defaultUser *CachedUser
}

// The expected folder structure is:
// ./groups.json
// ./users.yml
func LoadJsonPermission(folder string) (*JsonPermission, os.Error) {
	files, err := ioutil.ReadDir(folder)
	if err != nil {
		return nil, err
	}
	var fileNameUsers string
	var fileNameGroups string
	for _, file := range files {
		fileName := path.Base(file.Name)
		if fileName == FileNameGroups {
			fileNameGroups = file.Name
		} else if fileName == FileNameUsers {
			fileNameUsers = file.Name
		}
	}
	if len(fileNameUsers) == 0 {
		return nil, ErrFileUsers
	} else if len(fileNameGroups) == 0 {
		return nil, ErrFileGroups
	}
	// Load users
	var bytesUsers []byte
	bytesUsers, err = ioutil.ReadFile(fileNameUsers)
	if err != nil {
		return nil, err
	}
	var users Users
	err = json.Unmarshal(bytesUsers, users)
	if err != nil {
		return nil, err
	}
	// Load groups
	var bytesGroups []byte
	bytesGroups, err = ioutil.ReadFile(fileNameGroups)
	if err != nil {
		return nil, err
	}
	var groups Groups
	err = json.Unmarshal(bytesGroups, groups)
	if err != nil {
		return nil, err
	}
	jPermission := &JsonPermission{users: make(map[string]*CachedUser)}
	// Cache users and merge groups into users
	for name, user := range users {
		permissions := make([]string, len(user.Permissions))
		for i := range user.Permissions {
			permissions[i] = user.Permissions[i]
		}
		inhPerm := getInheritance(user.Groups, groups)
		for _, perm := range inhPerm {
			permissions = append(permissions, perm)

		}
		jPermission.users[name] = &CachedUser{permissions: permissions}
	}
	// Cache default group
	defaultUser := &CachedUser{permissions: make([]string, 0)}
	for _, group := range groups {
		if group.Default {
			for _, perm := range group.Permissions {
				defaultUser.permissions = append(defaultUser.permissions, perm)
			}
			inhPerm := getInheritance(group.Inheritance, groups)
			for _, perm := range inhPerm {
				defaultUser.permissions = append(defaultUser.permissions, perm)
			}
		}
	}
	jPermission.defaultUser = defaultUser
	return jPermission, nil
}

func getInheritance(groupList []string, groups Groups) []string {
	permList := make([]string, 0)
	for _, group := range groupList {
		for _, permission := range groups[group].Permissions {
			permList = append(permList, permission)
		}
		inhPerm := getInheritance(groups[group].Inheritance, groups)
		for _, permission := range inhPerm {
			permList = append(permList, permission)
		}
	}
	return permList
}

// Implementation of IPermissions
func (p *JsonPermission) UserPermissions(username string) IUserPermissions {
	if user, ok := p.users[username]; ok {
		return user
	}
	return p.defaultUser
}

// A JsonPermission user with chached permissions.
type CachedUser struct {
	permissions []string
}

// Implementation of IUserPermissions
func (u *CachedUser) Has(node string) bool {
	for _, p := range u.permissions {
		if p == node {
			return true
		}
	}
	return false
}
<commit_msg>Fix json.Unmarshal not pointer error<commit_after>package permission

import (
	"io/ioutil"
	"json"
	"path"
	"os"
)

const (
	FileNameGroups = "groups.json"
	FileNameUsers  = "users.json"
)

var (
	ErrFileGroups = os.NewError("Couldn't find groups.json")
	ErrFileUsers  = os.NewError("Couldn't find users.json")
)

// This is a permission system based on two json files "groups.json" and "users.json".
// It has one world support.
type JsonPermission struct {
	users       map[string]*CachedUser
	defaultUser *CachedUser
}

// The expected folder structure is:
// ./groups.json
// ./users.yml
func LoadJsonPermission(folder string) (*JsonPermission, os.Error) {
	files, err := ioutil.ReadDir(folder)
	if err != nil {
		return nil, err
	}
	var fileNameUsers string
	var fileNameGroups string
	for _, file := range files {
		fileName := path.Base(file.Name)
		if fileName == FileNameGroups {
			fileNameGroups = file.Name
		} else if fileName == FileNameUsers {
			fileNameUsers = file.Name
		}
	}
	if len(fileNameUsers) == 0 {
		return nil, ErrFileUsers
	} else if len(fileNameGroups) == 0 {
		return nil, ErrFileGroups
	}
	// Load users
	var bytesUsers []byte
	bytesUsers, err = ioutil.ReadFile(fileNameUsers)
	if err != nil {
		return nil, err
	}
	var users Users
	err = json.Unmarshal(bytesUsers, &users)
	if err != nil {
		return nil, err
	}
	// Load groups
	var bytesGroups []byte
	bytesGroups, err = ioutil.ReadFile(fileNameGroups)
	if err != nil {
		return nil, err
	}
	var groups Groups
	err = json.Unmarshal(bytesGroups, &groups)
	if err != nil {
		return nil, err
	}
	jPermission := &JsonPermission{users: make(map[string]*CachedUser)}
	// Cache users and merge groups into users
	for name, user := range users {
		permissions := make([]string, len(user.Permissions))
		for i := range user.Permissions {
			permissions[i] = user.Permissions[i]
		}
		inhPerm := getInheritance(user.Groups, groups)
		for _, perm := range inhPerm {
			permissions = append(permissions, perm)

		}
		jPermission.users[name] = &CachedUser{permissions: permissions}
	}
	// Cache default group
	defaultUser := &CachedUser{permissions: make([]string, 0)}
	for _, group := range groups {
		if group.Default {
			for _, perm := range group.Permissions {
				defaultUser.permissions = append(defaultUser.permissions, perm)
			}
			inhPerm := getInheritance(group.Inheritance, groups)
			for _, perm := range inhPerm {
				defaultUser.permissions = append(defaultUser.permissions, perm)
			}
		}
	}
	jPermission.defaultUser = defaultUser
	return jPermission, nil
}

func getInheritance(groupList []string, groups Groups) []string {
	permList := make([]string, 0)
	for _, group := range groupList {
		for _, permission := range groups[group].Permissions {
			permList = append(permList, permission)
		}
		inhPerm := getInheritance(groups[group].Inheritance, groups)
		for _, permission := range inhPerm {
			permList = append(permList, permission)
		}
	}
	return permList
}

// Implementation of IPermissions
func (p *JsonPermission) UserPermissions(username string) IUserPermissions {
	if user, ok := p.users[username]; ok {
		return user
	}
	return p.defaultUser
}

// A JsonPermission user with chached permissions.
type CachedUser struct {
	permissions []string
}

// Implementation of IUserPermissions
func (u *CachedUser) Has(node string) bool {
	// TODO Implement wildcard * for nodes
	for _, p := range u.permissions {
		if p == node {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package parcel

import "encoding/json"

// ExchangeMessage represents an individual message for processing by the
// server or returning to the client.
//
// See http://jmap.io/spec.html#the-structure-of-an-exchange
type ExchangeMessage struct {
	// Name specifies the method to be called on the server or the type of
	// response being sent to the client.
	Name string

	// Arguments is map containing named arguments for the method or response.
	Arguments map[string]interface{}

	// ClientID is an arbitary string to be echoed back with the responses
	// emitted bythe method call.
	ClientID string
}

func (m *ExchangeMessage) MarshalJSON() ([]byte, error) {
	arr := make([]interface{}, 3)
	arr[0] = m.Name
	arr[1] = m.Arguments
	arr[2] = m.ClientID

	return json.Marshal(arr)
}

func (m *ExchangeMessage) UnmarshalJSON(j []byte) error {
	arr := []interface{}{}
	if err := json.Unmarshal(j, &arr); err != nil {
		return err
	}

	m.Name = arr[0].(string)
	m.Arguments = arr[1].(map[string]interface{})
	m.ClientID = arr[2].(string)

	return nil
}

// Login provides access to one or multiple accounts.
type Login struct{}

// Capabilities describes the various capabilities of this server.
//
// The spec for this isn't complete and the types of the fields are guessed.
// See the bottom of http://jmap.io/spec.html#accounts for details.
type Capabilities struct {
	DelayedSend          bool  `json:"delayedSend"`
	MaxSendSize          int64 `json:"maxSendSize"`
	SupportsMultiMailbox bool  `json:"supportsMultiMailbox"`
	SupportsThreads      bool  `json:"supportsThreads"`
}

// Account represents an account on the JMAP server. It provides access to
// mail, contacts, and calendars.
//
// A single login may be used to access multiple accounts.
//
// All IDs are only unique within an account. IDs may clash across accounts.
//
// http://jmap.io/spec.html#accounts
type Account struct {
	// ID uniquely identifies the account.
	ID string `json:"id"`

	// Name is a user-friendly string to show when presenting content from this
	// account. e.g. the email address of the account.
	Name string `json:"name"`

	// IsPrimary is whether the account is the primary account. This must be true
	// for exactly one of the accounts returned.
	IsPrimary bool `json:"isPrimary"`

	// IsReadyOnly is true if the user has read-only access to this account. The
	// user may not use the `set` methods with this account.
	IsReadOnly bool `json:"isReadOnly"`

	// HasMail represents whether this account contains mail data. Clients may
	// use the Mail methods with this account.
	HasMail bool `json:"hasMail"`

	// HasContacts represents whether this account contains contact data. Clients
	// may use the Contacts methods with this account.
	HasContacts bool `json:"hasContacts"`

	// HasCalendars represents whether this account contains calendar data.
	// Clients may use the Calendar methods with this account.
	HasCalendars bool `json:"hasCalendars"`

	// Capabilities describes the various capabilities of this server.
	Capabilities Capabilities `json:"capabilities"`
}

// Mailbox represents a named set of emails. This is the primary mechanism for
// organizing messages within an account. It is analogous to a folder in IMAP
// or a label in other systems. A mailbox may perform a certain role in the
// system.
//
// http://jmap.io/spec.html#mailboxes
type Mailbox struct {
	// ID is an immutable identifier for the mailbox.
	ID string `json:"id"`

	// Name is the user-visible name for the mailbox, e.g. "Inbox". This may be
	// any UTF-8 string of at least 1 character in length and maximum 256 bytes
	// in size. Mailboxes may have the same name as a sibling mailbox.
	Name string `json:"name"`

	// ParentID is the mailbox id for the parent of this mailbox, or nil if this
	// mailbox is at the top level. Mailboxes form acyclic graphs and, therefore,
	// must not loop.
	ParentID *string `json:"parentId"`

	// Role identifies system mailboxes. This property is immutable.
	//
	// The following values should be used for the relevant mailboxes:
	//
	//     inbox - the mailbox to which new mail is delivered by default, unless
	//             diverted by a rule or spam filter, etc.
	//   archive - messages the user does not need right now, but does not wish
	//             to delete.
	//    drafts - messages the user is currently writing and are not yet sent.
	//    outbox - messages the user has finished writing and wishes to send.
	//      sent - messages the user has sent.
	//     trash - messages the user has deleted.
	//      spam - messages considered spam by the server.
	// templates - drafts which should be used as templates (i.e. used as the
	//             basis for creating new drafts).
	//
	// If the mailbox's role is trash, then it must be treated specially:
	//
	//  * Messages in the Trash are ignored when calculating the unreadThreads
	//    and totalThreads count of other mailboxes.
	//  * Messages not in the Trash are ignored when calculating the
	//    unreadThreads and totalThreads count for the Trash folder.
	Role *string `json:"role"`

	// MustBeOnlyMailbox is whether messages in this mailbox may be in other
	// mailboxes as well.
	MustBeOnlyMailbox bool `json:"mustBeOnlyMailbox"`

	// MayAddMessages represents whether the user may add messages to this
	// mailbox (by either creating a new message or modifying an existing one).
	MayAddMessages bool `json:"mayAddMessages"`

	// MayRemoveMessages represents whether the user may remove messages from
	// this mailbox (by either changing the mailboxes of a message or deleting
	// it).
	MayRemoveMessages bool `json:"mayRemoveMessages"`

	// MayCreateChlid represents whether the user may create a mailbox with this
	// mailbox as its parent.
	MayCreateChild bool `json:"mayCreateChild"`

	// MayRenameMailbox represents whether the user may rename the mailbox or
	// make it as a child of another mailbox.
	MayRenameMailbox bool `json:"mayRenameMailbox"`

	// MayDeleteMailbox represents whether the user may delete the mailbox
	// itself.
	MayDeleteMailbox bool `json:"mayDeleteMailbox"`

	// TotalMessages is the number of messages in this mailbox.
	TotalMessages int64 `json:"totalMessages"`

	// UnreadMessages is the number of messages in this mailbox where the
	// isUnread property of the message is set to true and the isDraft property
	// is false.
	UnreadMessages int64 `json:"unreadMessages"`

	// TotalThreads is the number of threads where at least one message in the
	// thread is in this mailbox.
	TotalThreads int64 `json:"totalThreads"`

	// UnreadThreads is the number of threads where at least one message in the
	// thread has the isUnread property set to true and the isDraft property set
	// to false and at least one message in the thread is in the mailbox. Note,
	// the unread message does not need to be the one in this mailbox.
	UnreadThreads int64 `json:"unreadThreads"`
}

// Thread represents a grouping of replies with the original message. It is
// simply a flat list of messages, ordered by date. Every message belongs to a
// thread, even if it's the only message in the thread.
//
// http://jmap.io/spec.html#threads
type Thread struct {
	// ID identifies the thread.
	ID string `json:"id"`

	// MessageIDs are the ids of the messages in the thread, sorted such that:
	//
	// * Any message with isDraft set to true and an inReplyToMessageId property
	//   that corresponds to another message in the thread comes immediately
	//   after that message in the sort order.
	// * Other than that, everything is sorted in date order (the same as the
	//   date property on the Message object), oldest first.
	MessagesIDs []string `json:"messageIds"`
}

// MailMessage represents a mail message. A MailMessage is immutable except for
// the boolean `isXXX` status properties and the set of mailboxes it is in.
type MailMessage struct {
	// A unique, immutable ID that does not change if the message changes
	// mailboxes.
	ID string

	// Has the email not yet been read?
	IsUnread bool

	// Has the email been flagged (starred, or pinned)?
	IsFlagged bool

	// Is the email a draft?
	IsDraft bool

	// Has the email been answered (replied to)?
	IsAnswered bool
}
<commit_msg>messages: implement model<commit_after>package parcel

import (
	"encoding/json"
	"time"
)

// ExchangeMessage represents an individual message for processing by the
// server or returning to the client.
//
// See http://jmap.io/spec.html#the-structure-of-an-exchange
type ExchangeMessage struct {
	// Name specifies the method to be called on the server or the type of
	// response being sent to the client.
	Name string

	// Arguments is map containing named arguments for the method or response.
	Arguments map[string]interface{}

	// ClientID is an arbitary string to be echoed back with the responses
	// emitted bythe method call.
	ClientID string
}

func (m *ExchangeMessage) MarshalJSON() ([]byte, error) {
	arr := make([]interface{}, 3)
	arr[0] = m.Name
	arr[1] = m.Arguments
	arr[2] = m.ClientID

	return json.Marshal(arr)
}

func (m *ExchangeMessage) UnmarshalJSON(j []byte) error {
	arr := []interface{}{}
	if err := json.Unmarshal(j, &arr); err != nil {
		return err
	}

	m.Name = arr[0].(string)
	m.Arguments = arr[1].(map[string]interface{})
	m.ClientID = arr[2].(string)

	return nil
}

// Login provides access to one or multiple accounts.
type Login struct{}

// Capabilities describes the various capabilities of this server.
//
// The spec for this isn't complete and the types of the fields are guessed.
// See the bottom of http://jmap.io/spec.html#accounts for details.
type Capabilities struct {
	DelayedSend          bool  `json:"delayedSend"`
	MaxSendSize          int64 `json:"maxSendSize"`
	SupportsMultiMailbox bool  `json:"supportsMultiMailbox"`
	SupportsThreads      bool  `json:"supportsThreads"`
}

// Account represents an account on the JMAP server. It provides access to
// mail, contacts, and calendars.
//
// A single login may be used to access multiple accounts.
//
// All IDs are only unique within an account. IDs may clash across accounts.
//
// http://jmap.io/spec.html#accounts
type Account struct {
	// ID uniquely identifies the account.
	ID string `json:"id"`

	// Name is a user-friendly string to show when presenting content from this
	// account. e.g. the email address of the account.
	Name string `json:"name"`

	// IsPrimary is whether the account is the primary account. This must be true
	// for exactly one of the accounts returned.
	IsPrimary bool `json:"isPrimary"`

	// IsReadyOnly is true if the user has read-only access to this account. The
	// user may not use the `set` methods with this account.
	IsReadOnly bool `json:"isReadOnly"`

	// HasMail represents whether this account contains mail data. Clients may
	// use the Mail methods with this account.
	HasMail bool `json:"hasMail"`

	// HasContacts represents whether this account contains contact data. Clients
	// may use the Contacts methods with this account.
	HasContacts bool `json:"hasContacts"`

	// HasCalendars represents whether this account contains calendar data.
	// Clients may use the Calendar methods with this account.
	HasCalendars bool `json:"hasCalendars"`

	// Capabilities describes the various capabilities of this server.
	Capabilities Capabilities `json:"capabilities"`
}

// Mailbox represents a named set of emails. This is the primary mechanism for
// organizing messages within an account. It is analogous to a folder in IMAP
// or a label in other systems. A mailbox may perform a certain role in the
// system.
//
// http://jmap.io/spec.html#mailboxes
type Mailbox struct {
	// ID is an immutable identifier for the mailbox.
	ID string `json:"id"`

	// Name is the user-visible name for the mailbox, e.g. "Inbox". This may be
	// any UTF-8 string of at least 1 character in length and maximum 256 bytes
	// in size. Mailboxes may have the same name as a sibling mailbox.
	Name string `json:"name"`

	// ParentID is the mailbox id for the parent of this mailbox, or nil if this
	// mailbox is at the top level. Mailboxes form acyclic graphs and, therefore,
	// must not loop.
	ParentID *string `json:"parentId"`

	// Role identifies system mailboxes. This property is immutable.
	//
	// The following values should be used for the relevant mailboxes:
	//
	//     inbox - the mailbox to which new mail is delivered by default, unless
	//             diverted by a rule or spam filter, etc.
	//   archive - messages the user does not need right now, but does not wish
	//             to delete.
	//    drafts - messages the user is currently writing and are not yet sent.
	//    outbox - messages the user has finished writing and wishes to send.
	//      sent - messages the user has sent.
	//     trash - messages the user has deleted.
	//      spam - messages considered spam by the server.
	// templates - drafts which should be used as templates (i.e. used as the
	//             basis for creating new drafts).
	//
	// If the mailbox's role is trash, then it must be treated specially:
	//
	//  * Messages in the Trash are ignored when calculating the unreadThreads
	//    and totalThreads count of other mailboxes.
	//  * Messages not in the Trash are ignored when calculating the
	//    unreadThreads and totalThreads count for the Trash folder.
	Role *string `json:"role"`

	// MustBeOnlyMailbox is whether messages in this mailbox may be in other
	// mailboxes as well.
	MustBeOnlyMailbox bool `json:"mustBeOnlyMailbox"`

	// MayAddMessages represents whether the user may add messages to this
	// mailbox (by either creating a new message or modifying an existing one).
	MayAddMessages bool `json:"mayAddMessages"`

	// MayRemoveMessages represents whether the user may remove messages from
	// this mailbox (by either changing the mailboxes of a message or deleting
	// it).
	MayRemoveMessages bool `json:"mayRemoveMessages"`

	// MayCreateChlid represents whether the user may create a mailbox with this
	// mailbox as its parent.
	MayCreateChild bool `json:"mayCreateChild"`

	// MayRenameMailbox represents whether the user may rename the mailbox or
	// make it as a child of another mailbox.
	MayRenameMailbox bool `json:"mayRenameMailbox"`

	// MayDeleteMailbox represents whether the user may delete the mailbox
	// itself.
	MayDeleteMailbox bool `json:"mayDeleteMailbox"`

	// TotalMessages is the number of messages in this mailbox.
	TotalMessages int64 `json:"totalMessages"`

	// UnreadMessages is the number of messages in this mailbox where the
	// isUnread property of the message is set to true and the isDraft property
	// is false.
	UnreadMessages int64 `json:"unreadMessages"`

	// TotalThreads is the number of threads where at least one message in the
	// thread is in this mailbox.
	TotalThreads int64 `json:"totalThreads"`

	// UnreadThreads is the number of threads where at least one message in the
	// thread has the isUnread property set to true and the isDraft property set
	// to false and at least one message in the thread is in the mailbox. Note,
	// the unread message does not need to be the one in this mailbox.
	UnreadThreads int64 `json:"unreadThreads"`
}

// Thread represents a grouping of replies with the original message. It is
// simply a flat list of messages, ordered by date. Every message belongs to a
// thread, even if it's the only message in the thread.
//
// http://jmap.io/spec.html#threads
type Thread struct {
	// ID identifies the thread.
	ID string `json:"id"`

	// MessageIDs are the ids of the messages in the thread, sorted such that:
	//
	// * Any message with isDraft set to true and an inReplyToMessageId property
	//   that corresponds to another message in the thread comes immediately
	//   after that message in the sort order.
	// * Other than that, everything is sorted in date order (the same as the
	//   date property on the Message object), oldest first.
	MessagesIDs []string `json:"messageIds"`
}

// Emailer represents a sender or recipient of an email.
type Emailer struct {
	// Name represents the name of the sender/recipient. If a name cannot be
	// extracted for an email, this property should be an empty string.
	Name string `json:"name"`

	// Email is the email address of the sender/recipient.
	Email string `json:"email"`
}

// Attachment represents an email attachment.
type Attachment struct {
	// ID identifies an attachment. This is only unique when paired with the
	// message id and has no meaning without reference to that.
	ID string `json:"id"`

	// URL links to the attachment. The HTTP request must be authenticated.
	URL string `json:"url"`

	// Type is the Content-Type of the attachment.
	Type string `json:"type"`

	// Name is the full file name.
	Name string `json:"name"`

	// Size is the size, in bytes, of the attachment when fully decoded (i.e. the
	// number of bytes in the file the user would download).
	Size int64 `json:"size"`

	// IsLine is whether the attachment is referenced by a cid: link from within
	// the HTML body of the message.
	IsInline bool `json:"isInline"`

	// Width is the width (in px) of the image, if the attachment is an image.
	Width int64 `json:"width,omitempty"`

	// Height is the height (in px) of the image, if the attachment is an image.
	Height int64 `json:"height,omitempty"`
}

// Message represents an email message. A message is immutable except for the
// boolean isXXX status properties and the set of mailboxes it is in.
type Message struct {
	// A unique, immutable ID that does not change if the message changes
	// mailboxes.
	ID string `json:"id"`

	// ThreadID is the id fo the thread to which this message belongs.
	ThreadID string `json:"threadId"`

	// MailboxIDs are the ids of the mailboxes the message is in. A message must
	// belong to one or more mailboxes at all times (until it is deleted). This
	// property is mutable.
	MailboxIDs []string `json:"mailboxIds"`

	// InReplyToMessageID is the id of the message this message is a reply to.
	InReplyToMessageID *string `json:"inReplyToMessageId"`

	// IsUnread is whether the email not yet been read. This corresponds to the
	// opposite of the \Seen system flag in IMAP. This property is mutable.
	IsUnread bool `json:"isUnread"`

	// IsFlagged is whether the email been flagged (starred, or pinned). This
	// corresponds to the \Flagged system flag in IMAP. This property is mutable.
	IsFlagged bool `json:"isFlagged"`

	// IsAnswered is whether the email has been replied to. This corresponds to
	// the \Answered system flag in IMAP. This property is mutable.
	IsAnswered bool `json:"isAnswered"`

	// IsDraft is whether the email is a draft. This corresponds to the \Draft
	// system flag in IMAP This property is mutable.
	IsDraft bool `json:"isDraft"`

	// HasAttachment is whether the message has any attachments.
	HasAttachment bool `json:"hasAttachment"`

	// RawURL is a url to download the original RFC2822 message from. The HTTP
	// request must be authenticated.
	RawURL string `json:"rawUrl"`

	// Headers is a map of the header name to (decoded) header value for all
	// headers in the message. For headers that occur multiple times (e.g.
	// Received), the values are concatenated with a single new line (\n)
	// character in between each one.
	Headers map[string]string `json:"headers"`

	// From contains the name/email from the parsed From header of the email. If
	// the email doesn't have a From header, this is nil.
	From *Emailer `json:"from"`

	// To is a slice of emailers representing the parsed To header of the email,
	// in the same order as they appear in the header. If the email doesn't have
	// a To header, this is nil. If the header exists, but does not have any
	// content, this property should be an empty slice.
	To *[]Emailer `json:"to"`

	// CC is a slice of emailers representing the parsed Cc header of the email,
	// in the same order as they appear in the header. If the email doesn't have
	// a Cc header, this is nil. If the header exists, but does not have any
	// content, this property should be an empty slice.
	CC *[]Emailer `json:"cc"`

	// BCC is a slice of emailers representing the parsed Bcc header of the
	// email. If the email doesn't have a Bcc header (which will be true for most
	// emails outside of the Sent mailbox), this is nil. If the header exists,
	// but does not have any content, this property should be an empty slice.
	BCC *[]Emailer `json:"bcc"`

	// ReplyTo is a emailer from the parsed Reply-To header of the email. If the
	// email doesn't have a Reply-To header, this is nil.
	ReplyTo *Emailer `json:"emailer"`

	// Subject is the subject of the message.
	Subject string `json:"subject"`

	// Date is the date the message was sent (or saved, if the message is a
	// draft).
	Date time.Time `json:"date"`

	// Size is the size in bytes of the whole message as counted by the server
	// towards the user's quota.
	Size int64 `json:"size"`

	// Preview is intended to be shown as a preview line on a mailbox listing. It
	// is up to 256 characters of the beginning of a plain text version of the
	// message body.
	Preview string `json:"preview"`

	// TextBody is the plain text body part for the message. If there is only an
	// HTML version of the body, a plain text version will be generated from
	// this.
	TextBody *string `json:"textBody"`

	// HTMLBody is the HTML body part for the message, if present. If there is
	// only a plain text version of the body, an HTML version will be generated
	// from this. Any scripting content, or references to external plugins, must
	// be stripped from the HTML by the server.
	HTMLBody *string `json:"htmlBody"`

	// Attachments is a slice of attachments detailing all the attachments to the
	// message.
	Attachments *[]Attachment `json:"attachments"`

	// AttachedMessages is a map from attachment ids to message objects with less
	// properties and some properties renamed. I'm not really sure what this
	// means and have asked in the mailing list for clarification.
	//
	// See attachedMessages in http://jmap.io/spec.html#messages. Mailing list
	// discussion: https://groups.google.com/forum/#!msg/jmap-discuss/coEBFDY_A7E/vbIhJFYHCogJ
	AttachedMessages *map[string]Message `json:"attachedMessages"`
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/jinzhu/gorm"
	"html"
	"html/template"
	"strconv"
)

type Categories struct {
	Category_id   int
	Category_name string
	Torrents      []Torrents       `gorm:"ForeignKey:category_id;AssociationForeignKey:category_id"`
	Sub_category  []Sub_Categories `gorm:"ForeignKey:category_id;AssociationForeignKey:parent_id"`
}

type Sub_Categories struct {
	Sub_category_id   int
	Sub_category_name string
	Parent_id         int
	Torrents          []Torrents `gorm:"ForeignKey:sub_category_id;AssociationForeignKey:sub_category_id"`
}

type Torrents struct {
	gorm.Model
	Id              int    `gorm:"column:torrent_id"`
	Name            string `gorm:"column:torrent_name"`
	Category_id     int    `gorm:"column:category_id"`
	Sub_category_id int
	Status          int            `gorm:"column:status_id"`
	Hash            string         `gorm:"column:torrent_hash"`
	Categories      Categories     `gorm:"ForeignKey:category_id;AssociationForeignKey:category_id"`
	Sub_Categories  Sub_Categories `gorm:"ForeignKey:sub_category_id;AssociationForeignKey:sub_category_id"`
}

/* We need JSON Object instead because of Magnet URL that is not in the database but generated dynamically
--------------------------------------------------------------------------------------------------------------
JSON Models Oject
--------------------------------------------------------------------------------------------------------------
*/

type CategoryJson struct {
	Category         string         `json: "category"`
	Torrents         []TorrentsJson `json: "torrents"`
	QueryRecordCount int            `json: "queryRecordCount"`
	TotalRecordCount int            `json: "totalRecordCount"`
}

type TorrentsJson struct {
	Id     string       `json: "id"` // Is there a need to put the ID?
	Name   string       `json: "name"`
	Status int          `json: "status"`
	Hash   string       `json: "hash"`
	Magnet template.URL `json: "magnet"`
}

type WhereParams struct {
	conditions string // Ex : name LIKE ? AND category_id LIKE ?
	params     []interface{}
}

/* Each Page should have an object to pass to their own template */

type HomeTemplateVariables struct {
	ListTorrents     []TorrentsJson
	ListCategories   []Categories
	Query            string
	Category         string
	QueryRecordCount int
	TotalRecordCount int
}

/* Function to interact with Models
 *
 * Get the torrents with where clause
 *
 */

func getTorrentById(id string) (Torrents, error) {
	var torrent Torrents

	if db.Order("torrent_id DESC").First(&torrent, "id = ?", html.EscapeString(id)).RecordNotFound() {
		return torrent, errors.New("Article is not found.")
	}

	return torrent, nil
}

func getTorrents(parameters WhereParams, limit int, offset int) []Torrents {
	var torrents []Torrents
	db.Limit(limit).Offset(offset).Order("torrent_id DESC").Where(parameters.conditions, parameters.params...).Preload("Categories").Preload("Sub_Categories").Find(&torrents)
	return torrents
}

func getTorrentsDB(parameters WhereParams) []Torrents {
	var torrents []Torrents
	db.Where(parameters.conditions, parameters.params...).Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents)
	return torrents
}

/* Function to get all torrents
 */

func getAllTorrents(limit int, offset int) []Torrents {
	var torrents []Torrents
	db.Model(&torrents).Limit(limit).Offset(offset).Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents)

	return torrents
}

func getAllTorrentsDB() []Torrents {
	var torrents []Torrents
	db.Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents)
	return torrents
}

/* Function to get all categories with/without torrents (bool)
 */
func getAllCategories(populatedWithTorrents bool) []Categories {
	var categories []Categories
	if populatedWithTorrents {
		db.Preload("Torrents").Preload("Sub_Categories").Find(&categories)
	} else {
		db.Preload("Sub_Categories").Find(&categories)
	}
	return categories
}

func (t *Torrents) toJson() TorrentsJson {
	magnet := "magnet:?xt=urn:btih:" + strings.TrimSpace(t.Hash) + "&dn=" + t.Name + trackers
	res := TorrentsJson{
		Id:     strconv.Itoa(t.Id),
		Name:   html.UnescapeString(t.Name),
		Status: t.Status,
		Hash:   t.Hash,
		Magnet: safe(magnet)}
	return res
}

func createWhereParams(conditions string, params ...string) WhereParams {
	whereParams := WhereParams{}
	whereParams.conditions = conditions
	for i, _ := range params {
		whereParams.params = append(whereParams.params, params[i])
	}

	return whereParams
}

/* Complete the functions when necessary... */
<commit_msg>add strings<commit_after>package main

import (
	"errors"
	"github.com/jinzhu/gorm"
	"html"
	"html/template"
	"strconv"
	"strings"
)

type Categories struct {
	Category_id   int
	Category_name string
	Torrents      []Torrents       `gorm:"ForeignKey:category_id;AssociationForeignKey:category_id"`
	Sub_category  []Sub_Categories `gorm:"ForeignKey:category_id;AssociationForeignKey:parent_id"`
}

type Sub_Categories struct {
	Sub_category_id   int
	Sub_category_name string
	Parent_id         int
	Torrents          []Torrents `gorm:"ForeignKey:sub_category_id;AssociationForeignKey:sub_category_id"`
}

type Torrents struct {
	gorm.Model
	Id              int    `gorm:"column:torrent_id"`
	Name            string `gorm:"column:torrent_name"`
	Category_id     int    `gorm:"column:category_id"`
	Sub_category_id int
	Status          int            `gorm:"column:status_id"`
	Hash            string         `gorm:"column:torrent_hash"`
	Categories      Categories     `gorm:"ForeignKey:category_id;AssociationForeignKey:category_id"`
	Sub_Categories  Sub_Categories `gorm:"ForeignKey:sub_category_id;AssociationForeignKey:sub_category_id"`
}

/* We need JSON Object instead because of Magnet URL that is not in the database but generated dynamically
--------------------------------------------------------------------------------------------------------------
JSON Models Oject
--------------------------------------------------------------------------------------------------------------
*/

type CategoryJson struct {
	Category         string         `json: "category"`
	Torrents         []TorrentsJson `json: "torrents"`
	QueryRecordCount int            `json: "queryRecordCount"`
	TotalRecordCount int            `json: "totalRecordCount"`
}

type TorrentsJson struct {
	Id     string       `json: "id"` // Is there a need to put the ID?
	Name   string       `json: "name"`
	Status int          `json: "status"`
	Hash   string       `json: "hash"`
	Magnet template.URL `json: "magnet"`
}

type WhereParams struct {
	conditions string // Ex : name LIKE ? AND category_id LIKE ?
	params     []interface{}
}

/* Each Page should have an object to pass to their own template */

type HomeTemplateVariables struct {
	ListTorrents     []TorrentsJson
	ListCategories   []Categories
	Query            string
	Category         string
	QueryRecordCount int
	TotalRecordCount int
}

/* Function to interact with Models
 *
 * Get the torrents with where clause
 *
 */

func getTorrentById(id string) (Torrents, error) {
	var torrent Torrents

	if db.Order("torrent_id DESC").First(&torrent, "id = ?", html.EscapeString(id)).RecordNotFound() {
		return torrent, errors.New("Article is not found.")
	}

	return torrent, nil
}

func getTorrents(parameters WhereParams, limit int, offset int) []Torrents {
	var torrents []Torrents
	db.Limit(limit).Offset(offset).Order("torrent_id DESC").Where(parameters.conditions, parameters.params...).Preload("Categories").Preload("Sub_Categories").Find(&torrents)
	return torrents
}

func getTorrentsDB(parameters WhereParams) []Torrents {
	var torrents []Torrents
	db.Where(parameters.conditions, parameters.params...).Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents)
	return torrents
}

/* Function to get all torrents
 */

func getAllTorrents(limit int, offset int) []Torrents {
	var torrents []Torrents
	db.Model(&torrents).Limit(limit).Offset(offset).Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents)

	return torrents
}

func getAllTorrentsDB() []Torrents {
	var torrents []Torrents
	db.Order("torrent_id DESC").Preload("Categories").Preload("Sub_Categories").Find(&torrents)
	return torrents
}

/* Function to get all categories with/without torrents (bool)
 */
func getAllCategories(populatedWithTorrents bool) []Categories {
	var categories []Categories
	if populatedWithTorrents {
		db.Preload("Torrents").Preload("Sub_Categories").Find(&categories)
	} else {
		db.Preload("Sub_Categories").Find(&categories)
	}
	return categories
}

func (t *Torrents) toJson() TorrentsJson {
	magnet := "magnet:?xt=urn:btih:" + strings.TrimSpace(t.Hash) + "&dn=" + t.Name + trackers
	res := TorrentsJson{
		Id:     strconv.Itoa(t.Id),
		Name:   html.UnescapeString(t.Name),
		Status: t.Status,
		Hash:   t.Hash,
		Magnet: safe(magnet)}
	return res
}

func createWhereParams(conditions string, params ...string) WhereParams {
	whereParams := WhereParams{}
	whereParams.conditions = conditions
	for i, _ := range params {
		whereParams.params = append(whereParams.params, params[i])
	}

	return whereParams
}

/* Complete the functions when necessary... */
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/gob"
	"fmt"
	"io"
	"net/http"

	log "github.com/Sirupsen/logrus"
	"io/ioutil"
)

// DBClient provides access to cache, http client and configuration
type DBClient struct {
	cache Cache
	http  *http.Client
	cfg   *Configuration
}

// request holds structure for request
type request struct {
	details requestDetails
}

var emptyResp = &http.Response{}

// requestDetails stores information about request, it's used for creating unique hash and also as a payload structure
type requestDetails struct {
	Path        string              `json:"path"`
	Method      string              `json:"method"`
	Destination string              `json:"destination"`
	Scheme      string              `json:"scheme"`
	Query       string              `json:"query"`
	Body        string              `json:"body"`
	RemoteAddr  string              `json:"remoteAddr"`
	Headers     map[string][]string `json:"headers"`
}

func (r *request) concatenate() string {
	var buffer bytes.Buffer

	buffer.WriteString(r.details.Destination)
	buffer.WriteString(r.details.Path)
	buffer.WriteString(r.details.Method)
	buffer.WriteString(r.details.Query)
	buffer.WriteString(r.details.Body)

	return buffer.String()
}

// hash returns unique hash key for request
func (r *request) hash() string {
	h := md5.New()
	io.WriteString(h, r.concatenate())
	return fmt.Sprintf("%x", h.Sum(nil))
}

// res structure hold response body from external service, body is not decoded and is supposed
// to be bytes, however headers should provide all required information for later decoding
// by the client.
type response struct {
	Status  int                 `json:"status"`
	Body    string              `json:"body"`
	Headers map[string][]string `json:"headers"`
}

// Payload structure holds request and response structure
type Payload struct {
	Response response       `json:"response"`
	Request  requestDetails `json:"request"`
	ID       string         `json:"id"`
}

// encode method encodes all exported Payload fields to bytes
func (p *Payload) encode() ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(p)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// decodePayload decodes supplied bytes into Payload structure
func decodePayload(data []byte) (*Payload, error) {
	var p *Payload
	buf := bytes.NewBuffer(data)
	dec := gob.NewDecoder(buf)
	err := dec.Decode(&p)
	if err != nil {
		return nil, err
	}
	return p, nil
}

// captureRequest saves request for later playback
func (d *DBClient) captureRequest(req *http.Request) (*http.Response, error) {

	// this is mainly for testing, since when you create
	if req.Body == nil {
		req.Body = ioutil.NopCloser(bytes.NewBuffer([]byte("")))
	}

	reqBody, err := ioutil.ReadAll(req.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
			"mode":  "capture",
		}).Error("Got error when reading request body")
	}

	// outputting request body if verbose logging is set
	log.WithFields(log.Fields{
		"body": string(reqBody),
		"mode": "capture",
	}).Debug("got request body")

	req.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody))

	// forwarding request
	resp, err := d.doRequest(req)

	if err == nil {
		respBody, err := extractBody(resp)

		if err != nil {

			log.WithFields(log.Fields{
				"error": err.Error(),
				"mode":  "capture",
			}).Error("Failed to copy response body.")

			return resp, err
		}

		// saving response body with request/response meta to cache
		d.save(req, reqBody, resp, respBody)
	}

	// return new response or error here
	return resp, err
}

func copyBody(body io.ReadCloser) (resp1, resp2 io.ReadCloser, err error) {
	var buf bytes.Buffer
	if _, err = buf.ReadFrom(body); err != nil {
		return nil, nil, err
	}
	if err = body.Close(); err != nil {
		return nil, nil, err
	}
	return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
}

func extractBody(resp *http.Response) (extract []byte, err error) {
	save := resp.Body
	savecl := resp.ContentLength

	save, resp.Body, err = copyBody(resp.Body)

	if err != nil {
		return
	}
	defer resp.Body.Close()
	extract, err = ioutil.ReadAll(resp.Body)

	resp.Body = save
	resp.ContentLength = savecl
	if err != nil {
		return nil, err
	}
	return extract, nil
}

// doRequest performs original request and returns response that should be returned to client and error (if there is one)
func (d *DBClient) doRequest(request *http.Request) (*http.Response, error) {

	// We can't have this set. And it only contains "/pkg/net/http/" anyway
	request.RequestURI = ""

	if d.cfg.middleware != "" {
		var payload Payload

		c := NewConstructor(request, payload)
		err := c.ApplyMiddleware(d.cfg.middleware)

		if err != nil {
			log.WithFields(log.Fields{
				"mode":   d.cfg.mode,
				"error":  err.Error(),
				"host":   request.Host,
				"method": request.Method,
				"path":   request.URL.Path,
			}).Error("could not forward request, middleware failed to modify request.")
			return nil, err
		}

		request, err = c.reconstructRequest()
		if err != nil {
			return nil, err
		}
	}

	resp, err := d.http.Do(request)

	if err != nil {
		log.WithFields(log.Fields{
			"mode":   d.cfg.mode,
			"error":  err.Error(),
			"host":   request.Host,
			"method": request.Method,
			"path":   request.URL.Path,
		}).Error("could not forward request, failed to do an HTTP request.")
		return nil, err
	}

	log.WithFields(log.Fields{
		"mode":   d.cfg.mode,
		"host":   request.Host,
		"method": request.Method,
		"path":   request.URL.Path,
	}).Debug("response from external service got successfuly!")

	resp.Header.Set("hoverfly", "Was-Here")
	return resp, nil

}

// save gets request fingerprint, extracts request body, status code and headers, then saves it to cache
func (d *DBClient) save(req *http.Request, reqBody []byte, resp *http.Response, respBody []byte) {
	// record request here
	key := getRequestFingerprint(req, reqBody)

	if resp == nil {
		resp = emptyResp
	} else {
		responseObj := response{
			Status:  resp.StatusCode,
			Body:    string(respBody),
			Headers: resp.Header,
		}

		log.WithFields(log.Fields{
			"path":          req.URL.Path,
			"rawQuery":      req.URL.RawQuery,
			"requestMethod": req.Method,
			"bodyLen":       len(reqBody),
			"destination":   req.Host,
			"hashKey":       key,
		}).Debug("Capturing")

		requestObj := requestDetails{
			Path:        req.URL.Path,
			Method:      req.Method,
			Destination: req.Host,
			Scheme:      req.URL.Scheme,
			Query:       req.URL.RawQuery,
			Body:        string(reqBody),
			RemoteAddr:  req.RemoteAddr,
			Headers:     req.Header,
		}

		payload := Payload{
			Response: responseObj,
			Request:  requestObj,
			ID:       key,
		}

		bts, err := payload.encode()
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to serialize payload")
		} else {
			d.cache.Set([]byte(key), bts)
		}
	}
}

// getRequestFingerprint returns request hash
func getRequestFingerprint(req *http.Request, requestBody []byte) string {
	details := requestDetails{
		Path:        req.URL.Path,
		Method:      req.Method,
		Destination: req.Host,
		Query:       req.URL.RawQuery,
		Body:        string(requestBody),
	}

	r := request{details: details}
	return r.hash()
}

// getResponse returns stored response from cache
func (d *DBClient) getResponse(req *http.Request) *http.Response {

	if req.Body == nil {
		req.Body = ioutil.NopCloser(bytes.NewBuffer([]byte("")))
	}

	reqBody, err := ioutil.ReadAll(req.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Got error when reading request body")
	}

	key := getRequestFingerprint(req, reqBody)

	payloadBts, err := d.cache.Get([]byte(key))

	if err == nil {
		// getting cache response
		payload, err := decodePayload(payloadBts)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
				"value": string(payloadBts),
				"key":   key,
			}).Error("Failed to decode payload")
			return hoverflyError(req, err, "Failed to virtualize", http.StatusInternalServerError)
		}

		c := NewConstructor(req, *payload)

		if d.cfg.middleware != "" {
			_ = c.ApplyMiddleware(d.cfg.middleware)
		}

		response := c.reconstructResponse()

		log.WithFields(log.Fields{
			"key":         key,
			"mode":        "virtualize",
			"middleware":  d.cfg.middleware,
			"path":        req.URL.Path,
			"rawQuery":    req.URL.RawQuery,
			"method":      req.Method,
			"destination": req.Host,
			"status":      payload.Response.Status,
			"bodyLength":  response.ContentLength,
		}).Info("Response found, returning")

		return response

	}

	log.WithFields(log.Fields{
		"key":         key,
		"error":       err.Error(),
		"query":       req.URL.RawQuery,
		"path":        req.URL.RawPath,
		"destination": req.Host,
		"method":      req.Method,
	}).Warn("Failed to retrieve response from cache")
	// return error? if we return nil - proxy forwards request to original destination
	return hoverflyError(req, err, "Could not find recorded request, please record it first!", http.StatusPreconditionFailed)
}

// modifyRequestResponse modifies outgoing request and then modifies incoming response, neither request nor response
// is saved to cache.
func (d *DBClient) modifyRequestResponse(req *http.Request, middleware string) (*http.Response, error) {

	// modifying request
	resp, err := d.doRequest(req)

	if err != nil {
		return nil, err
	}

	// preparing payload
	bodyBytes, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"error":      err.Error(),
			"middleware": middleware,
		}).Error("Failed to read response body after sending modified request")
		return nil, err
	}

	r := response{
		Status:  resp.StatusCode,
		Body:    string(bodyBytes),
		Headers: resp.Header,
	}
	payload := Payload{Response: r}

	c := NewConstructor(req, payload)
	// applying middleware to modify response
	err = c.ApplyMiddleware(middleware)

	if err != nil {
		return nil, err
	}

	newResponse := c.reconstructResponse()

	log.WithFields(log.Fields{
		"status":     newResponse.StatusCode,
		"middleware": middleware,
	}).Info("Response modified, returning")

	return newResponse, nil

}
<commit_msg>show a bit more verbose information during modify mode<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/gob"
	"fmt"
	"io"
	"net/http"

	log "github.com/Sirupsen/logrus"
	"io/ioutil"
)

// DBClient provides access to cache, http client and configuration
type DBClient struct {
	cache Cache
	http  *http.Client
	cfg   *Configuration
}

// request holds structure for request
type request struct {
	details requestDetails
}

var emptyResp = &http.Response{}

// requestDetails stores information about request, it's used for creating unique hash and also as a payload structure
type requestDetails struct {
	Path        string              `json:"path"`
	Method      string              `json:"method"`
	Destination string              `json:"destination"`
	Scheme      string              `json:"scheme"`
	Query       string              `json:"query"`
	Body        string              `json:"body"`
	RemoteAddr  string              `json:"remoteAddr"`
	Headers     map[string][]string `json:"headers"`
}

func (r *request) concatenate() string {
	var buffer bytes.Buffer

	buffer.WriteString(r.details.Destination)
	buffer.WriteString(r.details.Path)
	buffer.WriteString(r.details.Method)
	buffer.WriteString(r.details.Query)
	buffer.WriteString(r.details.Body)

	return buffer.String()
}

// hash returns unique hash key for request
func (r *request) hash() string {
	h := md5.New()
	io.WriteString(h, r.concatenate())
	return fmt.Sprintf("%x", h.Sum(nil))
}

// res structure hold response body from external service, body is not decoded and is supposed
// to be bytes, however headers should provide all required information for later decoding
// by the client.
type response struct {
	Status  int                 `json:"status"`
	Body    string              `json:"body"`
	Headers map[string][]string `json:"headers"`
}

// Payload structure holds request and response structure
type Payload struct {
	Response response       `json:"response"`
	Request  requestDetails `json:"request"`
	ID       string         `json:"id"`
}

// encode method encodes all exported Payload fields to bytes
func (p *Payload) encode() ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(p)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// decodePayload decodes supplied bytes into Payload structure
func decodePayload(data []byte) (*Payload, error) {
	var p *Payload
	buf := bytes.NewBuffer(data)
	dec := gob.NewDecoder(buf)
	err := dec.Decode(&p)
	if err != nil {
		return nil, err
	}
	return p, nil
}

// captureRequest saves request for later playback
func (d *DBClient) captureRequest(req *http.Request) (*http.Response, error) {

	// this is mainly for testing, since when you create
	if req.Body == nil {
		req.Body = ioutil.NopCloser(bytes.NewBuffer([]byte("")))
	}

	reqBody, err := ioutil.ReadAll(req.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
			"mode":  "capture",
		}).Error("Got error when reading request body")
	}

	// outputting request body if verbose logging is set
	log.WithFields(log.Fields{
		"body": string(reqBody),
		"mode": "capture",
	}).Debug("got request body")

	req.Body = ioutil.NopCloser(bytes.NewBuffer(reqBody))

	// forwarding request
	resp, err := d.doRequest(req)

	if err == nil {
		respBody, err := extractBody(resp)

		if err != nil {

			log.WithFields(log.Fields{
				"error": err.Error(),
				"mode":  "capture",
			}).Error("Failed to copy response body.")

			return resp, err
		}

		// saving response body with request/response meta to cache
		d.save(req, reqBody, resp, respBody)
	}

	// return new response or error here
	return resp, err
}

func copyBody(body io.ReadCloser) (resp1, resp2 io.ReadCloser, err error) {
	var buf bytes.Buffer
	if _, err = buf.ReadFrom(body); err != nil {
		return nil, nil, err
	}
	if err = body.Close(); err != nil {
		return nil, nil, err
	}
	return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
}

func extractBody(resp *http.Response) (extract []byte, err error) {
	save := resp.Body
	savecl := resp.ContentLength

	save, resp.Body, err = copyBody(resp.Body)

	if err != nil {
		return
	}
	defer resp.Body.Close()
	extract, err = ioutil.ReadAll(resp.Body)

	resp.Body = save
	resp.ContentLength = savecl
	if err != nil {
		return nil, err
	}
	return extract, nil
}

// doRequest performs original request and returns response that should be returned to client and error (if there is one)
func (d *DBClient) doRequest(request *http.Request) (*http.Response, error) {

	// We can't have this set. And it only contains "/pkg/net/http/" anyway
	request.RequestURI = ""

	if d.cfg.middleware != "" {
		var payload Payload

		c := NewConstructor(request, payload)
		err := c.ApplyMiddleware(d.cfg.middleware)

		if err != nil {
			log.WithFields(log.Fields{
				"mode":   d.cfg.mode,
				"error":  err.Error(),
				"host":   request.Host,
				"method": request.Method,
				"path":   request.URL.Path,
			}).Error("could not forward request, middleware failed to modify request.")
			return nil, err
		}

		request, err = c.reconstructRequest()
		if err != nil {
			return nil, err
		}
	}

	resp, err := d.http.Do(request)

	if err != nil {
		log.WithFields(log.Fields{
			"mode":   d.cfg.mode,
			"error":  err.Error(),
			"host":   request.Host,
			"method": request.Method,
			"path":   request.URL.Path,
		}).Error("could not forward request, failed to do an HTTP request.")
		return nil, err
	}

	log.WithFields(log.Fields{
		"mode":   d.cfg.mode,
		"host":   request.Host,
		"method": request.Method,
		"path":   request.URL.Path,
	}).Debug("response from external service got successfuly!")

	resp.Header.Set("hoverfly", "Was-Here")
	return resp, nil

}

// save gets request fingerprint, extracts request body, status code and headers, then saves it to cache
func (d *DBClient) save(req *http.Request, reqBody []byte, resp *http.Response, respBody []byte) {
	// record request here
	key := getRequestFingerprint(req, reqBody)

	if resp == nil {
		resp = emptyResp
	} else {
		responseObj := response{
			Status:  resp.StatusCode,
			Body:    string(respBody),
			Headers: resp.Header,
		}

		log.WithFields(log.Fields{
			"path":          req.URL.Path,
			"rawQuery":      req.URL.RawQuery,
			"requestMethod": req.Method,
			"bodyLen":       len(reqBody),
			"destination":   req.Host,
			"hashKey":       key,
		}).Debug("Capturing")

		requestObj := requestDetails{
			Path:        req.URL.Path,
			Method:      req.Method,
			Destination: req.Host,
			Scheme:      req.URL.Scheme,
			Query:       req.URL.RawQuery,
			Body:        string(reqBody),
			RemoteAddr:  req.RemoteAddr,
			Headers:     req.Header,
		}

		payload := Payload{
			Response: responseObj,
			Request:  requestObj,
			ID:       key,
		}

		bts, err := payload.encode()
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to serialize payload")
		} else {
			d.cache.Set([]byte(key), bts)
		}
	}
}

// getRequestFingerprint returns request hash
func getRequestFingerprint(req *http.Request, requestBody []byte) string {
	details := requestDetails{
		Path:        req.URL.Path,
		Method:      req.Method,
		Destination: req.Host,
		Query:       req.URL.RawQuery,
		Body:        string(requestBody),
	}

	r := request{details: details}
	return r.hash()
}

// getResponse returns stored response from cache
func (d *DBClient) getResponse(req *http.Request) *http.Response {

	if req.Body == nil {
		req.Body = ioutil.NopCloser(bytes.NewBuffer([]byte("")))
	}

	reqBody, err := ioutil.ReadAll(req.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Got error when reading request body")
	}

	key := getRequestFingerprint(req, reqBody)

	payloadBts, err := d.cache.Get([]byte(key))

	if err == nil {
		// getting cache response
		payload, err := decodePayload(payloadBts)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
				"value": string(payloadBts),
				"key":   key,
			}).Error("Failed to decode payload")
			return hoverflyError(req, err, "Failed to virtualize", http.StatusInternalServerError)
		}

		c := NewConstructor(req, *payload)

		if d.cfg.middleware != "" {
			_ = c.ApplyMiddleware(d.cfg.middleware)
		}

		response := c.reconstructResponse()

		log.WithFields(log.Fields{
			"key":         key,
			"mode":        "virtualize",
			"middleware":  d.cfg.middleware,
			"path":        req.URL.Path,
			"rawQuery":    req.URL.RawQuery,
			"method":      req.Method,
			"destination": req.Host,
			"status":      payload.Response.Status,
			"bodyLength":  response.ContentLength,
		}).Info("Response found, returning")

		return response

	}

	log.WithFields(log.Fields{
		"key":         key,
		"error":       err.Error(),
		"query":       req.URL.RawQuery,
		"path":        req.URL.RawPath,
		"destination": req.Host,
		"method":      req.Method,
	}).Warn("Failed to retrieve response from cache")
	// return error? if we return nil - proxy forwards request to original destination
	return hoverflyError(req, err, "Could not find recorded request, please record it first!", http.StatusPreconditionFailed)
}

// modifyRequestResponse modifies outgoing request and then modifies incoming response, neither request nor response
// is saved to cache.
func (d *DBClient) modifyRequestResponse(req *http.Request, middleware string) (*http.Response, error) {

	// modifying request
	resp, err := d.doRequest(req)

	if err != nil {
		return nil, err
	}

	// preparing payload
	bodyBytes, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"error":      err.Error(),
			"middleware": middleware,
		}).Error("Failed to read response body after sending modified request")
		return nil, err
	}

	r := response{
		Status:  resp.StatusCode,
		Body:    string(bodyBytes),
		Headers: resp.Header,
	}
	payload := Payload{Response: r}

	c := NewConstructor(req, payload)
	// applying middleware to modify response
	err = c.ApplyMiddleware(middleware)

	if err != nil {
		return nil, err
	}

	newResponse := c.reconstructResponse()

	log.WithFields(log.Fields{
		"status":      newResponse.StatusCode,
		"middleware":  middleware,
		"mode":        "modify",
		"path":        c.request.URL.Path,
		"rawQuery":    c.request.URL.RawQuery,
		"method":      c.request.Method,
		"destination": c.request.Host,
	}).Info("request and response modified, returning")

	return newResponse, nil

}
<|endoftext|>


<commit_before>package vapor

import (
	"github.com/csm/go-edn"
	"github.com/csm/go-edn/types"
	"os"
	"bufio"
	"fmt"
)

type Module interface {
	TakesInput() bool
	Exec(types.Value) (types.Value, error)
}

func RunModule(module Module) {
	var input types.Value = nil
	var err error = nil
	if module.TakesInput() {
		input, err = edn.ParseReader(bufio.NewReader(os.Stdin))
	}
	if err != nil {
		os.Exit(1)
	}
	var output types.Value = nil
	output, err = module.Exec(input)
	if err != nil {
		if output != nil {
			fmt.Print(edn.DumpString(output))
		}
		os.Exit(1)
	}
	if output != nil {
		fmt.Println(edn.DumpString(output))
	}
	os.Exit(0)
}

type BoolType bool

func (self BoolType) Equals(other types.Value) {
	return self == other
}

func (self BoolType) String() string {
	if self {
		return "true"
	} else {
		return "false"
	}
}<commit_msg>Remove custom booltype stuff, go-edn is better at this now.<commit_after>package vapor

import (
	"github.com/csm/go-edn"
	"github.com/csm/go-edn/types"
	"os"
	"bufio"
	"fmt"
)

type Module interface {
	TakesInput() bool
	Exec(types.Value) (types.Value, error)
}

func RunModule(module Module) {
	var input types.Value = nil
	var err error = nil
	if module.TakesInput() {
		input, err = edn.ParseReader(bufio.NewReader(os.Stdin))
	}
	if err != nil {
		os.Exit(1)
	}
	var output types.Value = nil
	output, err = module.Exec(input)
	if err != nil {
		if output != nil {
			fmt.Print(edn.DumpString(output))
		}
		os.Exit(1)
	}
	if output != nil {
		fmt.Println(edn.DumpString(output))
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>/*
Package nakadi is a client library for the Nakadi event broker. It provides convenient access
to many features of Nakadi's API. The package can be used to manage event type definitions.

The EventAPI can be used to inspect existing event types and allows further to create new event
types and to update existing ones. The SubscriptionAPI provides subscription management: existing
subscriptions can be fetched from Nakadi and of course it is also possible to create new ones.
The PublishAPI of this package is used to broadcast event types of all event type categories via
Nakadi. Last but not least, the package also implements a StreamAPI, which enables event processing
on top of Nakadi's subscription based high level API.

To make the communication with Nakadi more resilient all sub APIs of this package can be configured
to retry failed requests using an exponential back-off algorithm.
*/
package nakadi

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/pkg/errors"
)

const (
	defaultTimeOut              = 30 * time.Second
	defaultNakadiURL            = "http://localhost:8080"
	defaultInitialRetryInterval = time.Millisecond * 10
	defaultMaxRetryInterval     = 10 * time.Second
	defaultMaxElapsedTime       = 30 * time.Second
)

// A Client represents a basic configuration to access a Nakadi instance. The client is used to configure
// other sub APIs of the `go-nakadi` package.
type Client struct {
	nakadiURL        string
	tokenProvider    func() (string, error)
	timeout          time.Duration
	httpClient       *http.Client
	httpStreamClient *http.Client
}

// ClientOptions contains all non mandatory parameters used to instantiate the Nakadi client.
type ClientOptions struct {
	TokenProvider     func() (string, error)
	ConnectionTimeout time.Duration
}

func (o *ClientOptions) withDefaults() *ClientOptions {
	var copyOptions ClientOptions
	if o != nil {
		copyOptions = *o
	}
	if copyOptions.ConnectionTimeout == 0 {
		copyOptions.ConnectionTimeout = defaultTimeOut
	}
	return &copyOptions
}

// New creates a new Nakadi client. New receives the URL of the Nakadi instance the client should connect to.
// In addition the second parameter options can be used to configure the behavior of the client and of all sub
// APIs in this package. The options may be nil.
func New(url string, options *ClientOptions) *Client {
	options = options.withDefaults()

	client := &Client{
		nakadiURL:        url,
		timeout:          options.ConnectionTimeout,
		tokenProvider:    options.TokenProvider,
		httpClient:       newHTTPClient(options.ConnectionTimeout),
		httpStreamClient: newHTTPStream(options.ConnectionTimeout)}

	return client
}

// httpGET fetches json encoded data with a GET request.
func (c *Client) httpGET(backOff backoff.BackOff, url string, body interface{}, msg string) error {
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return errors.Wrapf(err, "%s: unable to prepare request", msg)
	}

	if c.tokenProvider != nil {
		token, err := c.tokenProvider()
		if err != nil {
			return errors.Wrapf(err, "%s: unable to prepare request", msg)
		}
		request.Header.Set("Authorization", "Bearer "+token)
	}

	var response *http.Response
	err = backoff.Retry(func() error {
		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	if err != nil {
		return err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		buffer, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return errors.Wrap(err, "unable to read response body")
		}
		return decodeResponseToError(buffer, msg)
	}

	err = json.NewDecoder(response.Body).Decode(body)
	if err != nil {
		return errors.Wrap(err, "unable to decode response body")
	}

	return nil
}

// httpPUT sends json encoded data via PUT request and returns a response.
func (c *Client) httpPUT(backOff backoff.BackOff, url string, body interface{}, msg string) (*http.Response, error) {
	encoded, err := json.Marshal(body)
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to encode json body", msg)
	}

	request, err := http.NewRequest("PUT", url, bytes.NewReader(encoded))
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to prepare request", msg)
	}

	request.Header.Set("Content-Type", "application/json;charset=UTF-8")
	if c.tokenProvider != nil {
		token, err := c.tokenProvider()
		if err != nil {
			return nil, errors.Wrapf(err, "%s: unable to prepare request", msg)
		}
		request.Header.Set("Authorization", "Bearer "+token)
	}

	var response *http.Response
	err = backoff.Retry(func() error {
		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	return response, err
}

// httpPOST sends json encoded data via POST request and returns a response.
func (c *Client) httpPOST(backOff backoff.BackOff, url string, body interface{}, msg string) (*http.Response, error) {
	encoded, err := json.Marshal(body)
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to encode json body", msg)
	}

	request, err := http.NewRequest("POST", url, bytes.NewReader(encoded))
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to prepare request", msg)
	}

	request.Header.Set("Content-Type", "application/json;charset=UTF-8")
	if c.tokenProvider != nil {
		token, err := c.tokenProvider()
		if err != nil {
			return nil, errors.Wrapf(err, "%s: unable to prepare request", msg)
		}
		request.Header.Set("Authorization", "Bearer "+token)
	}

	var response *http.Response
	err = backoff.Retry(func() error {
		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	return response, err
}

// httpDELETE sends a DELETE request. On errors httpDELETE expects a response body to contain
// an error message in the format of application/problem+json.
func (c *Client) httpDELETE(backOff backoff.BackOff, url, msg string) error {
	request, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return errors.Wrapf(err, "%s: unable to prepare request", msg)
	}

	if c.tokenProvider != nil {
		token, err := c.tokenProvider()
		if err != nil {
			return errors.Wrapf(err, "%s: unable to prepare request", msg)
		}
		request.Header.Set("Authorization", "Bearer "+token)
	}

	var response *http.Response
	err = backoff.Retry(func() error {
		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	if err != nil {
		return err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNoContent {
		buffer, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return errors.Wrapf(err, "%s: unable to read response body", msg)
		}
		return decodeResponseToError(buffer, msg)
	}

	return nil
}
<commit_msg>Recreate request instances when retrying<commit_after>/*
Package nakadi is a client library for the Nakadi event broker. It provides convenient access
to many features of Nakadi's API. The package can be used to manage event type definitions.

The EventAPI can be used to inspect existing event types and allows further to create new event
types and to update existing ones. The SubscriptionAPI provides subscription management: existing
subscriptions can be fetched from Nakadi and of course it is also possible to create new ones.
The PublishAPI of this package is used to broadcast event types of all event type categories via
Nakadi. Last but not least, the package also implements a StreamAPI, which enables event processing
on top of Nakadi's subscription based high level API.

To make the communication with Nakadi more resilient all sub APIs of this package can be configured
to retry failed requests using an exponential back-off algorithm.
*/
package nakadi

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/pkg/errors"
)

const (
	defaultTimeOut              = 30 * time.Second
	defaultNakadiURL            = "http://localhost:8080"
	defaultInitialRetryInterval = time.Millisecond * 10
	defaultMaxRetryInterval     = 10 * time.Second
	defaultMaxElapsedTime       = 30 * time.Second
)

// A Client represents a basic configuration to access a Nakadi instance. The client is used to configure
// other sub APIs of the `go-nakadi` package.
type Client struct {
	nakadiURL        string
	tokenProvider    func() (string, error)
	timeout          time.Duration
	httpClient       *http.Client
	httpStreamClient *http.Client
}

// ClientOptions contains all non mandatory parameters used to instantiate the Nakadi client.
type ClientOptions struct {
	TokenProvider     func() (string, error)
	ConnectionTimeout time.Duration
}

func (o *ClientOptions) withDefaults() *ClientOptions {
	var copyOptions ClientOptions
	if o != nil {
		copyOptions = *o
	}
	if copyOptions.ConnectionTimeout == 0 {
		copyOptions.ConnectionTimeout = defaultTimeOut
	}
	return &copyOptions
}

// New creates a new Nakadi client. New receives the URL of the Nakadi instance the client should connect to.
// In addition the second parameter options can be used to configure the behavior of the client and of all sub
// APIs in this package. The options may be nil.
func New(url string, options *ClientOptions) *Client {
	options = options.withDefaults()

	client := &Client{
		nakadiURL:        url,
		timeout:          options.ConnectionTimeout,
		tokenProvider:    options.TokenProvider,
		httpClient:       newHTTPClient(options.ConnectionTimeout),
		httpStreamClient: newHTTPStream(options.ConnectionTimeout)}

	return client
}

// httpGET fetches json encoded data with a GET request.
func (c *Client) httpGET(backOff backoff.BackOff, url string, body interface{}, msg string) error {
	var response *http.Response
	err := backoff.Retry(func() error {
		request, err := http.NewRequest("GET", url, nil)
		if err != nil {
			return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
		}

		if c.tokenProvider != nil {
			token, err := c.tokenProvider()
			if err != nil {
				return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
			}
			request.Header.Set("Authorization", "Bearer "+token)
		}

		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	if err != nil {
		return err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		buffer, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return errors.Wrap(err, "unable to read response body")
		}
		return decodeResponseToError(buffer, msg)
	}

	err = json.NewDecoder(response.Body).Decode(body)
	if err != nil {
		return errors.Wrap(err, "unable to decode response body")
	}

	return nil
}

// httpPUT sends json encoded data via PUT request and returns a response.
func (c *Client) httpPUT(backOff backoff.BackOff, url string, body interface{}, msg string) (*http.Response, error) {
	encoded, err := json.Marshal(body)
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to encode json body", msg)
	}

	var response *http.Response
	err = backoff.Retry(func() error {
		request, err := http.NewRequest("PUT", url, bytes.NewReader(encoded))
		if err != nil {
			return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
		}

		request.Header.Set("Content-Type", "application/json;charset=UTF-8")
		if c.tokenProvider != nil {
			token, err := c.tokenProvider()
			if err != nil {
				return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
			}
			request.Header.Set("Authorization", "Bearer "+token)
		}

		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	return response, err
}

// httpPOST sends json encoded data via POST request and returns a response.
func (c *Client) httpPOST(backOff backoff.BackOff, url string, body interface{}, msg string) (*http.Response, error) {
	encoded, err := json.Marshal(body)
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to encode json body", msg)
	}

	var response *http.Response
	err = backoff.Retry(func() error {
		request, err := http.NewRequest("POST", url, bytes.NewReader(encoded))
		if err != nil {
			return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
		}

		request.Header.Set("Content-Type", "application/json;charset=UTF-8")
		if c.tokenProvider != nil {
			token, err := c.tokenProvider()
			if err != nil {
				return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
			}
			request.Header.Set("Authorization", "Bearer "+token)
		}

		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	return response, err
}

// httpDELETE sends a DELETE request. On errors httpDELETE expects a response body to contain
// an error message in the format of application/problem+json.
func (c *Client) httpDELETE(backOff backoff.BackOff, url, msg string) error {
	var response *http.Response
	err := backoff.Retry(func() error {
		request, err := http.NewRequest("DELETE", url, nil)
		if err != nil {
			return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
		}

		if c.tokenProvider != nil {
			token, err := c.tokenProvider()
			if err != nil {
				return backoff.Permanent(errors.Wrapf(err, "%s: unable to prepare request", msg))
			}
			request.Header.Set("Authorization", "Bearer "+token)
		}

		response, err = c.httpClient.Do(request)
		if err != nil {
			return errors.Wrap(err, msg)
		}

		if response.StatusCode >= 500 {
			buffer, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return errors.Wrapf(err, "%s: unable to read response body", msg)
			}
			err = decodeResponseToError(buffer, msg)
			response.Body.Close()
			return err
		}

		return nil
	}, backOff)

	if err != nil {
		return err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNoContent {
		buffer, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return errors.Wrapf(err, "%s: unable to read response body", msg)
		}
		return decodeResponseToError(buffer, msg)
	}

	return nil
}
<|endoftext|>


<commit_before>// +build linux, arm

// **********************************************************************
//    Copyright (c) 2017 Henry Seurer
//
//   Permission is hereby granted, free of charge, to any person
//    obtaining a copy of this software and associated documentation
//    files (the "Software"), to deal in the Software without
//    restriction, including without limitation the rights to use,
//    copy, modify, merge, publish, distribute, sublicense, and/or sell
//    copies of the Software, and to permit persons to whom the
//    Software is furnished to do so, subject to the following
//    conditions:
//
//   The above copyright notice and this permission notice shall be
//   included in all copies or substantial portions of the Software.
//
//    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//    OTHER DEALINGS IN THE SOFTWARE.
//
// **********************************************************************

package wiringpi

/*
#cgo LDFLAGS: -lwiringPi
#cgo CFLAGS: -O0

#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <stdlib.h>
#define nil ((void*)0)

#define GEN_INTERRUPTER(PIN) static void interrupt_handler_##PIN() { \
	context ctxt;   \
	ctxt.pin = PIN;  \
	ctxt.ret = PIN;  \
	callback_func(goCallback, &ctxt); \
}

typedef struct context context;
struct context {
	int pin;
	int ret;
};

static void(*callback_func)(void (*f)(void*), void*);

extern void goCallback(void *);

GEN_INTERRUPTER(0)
GEN_INTERRUPTER(1)
GEN_INTERRUPTER(2)
GEN_INTERRUPTER(3)
GEN_INTERRUPTER(4)
GEN_INTERRUPTER(5)
GEN_INTERRUPTER(6)
GEN_INTERRUPTER(7)
GEN_INTERRUPTER(8)
GEN_INTERRUPTER(9)
GEN_INTERRUPTER(10)
GEN_INTERRUPTER(11)
GEN_INTERRUPTER(12)
GEN_INTERRUPTER(13)
GEN_INTERRUPTER(14)
GEN_INTERRUPTER(15)
GEN_INTERRUPTER(16)
GEN_INTERRUPTER(17)
GEN_INTERRUPTER(18)
GEN_INTERRUPTER(19)
GEN_INTERRUPTER(20)

static int native_wiring_isr(int pin, int mode) {
	switch(pin) {
		case 0: return wiringPiISR(pin, mode, &interrupt_handler_0);
		case 1: return wiringPiISR(pin, mode, &interrupt_handler_1);
		case 2: return wiringPiISR(pin, mode, &interrupt_handler_2);
		case 3: return wiringPiISR(pin, mode, &interrupt_handler_3);
		case 4: return wiringPiISR(pin, mode, &interrupt_handler_4);
		case 5: return wiringPiISR(pin, mode, &interrupt_handler_5);
		case 6: return wiringPiISR(pin, mode, &interrupt_handler_6);
		case 7: return wiringPiISR(pin, mode, &interrupt_handler_7);
		case 8: return wiringPiISR(pin, mode, &interrupt_handler_8);
		case 9: return wiringPiISR(pin, mode, &interrupt_handler_9);
		case 10: return wiringPiISR(pin, mode, &interrupt_handler_10);
		case 11: return wiringPiISR(pin, mode, &interrupt_handler_11);
		case 12: return wiringPiISR(pin, mode, &interrupt_handler_12);
		case 13: return wiringPiISR(pin, mode, &interrupt_handler_13);
		case 14: return wiringPiISR(pin, mode, &interrupt_handler_14);
		case 15: return wiringPiISR(pin, mode, &interrupt_handler_15);
		case 16: return wiringPiISR(pin, mode, &interrupt_handler_16);
		case 17: return wiringPiISR(pin, mode, &interrupt_handler_17);
		case 18: return wiringPiISR(pin, mode, &interrupt_handler_18);
		case 19: return wiringPiISR(pin, mode, &interrupt_handler_19);
		case 20: return wiringPiISR(pin, mode, &interrupt_handler_20);
	}
	return -1;
}

static void init(void *p) {
	callback_func = p;
}
*/
import "C"
import "unsafe"

import (
	"github.com/henryse/go-callback"
	"sync"
)

const (
	WPI_MODE_PINS          = C.WPI_MODE_PINS
	WPI_MODE_GPIO          = C.WPI_MODE_GPIO
	WPI_MODE_GPIO_SYS      = C.WPI_MODE_GPIO_SYS
	WPI_MODE_PIFACE        = C.WPI_MODE_PIFACE
	WPI_MODE_UNINITIALISED = C.WPI_MODE_UNINITIALISED

	INPUT      = C.INPUT
	OUTPUT     = C.OUTPUT
	PWM_OUTPUT = C.PWM_OUTPUT
	GPIO_CLOCK = C.GPIO_CLOCK

	LOW  = C.LOW
	HIGH = C.HIGH

	PUD_OFF  = C.PUD_OFF
	PUD_DOWN = C.PUD_DOWN
	PUD_UP   = C.PUD_UP

	PWM_MODE_MS  = C.PWM_MODE_MS
	PWM_MODE_BAL = C.PWM_MODE_BAL

	INT_EDGE_SETUP   = C.INT_EDGE_SETUP
	INT_EDGE_FALLING = C.INT_EDGE_FALLING
	INT_EDGE_RISING  = C.INT_EDGE_RISING
	INT_EDGE_BOTH    = C.INT_EDGE_BOTH
)

var mutex = &sync.Mutex{}

func internalPinToGpio(pin int) int {
	return int(C.wpiPinToGpio(C.int(pin)))
}

func internalSetup() int {
	return int(C.wiringPiSetup())
}

func internalSetupGpio() int {
	return int(C.wiringPiSetupGpio())
}

func internalSetupPhys() int {
	return int(C.wiringPiSetupPhys())
}

func internalSetupSys() int {
	return int(C.wiringPiSetupSys())
}

func internalPinMode(pin int, mode int) {
	C.pinMode(C.int(pin), C.int(mode))
}

func internalPullUpDnControl(pin int, pud int) {
	C.pullUpDnControl(C.int(pin), C.int(pud))
}

func internalPwmWrite(pin int, value int) {
	C.pwmWrite(C.int(pin), C.int(value))
}

func internalDigitalWrite(pin int, mode int) {
	C.digitalWrite(C.int(pin), C.int(mode))
}

func internalDigitalRead(pin int) int {
	value := int(C.digitalRead(C.int(pin)))

	println("internalDigitalRead pin: %d = %d", pin, value)
	return value
}

func internalGetMode(pin int) int {
	return int(C.getAlt(C.int(pin)))
}

func internalDelay(ms int) {
	C.delay(C.uint(ms))
}

func internalDelayMicroseconds(microSec int) {
	C.delayMicroseconds(C.uint(microSec))
}

func internalWiringISR(pin int, mode int) chan int {
	mutex.Lock()
	defer mutex.Unlock()
	if interrupt_channels[pin] == nil {
		interrupt_channels[pin] = make(chan int)
	}
	C.native_wiring_isr(C.int(pin), C.int(mode))
	return interrupt_channels[pin]
}

func init() {
	C.init(callback.Func)
}

var interrupt_channels = [64]chan int{}

//export goCallback
func goCallback(arg unsafe.Pointer) {
	ctxt := (*C.context)(arg)
	interrupt_channels[int(ctxt.pin)] <- int(ctxt.ret)
}

// This initialises the I2C system with your given device identifier.
// The ID is the I2C number of the device and you can use the i2cdetect
// program to find this out. wiringPiI2CSetup() will work out which
// revision Raspberry Pi you have and open the appropriate device in /dev.
//
// The return value is the standard Linux filehandle, or -1 if any
// error – in which case, you can consult errno as usual.
//
func internalSetupI2C(devId int) int {
	return int(C.wiringPiI2CSetup(C.int(devId)))
}

// Simple device read. Some devices present data when you read them
// without having to do any register transactions.
//
func internalI2CRead(fd int) int {
	return int(C.wiringPiI2CRead(C.int(fd)))
}
<commit_msg>More logging<commit_after>// +build linux, arm

// **********************************************************************
//    Copyright (c) 2017 Henry Seurer
//
//   Permission is hereby granted, free of charge, to any person
//    obtaining a copy of this software and associated documentation
//    files (the "Software"), to deal in the Software without
//    restriction, including without limitation the rights to use,
//    copy, modify, merge, publish, distribute, sublicense, and/or sell
//    copies of the Software, and to permit persons to whom the
//    Software is furnished to do so, subject to the following
//    conditions:
//
//   The above copyright notice and this permission notice shall be
//   included in all copies or substantial portions of the Software.
//
//    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//    OTHER DEALINGS IN THE SOFTWARE.
//
// **********************************************************************

package wiringpi

/*
#cgo LDFLAGS: -lwiringPi
#cgo CFLAGS: -O0

#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <stdlib.h>
#define nil ((void*)0)

#define GEN_INTERRUPTER(PIN) static void interrupt_handler_##PIN() { \
	context ctxt;   \
	ctxt.pin = PIN;  \
	ctxt.ret = PIN;  \
	callback_func(goCallback, &ctxt); \
}

typedef struct context context;
struct context {
	int pin;
	int ret;
};

static void(*callback_func)(void (*f)(void*), void*);

extern void goCallback(void *);

GEN_INTERRUPTER(0)
GEN_INTERRUPTER(1)
GEN_INTERRUPTER(2)
GEN_INTERRUPTER(3)
GEN_INTERRUPTER(4)
GEN_INTERRUPTER(5)
GEN_INTERRUPTER(6)
GEN_INTERRUPTER(7)
GEN_INTERRUPTER(8)
GEN_INTERRUPTER(9)
GEN_INTERRUPTER(10)
GEN_INTERRUPTER(11)
GEN_INTERRUPTER(12)
GEN_INTERRUPTER(13)
GEN_INTERRUPTER(14)
GEN_INTERRUPTER(15)
GEN_INTERRUPTER(16)
GEN_INTERRUPTER(17)
GEN_INTERRUPTER(18)
GEN_INTERRUPTER(19)
GEN_INTERRUPTER(20)

static int native_wiring_isr(int pin, int mode) {
	switch(pin) {
		case 0: return wiringPiISR(pin, mode, &interrupt_handler_0);
		case 1: return wiringPiISR(pin, mode, &interrupt_handler_1);
		case 2: return wiringPiISR(pin, mode, &interrupt_handler_2);
		case 3: return wiringPiISR(pin, mode, &interrupt_handler_3);
		case 4: return wiringPiISR(pin, mode, &interrupt_handler_4);
		case 5: return wiringPiISR(pin, mode, &interrupt_handler_5);
		case 6: return wiringPiISR(pin, mode, &interrupt_handler_6);
		case 7: return wiringPiISR(pin, mode, &interrupt_handler_7);
		case 8: return wiringPiISR(pin, mode, &interrupt_handler_8);
		case 9: return wiringPiISR(pin, mode, &interrupt_handler_9);
		case 10: return wiringPiISR(pin, mode, &interrupt_handler_10);
		case 11: return wiringPiISR(pin, mode, &interrupt_handler_11);
		case 12: return wiringPiISR(pin, mode, &interrupt_handler_12);
		case 13: return wiringPiISR(pin, mode, &interrupt_handler_13);
		case 14: return wiringPiISR(pin, mode, &interrupt_handler_14);
		case 15: return wiringPiISR(pin, mode, &interrupt_handler_15);
		case 16: return wiringPiISR(pin, mode, &interrupt_handler_16);
		case 17: return wiringPiISR(pin, mode, &interrupt_handler_17);
		case 18: return wiringPiISR(pin, mode, &interrupt_handler_18);
		case 19: return wiringPiISR(pin, mode, &interrupt_handler_19);
		case 20: return wiringPiISR(pin, mode, &interrupt_handler_20);
	}
	return -1;
}

static void init(void *p) {
	callback_func = p;
}
*/
import "C"
import "unsafe"

import (
	"github.com/henryse/go-callback"
	"sync"
)

const (
	WPI_MODE_PINS          = C.WPI_MODE_PINS
	WPI_MODE_GPIO          = C.WPI_MODE_GPIO
	WPI_MODE_GPIO_SYS      = C.WPI_MODE_GPIO_SYS
	WPI_MODE_PIFACE        = C.WPI_MODE_PIFACE
	WPI_MODE_UNINITIALISED = C.WPI_MODE_UNINITIALISED

	INPUT      = C.INPUT
	OUTPUT     = C.OUTPUT
	PWM_OUTPUT = C.PWM_OUTPUT
	GPIO_CLOCK = C.GPIO_CLOCK

	LOW  = C.LOW
	HIGH = C.HIGH

	PUD_OFF  = C.PUD_OFF
	PUD_DOWN = C.PUD_DOWN
	PUD_UP   = C.PUD_UP

	PWM_MODE_MS  = C.PWM_MODE_MS
	PWM_MODE_BAL = C.PWM_MODE_BAL

	INT_EDGE_SETUP   = C.INT_EDGE_SETUP
	INT_EDGE_FALLING = C.INT_EDGE_FALLING
	INT_EDGE_RISING  = C.INT_EDGE_RISING
	INT_EDGE_BOTH    = C.INT_EDGE_BOTH
)

var mutex = &sync.Mutex{}

func internalPinToGpio(pin int) int {
	return int(C.wpiPinToGpio(C.int(pin)))
}

func internalSetup() int {
	return int(C.wiringPiSetup())
}

func internalSetupGpio() int {
	return int(C.wiringPiSetupGpio())
}

func internalSetupPhys() int {
	return int(C.wiringPiSetupPhys())
}

func internalSetupSys() int {
	return int(C.wiringPiSetupSys())
}

func internalPinMode(pin int, mode int) {
	C.pinMode(C.int(pin), C.int(mode))
}

func internalPullUpDnControl(pin int, pud int) {
	C.pullUpDnControl(C.int(pin), C.int(pud))
}

func internalPwmWrite(pin int, value int) {
	C.pwmWrite(C.int(pin), C.int(value))
}

func internalDigitalWrite(pin int, mode int) {
	C.digitalWrite(C.int(pin), C.int(mode))
}

func internalDigitalRead(pin int) int {
	value := int(C.digitalRead(C.int(pin)))

	fmt.Printf("internalDigitalRead pin: %d = %d", pin, value)
	return value
}

func internalGetMode(pin int) int {
	return int(C.getAlt(C.int(pin)))
}

func internalDelay(ms int) {
	C.delay(C.uint(ms))
}

func internalDelayMicroseconds(microSec int) {
	C.delayMicroseconds(C.uint(microSec))
}

func internalWiringISR(pin int, mode int) chan int {
	mutex.Lock()
	defer mutex.Unlock()
	if interrupt_channels[pin] == nil {
		interrupt_channels[pin] = make(chan int)
	}
	C.native_wiring_isr(C.int(pin), C.int(mode))
	return interrupt_channels[pin]
}

func init() {
	C.init(callback.Func)
}

var interrupt_channels = [64]chan int{}

//export goCallback
func goCallback(arg unsafe.Pointer) {
	ctxt := (*C.context)(arg)
	interrupt_channels[int(ctxt.pin)] <- int(ctxt.ret)
}

// This initialises the I2C system with your given device identifier.
// The ID is the I2C number of the device and you can use the i2cdetect
// program to find this out. wiringPiI2CSetup() will work out which
// revision Raspberry Pi you have and open the appropriate device in /dev.
//
// The return value is the standard Linux filehandle, or -1 if any
// error – in which case, you can consult errno as usual.
//
func internalSetupI2C(devId int) int {
	return int(C.wiringPiI2CSetup(C.int(devId)))
}

// Simple device read. Some devices present data when you read them
// without having to do any register transactions.
//
func internalI2CRead(fd int) int {
	return int(C.wiringPiI2CRead(C.int(fd)))
}
<|endoftext|>


<commit_before>/*
* MoveLegsSkill implements a skill
* that makes the HEXA to move its right
* arm up and down and left arm in a circle
 */

package examples

import (
	"math"
	"os"

	"mind/core/framework/drivers/hexabody"
	"mind/core/framework/skill"
)

type MoveLegsSkill struct {
	skill.Base
	stop chan bool
}

func NewSkill() skill.Interface {
	return &MoveLegsSkill{
		stop: make(chan bool),
	}
}

func ready() {
	hexabody.Stand()
	hexabody.MoveHead(0.0, 1)
	hexabody.MoveLeg(2, hexabody.NewLegPosition(-100, 50.0, 70.0), 1)
	hexabody.MoveLeg(5, hexabody.NewLegPosition(100, 50.0, 70.0), 1)
	hexabody.MoveJoint(0, 1, 90, 1)
	hexabody.MoveJoint(0, 2, 45, 1)
	hexabody.MoveJoint(1, 1, 90, 1)
	hexabody.MoveJoint(1, 2, 45, 1)
}

func moveLegs(v float64) {
	hexabody.MoveJoint(0, 1, 45*math.Sin(v*math.Pi/180)+70, 1)
	hexabody.MoveJoint(0, 0, 45*math.Cos(v*math.Pi/180)+100, 1)
	hexabody.MoveJoint(1, 1, 45*math.Cos(v*math.Pi/180)+70, 1)
}

func (d *MoveLegsSkill) play() {
	ready()
	v := 0.0
	for {
		select {
		case <-d.stop:
			return
		default:
			moveLegs(v)
			v += 1
		}
	}
}
func (d *MoveLegsSkill) OnStart() {
	hexabody.Start()
}

func (d *MoveLegsSkill) OnClose() {
	hexabody.Close()
}

func (d *MoveLegsSkill) OnDisconnect() {
	os.Exit(0) // Closes the process when remote disconnects
}

func (d *MoveLegsSkill) OnRecvString(data string) {
	switch data {
	case "start":
		go d.play()
	case "stop":
		d.stop <- true
		hexabody.RelaxLegs()
	}
}
<commit_msg>Smaller circle<commit_after>/*
* MoveLegsSkill implements a skill
* that makes the HEXA to move its right
* arm up and down and left arm in a circle
 */

package examples

import (
	"math"
	"os"

	"mind/core/framework/drivers/hexabody"
	"mind/core/framework/skill"
)

type MoveLegsSkill struct {
	skill.Base
	stop chan bool
}

func NewSkill() skill.Interface {
	return &MoveLegsSkill{
		stop: make(chan bool),
	}
}

func ready() {
	hexabody.Stand()
	hexabody.MoveHead(0.0, 1)
	hexabody.MoveLeg(2, hexabody.NewLegPosition(-100, 50.0, 70.0), 1)
	hexabody.MoveLeg(5, hexabody.NewLegPosition(100, 50.0, 70.0), 1)
	hexabody.MoveJoint(0, 1, 90, 1)
	hexabody.MoveJoint(0, 2, 45, 1)
	hexabody.MoveJoint(1, 1, 90, 1)
	hexabody.MoveJoint(1, 2, 45, 1)
}

func moveLegs(v float64) {
	hexabody.MoveJoint(0, 1, 45*math.Sin(v*math.Pi/180)+70, 1)
	hexabody.MoveJoint(0, 0, 35*math.Cos(v*math.Pi/180)+60, 1)
	hexabody.MoveJoint(1, 1, 45*math.Cos(v*math.Pi/180)+70, 1)
}

func (d *MoveLegsSkill) play() {
	ready()
	v := 0.0
	for {
		select {
		case <-d.stop:
			return
		default:
			moveLegs(v)
			v += 1
		}
	}
}
func (d *MoveLegsSkill) OnStart() {
	hexabody.Start()
}

func (d *MoveLegsSkill) OnClose() {
	hexabody.Close()
}

func (d *MoveLegsSkill) OnDisconnect() {
	os.Exit(0) // Closes the process when remote disconnects
}

func (d *MoveLegsSkill) OnRecvString(data string) {
	switch data {
	case "start":
		go d.play()
	case "stop":
		d.stop <- true
		hexabody.RelaxLegs()
	}
}
<|endoftext|>