<commit_before>package phpobject

import (
	"errors"
	"fmt"
	"io"
	"regexp"
)

var patNumber, _ = regexp.Compile(`^-?[1-9][0-9]*$`)
var patVarName, _ = regexp.Compile(`^[[:alpha:]_]\w*$`)

type PValueType int

const (
	PTNil PValueType = iota
	PTBool
	PTLong
	PTDouble
	PTString
	PTArray
	PTObject
)

var pValueNames = [9]string{"nil", "boolean", "long", "double", "string", "array", "object"}

func defaultFormat(v interface{}, f fmt.State, c rune) {
	buf := make([]string, 0, 10)
	buf = append(buf, "%")
	for i := 0; i < 128; i++ {
		if f.Flag(i) {
			buf = append(buf, string(i))
		}
	}

	if w, ok := f.Width(); ok {
		buf = append(buf, strconv.Itoa(w))
	}
	if p, ok := f.Precision(); ok {
		buf = append(buf, "."+strconv.Itoa(p))
	}
	buf = append(buf, string(c))
	format := strings.Join(buf, "")
	fmt.Fprintf(f, format, v)
}

func (vt PValueType) String() string {
	return pValueNames[int(vt)]
}

type PValue interface {
	String() string
	Type() PValueType
	serialize(w io.Writer)
	//unserialize(r io.Reader)
}

type PNilType struct{}

func (nl *PNilType) String() string   { return "nil" }
func (nl *PNilType) Type() PValueType { return PTNil }
func (nl *PNilType) serialize(w io.Writer) {
	w.Write([]byte("N;"))
}

var PNil = PValue(&PNilType{})

type PBool bool

func (bl PBool) String() string {
	if bool(bl) {
		return "true"
	}
	return "false"
}
func (bl PBool) Type() PValueType { return PTBool }
func (bl PBool) serialize(w io.Writer) {
	if bl {
		w.Write([]byte("b:1;"))
	} else {
		w.Write([]byte("b:0;"))
	}
}

var PTrue = PBool(true)
var PFalse = PBool(false)

type PLong int

func (lt PLong) String() string   { return fmt.Sprint(int(lt)) }
func (lt PLong) Type() PValueType { return PTLong }
func (lt PLong) serialize(w io.Writer) {
	fmt.Fprintf(w, "i:%d;", lt)
}

type PDouble float64

func (dt PDouble) String() string   { return fmt.Sprint(float64(dt)) }
func (dt PDouble) Type() PValueType { return PTDouble }
func (dt PDouble) serialize(w io.Writer) {
	fmt.Fprintf(w, "d:%f;", dt)
}

type PString string

func (st PString) String() string   { return string(st) }
func (st PString) Type() PValueType { return PTString }
func (st PString) serialize(w io.Writer) {
	fmt.Fprintf(w, "s:%d:\"", len(st))
	fmt.Fprint(w, st)
	fmt.Fprint(w, "\";")
}

const (
	NumArray = 1
	KeyArray = 2
)

type PArray struct {
	array map[string]PValue
	//forceType int
}

func NewArray() *PArray {
	var at PArray
	at.array = make(map[string]PValue)
	return &at
}

func (tb *PArray) Iget(index int) (PValue, bool) {
	key := fmt.Sprintf("%d", index)
	v, o := tb.array[key]
	return v, o
}
func (tb *PArray) Get(key string) (PValue, bool) {
	v, o := tb.array[key]
	return v, o
}

func (tb *PArray) Iset(index int, value PValue) {
	key := fmt.Sprintf("%d", index)
	tb.array[key] = value
}
func (tb *PArray) Set(key string, value PValue) bool {
	tb.array[key] = value
	if key == "0" || patNumber.MatchString(key) {
		return true
	} else {
		return false
	}
}

func serializeKey(w io.Writer, key string) {
	if key == "0" || patNumber.MatchString(key) {
		fmt.Fprintf(w, "i:%s;", key)
	} else {
		fmt.Fprintf(w, "s:%d:\"", len(key))
		fmt.Fprint(w, key)
		fmt.Fprint(w, "\";")
	}
}

func (tb *PArray) String() string   { return fmt.Sprintf("table: %v", tb) }
func (tb *PArray) Type() PValueType { return PTArray }

// fmt.Formatter interface
func (tb *PArray) Format(f fmt.State, c rune) {
	switch c {
	case 'q', 's':
		defaultFormat(nm.String(), f, c)
	case 'b', 'c', 'd', 'o', 'x', 'X', 'U':
		defaultFormat(int64(nm), f, c)
	case 'e', 'E', 'f', 'F', 'g', 'G':
		defaultFormat(float64(nm), f, c)
	case 'i':
		defaultFormat(int64(nm), f, 'd')
	default:
		if isInteger(nm) {
			defaultFormat(int64(nm), f, c)
		} else {
			defaultFormat(float64(nm), f, c)
		}
	}
}

func (tb *PArray) serialize(w io.Writer) {
	fmt.Fprintf(w, "a:%d:{", len(tb.array))
	for k, v := range tb.array {
		serializeKey(w, k)
		v.serialize(w)
	}
	w.Write([]byte("}"))
}

const (
	PublicVar      = 0
	ProtectedVar   = 1
	PrivateVar     = 2
	BasePrivateVar = 4
	endVarType     = 5
)

type oValue struct {
	value   PValue
	varType int
}

type PObject struct {
	vars  map[string]oValue
	class string
}

func NewObject(class string) *PObject {
	var ot PObject
	ot.vars = make(map[string]oValue)
	ot.class = class
	return &ot
}

func (ot *PObject) SetVar(varname string, vtype int, value PValue) error {
	if vtype == BasePrivateVar {
		return errors.New("You should use SetBaseVar")
	}
	if vtype > BasePrivateVar || vtype < 0 {
		return errors.New("Error var type")
	}
	if !patVarName.MatchString(varname) {
		return errors.New("Error varname")
	}
	ot.vars[varname] = oValue{value, vtype}
	return nil
}

func (ot *PObject) SetPublicVar(varname string, value PValue) error {
	return ot.SetVar(varname, PublicVar, value)
}

func (ot *PObject) SetProtectedVar(varname string, value PValue) error {
	return ot.SetVar(varname, ProtectedVar, value)
}

func (ot *PObject) SetPrivateVar(varname string, value PValue) error {
	return ot.SetVar(varname, PrivateVar, value)
}

func (ot *PObject) SetBaseVar(clsname, varname string, value PValue) error {
	if !patVarName.MatchString(varname) {
		return errors.New("Error varname")
	}
	if !patVarName.MatchString(clsname) {
		return errors.New("Error class name")
	}
	key := fmt.Sprintf("\x00%s\x00%s", clsname, varname)
	ot.vars[key] = oValue{value, BasePrivateVar}
	return nil
}

func (ot *PObject) GetVar(varname string) (value PValue, vtype int, ok bool) {
	oval, ok := ot.vars[varname]
	return oval.value, oval.varType, ok
}

func (ot *PObject) GetBaseVar(clsname, varname string) (value PValue, ok bool) {
	key := fmt.Sprintf("\x00%s\x00%s", clsname, varname)
	oval, ok := ot.vars[key]
	return oval.value, ok
}

func (ot *PObject) String() string   { return fmt.Sprintf("object: %v", ot) }
func (ot *PObject) Type() PValueType { return PTObject }
func (ot *PObject) serialize(w io.Writer) {
	fmt.Fprintf(w, "O:%d:\"%s\"", len(ot.class), ot.class)
	fmt.Fprintf(w, ":%d:{", len(ot.vars))
	for k, v := range ot.vars {
		key := PString(k)
		switch v.varType {
		case ProtectedVar:
			key = PString("\x00*\x00" + k)
		case PrivateVar:
			key = PString(fmt.Sprintf("\x00%s\x00%s", ot.class, k))
			//case PublicVar, BasePrivateVar:
			//	key = k
		}
		key.serialize(w)
		v.value.serialize(w)
	}
	w.Write([]byte("}"))
}
<commit_msg>complete String()<commit_after>package phpobject

import (
	"errors"
	"fmt"
	"io"
	"regexp"
	"strconv"
	"strings"
)

var patNumber, _ = regexp.Compile(`^-?[1-9][0-9]*$`)
var patVarName, _ = regexp.Compile(`^[[:alpha:]_]\w*$`)

type PValueType int

const (
	PTNil PValueType = iota
	PTBool
	PTLong
	PTDouble
	PTString
	PTArray
	PTObject
)

var pValueNames = [9]string{"nil", "boolean", "long", "double", "string", "array", "object"}

func (vt PValueType) String() string {
	return pValueNames[int(vt)]
}

type PValue interface {
	String() string
	Type() PValueType
	serialize(w io.Writer)
	//unserialize(r io.Reader)
}

type PNilType struct{}

func (nl *PNilType) String() string   { return "nil" }
func (nl *PNilType) Type() PValueType { return PTNil }
func (nl *PNilType) serialize(w io.Writer) {
	w.Write([]byte("N;"))
}

var PNil = PValue(&PNilType{})

type PBool bool

func (bl PBool) String() string {
	if bool(bl) {
		return "true"
	}
	return "false"
}
func (bl PBool) Type() PValueType { return PTBool }
func (bl PBool) serialize(w io.Writer) {
	if bl {
		w.Write([]byte("b:1;"))
	} else {
		w.Write([]byte("b:0;"))
	}
}

var PTrue = PBool(true)
var PFalse = PBool(false)

type PLong int

func (lt PLong) String() string   { return fmt.Sprint(int(lt)) }
func (lt PLong) Type() PValueType { return PTLong }
func (lt PLong) serialize(w io.Writer) {
	fmt.Fprintf(w, "i:%d;", lt)
}

type PDouble float64

func (dt PDouble) String() string   { return fmt.Sprint(float64(dt)) }
func (dt PDouble) Type() PValueType { return PTDouble }
func (dt PDouble) serialize(w io.Writer) {
	fmt.Fprintf(w, "d:%f;", dt)
}

type PString string

func (st PString) String() string   { return string(st) }
func (st PString) Type() PValueType { return PTString }
func (st PString) serialize(w io.Writer) {
	fmt.Fprintf(w, "s:%d:\"", len(st))
	fmt.Fprint(w, st)
	fmt.Fprint(w, "\";")
}

const (
	NumArray = 1
	KeyArray = 2
)

type PArray struct {
	array map[string]PValue
	//forceType int
}

func NewArray() *PArray {
	var at PArray
	at.array = make(map[string]PValue)
	return &at
}

func (tb *PArray) Iget(index int) (PValue, bool) {
	key := fmt.Sprintf("%d", index)
	v, o := tb.array[key]
	return v, o
}
func (tb *PArray) Get(key string) (PValue, bool) {
	v, o := tb.array[key]
	return v, o
}

func (tb *PArray) Iset(index int, value PValue) {
	key := fmt.Sprintf("%d", index)
	tb.array[key] = value
}
func (tb *PArray) Set(key string, value PValue) bool {
	tb.array[key] = value
	if key == "0" || patNumber.MatchString(key) {
		return true
	} else {
		return false
	}
}

func serializeKey(w io.Writer, key string) {
	if key == "0" || patNumber.MatchString(key) {
		fmt.Fprintf(w, "i:%s;", key)
	} else {
		fmt.Fprintf(w, "s:%d:\"", len(key))
		fmt.Fprint(w, key)
		fmt.Fprint(w, "\";")
	}
}

func (tb *PArray) String() string {
	slist := make([]string, len(tb.array)+2)
	slist[0] = fmt.Sprintf("Array(%d) [", len(tb.array))
	i := 1
	for k, v := range tb.array {
		slist[i] = fmt.Sprintf("%s : %s,", k, v.String())
		i++
	}
	slist[i] = "]"
	return strings.Join(slist, " ")
}
func (tb *PArray) Type() PValueType { return PTArray }

func (tb *PArray) serialize(w io.Writer) {
	fmt.Fprintf(w, "a:%d:{", len(tb.array))
	for k, v := range tb.array {
		serializeKey(w, k)
		v.serialize(w)
	}
	w.Write([]byte("}"))
}

const (
	PublicVar      = 0
	ProtectedVar   = 1
	PrivateVar     = 2
	BasePrivateVar = 4
	endVarType     = 5
)

type oValue struct {
	value   PValue
	varType int
}

type PObject struct {
	vars  map[string]oValue
	class string
}

func NewObject(class string) *PObject {
	var ot PObject
	ot.vars = make(map[string]oValue)
	ot.class = class
	return &ot
}

func (ot *PObject) SetVar(varname string, vtype int, value PValue) error {
	if vtype == BasePrivateVar {
		return errors.New("You should use SetBaseVar")
	}
	if vtype > BasePrivateVar || vtype < 0 {
		return errors.New("Error var type")
	}
	if !patVarName.MatchString(varname) {
		return errors.New("Error varname")
	}
	ot.vars[varname] = oValue{value, vtype}
	return nil
}

func (ot *PObject) SetPublicVar(varname string, value PValue) error {
	return ot.SetVar(varname, PublicVar, value)
}

func (ot *PObject) SetProtectedVar(varname string, value PValue) error {
	return ot.SetVar(varname, ProtectedVar, value)
}

func (ot *PObject) SetPrivateVar(varname string, value PValue) error {
	return ot.SetVar(varname, PrivateVar, value)
}

func (ot *PObject) SetBaseVar(clsname, varname string, value PValue) error {
	if !patVarName.MatchString(varname) {
		return errors.New("Error varname")
	}
	if !patVarName.MatchString(clsname) {
		return errors.New("Error class name")
	}
	key := fmt.Sprintf("\x00%s\x00%s", clsname, varname)
	ot.vars[key] = oValue{value, BasePrivateVar}
	return nil
}

func (ot *PObject) GetVar(varname string) (value PValue, vtype int, ok bool) {
	oval, ok := ot.vars[varname]
	return oval.value, oval.varType, ok
}

func (ot *PObject) GetBaseVar(clsname, varname string) (value PValue, ok bool) {
	key := fmt.Sprintf("\x00%s\x00%s", clsname, varname)
	oval, ok := ot.vars[key]
	return oval.value, ok
}

func (ot *PObject) String() string {
	slist := make([]string, len(ot.vars)+2)
	slist[0] = fmt.Sprintf("Object(%s:%d) {", ot.class, len(ot.vars))
	i := 1
	for k, v := range ot.vars {
		switch v.varType {
		case PublicVar:
			slist[i] = fmt.Sprintf("%s : %s,", k, v.value.String())
		case ProtectedVar:
			slist[i] = fmt.Sprintf("-%s : %s,", k, v.value.String())
		case PrivateVar:
			slist[i] = fmt.Sprintf("*%s : %s,", k, v.value.String())
		case BasePrivateVar:
			kk := strings.Replace(k, "\x00", "*", 2)
			slist[i] = fmt.Sprintf("%s : %s,", kk[1:], v.value.String())
		}
		i++
	}
	slist[i] = "}"
	return strings.Join(slist, " ")
}
func (ot *PObject) Type() PValueType { return PTObject }

func (ot *PObject) serialize(w io.Writer) {
	fmt.Fprintf(w, "O:%d:\"%s\"", len(ot.class), ot.class)
	fmt.Fprintf(w, ":%d:{", len(ot.vars))
	for k, v := range ot.vars {
		key := PString(k)
		switch v.varType {
		case ProtectedVar:
			key = PString("\x00*\x00" + k)
		case PrivateVar:
			key = PString(fmt.Sprintf("\x00%s\x00%s", ot.class, k))
			//case PublicVar, BasePrivateVar:
			//	key = k
		}
		key.serialize(w)
		v.value.serialize(w)
	}
	w.Write([]byte("}"))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"log"
	"net"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"git.edgecastcdn.net/vflow/sflow"
)

type SFServer struct {
	port        string
	addr        string
	laddr       *net.UDPAddr
	readTimeout time.Duration
	udpSize     int
	workers     int
	stop        bool
}

type UDPMsg struct {
	raddr *net.UDPAddr
	body  *bytes.Reader
}

var (
	udpChn = make(chan UDPMsg, 1000)
)

func (s *SFServer) run() {
	var (
		b  = make([]byte, s.udpSize)
		wg sync.WaitGroup
	)

	hostPort := net.JoinHostPort(s.addr, s.port)
	udpAddr, _ := net.ResolveUDPAddr("udp", hostPort)

	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	for i := 0; i < s.workers; i++ {
		go func() {
			wg.Add(1)
			defer wg.Done()
			sFlowWorker()

		}()
	}

	for !s.stop {
		n, raddr, err := conn.ReadFromUDP(b)
		if err != nil {
			log.Println(err)
			continue
		}
		udpChn <- UDPMsg{raddr, bytes.NewReader(b[:n])}
	}

	wg.Wait()
}

func (s *SFServer) shutdown() {
	s.stop = true
	log.Println("stopped sflow service gracefully ...")
	time.Sleep(1 * time.Second)
	log.Println("vFlow has been shutdown")
	close(udpChn)
}

func sFlowWorker() {
	var (
		msg    UDPMsg
		ok     bool
		filter = []uint32{sflow.DataCounterSample}
	)

	for {
		if msg, ok = <-udpChn; !ok {
			break
		}
		log.Println("rcvd", msg.body.Size())
		d := sflow.NewSFDecoder(msg.body, filter)
		d.SFDecode()
	}
}

func main() {
	var wg sync.WaitGroup
	signalCh := make(chan os.Signal, 1)
	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)

	sFlow := SFServer{
		port:    "6343",
		udpSize: 1500,
		workers: 10,
	}

	go func() {
		wg.Add(1)
		defer wg.Done()
		sFlow.run()
	}()

	<-signalCh
	sFlow.shutdown()
	wg.Wait()
}
<commit_msg>add udp read timeout 1 nano<commit_after>package main

import (
	"bytes"
	"log"
	"net"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"git.edgecastcdn.net/vflow/sflow"
)

type SFServer struct {
	port        string
	addr        string
	laddr       *net.UDPAddr
	readTimeout time.Duration
	udpSize     int
	workers     int
	stop        bool
}

type UDPMsg struct {
	raddr *net.UDPAddr
	body  *bytes.Reader
}

var (
	udpChn = make(chan UDPMsg, 1000)
)

func (s *SFServer) run() {
	var (
		b  = make([]byte, s.udpSize)
		wg sync.WaitGroup
	)

	hostPort := net.JoinHostPort(s.addr, s.port)
	udpAddr, _ := net.ResolveUDPAddr("udp", hostPort)

	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	for i := 0; i < s.workers; i++ {
		go func() {
			wg.Add(1)
			defer wg.Done()
			sFlowWorker()

		}()
	}

	for !s.stop {
		conn.SetReadDeadline(time.Now().Add(1e9))
		n, raddr, err := conn.ReadFromUDP(b)
		if err != nil {
			continue
		}
		udpChn <- UDPMsg{raddr, bytes.NewReader(b[:n])}
	}

	wg.Wait()
}

func (s *SFServer) shutdown() {
	s.stop = true
	log.Println("stopped sflow service gracefully ...")
	time.Sleep(1 * time.Second)
	log.Println("vFlow has been shutdown")
	close(udpChn)
}

func sFlowWorker() {
	var (
		msg    UDPMsg
		ok     bool
		filter = []uint32{sflow.DataCounterSample}
	)

	for {
		if msg, ok = <-udpChn; !ok {
			break
		}
		log.Println("rcvd", msg.body.Size())
		d := sflow.NewSFDecoder(msg.body, filter)
		d.SFDecode()
	}
}

func main() {
	var wg sync.WaitGroup
	signalCh := make(chan os.Signal, 1)
	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)

	sFlow := SFServer{
		port:    "6343",
		udpSize: 1500,
		workers: 10,
	}

	go func() {
		wg.Add(1)
		defer wg.Done()
		sFlow.run()
	}()

	<-signalCh
	sFlow.shutdown()
	wg.Wait()
}
<|endoftext|>


<commit_before>package vk

import (
	"bytes"
	"encoding/json"
)

const (
	methodVideoGet = "video.get"
)

type Video struct {
	Resource
}

type VideoGetFields struct {
	Offset   int    `url:"offset,omitempty"`
	Count    int    `url:"count,omitempty"`
	Extended Bool   `url:"extended,omitempty"`
	Videos   string `url:"videos,omitempty"`
}

type videoImage struct {
	Height int    `json:"height"`
	Width  int    `json:"width"`
	URL    string `json:"url"`
}

type VideoImage struct {
	Height int    `json:"height"`
	Width  int    `json:"width"`
	URL    string `json:"url"`
}

func (v *VideoImage) UnmarshalJSON(b []byte) error {
	if bytes.HasPrefix(b, []byte(`{`)) {
		// Blank image.
		return nil
	}
	var im videoImage
	if err := json.Unmarshal(b, &im); err != nil {
		return err
	}
	*v = VideoImage(im)
	return nil
}

type VideoItem struct {
	Duration int          `json:"duration"`
	Player   string       `json:"player"`
	Files    VideoFiles   `json:"files"`
	Images   []VideoImage `json:"image"`
}

type VideoFiles struct {
	External string `json:"external"`
}

type VideoGetResult struct {
	Count int         `json:"count"`
	Items []VideoItem `json:"items"`
}

func (v Video) Get(fields VideoGetFields) (result VideoGetResult, err error) {
	return result, v.Decode(v.Request(methodVideoGet, fields), &result)
}
<commit_msg>video: fix hack<commit_after>package vk

import (
	"bytes"
	"encoding/json"
)

const (
	methodVideoGet = "video.get"
)

type Video struct {
	Resource
}

type VideoGetFields struct {
	Offset   int    `url:"offset,omitempty"`
	Count    int    `url:"count,omitempty"`
	Extended Bool   `url:"extended,omitempty"`
	Videos   string `url:"videos,omitempty"`
}

type videoImage struct {
	Height int    `json:"height"`
	Width  int    `json:"width"`
	URL    string `json:"url"`
}

type VideoImage struct {
	Height int    `json:"height"`
	Width  int    `json:"width"`
	URL    string `json:"url"`
}

func (v *VideoImage) UnmarshalJSON(b []byte) error {
	if bytes.HasPrefix(b, []byte(`[`)) {
		// Blank image.
		return nil
	}
	var im videoImage
	if err := json.Unmarshal(b, &im); err != nil {
		return err
	}
	*v = VideoImage(im)
	return nil
}

type VideoItem struct {
	Duration int          `json:"duration"`
	Player   string       `json:"player"`
	Files    VideoFiles   `json:"files"`
	Images   []VideoImage `json:"image"`
}

type VideoFiles struct {
	External string `json:"external"`
}

type VideoGetResult struct {
	Count int         `json:"count"`
	Items []VideoItem `json:"items"`
}

func (v Video) Get(fields VideoGetFields) (result VideoGetResult, err error) {
	return result, v.Decode(v.Request(methodVideoGet, fields), &result)
}
<|endoftext|>


<commit_before>package webgui

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"

	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fs/config"
)

// PackageJSON is the structure of package.json of a plugin
type PackageJSON struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Description string `json:"description"`
	Author      string `json:"author"`
	Copyright   string `json:"copyright"`
	License     string `json:"license"`
	Private     bool   `json:"private"`
	Homepage    string `json:"homepage"`
	TestURL     string `json:"testUrl"`
	Repository  struct {
		Type string `json:"type"`
		URL  string `json:"url"`
	} `json:"repository"`
	Bugs struct {
		URL string `json:"url"`
	} `json:"bugs"`
	Rclone RcloneConfig `json:"rclone"`
}

// RcloneConfig represents the rclone specific config
type RcloneConfig struct {
	HandlesType      []string `json:"handlesType"`
	PluginType       string   `json:"pluginType"`
	RedirectReferrer bool     `json:"redirectReferrer"`
	Test             bool     `json:"-"`
}

func (r *PackageJSON) isTesting() bool {
	return r.Rclone.Test
}

var (
	//loadedTestPlugins *Plugins
	cachePath string

	loadedPlugins *Plugins
	pluginsProxy  = &httputil.ReverseProxy{}
	// PluginsMatch is used for matching author and plugin name in the url path
	PluginsMatch = regexp.MustCompile(`^plugins\/([^\/]*)\/([^\/\?]+)[\/]?(.*)$`)
	// PluginsPath is the base path where webgui plugins are stored
	PluginsPath              string
	pluginsConfigPath        string
	availablePluginsJSONPath = "availablePlugins.json"
)

func init() {
	cachePath = filepath.Join(config.CacheDir, "webgui")
	PluginsPath = filepath.Join(cachePath, "plugins")
	pluginsConfigPath = filepath.Join(PluginsPath, "config")

	loadedPlugins = newPlugins(availablePluginsJSONPath)
	err := loadedPlugins.readFromFile()
	if err != nil {
		fs.Errorf(nil, "error reading available plugins: %v", err)
	}
}

// Plugins represents the structure how plugins are saved onto disk
type Plugins struct {
	mutex         sync.Mutex
	LoadedPlugins map[string]PackageJSON `json:"loadedPlugins"`
	fileName      string
}

func newPlugins(fileName string) *Plugins {
	p := Plugins{LoadedPlugins: map[string]PackageJSON{}}
	p.fileName = fileName
	p.mutex = sync.Mutex{}
	return &p
}

func (p *Plugins) readFromFile() (err error) {
	//p.mutex.Lock()
	//defer p.mutex.Unlock()
	err = CreatePathIfNotExist(pluginsConfigPath)
	if err != nil {
		return err
	}
	availablePluginsJSON := filepath.Join(pluginsConfigPath, p.fileName)
	_, err = os.Stat(availablePluginsJSON)
	if err == nil {
		data, err := ioutil.ReadFile(availablePluginsJSON)
		if err != nil {
			return err
		}
		err = json.Unmarshal(data, &p)
		if err != nil {
			fs.Logf(nil, "%s", err)
		}
		return nil
	} else if os.IsNotExist(err) {
		// path does not exist
		err = p.writeToFile()
		if err != nil {
			return err
		}
	}
	return nil
}

func (p *Plugins) addPlugin(pluginName string, packageJSONPath string) (err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	data, err := ioutil.ReadFile(packageJSONPath)
	if err != nil {
		return err
	}
	var pkgJSON = PackageJSON{}
	err = json.Unmarshal(data, &pkgJSON)
	if err != nil {
		return err
	}
	p.LoadedPlugins[pluginName] = pkgJSON

	err = p.writeToFile()
	if err != nil {
		return err
	}

	return nil
}

func (p *Plugins) addTestPlugin(pluginName string, testURL string, handlesType []string) (err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	err = p.readFromFile()
	if err != nil {
		return err
	}

	var pkgJSON = PackageJSON{
		Name:    pluginName,
		TestURL: testURL,
		Rclone: RcloneConfig{
			HandlesType: handlesType,
			Test:        true,
		},
	}

	p.LoadedPlugins[pluginName] = pkgJSON

	err = p.writeToFile()
	if err != nil {
		return err
	}

	return nil
}

func (p *Plugins) writeToFile() (err error) {
	//p.mutex.Lock()
	//defer p.mutex.Unlock()
	availablePluginsJSON := filepath.Join(pluginsConfigPath, p.fileName)

	file, err := json.MarshalIndent(p, "", " ")

	err = ioutil.WriteFile(availablePluginsJSON, file, 0755)
	if err != nil {
		fs.Logf(nil, "%s", err)
	}
	return nil
}

func (p *Plugins) removePlugin(name string) (err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	err = p.readFromFile()
	if err != nil {
		return err
	}

	_, ok := p.LoadedPlugins[name]
	if !ok {
		return fmt.Errorf("plugin %s not loaded", name)
	}
	delete(p.LoadedPlugins, name)

	err = p.writeToFile()
	if err != nil {
		return err
	}
	return nil
}

// GetPluginByName returns the plugin object for the key (author/plugin-name)
func (p *Plugins) GetPluginByName(name string) (out *PackageJSON, err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	po, ok := p.LoadedPlugins[name]
	if !ok {
		return nil, fmt.Errorf("plugin %s not loaded", name)
	}
	return &po, nil

}

// getAuthorRepoBranchGithub gives author, repoName and branch from a github.com url
//	url examples:
//	https://github.com/rclone/rclone-webui-react/
//	http://github.com/rclone/rclone-webui-react
//	https://github.com/rclone/rclone-webui-react/tree/caman-js
// 	github.com/rclone/rclone-webui-react
//
func getAuthorRepoBranchGithub(url string) (author string, repoName string, branch string, err error) {
	repoURL := url
	repoURL = strings.Replace(repoURL, "https://", "", 1)
	repoURL = strings.Replace(repoURL, "http://", "", 1)

	urlSplits := strings.Split(repoURL, "/")

	if len(urlSplits) < 3 || len(urlSplits) > 5 || urlSplits[0] != "github.com" {
		return "", "", "", fmt.Errorf("invalid github url: %s", url)
	}

	// get branch name
	if len(urlSplits) == 5 && urlSplits[3] == "tree" {
		return urlSplits[1], urlSplits[2], urlSplits[4], nil
	}

	return urlSplits[1], urlSplits[2], "master", nil
}

func filterPlugins(plugins *Plugins, compare func(packageJSON *PackageJSON) bool) map[string]PackageJSON {
	output := map[string]PackageJSON{}

	for key, val := range plugins.LoadedPlugins {
		if compare(&val) {
			output[key] = val
		}
	}

	return output
}

// getDirectorForProxy is a helper function for reverse proxy of test plugins
func getDirectorForProxy(origin *url.URL) func(req *http.Request) {
	return func(req *http.Request) {
		req.Header.Add("X-Forwarded-Host", req.Host)
		req.Header.Add("X-Origin-Host", origin.Host)
		req.URL.Scheme = "http"
		req.URL.Host = origin.Host
		req.URL.Path = origin.Path
	}
}

// ServePluginOK checks the plugin url and uses reverse proxy to allow redirection for content not being served by rclone
func ServePluginOK(w http.ResponseWriter, r *http.Request, pluginsMatchResult []string) (ok bool) {
	testPlugin, err := loadedPlugins.GetPluginByName(fmt.Sprintf("%s/%s", pluginsMatchResult[1], pluginsMatchResult[2]))
	if err != nil {
		return false
	}
	if !testPlugin.Rclone.Test {
		return false
	}
	origin, _ := url.Parse(fmt.Sprintf("%s/%s", testPlugin.TestURL, pluginsMatchResult[3]))

	director := getDirectorForProxy(origin)

	pluginsProxy.Director = director
	pluginsProxy.ServeHTTP(w, r)
	return true
}

var referrerPathReg = regexp.MustCompile("^(https?)://(.+):([0-9]+)?/(.*)$")

// ServePluginWithReferrerOK check if redirectReferrer is set for the referred a plugin, if yes,
// sends a redirect to actual url. This function is useful for plugins to refer to absolute paths when
// the referrer in http.Request is set
func ServePluginWithReferrerOK(w http.ResponseWriter, r *http.Request, path string) (ok bool) {
	referrer := r.Referer()
	referrerPathMatch := referrerPathReg.FindStringSubmatch(referrer)

	if referrerPathMatch != nil {
		referrerPluginMatch := PluginsMatch.FindStringSubmatch(referrerPathMatch[4])
		pluginKey := fmt.Sprintf("%s/%s", referrerPluginMatch[1], referrerPluginMatch[2])
		currentPlugin, err := loadedPlugins.GetPluginByName(pluginKey)
		if err != nil {
			return false
		}
		if referrerPluginMatch != nil && currentPlugin.Rclone.RedirectReferrer {
			path = fmt.Sprintf("/plugins/%s/%s/%s", referrerPluginMatch[1], referrerPluginMatch[2], path)

			http.Redirect(w, r, path, http.StatusMovedPermanently)
			//s.pluginsHandler.ServeHTTP(w, r)
			return true
		}
	}
	return false
}
<commit_msg>plugins: Add url query params to regex for referrer path<commit_after>package webgui

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"

	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fs/config"
)

// PackageJSON is the structure of package.json of a plugin
type PackageJSON struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Description string `json:"description"`
	Author      string `json:"author"`
	Copyright   string `json:"copyright"`
	License     string `json:"license"`
	Private     bool   `json:"private"`
	Homepage    string `json:"homepage"`
	TestURL     string `json:"testUrl"`
	Repository  struct {
		Type string `json:"type"`
		URL  string `json:"url"`
	} `json:"repository"`
	Bugs struct {
		URL string `json:"url"`
	} `json:"bugs"`
	Rclone RcloneConfig `json:"rclone"`
}

// RcloneConfig represents the rclone specific config
type RcloneConfig struct {
	HandlesType      []string `json:"handlesType"`
	PluginType       string   `json:"pluginType"`
	RedirectReferrer bool     `json:"redirectReferrer"`
	Test             bool     `json:"-"`
}

func (r *PackageJSON) isTesting() bool {
	return r.Rclone.Test
}

var (
	//loadedTestPlugins *Plugins
	cachePath string

	loadedPlugins *Plugins
	pluginsProxy  = &httputil.ReverseProxy{}
	// PluginsMatch is used for matching author and plugin name in the url path
	PluginsMatch = regexp.MustCompile(`^plugins\/([^\/]*)\/([^\/\?]+)[\/]?(.*)$`)
	// PluginsPath is the base path where webgui plugins are stored
	PluginsPath              string
	pluginsConfigPath        string
	availablePluginsJSONPath = "availablePlugins.json"
)

func init() {
	cachePath = filepath.Join(config.CacheDir, "webgui")
	PluginsPath = filepath.Join(cachePath, "plugins")
	pluginsConfigPath = filepath.Join(PluginsPath, "config")

	loadedPlugins = newPlugins(availablePluginsJSONPath)
	err := loadedPlugins.readFromFile()
	if err != nil {
		fs.Errorf(nil, "error reading available plugins: %v", err)
	}
}

// Plugins represents the structure how plugins are saved onto disk
type Plugins struct {
	mutex         sync.Mutex
	LoadedPlugins map[string]PackageJSON `json:"loadedPlugins"`
	fileName      string
}

func newPlugins(fileName string) *Plugins {
	p := Plugins{LoadedPlugins: map[string]PackageJSON{}}
	p.fileName = fileName
	p.mutex = sync.Mutex{}
	return &p
}

func (p *Plugins) readFromFile() (err error) {
	//p.mutex.Lock()
	//defer p.mutex.Unlock()
	err = CreatePathIfNotExist(pluginsConfigPath)
	if err != nil {
		return err
	}
	availablePluginsJSON := filepath.Join(pluginsConfigPath, p.fileName)
	_, err = os.Stat(availablePluginsJSON)
	if err == nil {
		data, err := ioutil.ReadFile(availablePluginsJSON)
		if err != nil {
			return err
		}
		err = json.Unmarshal(data, &p)
		if err != nil {
			fs.Logf(nil, "%s", err)
		}
		return nil
	} else if os.IsNotExist(err) {
		// path does not exist
		err = p.writeToFile()
		if err != nil {
			return err
		}
	}
	return nil
}

func (p *Plugins) addPlugin(pluginName string, packageJSONPath string) (err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	data, err := ioutil.ReadFile(packageJSONPath)
	if err != nil {
		return err
	}
	var pkgJSON = PackageJSON{}
	err = json.Unmarshal(data, &pkgJSON)
	if err != nil {
		return err
	}
	p.LoadedPlugins[pluginName] = pkgJSON

	err = p.writeToFile()
	if err != nil {
		return err
	}

	return nil
}

func (p *Plugins) addTestPlugin(pluginName string, testURL string, handlesType []string) (err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	err = p.readFromFile()
	if err != nil {
		return err
	}

	var pkgJSON = PackageJSON{
		Name:    pluginName,
		TestURL: testURL,
		Rclone: RcloneConfig{
			HandlesType: handlesType,
			Test:        true,
		},
	}

	p.LoadedPlugins[pluginName] = pkgJSON

	err = p.writeToFile()
	if err != nil {
		return err
	}

	return nil
}

func (p *Plugins) writeToFile() (err error) {
	//p.mutex.Lock()
	//defer p.mutex.Unlock()
	availablePluginsJSON := filepath.Join(pluginsConfigPath, p.fileName)

	file, err := json.MarshalIndent(p, "", " ")

	err = ioutil.WriteFile(availablePluginsJSON, file, 0755)
	if err != nil {
		fs.Logf(nil, "%s", err)
	}
	return nil
}

func (p *Plugins) removePlugin(name string) (err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	err = p.readFromFile()
	if err != nil {
		return err
	}

	_, ok := p.LoadedPlugins[name]
	if !ok {
		return fmt.Errorf("plugin %s not loaded", name)
	}
	delete(p.LoadedPlugins, name)

	err = p.writeToFile()
	if err != nil {
		return err
	}
	return nil
}

// GetPluginByName returns the plugin object for the key (author/plugin-name)
func (p *Plugins) GetPluginByName(name string) (out *PackageJSON, err error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	po, ok := p.LoadedPlugins[name]
	if !ok {
		return nil, fmt.Errorf("plugin %s not loaded", name)
	}
	return &po, nil

}

// getAuthorRepoBranchGithub gives author, repoName and branch from a github.com url
//	url examples:
//	https://github.com/rclone/rclone-webui-react/
//	http://github.com/rclone/rclone-webui-react
//	https://github.com/rclone/rclone-webui-react/tree/caman-js
// 	github.com/rclone/rclone-webui-react
//
func getAuthorRepoBranchGithub(url string) (author string, repoName string, branch string, err error) {
	repoURL := url
	repoURL = strings.Replace(repoURL, "https://", "", 1)
	repoURL = strings.Replace(repoURL, "http://", "", 1)

	urlSplits := strings.Split(repoURL, "/")

	if len(urlSplits) < 3 || len(urlSplits) > 5 || urlSplits[0] != "github.com" {
		return "", "", "", fmt.Errorf("invalid github url: %s", url)
	}

	// get branch name
	if len(urlSplits) == 5 && urlSplits[3] == "tree" {
		return urlSplits[1], urlSplits[2], urlSplits[4], nil
	}

	return urlSplits[1], urlSplits[2], "master", nil
}

func filterPlugins(plugins *Plugins, compare func(packageJSON *PackageJSON) bool) map[string]PackageJSON {
	output := map[string]PackageJSON{}

	for key, val := range plugins.LoadedPlugins {
		if compare(&val) {
			output[key] = val
		}
	}

	return output
}

// getDirectorForProxy is a helper function for reverse proxy of test plugins
func getDirectorForProxy(origin *url.URL) func(req *http.Request) {
	return func(req *http.Request) {
		req.Header.Add("X-Forwarded-Host", req.Host)
		req.Header.Add("X-Origin-Host", origin.Host)
		req.URL.Scheme = "http"
		req.URL.Host = origin.Host
		req.URL.Path = origin.Path
	}
}

// ServePluginOK checks the plugin url and uses reverse proxy to allow redirection for content not being served by rclone
func ServePluginOK(w http.ResponseWriter, r *http.Request, pluginsMatchResult []string) (ok bool) {
	testPlugin, err := loadedPlugins.GetPluginByName(fmt.Sprintf("%s/%s", pluginsMatchResult[1], pluginsMatchResult[2]))
	if err != nil {
		return false
	}
	if !testPlugin.Rclone.Test {
		return false
	}
	origin, _ := url.Parse(fmt.Sprintf("%s/%s", testPlugin.TestURL, pluginsMatchResult[3]))

	director := getDirectorForProxy(origin)

	pluginsProxy.Director = director
	pluginsProxy.ServeHTTP(w, r)
	return true
}

var referrerPathReg = regexp.MustCompile("^(https?):\\/\\/(.+):([0-9]+)?\\/(.*)\\/?\\?(.*)$")

// ServePluginWithReferrerOK check if redirectReferrer is set for the referred a plugin, if yes,
// sends a redirect to actual url. This function is useful for plugins to refer to absolute paths when
// the referrer in http.Request is set
func ServePluginWithReferrerOK(w http.ResponseWriter, r *http.Request, path string) (ok bool) {
	referrer := r.Referer()
	referrerPathMatch := referrerPathReg.FindStringSubmatch(referrer)

	if referrerPathMatch != nil {
		referrerPluginMatch := PluginsMatch.FindStringSubmatch(referrerPathMatch[4])
		pluginKey := fmt.Sprintf("%s/%s", referrerPluginMatch[1], referrerPluginMatch[2])
		currentPlugin, err := loadedPlugins.GetPluginByName(pluginKey)
		if err != nil {
			return false
		}
		if referrerPluginMatch != nil && currentPlugin.Rclone.RedirectReferrer {
			path = fmt.Sprintf("/plugins/%s/%s/%s", referrerPluginMatch[1], referrerPluginMatch[2], path)

			http.Redirect(w, r, path, http.StatusMovedPermanently)
			//s.pluginsHandler.ServeHTTP(w, r)
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2016 Mender Software AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

package main

import (
	"github.com/ant0ine/go-json-rest/rest"
	"github.com/pkg/errors"
	"gopkg.in/mgo.v2"

	"github.com/mendersoftware/deployments/config"
	"github.com/mendersoftware/deployments/integration"
	deploymentsController "github.com/mendersoftware/deployments/resources/deployments/controller"
	"github.com/mendersoftware/deployments/resources/deployments/generator"
	deploymentsModel "github.com/mendersoftware/deployments/resources/deployments/model"
	deploymentsMongo "github.com/mendersoftware/deployments/resources/deployments/mongo"
	deploymentsView "github.com/mendersoftware/deployments/resources/deployments/view"
	imagesController "github.com/mendersoftware/deployments/resources/images/controller"
	imagesModel "github.com/mendersoftware/deployments/resources/images/model"
	imagesMongo "github.com/mendersoftware/deployments/resources/images/mongo"
	"github.com/mendersoftware/deployments/resources/images/s3"
	imagesView "github.com/mendersoftware/deployments/resources/images/view"
	"github.com/mendersoftware/deployments/utils/restutil"
)

func SetupS3(c config.ConfigReader) (imagesModel.FileStorage, error) {

	bucket := c.GetString(SettingAwsS3Bucket)
	region := c.GetString(SettingAwsS3Region)
	if c.IsSet(SettingsAwsAuth) || (c.IsSet(SettingAwsAuthKeyId) && c.IsSet(SettingAwsAuthSecret) && c.IsSet(SettingAwsURI)) {
		return s3.NewSimpleStorageServiceStatic(
			bucket,
			c.GetString(SettingAwsAuthKeyId),
			c.GetString(SettingAwsAuthSecret),
			region,
			c.GetString(SettingAwsAuthToken),
			c.GetString(SettingAwsURI),
		)
	}

	return s3.NewSimpleStorageServiceDefaults(bucket, region)
}

// NewRouter defines all REST API routes.
func NewRouter(c config.ConfigReader) (rest.App, error) {

	dbSession, err := mgo.Dial(c.GetString(SettingMongo))
	if err != nil {
		return nil, err
	}
	dbSession.SetSafe(&mgo.Safe{
		W: 1,
		J: true,
	})

	// Storage Layer
	fileStorage, err := SetupS3(c)
	if err != nil {
		return nil, err
	}
	deploymentsStorage := deploymentsMongo.NewDeploymentsStorage(dbSession)
	deviceDeploymentsStorage := deploymentsMongo.NewDeviceDeploymentsStorage(dbSession)
	deviceDeploymentLogsStorage := deploymentsMongo.NewDeviceDeploymentLogsStorage(dbSession)
	imagesStorage := imagesMongo.NewSoftwareImagesStorage(dbSession)
	if err := imagesStorage.IndexStorage(); err != nil {
		return nil, err
	}

	inventory, err := integration.NewMenderAPI(c.GetString(SettingGateway))
	if err != nil {
		return nil, errors.Wrap(err, "init inventory client")
	}

	// Domain Models
	deploymentModel := deploymentsModel.NewDeploymentModel(deploymentsModel.DeploymentsModelConfig{
		DeploymentsStorage:          deploymentsStorage,
		DeviceDeploymentsStorage:    deviceDeploymentsStorage,
		DeviceDeploymentLogsStorage: deviceDeploymentLogsStorage,
		ImageLinker:                 fileStorage,
		DeviceDeploymentGenerator: generator.NewImageBasedDeviceDeployment(
			imagesStorage,
			generator.NewInventory(inventory),
		),
		ImageContentType: imagesModel.ArtifactContentType,
	})

	imagesModel := imagesModel.NewImagesModel(fileStorage, deploymentModel, imagesStorage)

	// Controllers
	imagesController := imagesController.NewSoftwareImagesController(imagesModel, new(imagesView.RESTView))
	deploymentsController := deploymentsController.NewDeploymentsController(deploymentModel, new(deploymentsView.DeploymentsView))

	// Routing
	imageRoutes := NewImagesResourceRoutes(imagesController)
	deploymentsRoutes := NewDeploymentsResourceRoutes(deploymentsController)

	routes := append(imageRoutes, deploymentsRoutes...)

	return rest.MakeRouter(restutil.AutogenOptionsRoutes(restutil.NewOptionsHandler, routes...)...)
}

func NewImagesResourceRoutes(controller *imagesController.SoftwareImagesController) []*rest.Route {

	if controller == nil {
		return []*rest.Route{}
	}

	return []*rest.Route{
		rest.Post("/api/0.0.1/artifacts", controller.NewImage),
		rest.Get("/api/0.0.1/artifacts", controller.ListImages),

		rest.Get("/api/0.0.1/artifacts/:id", controller.GetImage),
		rest.Delete("/api/0.0.1/artifacts/:id", controller.DeleteImage),
		rest.Put("/api/0.0.1/artifacts/:id", controller.EditImage),

		rest.Get("/api/0.0.1/artifacts/:id/download", controller.DownloadLink),
	}
}

func NewDeploymentsResourceRoutes(controller *deploymentsController.DeploymentsController) []*rest.Route {

	if controller == nil {
		return []*rest.Route{}
	}

	return []*rest.Route{

		// Deployments
		rest.Post("/api/0.0.1/deployments", controller.PostDeployment),
		rest.Get("/api/0.0.1/deployments", controller.LookupDeployment),
		rest.Get("/api/0.0.1/deployments/:id", controller.GetDeployment),
		rest.Get("/api/0.0.1/deployments/:id/statistics", controller.GetDeploymentStats),
		rest.Put("/api/0.0.1/deployments/:id/status", controller.AbortDeployment),
		rest.Get("/api/0.0.1/deployments/:id/devices",
			controller.GetDeviceStatusesForDeployment),
		rest.Get("/api/0.0.1/deployments/:id/devices/:devid/log",
			controller.GetDeploymentLogForDevice),
		rest.Delete("/api/0.0.1/deployments/devices/:id",
			controller.DecommissionDevice),

		// Devices
		rest.Get("/api/0.0.1/device/deployments/next", controller.GetDeploymentForDevice),
		rest.Put("/api/0.0.1/device/deployments/:id/status",
			controller.PutDeploymentStatusForDevice),
		rest.Put("/api/0.0.1/device/deployments/:id/log",
			controller.PutDeploymentLogForDevice),
	}
}
<commit_msg>routing: match changes in images storage API<commit_after>// Copyright 2016 Mender Software AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

package main

import (
	"context"

	"github.com/ant0ine/go-json-rest/rest"
	"github.com/pkg/errors"
	"gopkg.in/mgo.v2"

	"github.com/mendersoftware/deployments/config"
	"github.com/mendersoftware/deployments/integration"
	deploymentsController "github.com/mendersoftware/deployments/resources/deployments/controller"
	"github.com/mendersoftware/deployments/resources/deployments/generator"
	deploymentsModel "github.com/mendersoftware/deployments/resources/deployments/model"
	deploymentsMongo "github.com/mendersoftware/deployments/resources/deployments/mongo"
	deploymentsView "github.com/mendersoftware/deployments/resources/deployments/view"
	imagesController "github.com/mendersoftware/deployments/resources/images/controller"
	imagesModel "github.com/mendersoftware/deployments/resources/images/model"
	imagesMongo "github.com/mendersoftware/deployments/resources/images/mongo"
	"github.com/mendersoftware/deployments/resources/images/s3"
	imagesView "github.com/mendersoftware/deployments/resources/images/view"
	"github.com/mendersoftware/deployments/utils/restutil"
)

func SetupS3(c config.ConfigReader) (imagesModel.FileStorage, error) {

	bucket := c.GetString(SettingAwsS3Bucket)
	region := c.GetString(SettingAwsS3Region)
	if c.IsSet(SettingsAwsAuth) || (c.IsSet(SettingAwsAuthKeyId) && c.IsSet(SettingAwsAuthSecret) && c.IsSet(SettingAwsURI)) {
		return s3.NewSimpleStorageServiceStatic(
			bucket,
			c.GetString(SettingAwsAuthKeyId),
			c.GetString(SettingAwsAuthSecret),
			region,
			c.GetString(SettingAwsAuthToken),
			c.GetString(SettingAwsURI),
		)
	}

	return s3.NewSimpleStorageServiceDefaults(bucket, region)
}

// NewRouter defines all REST API routes.
func NewRouter(c config.ConfigReader) (rest.App, error) {

	dbSession, err := mgo.Dial(c.GetString(SettingMongo))
	if err != nil {
		return nil, err
	}
	dbSession.SetSafe(&mgo.Safe{
		W: 1,
		J: true,
	})

	// Storage Layer
	fileStorage, err := SetupS3(c)
	if err != nil {
		return nil, err
	}
	deploymentsStorage := deploymentsMongo.NewDeploymentsStorage(dbSession)
	deviceDeploymentsStorage := deploymentsMongo.NewDeviceDeploymentsStorage(dbSession)
	deviceDeploymentLogsStorage := deploymentsMongo.NewDeviceDeploymentLogsStorage(dbSession)
	imagesStorage := imagesMongo.NewSoftwareImagesStorage(dbSession)
	if err := imagesStorage.IndexStorage(context.Background()); err != nil {
		return nil, err
	}

	inventory, err := integration.NewMenderAPI(c.GetString(SettingGateway))
	if err != nil {
		return nil, errors.Wrap(err, "init inventory client")
	}

	// Domain Models
	deploymentModel := deploymentsModel.NewDeploymentModel(deploymentsModel.DeploymentsModelConfig{
		DeploymentsStorage:          deploymentsStorage,
		DeviceDeploymentsStorage:    deviceDeploymentsStorage,
		DeviceDeploymentLogsStorage: deviceDeploymentLogsStorage,
		ImageLinker:                 fileStorage,
		DeviceDeploymentGenerator: generator.NewImageBasedDeviceDeployment(
			imagesStorage,
			generator.NewInventory(inventory),
		),
		ImageContentType: imagesModel.ArtifactContentType,
	})

	imagesModel := imagesModel.NewImagesModel(fileStorage, deploymentModel, imagesStorage)

	// Controllers
	imagesController := imagesController.NewSoftwareImagesController(imagesModel, new(imagesView.RESTView))
	deploymentsController := deploymentsController.NewDeploymentsController(deploymentModel, new(deploymentsView.DeploymentsView))

	// Routing
	imageRoutes := NewImagesResourceRoutes(imagesController)
	deploymentsRoutes := NewDeploymentsResourceRoutes(deploymentsController)

	routes := append(imageRoutes, deploymentsRoutes...)

	return rest.MakeRouter(restutil.AutogenOptionsRoutes(restutil.NewOptionsHandler, routes...)...)
}

func NewImagesResourceRoutes(controller *imagesController.SoftwareImagesController) []*rest.Route {

	if controller == nil {
		return []*rest.Route{}
	}

	return []*rest.Route{
		rest.Post("/api/0.0.1/artifacts", controller.NewImage),
		rest.Get("/api/0.0.1/artifacts", controller.ListImages),

		rest.Get("/api/0.0.1/artifacts/:id", controller.GetImage),
		rest.Delete("/api/0.0.1/artifacts/:id", controller.DeleteImage),
		rest.Put("/api/0.0.1/artifacts/:id", controller.EditImage),

		rest.Get("/api/0.0.1/artifacts/:id/download", controller.DownloadLink),
	}
}

func NewDeploymentsResourceRoutes(controller *deploymentsController.DeploymentsController) []*rest.Route {

	if controller == nil {
		return []*rest.Route{}
	}

	return []*rest.Route{

		// Deployments
		rest.Post("/api/0.0.1/deployments", controller.PostDeployment),
		rest.Get("/api/0.0.1/deployments", controller.LookupDeployment),
		rest.Get("/api/0.0.1/deployments/:id", controller.GetDeployment),
		rest.Get("/api/0.0.1/deployments/:id/statistics", controller.GetDeploymentStats),
		rest.Put("/api/0.0.1/deployments/:id/status", controller.AbortDeployment),
		rest.Get("/api/0.0.1/deployments/:id/devices",
			controller.GetDeviceStatusesForDeployment),
		rest.Get("/api/0.0.1/deployments/:id/devices/:devid/log",
			controller.GetDeploymentLogForDevice),
		rest.Delete("/api/0.0.1/deployments/devices/:id",
			controller.DecommissionDevice),

		// Devices
		rest.Get("/api/0.0.1/device/deployments/next", controller.GetDeploymentForDevice),
		rest.Put("/api/0.0.1/device/deployments/:id/status",
			controller.PutDeploymentStatusForDevice),
		rest.Put("/api/0.0.1/device/deployments/:id/log",
			controller.PutDeploymentLogForDevice),
	}
}
<|endoftext|>


<commit_before>package rpc

import (
	"import.moetang.info/go/nekoq-common/async"
	"import.moetang.info/go/nekoq-common/context"
)

type Client interface {
	CallSync(method string, param interface{}, appInfo *context.AppInfo) (interface{}, error)
	CallAsync(method string, param interface{}, AppInfo *context.AppInfo) (async.Future, error)

	CloseSync() error
}
<commit_msg>remove rpc<commit_after><|endoftext|>


<commit_before>// package rpi provides a GPIO implementation customised for the RPi.
package rpi

import (
	"log"
	"os"
	"sync"
)

const (
	// Physical addresses for various peripheral register sets

	// Base Physical Address of the BCM 2835 peripheral registers
	BCM2835_PERI_BASE = 0x20000000

	// Base Physical Address of the System Timer registers
	BCM2835_ST_BASE = BCM2835_PERI_BASE + 0x3000

	// Base Physical Address of the Pads registers
	BCM2835_GPIO_PADS = BCM2835_PERI_BASE + 0x100000

	// Base Physical Address of the Clock/timer registers
	BCM2835_CLOCK_BASE = BCM2835_PERI_BASE + 0x101000

	// Base Physical Address of the GPIO registers
	BCM2835_GPIO_BASE = BCM2835_PERI_BASE + 0x200000

	// Base Physical Address of the SPI0 registers
	BCM2835_SPI0_BASE = BCM2835_PERI_BASE + 0x204000

	// Base Physical Address of the BSC0 registers
	BCM2835_BSC0_BASE = BCM2835_PERI_BASE + 0x205000

	// Base Physical Address of the PWM registers
	BCM2835_GPIO_PWM = BCM2835_PERI_BASE + 0x20C000

	// Base Physical Address of the BSC1 registers
	BCM2835_BSC1_BASE = BCM2835_PERI_BASE + 0x804000

	// Size of memory page on RPi
	BCM2835_PAGE_SIZE = 4 * 1024

	// Size of memory block on RPi
	BCM2835_BLOCK_SIZE = 4 * 1024

	BCM2835_GPFSEL0   = 0x0000 // GPIO Function Select 0
	BCM2835_GPFSEL1   = 0x0004 // GPIO Function Select 1
	BCM2835_GPFSEL2   = 0x0008 // GPIO Function Select 2
	BCM2835_GPFSEL3   = 0x000c // GPIO Function Select 3
	BCM2835_GPFSEL4   = 0x0010 // GPIO Function Select 4
	BCM2835_GPFSEL5   = 0x0014 // GPIO Function Select 5
	BCM2835_GPSET0    = 0x001c // GPIO Pin Output Set 0
	BCM2835_GPSET1    = 0x0020 // GPIO Pin Output Set 1
	BCM2835_GPCLR0    = 0x0028 // GPIO Pin Output Clear 0
	BCM2835_GPCLR1    = 0x002c // GPIO Pin Output Clear 1
	BCM2835_GPLEV0    = 0x0034 // GPIO Pin Level 0
	BCM2835_GPLEV1    = 0x0038 // GPIO Pin Level 1
	BCM2835_GPEDS0    = 0x0040 // GPIO Pin Event Detect Status 0
	BCM2835_GPEDS1    = 0x0044 // GPIO Pin Event Detect Status 1
	BCM2835_GPREN0    = 0x004c // GPIO Pin Rising Edge Detect Enable 0
	BCM2835_GPREN1    = 0x0050 // GPIO Pin Rising Edge Detect Enable 1
	BCM2835_GPFEN0    = 0x0048 // GPIO Pin Falling Edge Detect Enable 0
	BCM2835_GPFEN1    = 0x005c // GPIO Pin Falling Edge Detect Enable 1
	BCM2835_GPHEN0    = 0x0064 // GPIO Pin High Detect Enable 0
	BCM2835_GPHEN1    = 0x0068 // GPIO Pin High Detect Enable 1
	BCM2835_GPLEN0    = 0x0070 // GPIO Pin Low Detect Enable 0
	BCM2835_GPLEN1    = 0x0074 // GPIO Pin Low Detect Enable 1
	BCM2835_GPAREN0   = 0x007c // GPIO Pin Async. Rising Edge Detect 0
	BCM2835_GPAREN1   = 0x0080 // GPIO Pin Async. Rising Edge Detect 1
	BCM2835_GPAFEN0   = 0x0088 // GPIO Pin Async. Falling Edge Detect 0
	BCM2835_GPAFEN1   = 0x008c // GPIO Pin Async. Falling Edge Detect 1
	BCM2835_GPPUD     = 0x0094 // GPIO Pin Pull-up/down Enable
	BCM2835_GPPUDCLK0 = 0x0098 // GPIO Pin Pull-up/down Enable Clock 0
	BCM2835_GPPUDCLK1 = 0x009c // GPIO Pin Pull-up/down Enable Clock 1

	BCM2835_GPIO_FSEL_INPT        = 0x0 // Input
	BCM2835_GPIO_FSEL_OUTP        = 0x1 // Output
	BCM2835_GPIO_FSEL_ALT0        = 0x4 // Alternate function 0
	BCM2835_GPIO_FSEL_ALT1        = 0x5 // Alternate function 1
	BCM2835_GPIO_FSEL_ALT2        = 0x6 // Alternate function 2
	BCM2835_GPIO_FSEL_ALT3        = 0x7 // Alternate function 3
	BCM2835_GPIO_FSEL_ALT4        = 0x3 // Alternate function 4
	BCM2835_GPIO_FSEL_ALT5        = 0x2 // Alternate function 5
	BCM2835_GPIO_FSEL_MASK uint32 = 0x7

	GPIO_P1_12 = 18
	GPIO_P1_13 = 27
	GPIO_P1_15 = 22
	GPIO_P1_18 = 24
	GPIO_P1_22 = 25

	GPIO21 = GPIO_P1_13
	GPIO22 = GPIO_P1_15
	GPIO25 = GPIO_P1_22
	GPIO24 = GPIO_P1_18
	GPIO27 = GPIO_P1_13
)

func initRPi() {
	memfd, err := os.OpenFile("/dev/mem", os.O_RDWR|os.O_SYNC, 0)
	if err != nil {
		log.Fatalf("rpi: unable to open /dev/mem: %v", err)
	}
	initGPIO(int(memfd.Fd()))
	memfd.Close()
}

var initOnce sync.Once
<commit_msg>Adding pinout data for GPIO_P1_16 (GPIO23) and GPIO_P1_11 (GPIO17)<commit_after>// package rpi provides a GPIO implementation customised for the RPi.
package rpi

import (
	"log"
	"os"
	"sync"
)

const (
	// Physical addresses for various peripheral register sets

	// Base Physical Address of the BCM 2835 peripheral registers
	BCM2835_PERI_BASE = 0x20000000

	// Base Physical Address of the System Timer registers
	BCM2835_ST_BASE = BCM2835_PERI_BASE + 0x3000

	// Base Physical Address of the Pads registers
	BCM2835_GPIO_PADS = BCM2835_PERI_BASE + 0x100000

	// Base Physical Address of the Clock/timer registers
	BCM2835_CLOCK_BASE = BCM2835_PERI_BASE + 0x101000

	// Base Physical Address of the GPIO registers
	BCM2835_GPIO_BASE = BCM2835_PERI_BASE + 0x200000

	// Base Physical Address of the SPI0 registers
	BCM2835_SPI0_BASE = BCM2835_PERI_BASE + 0x204000

	// Base Physical Address of the BSC0 registers
	BCM2835_BSC0_BASE = BCM2835_PERI_BASE + 0x205000

	// Base Physical Address of the PWM registers
	BCM2835_GPIO_PWM = BCM2835_PERI_BASE + 0x20C000

	// Base Physical Address of the BSC1 registers
	BCM2835_BSC1_BASE = BCM2835_PERI_BASE + 0x804000

	// Size of memory page on RPi
	BCM2835_PAGE_SIZE = 4 * 1024

	// Size of memory block on RPi
	BCM2835_BLOCK_SIZE = 4 * 1024

	BCM2835_GPFSEL0   = 0x0000 // GPIO Function Select 0
	BCM2835_GPFSEL1   = 0x0004 // GPIO Function Select 1
	BCM2835_GPFSEL2   = 0x0008 // GPIO Function Select 2
	BCM2835_GPFSEL3   = 0x000c // GPIO Function Select 3
	BCM2835_GPFSEL4   = 0x0010 // GPIO Function Select 4
	BCM2835_GPFSEL5   = 0x0014 // GPIO Function Select 5
	BCM2835_GPSET0    = 0x001c // GPIO Pin Output Set 0
	BCM2835_GPSET1    = 0x0020 // GPIO Pin Output Set 1
	BCM2835_GPCLR0    = 0x0028 // GPIO Pin Output Clear 0
	BCM2835_GPCLR1    = 0x002c // GPIO Pin Output Clear 1
	BCM2835_GPLEV0    = 0x0034 // GPIO Pin Level 0
	BCM2835_GPLEV1    = 0x0038 // GPIO Pin Level 1
	BCM2835_GPEDS0    = 0x0040 // GPIO Pin Event Detect Status 0
	BCM2835_GPEDS1    = 0x0044 // GPIO Pin Event Detect Status 1
	BCM2835_GPREN0    = 0x004c // GPIO Pin Rising Edge Detect Enable 0
	BCM2835_GPREN1    = 0x0050 // GPIO Pin Rising Edge Detect Enable 1
	BCM2835_GPFEN0    = 0x0048 // GPIO Pin Falling Edge Detect Enable 0
	BCM2835_GPFEN1    = 0x005c // GPIO Pin Falling Edge Detect Enable 1
	BCM2835_GPHEN0    = 0x0064 // GPIO Pin High Detect Enable 0
	BCM2835_GPHEN1    = 0x0068 // GPIO Pin High Detect Enable 1
	BCM2835_GPLEN0    = 0x0070 // GPIO Pin Low Detect Enable 0
	BCM2835_GPLEN1    = 0x0074 // GPIO Pin Low Detect Enable 1
	BCM2835_GPAREN0   = 0x007c // GPIO Pin Async. Rising Edge Detect 0
	BCM2835_GPAREN1   = 0x0080 // GPIO Pin Async. Rising Edge Detect 1
	BCM2835_GPAFEN0   = 0x0088 // GPIO Pin Async. Falling Edge Detect 0
	BCM2835_GPAFEN1   = 0x008c // GPIO Pin Async. Falling Edge Detect 1
	BCM2835_GPPUD     = 0x0094 // GPIO Pin Pull-up/down Enable
	BCM2835_GPPUDCLK0 = 0x0098 // GPIO Pin Pull-up/down Enable Clock 0
	BCM2835_GPPUDCLK1 = 0x009c // GPIO Pin Pull-up/down Enable Clock 1

	BCM2835_GPIO_FSEL_INPT        = 0x0 // Input
	BCM2835_GPIO_FSEL_OUTP        = 0x1 // Output
	BCM2835_GPIO_FSEL_ALT0        = 0x4 // Alternate function 0
	BCM2835_GPIO_FSEL_ALT1        = 0x5 // Alternate function 1
	BCM2835_GPIO_FSEL_ALT2        = 0x6 // Alternate function 2
	BCM2835_GPIO_FSEL_ALT3        = 0x7 // Alternate function 3
	BCM2835_GPIO_FSEL_ALT4        = 0x3 // Alternate function 4
	BCM2835_GPIO_FSEL_ALT5        = 0x2 // Alternate function 5
	BCM2835_GPIO_FSEL_MASK uint32 = 0x7

	GPIO_P1_12 = 18
	GPIO_P1_13 = 27
	GPIO_P1_15 = 22
	GPIO_P1_18 = 24
	GPIO_P1_22 = 25
	GPIO_P1_16 = 23
	GPIO_P1_11 = 17

	GPIO21 = GPIO_P1_13
	GPIO22 = GPIO_P1_15
	GPIO23 = GPIO_P1_16
	GPIO25 = GPIO_P1_22
	GPIO24 = GPIO_P1_18
	GPIO27 = GPIO_P1_13
	GPIO17 = GPIO_P1_11
)

func initRPi() {
	memfd, err := os.OpenFile("/dev/mem", os.O_RDWR|os.O_SYNC, 0)
	if err != nil {
		log.Fatalf("rpi: unable to open /dev/mem: %v", err)
	}
	initGPIO(int(memfd.Fd()))
	memfd.Close()
}

var initOnce sync.Once
<|endoftext|>


<commit_before>package pathfs

import (
	"fmt"
	"path/filepath"
	"time"

	"github.com/hanwen/go-fuse/fuse"
)

// PrefixFileSystem adds a path prefix to incoming calls.
type PrefixFileSystem struct {
	FileSystem
	Prefix string
}

func (fs *PrefixFileSystem) prefixed(n string) string {
	return filepath.Join(fs.Prefix, n)
}

func (fs *PrefixFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	return fs.FileSystem.GetAttr(fs.prefixed(name), context)
}

func (fs *PrefixFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
	return fs.FileSystem.Readlink(fs.prefixed(name), context)
}

func (fs *PrefixFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status {
	return fs.FileSystem.Mknod(fs.prefixed(name), mode, dev, context)
}

func (fs *PrefixFileSystem) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
	return fs.FileSystem.Mkdir(fs.prefixed(name), mode, context)
}

func (fs *PrefixFileSystem) Unlink(name string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Unlink(fs.prefixed(name), context)
}

func (fs *PrefixFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Rmdir(fs.prefixed(name), context)
}

func (fs *PrefixFileSystem) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Symlink(value, fs.prefixed(linkName), context)
}

func (fs *PrefixFileSystem) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Rename(fs.prefixed(oldName), fs.prefixed(newName), context)
}

func (fs *PrefixFileSystem) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Link(fs.prefixed(oldName), fs.prefixed(newName), context)
}

func (fs *PrefixFileSystem) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chmod(fs.prefixed(name), mode, context)
}

func (fs *PrefixFileSystem) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chown(fs.prefixed(name), uid, gid, context)
}

func (fs *PrefixFileSystem) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Truncate(fs.prefixed(name), offset, context)
}

func (fs *PrefixFileSystem) Open(name string, flags uint32, context *fuse.Context) (file fuse.File, code fuse.Status) {
	return fs.FileSystem.Open(fs.prefixed(name), flags, context)
}

func (fs *PrefixFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
	return fs.FileSystem.OpenDir(fs.prefixed(name), context)
}

func (fs *PrefixFileSystem) OnMount(nodeFs *PathNodeFs) {
	fs.FileSystem.OnMount(nodeFs)
}

func (fs *PrefixFileSystem) OnUnmount() {
	fs.FileSystem.OnUnmount()
}

func (fs *PrefixFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Access(fs.prefixed(name), mode, context)
}

func (fs *PrefixFileSystem) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file fuse.File, code fuse.Status) {
	return fs.FileSystem.Create(fs.prefixed(name), flags, mode, context)
}

func (fs *PrefixFileSystem) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Utimens(fs.prefixed(name), Atime, Mtime, context)
}

func (fs *PrefixFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
	return fs.FileSystem.GetXAttr(fs.prefixed(name), attr, context)
}

func (fs *PrefixFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
	return fs.FileSystem.SetXAttr(fs.prefixed(name), attr, data, flags, context)
}

func (fs *PrefixFileSystem) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
	return fs.FileSystem.ListXAttr(fs.prefixed(name), context)
}

func (fs *PrefixFileSystem) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
	return fs.FileSystem.RemoveXAttr(fs.prefixed(name), attr, context)
}

func (fs *PrefixFileSystem) String() string {
	return fmt.Sprintf("PrefixFileSystem(%s,%s)", fs.FileSystem.String(), fs.Prefix)
}
<commit_msg>Hide PrefixFileSystem type.<commit_after>package pathfs

import (
	"fmt"
	"path/filepath"
	"time"

	"github.com/hanwen/go-fuse/fuse"
)

// PrefixFileSystem adds a path prefix to incoming calls.
type prefixFileSystem struct {
	FileSystem FileSystem
	Prefix string
}

func NewPrefixFileSystem(fs FileSystem, prefix string) FileSystem {
	return &prefixFileSystem{fs, prefix}
}

func (fs *prefixFileSystem) prefixed(n string) string {
	return filepath.Join(fs.Prefix, n)
}

func (fs *prefixFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	return fs.FileSystem.GetAttr(fs.prefixed(name), context)
}

func (fs *prefixFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
	return fs.FileSystem.Readlink(fs.prefixed(name), context)
}

func (fs *prefixFileSystem) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status {
	return fs.FileSystem.Mknod(fs.prefixed(name), mode, dev, context)
}

func (fs *prefixFileSystem) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
	return fs.FileSystem.Mkdir(fs.prefixed(name), mode, context)
}

func (fs *prefixFileSystem) Unlink(name string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Unlink(fs.prefixed(name), context)
}

func (fs *prefixFileSystem) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Rmdir(fs.prefixed(name), context)
}

func (fs *prefixFileSystem) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Symlink(value, fs.prefixed(linkName), context)
}

func (fs *prefixFileSystem) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Rename(fs.prefixed(oldName), fs.prefixed(newName), context)
}

func (fs *prefixFileSystem) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Link(fs.prefixed(oldName), fs.prefixed(newName), context)
}

func (fs *prefixFileSystem) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chmod(fs.prefixed(name), mode, context)
}

func (fs *prefixFileSystem) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Chown(fs.prefixed(name), uid, gid, context)
}

func (fs *prefixFileSystem) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Truncate(fs.prefixed(name), offset, context)
}

func (fs *prefixFileSystem) Open(name string, flags uint32, context *fuse.Context) (file fuse.File, code fuse.Status) {
	return fs.FileSystem.Open(fs.prefixed(name), flags, context)
}

func (fs *prefixFileSystem) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
	return fs.FileSystem.OpenDir(fs.prefixed(name), context)
}

func (fs *prefixFileSystem) OnMount(nodeFs *PathNodeFs) {
	fs.FileSystem.OnMount(nodeFs)
}

func (fs *prefixFileSystem) OnUnmount() {
	fs.FileSystem.OnUnmount()
}

func (fs *prefixFileSystem) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Access(fs.prefixed(name), mode, context)
}

func (fs *prefixFileSystem) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file fuse.File, code fuse.Status) {
	return fs.FileSystem.Create(fs.prefixed(name), flags, mode, context)
}

func (fs *prefixFileSystem) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
	return fs.FileSystem.Utimens(fs.prefixed(name), Atime, Mtime, context)
}

func (fs *prefixFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
	return fs.FileSystem.GetXAttr(fs.prefixed(name), attr, context)
}

func (fs *prefixFileSystem) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
	return fs.FileSystem.SetXAttr(fs.prefixed(name), attr, data, flags, context)
}

func (fs *prefixFileSystem) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
	return fs.FileSystem.ListXAttr(fs.prefixed(name), context)
}

func (fs *prefixFileSystem) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
	return fs.FileSystem.RemoveXAttr(fs.prefixed(name), attr, context)
}

func (fs *prefixFileSystem) String() string {
	return fmt.Sprintf("prefixFileSystem(%s,%s)", fs.FileSystem.String(), fs.Prefix)
}

func (fs *prefixFileSystem) StatFs(name string) *fuse.StatfsOut {
	return fs.FileSystem.StatFs(fs.prefixed(name))
}
<|endoftext|>


<commit_before>package rss

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"sort"
	"strings"
	"time"
)

func parseRSS2(data []byte, read *db) (*Feed, error) {
	warnings := false
	feed := rss2_0Feed{}
	p := xml.NewDecoder(bytes.NewReader(data))
	p.CharsetReader = charsetReader
	err := p.Decode(&feed)
	if err != nil {
		return nil, err
	}
	if feed.Channel == nil {
		return nil, fmt.Errorf("Error: no channel found in %q.", string(data))
	}

	channel := feed.Channel

	out := new(Feed)
	out.Title = channel.Title
	out.Description = channel.Description
	out.Link = channel.Link
	out.Image = channel.Image.Image()
	if channel.MinsToLive != 0 {
		sort.Ints(channel.SkipHours)
		next := time.Now().Add(time.Duration(channel.MinsToLive) * time.Minute)
		for _, hour := range channel.SkipHours {
			if hour == next.Hour() {
				next.Add(time.Duration(60-next.Minute()) * time.Minute)
			}
		}
		trying := true
		for trying {
			trying = false
			for _, day := range channel.SkipDays {
				if strings.Title(day) == next.Weekday().String() {
					next.Add(time.Duration(24-next.Hour()) * time.Hour)
					trying = true
					break
				}
			}
		}

		out.Refresh = next
	}

	if out.Refresh.IsZero() {
		out.Refresh = time.Now().Add(10 * time.Minute)
	}

	if channel.Items == nil {
		return nil, fmt.Errorf("Error: no feeds found in %q.", string(data))
	}

	out.Items = make([]*Item, 0, len(channel.Items))
	out.ItemMap = make(map[string]struct{})

	// Process items.
	for _, item := range channel.Items {

		if item.ID == "" {
			if item.Link == "" {
				if debug {
					fmt.Printf("[w] Item %q has no ID or link and will be ignored.\n", item.Title)
					fmt.Printf("[w] %#v\n", item)
				}
				warnings = true
				continue
			}
			item.ID = item.Link
		}

		// Skip items already known.
		if read.req <- item.ID; <-read.res {
			continue
		}

		next := new(Item)
		next.Title = item.Title
		next.Content = item.Content
		next.Link = item.Link
		if item.Date != "" {
			next.Date, err = parseTime(item.Date)
			if err != nil {
				return nil, err
			}
		} else if item.PubDate != "" {
			next.Date, err = parseTime(item.PubDate)
			if err != nil {
				return nil, err
			}
		}
		next.ID = item.ID
		if len(item.Enclosures) > 0 {
			next.Enclosures = make([]*Enclosure, len(item.Enclosures))
			for i := range item.Enclosures {
				next.Enclosures[i] = item.Enclosures[i].Enclosure()
			}
		}
		next.Read = false

		if _, ok := out.ItemMap[next.ID]; ok {
			if debug {
				fmt.Printf("[w] Item %q has duplicate ID.\n", next.Title)
				fmt.Printf("[w] %#v\n", next)
			}
			warnings = true
			continue
		}

		out.Items = append(out.Items, next)
		out.ItemMap[next.ID] = struct{}{}
		out.Unread++
	}

	if warnings && debug {
		fmt.Printf("[i] Encountered warnings:\n%s\n", data)
	}

	return out, nil
}

type rss2_0Feed struct {
	XMLName xml.Name       `xml:"rss"`
	Channel *rss2_0Channel `xml:"channel"`
}

type rss2_0Channel struct {
	XMLName     xml.Name     `xml:"channel"`
	Title       string       `xml:"title"`
	Description string       `xml:"description"`
	Link        string       `xml:"link"`
	Image       rss2_0Image  `xml:"image"`
	Items       []rss2_0Item `xml:"item"`
	MinsToLive  int          `xml:"ttl"`
	SkipHours   []int        `xml:"skipHours>hour"`
	SkipDays    []string     `xml:"skipDays>day"`
}

type rss2_0Item struct {
	XMLName    xml.Name          `xml:"item"`
	Title      string            `xml:"title"`
	Content    string            `xml:"description"`
	Link       string            `xml:"link"`
	PubDate    string            `xml:"pubDate"`
	Date       string            `xml:"date"`
	ID         string            `xml:"guid"`
	Enclosures []rss2_0Enclosure `xml:"enclosure"`
}

type rss2_0Enclosure struct {
	XMLName xml.Name `xml:"enclosure"`
	Url     string   `xml:"url"`
	Type    string   `xml:"type"`
	Length  int      `xml:"length"`
}

func (r *rss2_0Enclosure) Enclosure() *Enclosure {
	out := new(Enclosure)
	out.Url = r.Url
	out.Type = r.Type
	out.Length = r.Length
	return out
}

type rss2_0Image struct {
	XMLName xml.Name `xml:"image"`
	Title   string   `xml:"title"`
	Url     string   `xml:"url"`
	Height  int      `xml:"height"`
	Width   int      `xml:"width"`
}

func (i *rss2_0Image) Image() *Image {
	out := new(Image)
	out.Title = i.Title
	out.Url = i.Url
	out.Height = uint32(i.Height)
	out.Width = uint32(i.Width)
	return out
}
<commit_msg>Updated rss_2.0.go to support multiple Link<commit_after>package rss

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"sort"
	"strings"
	"time"
)

func parseRSS2(data []byte, read *db) (*Feed, error) {
	warnings := false
	feed := rss2_0Feed{}
	p := xml.NewDecoder(bytes.NewReader(data))
	p.CharsetReader = charsetReader
	err := p.Decode(&feed)
	if err != nil {
		return nil, err
	}
	if feed.Channel == nil {
		return nil, fmt.Errorf("Error: no channel found in %q.", string(data))
	}

	channel := feed.Channel

	out := new(Feed)
	out.Title = channel.Title
	out.Description = channel.Description
	for _, link := range channel.Link {
		if link != "" {
			out.Link = link
		}
	}
	out.Image = channel.Image.Image()
	if channel.MinsToLive != 0 {
		sort.Ints(channel.SkipHours)
		next := time.Now().Add(time.Duration(channel.MinsToLive) * time.Minute)
		for _, hour := range channel.SkipHours {
			if hour == next.Hour() {
				next.Add(time.Duration(60-next.Minute()) * time.Minute)
			}
		}
		trying := true
		for trying {
			trying = false
			for _, day := range channel.SkipDays {
				if strings.Title(day) == next.Weekday().String() {
					next.Add(time.Duration(24-next.Hour()) * time.Hour)
					trying = true
					break
				}
			}
		}

		out.Refresh = next
	}

	if out.Refresh.IsZero() {
		out.Refresh = time.Now().Add(10 * time.Minute)
	}

	if channel.Items == nil {
		return nil, fmt.Errorf("Error: no feeds found in %q.", string(data))
	}

	out.Items = make([]*Item, 0, len(channel.Items))
	out.ItemMap = make(map[string]struct{})

	// Process items.
	for _, item := range channel.Items {

		if item.ID == "" {
			if item.Link == "" {
				if debug {
					fmt.Printf("[w] Item %q has no ID or link and will be ignored.\n", item.Title)
					fmt.Printf("[w] %#v\n", item)
				}
				warnings = true
				continue
			}
			item.ID = item.Link
		}

		// Skip items already known.
		if read.req <- item.ID; <-read.res {
			continue
		}

		next := new(Item)
		next.Title = item.Title
		next.Content = item.Content
		next.Link = item.Link
		if item.Date != "" {
			next.Date, err = parseTime(item.Date)
			if err != nil {
				return nil, err
			}
		} else if item.PubDate != "" {
			next.Date, err = parseTime(item.PubDate)
			if err != nil {
				return nil, err
			}
		}
		next.ID = item.ID
		if len(item.Enclosures) > 0 {
			next.Enclosures = make([]*Enclosure, len(item.Enclosures))
			for i := range item.Enclosures {
				next.Enclosures[i] = item.Enclosures[i].Enclosure()
			}
		}
		next.Read = false

		if _, ok := out.ItemMap[next.ID]; ok {
			if debug {
				fmt.Printf("[w] Item %q has duplicate ID.\n", next.Title)
				fmt.Printf("[w] %#v\n", next)
			}
			warnings = true
			continue
		}

		out.Items = append(out.Items, next)
		out.ItemMap[next.ID] = struct{}{}
		out.Unread++
	}

	if warnings && debug {
		fmt.Printf("[i] Encountered warnings:\n%s\n", data)
	}

	return out, nil
}

type rss2_0Feed struct {
	XMLName xml.Name       `xml:"rss"`
	Channel *rss2_0Channel `xml:"channel"`
}

type rss2_0Channel struct {
	XMLName     xml.Name     `xml:"channel"`
	Title       string       `xml:"title"`
	Description string       `xml:"description"`
	Link        []string     `xml:"link"`
	Image       rss2_0Image  `xml:"image"`
	Items       []rss2_0Item `xml:"item"`
	MinsToLive  int          `xml:"ttl"`
	SkipHours   []int        `xml:"skipHours>hour"`
	SkipDays    []string     `xml:"skipDays>day"`
}

type rss2_0Item struct {
	XMLName    xml.Name          `xml:"item"`
	Title      string            `xml:"title"`
	Content    string            `xml:"description"`
	Link       string            `xml:"link"`
	PubDate    string            `xml:"pubDate"`
	Date       string            `xml:"date"`
	ID         string            `xml:"guid"`
	Enclosures []rss2_0Enclosure `xml:"enclosure"`
}

type rss2_0Enclosure struct {
	XMLName xml.Name `xml:"enclosure"`
	Url     string   `xml:"url"`
	Type    string   `xml:"type"`
	Length  int      `xml:"length"`
}

func (r *rss2_0Enclosure) Enclosure() *Enclosure {
	out := new(Enclosure)
	out.Url = r.Url
	out.Type = r.Type
	out.Length = r.Length
	return out
}

type rss2_0Image struct {
	XMLName xml.Name `xml:"image"`
	Title   string   `xml:"title"`
	Url     string   `xml:"url"`
	Height  int      `xml:"height"`
	Width   int      `xml:"width"`
}

func (i *rss2_0Image) Image() *Image {
	out := new(Image)
	out.Title = i.Title
	out.Url = i.Url
	out.Height = uint32(i.Height)
	out.Width = uint32(i.Width)
	return out
}
<|endoftext|>


<commit_before>package vimeo

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"

	"github.com/google/go-querystring/query"
)

const (
	libraryVersion   = "1.1.0"
	defaultBaseURL   = "https://api.vimeo.com/"
	defaultUserAgent = "go-vimeo/" + libraryVersion

	mediaTypeVersion = "application/vnd.vimeo.*+json;version=3.2"
)

// Client manages communication with Vimeo API.
type Client struct {
	client *http.Client

	BaseURL *url.URL

	UserAgent string

	// Services used for communicating with the API
	Categories      *CategoriesService
	Channels        *ChannelsService
	ContentRatings  *ContentRatingsService
	CreativeCommons *CreativeCommonsService
	Groups          *GroupsService
	Languages       *LanguagesService
	Tags            *TagsService
	Videos          *VideosService
	Users           *UsersService
}

type service struct {
	client *Client
}

// NewClient returns a new Vimeo API client. If a nil httpClient is
// provided, http.DefaultClient will be used. To use API methods which require
// authentication, provide an http.Client that will perform the authentication
// for you (such as that provided by the golang.org/x/oauth2 library).
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: defaultUserAgent}
	c.Categories = &CategoriesService{client: c}
	c.Channels = &ChannelsService{client: c}
	c.ContentRatings = &ContentRatingsService{client: c}
	c.CreativeCommons = &CreativeCommonsService{client: c}
	c.Groups = &GroupsService{client: c}
	c.Languages = &LanguagesService{client: c}
	c.Tags = &TagsService{client: c}
	c.Videos = &VideosService{client: c}
	c.Users = &UsersService{client: c}
	return c
}

// Client returns the HTTP client configured for this client.
func (c *Client) Client() *http.Client {
	return c.client
}

// NewRequest creates an API request.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	if body != nil {
		req.Header.Set("Content-Type", "application/json")
	}

	req.Header.Set("Accept", mediaTypeVersion)

	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}

	return req, nil
}

// NewUploadRequest creates an upload request.
func (c *Client) NewUploadRequest(url string, reader io.Reader, size, lastByte int64) (*http.Request, error) {
	req, err := http.NewRequest("PUT", url, reader)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Length", fmt.Sprintf("%d", size))
	req.Header.Set("Content-Range", fmt.Sprintf("bytes: %d-%d/%d", lastByte, size, size))

	return req, nil
}

// Do sends an API request and returns the API response. The API response is JSON decoded and stored in the value
// pointed to by v, or returned as an error if an API error has occurred. If v implements the io.Writer interface,
// the raw response will be written to v, without attempting to decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer func() {
		io.CopyN(ioutil.Discard, resp.Body, 512)
		resp.Body.Close()
	}()

	response := newResponse(resp)

	err = CheckResponse(resp)
	if err != nil {
		return response, err
	}

	if v != nil {
		if w, ok := v.(io.Writer); ok {
			_, err = io.Copy(w, resp.Body)
			if err != nil {
				return nil, err
			}
		} else {
			err = json.NewDecoder(resp.Body).Decode(v)
			if err == io.EOF {
				err = nil
			}
		}
	}

	return response, err
}

type paginator interface {
	GetPage() int
	GetTotal() int
	GetPaging() (string, string, string, string)
}

type paging struct {
	Next  string `json:"next,omitempty"`
	Prev  string `json:"previous,omitempty"`
	First string `json:"first,omitempty"`
	Last  string `json:"last,omitempty"`
}

type pagination struct {
	Total  int    `json:"total,omitempty"`
	Page   int    `json:"page,omitempty"`
	Paging paging `json:"paging,omitempty"`
}

// GetPage returns the current page number.
func (p pagination) GetPage() int {
	return p.Page
}

// GetTotal returns the total number of pages.
func (p pagination) GetTotal() int {
	return p.Total
}

// GetPaging returns the data pagination presented as relative references.
// In the following procedure: next, previous, first, last page.
func (p pagination) GetPaging() (string, string, string, string) {
	return p.Paging.Next, p.Paging.Prev, p.Paging.First, p.Paging.Last
}

// Response is a Vimeo response. This wraps the standard http.Response.
// Provides access pagination links.
type Response struct {
	*http.Response
	// Pagination
	Page       int
	TotalPages int
	NextPage   string
	PrevPage   string
	FirstPage  string
	LastPage   string
}

func (r *Response) setPaging(p paginator) {
	r.Page = p.GetPage()
	r.TotalPages = p.GetTotal()
	r.NextPage, r.PrevPage, r.FirstPage, r.LastPage = p.GetPaging()
}

// ErrorResponse is a Vimeo error response. This wraps the standard http.Response.
// Provides access error message returned Vimeo.
type ErrorResponse struct {
	Response *http.Response
	Message  string `json:"error"`
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
		r.Response.StatusCode, r.Message)
}

func sanitizeURL(uri *url.URL) *url.URL {
	if uri == nil {
		return nil
	}
	params := uri.Query()
	if len(params.Get("client_secret")) > 0 {
		params.Set("client_secret", "REDACTED")
		uri.RawQuery = params.Encode()
	}
	return uri
}

func newResponse(r *http.Response) *Response {
	response := &Response{Response: r}
	return response
}

// CheckResponse checks the API response for errors, and returns them if
// present.  A response is considered an error if it has a status code outside
// the 200 range.  API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse.  Any other
// response body will be silently ignored.
func CheckResponse(r *http.Response) error {
	if code := r.StatusCode; 200 <= code && code <= 299 || code == 308 {
		return nil
	}

	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)

	if err == nil && data != nil {
		json.Unmarshal(data, errorResponse)
	}

	return errorResponse
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	Page      int `url:"page,omitempty"`
	PerPage   int `url:"per_page,omitempty"`
	Sort      int `url:"sort,omitempty"`
	Direction int `url:"direction,omitempty"`
}

func addOptions(s string, opt interface{}) (string, error) {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opt)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}
<commit_msg>Prepare 1.2.0<commit_after>package vimeo

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"

	"github.com/google/go-querystring/query"
)

const (
	libraryVersion   = "1.2.0"
	defaultBaseURL   = "https://api.vimeo.com/"
	defaultUserAgent = "go-vimeo/" + libraryVersion

	mediaTypeVersion = "application/vnd.vimeo.*+json;version=3.2"
)

// Client manages communication with Vimeo API.
type Client struct {
	client *http.Client

	BaseURL *url.URL

	UserAgent string

	// Services used for communicating with the API
	Categories      *CategoriesService
	Channels        *ChannelsService
	ContentRatings  *ContentRatingsService
	CreativeCommons *CreativeCommonsService
	Groups          *GroupsService
	Languages       *LanguagesService
	Tags            *TagsService
	Videos          *VideosService
	Users           *UsersService
}

type service struct {
	client *Client
}

// NewClient returns a new Vimeo API client. If a nil httpClient is
// provided, http.DefaultClient will be used. To use API methods which require
// authentication, provide an http.Client that will perform the authentication
// for you (such as that provided by the golang.org/x/oauth2 library).
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: defaultUserAgent}
	c.Categories = &CategoriesService{client: c}
	c.Channels = &ChannelsService{client: c}
	c.ContentRatings = &ContentRatingsService{client: c}
	c.CreativeCommons = &CreativeCommonsService{client: c}
	c.Groups = &GroupsService{client: c}
	c.Languages = &LanguagesService{client: c}
	c.Tags = &TagsService{client: c}
	c.Videos = &VideosService{client: c}
	c.Users = &UsersService{client: c}
	return c
}

// Client returns the HTTP client configured for this client.
func (c *Client) Client() *http.Client {
	return c.client
}

// NewRequest creates an API request.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	if body != nil {
		req.Header.Set("Content-Type", "application/json")
	}

	req.Header.Set("Accept", mediaTypeVersion)

	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}

	return req, nil
}

// NewUploadRequest creates an upload request.
func (c *Client) NewUploadRequest(url string, reader io.Reader, size, lastByte int64) (*http.Request, error) {
	req, err := http.NewRequest("PUT", url, reader)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Length", fmt.Sprintf("%d", size))
	req.Header.Set("Content-Range", fmt.Sprintf("bytes: %d-%d/%d", lastByte, size, size))

	return req, nil
}

// Do sends an API request and returns the API response. The API response is JSON decoded and stored in the value
// pointed to by v, or returned as an error if an API error has occurred. If v implements the io.Writer interface,
// the raw response will be written to v, without attempting to decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer func() {
		io.CopyN(ioutil.Discard, resp.Body, 512)
		resp.Body.Close()
	}()

	response := newResponse(resp)

	err = CheckResponse(resp)
	if err != nil {
		return response, err
	}

	if v != nil {
		if w, ok := v.(io.Writer); ok {
			_, err = io.Copy(w, resp.Body)
			if err != nil {
				return nil, err
			}
		} else {
			err = json.NewDecoder(resp.Body).Decode(v)
			if err == io.EOF {
				err = nil
			}
		}
	}

	return response, err
}

type paginator interface {
	GetPage() int
	GetTotal() int
	GetPaging() (string, string, string, string)
}

type paging struct {
	Next  string `json:"next,omitempty"`
	Prev  string `json:"previous,omitempty"`
	First string `json:"first,omitempty"`
	Last  string `json:"last,omitempty"`
}

type pagination struct {
	Total  int    `json:"total,omitempty"`
	Page   int    `json:"page,omitempty"`
	Paging paging `json:"paging,omitempty"`
}

// GetPage returns the current page number.
func (p pagination) GetPage() int {
	return p.Page
}

// GetTotal returns the total number of pages.
func (p pagination) GetTotal() int {
	return p.Total
}

// GetPaging returns the data pagination presented as relative references.
// In the following procedure: next, previous, first, last page.
func (p pagination) GetPaging() (string, string, string, string) {
	return p.Paging.Next, p.Paging.Prev, p.Paging.First, p.Paging.Last
}

// Response is a Vimeo response. This wraps the standard http.Response.
// Provides access pagination links.
type Response struct {
	*http.Response
	// Pagination
	Page       int
	TotalPages int
	NextPage   string
	PrevPage   string
	FirstPage  string
	LastPage   string
}

func (r *Response) setPaging(p paginator) {
	r.Page = p.GetPage()
	r.TotalPages = p.GetTotal()
	r.NextPage, r.PrevPage, r.FirstPage, r.LastPage = p.GetPaging()
}

// ErrorResponse is a Vimeo error response. This wraps the standard http.Response.
// Provides access error message returned Vimeo.
type ErrorResponse struct {
	Response *http.Response
	Message  string `json:"error"`
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, sanitizeURL(r.Response.Request.URL),
		r.Response.StatusCode, r.Message)
}

func sanitizeURL(uri *url.URL) *url.URL {
	if uri == nil {
		return nil
	}
	params := uri.Query()
	if len(params.Get("client_secret")) > 0 {
		params.Set("client_secret", "REDACTED")
		uri.RawQuery = params.Encode()
	}
	return uri
}

func newResponse(r *http.Response) *Response {
	response := &Response{Response: r}
	return response
}

// CheckResponse checks the API response for errors, and returns them if
// present.  A response is considered an error if it has a status code outside
// the 200 range.  API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse.  Any other
// response body will be silently ignored.
func CheckResponse(r *http.Response) error {
	if code := r.StatusCode; 200 <= code && code <= 299 || code == 308 {
		return nil
	}

	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)

	if err == nil && data != nil {
		json.Unmarshal(data, errorResponse)
	}

	return errorResponse
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	Page      int `url:"page,omitempty"`
	PerPage   int `url:"per_page,omitempty"`
	Sort      int `url:"sort,omitempty"`
	Direction int `url:"direction,omitempty"`
}

func addOptions(s string, opt interface{}) (string, error) {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opt)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}
<|endoftext|>


<commit_before>package run

import (
	"errors"
	"net/http"
	"os"
	"strconv"
	"time"

	"gopkg.in/tylerb/graceful.v1"

	"github.com/Sirupsen/logrus"
	"github.com/solher/snakepit/root"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	Port    = "app.port"
	Timeout = "app.timeout"
)

var (
	Logger = logrus.New()
)

var Builder func(v *viper.Viper, l *logrus.Logger) (http.Handler, error)

var Cmd = &cobra.Command{
	Use:   "run",
	Short: "Runs the service",
	RunE: func(cmd *cobra.Command, args []string) error {
		if Builder == nil {
			return errors.New("nil builder func")
		}

		Logger.Infof("Building...")
		appHandler, err := Builder(root.Viper, Logger)
		if err != nil {
			return err
		}

		port := root.Viper.GetInt(Port)
		timeout := root.Viper.GetDuration(Timeout)

		Logger.Infof("Listening on port %d.", port)
		graceful.Run(":"+strconv.Itoa(port), timeout, appHandler)
		return nil
	},
}

func init() {
	root.Cmd.AddCommand(Cmd)

	Logger.Formatter = &logrus.TextFormatter{}
	Logger.Out = os.Stdout
	Logger.Level = logrus.DebugLevel

	root.Cmd.RunE = Cmd.RunE

	Cmd.PersistentFlags().IntP("port", "p", 3000, "listening port")
	root.Viper.BindPFlag(Port, Cmd.PersistentFlags().Lookup("port"))

	Cmd.PersistentFlags().Duration("timeout", 5*time.Second, "graceful shutdown timeout (0 for infinite)")
	root.Viper.BindPFlag(Timeout, Cmd.PersistentFlags().Lookup("timeout"))
}
<commit_msg>Log colors now forced<commit_after>package run

import (
	"errors"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/tylerb/graceful"

	"github.com/Sirupsen/logrus"
	"github.com/solher/snakepit/root"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	Port    = "app.port"
	Timeout = "app.timeout"
)

var (
	Logger = logrus.New()
)

var Builder func(v *viper.Viper, l *logrus.Logger) (http.Handler, error)

var Cmd = &cobra.Command{
	Use:   "run",
	Short: "Runs the service",
	RunE: func(cmd *cobra.Command, args []string) error {
		if Builder == nil {
			return errors.New("nil builder func")
		}

		Logger.Infof("Building...")
		appHandler, err := Builder(root.Viper, Logger)
		if err != nil {
			return err
		}

		port := root.Viper.GetInt(Port)
		timeout := root.Viper.GetDuration(Timeout)

		Logger.Infof("Listening on port %d.", port)
		graceful.Run(":"+strconv.Itoa(port), timeout, appHandler)
		return nil
	},
}

func init() {
	root.Cmd.AddCommand(Cmd)

	Logger.Formatter = &logrus.TextFormatter{
		ForceColors: true,
	}
	Logger.Out = os.Stdout
	Logger.Level = logrus.DebugLevel

	root.Cmd.RunE = Cmd.RunE

	Cmd.PersistentFlags().IntP("port", "p", 3000, "listening port")
	root.Viper.BindPFlag(Port, Cmd.PersistentFlags().Lookup("port"))

	Cmd.PersistentFlags().Duration("timeout", 5*time.Second, "graceful shutdown timeout (0 for infinite)")
	root.Viper.BindPFlag(Timeout, Cmd.PersistentFlags().Lookup("timeout"))
}
<|endoftext|>


<commit_before>// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com

package auth

import (
	"fmt"
	"net/http"
	"strings"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
	"github.com/documize/community/core/env"
	"github.com/documize/community/domain"
)

// GenerateJWT generates JSON Web Token (http://jwt.io)
func GenerateJWT(rt *env.Runtime, user, org, domain string) string {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"iss":    "Documize",
		"sub":    "webapp",
		"exp":    time.Now().Add(time.Hour * 168).Unix(),
		"user":   user,
		"org":    org,
		"domain": domain,
	})

	tokenString, _ := token.SignedString([]byte(rt.Flags.Salt))

	return tokenString
}

// FindJWT looks for 'Authorization' request header OR query string "?token=XXX".
func FindJWT(r *http.Request) (token string) {
	header := r.Header.Get("Authorization")

	if header != "" {
		header = strings.Replace(header, "Bearer ", "", 1)
	}

	if len(header) > 1 {
		token = header
	} else {
		query := r.URL.Query()
		token = query.Get("token")
	}

	if token == "null" {
		token = ""
	}

	return
}

// DecodeJWT decodes raw token.
func DecodeJWT(rt *env.Runtime, tokenString string) (c domain.RequestContext, claims jwt.Claims, err error) {
	// sensible defaults
	c.UserID = ""
	c.OrgID = ""
	c.Authenticated = false
	c.Guest = false

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return []byte(rt.Flags.Salt), nil
	})

	if err != nil {
		err = fmt.Errorf("bad authorization token")
		return
	}

	if !token.Valid {
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				err = fmt.Errorf("bad token")
				return
			} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
				err = fmt.Errorf("expired token")
				return
			} else {
				err = fmt.Errorf("bad token")
				return
			}
		} else {
			err = fmt.Errorf("bad token")
			return
		}
	}

	c = domain.RequestContext{}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		c.UserID = claims["user"].(string)
		c.OrgID = claims["org"].(string)
	} else {
		fmt.Println(err)
	}

	if len(c.UserID) == 0 || len(c.OrgID) == 0 {
		err = fmt.Errorf("unable parse token data")
		return
	}

	c.Authenticated = true
	c.Guest = false

	return c, token.Claims, nil
}

// DecodeKeycloakJWT takes in Keycloak token string and decodes it.
func DecodeKeycloakJWT(t, pk string) (c jwt.MapClaims, err error) {
	token, err := jwt.Parse(t, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}

		return jwt.ParseRSAPublicKeyFromPEM([]byte(pk))
	})

	if c, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return c, nil
	}

	return nil, err
}
<commit_msg>increase token expiry<commit_after>// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com

package auth

import (
	"fmt"
	"net/http"
	"strings"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
	"github.com/documize/community/core/env"
	"github.com/documize/community/domain"
)

// GenerateJWT generates JSON Web Token (http://jwt.io)
func GenerateJWT(rt *env.Runtime, user, org, domain string) string {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"iss":    "Documize",
		"sub":    "webapp",
		"exp":    time.Now().Add(time.Hour * 8760).Unix(),
		"user":   user,
		"org":    org,
		"domain": domain,
	})

	tokenString, _ := token.SignedString([]byte(rt.Flags.Salt))

	return tokenString
}

// FindJWT looks for 'Authorization' request header OR query string "?token=XXX".
func FindJWT(r *http.Request) (token string) {
	header := r.Header.Get("Authorization")

	if header != "" {
		header = strings.Replace(header, "Bearer ", "", 1)
	}

	if len(header) > 1 {
		token = header
	} else {
		query := r.URL.Query()
		token = query.Get("token")
	}

	if token == "null" {
		token = ""
	}

	return
}

// DecodeJWT decodes raw token.
func DecodeJWT(rt *env.Runtime, tokenString string) (c domain.RequestContext, claims jwt.Claims, err error) {
	// sensible defaults
	c.UserID = ""
	c.OrgID = ""
	c.Authenticated = false
	c.Guest = false

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return []byte(rt.Flags.Salt), nil
	})

	if err != nil {
		err = fmt.Errorf("bad authorization token")
		return
	}

	if !token.Valid {
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				err = fmt.Errorf("bad token")
				return
			} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
				err = fmt.Errorf("expired token")
				return
			} else {
				err = fmt.Errorf("bad token")
				return
			}
		} else {
			err = fmt.Errorf("bad token")
			return
		}
	}

	c = domain.RequestContext{}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		c.UserID = claims["user"].(string)
		c.OrgID = claims["org"].(string)
	} else {
		fmt.Println(err)
	}

	if len(c.UserID) == 0 || len(c.OrgID) == 0 {
		err = fmt.Errorf("unable parse token data")
		return
	}

	c.Authenticated = true
	c.Guest = false

	return c, token.Claims, nil
}

// DecodeKeycloakJWT takes in Keycloak token string and decodes it.
func DecodeKeycloakJWT(t, pk string) (c jwt.MapClaims, err error) {
	token, err := jwt.Parse(t, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}

		return jwt.ParseRSAPublicKeyFromPEM([]byte(pk))
	})

	if c, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return c, nil
	}

	return nil, err
}
<|endoftext|>