<commit_before>package alioss

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	DefaultDownloadConcurrency int   = 5
	DefaultDownloadPartSize    int64 = 5 * 1024 * 1024 // 5Mb

)

// Download remote "fileName" to local file in "destinationPath"
func (alioss AliOss) Download(fileName, destinationPath string) error {
	bucket, err := alioss.Svc.Bucket(alioss.Bucket)
	if err != nil {
		return fmt.Errorf("Failed to download file %s: %s\n", fileName, err)
	}

	fileName = strings.TrimPrefix(fileName, "/")
	err = bucket.GetObjectToFile(fileName, destinationPath)
	if err != nil {
		return fmt.Errorf("Failed to download file %s to %s: %s\n", fileName, destinationPath, err)
	}

	return nil
}

// Resume download of remote "fileName" to existed local file in "destinationPath"
func (alioss AliOss) ResumeDownload(fileName, destinationPath string) error {
	remoteFileInfo, err := alioss.GetFileInfo(fileName)
	if err != nil {
		alioss.Log.Printf("Failed to get file %s: %s\n", fileName, err)
		return err
	}

	file, err := os.OpenFile(destinationPath, os.O_WRONLY, 666)
	if err != nil {
		return fmt.Errorf("Failed to create destination file %s: %s\n", destinationPath, err)
	}
	defer alioss.IoClose(file)

	stat, err := file.Stat()
	if err != nil {
		return fmt.Errorf("Failed to stat destination file %s: %s\n", destinationPath, err)
	}

	tmpContentLength, err := strconv.Atoi(remoteFileInfo.Get("Content-Length"))
	if err != nil {
		return fmt.Errorf("Failed to get header Content-Length of remote file %s: %s\n", fileName, err)
	}

	var contentLength int64
	contentLength = int64(tmpContentLength)
	if contentLength < stat.Size() {
		return fmt.Errorf("Failed to compare size of remote %s and destination file %s: %d <= %d\n", fileName, destinationPath, contentLength, stat.Size())
	}

	if contentLength == stat.Size() {
		alioss.Log.Printf("Size of remote %s and destination %s file match: %d == %d. Nothing to do.\n", fileName, destinationPath, contentLength, stat.Size())
		return nil
	}

	d := downloader{
		AliOss:     alioss,
		File:       file,
		FileOffset: stat.Size(),
	}

	taskPartChan := make(chan filePart, DefaultDownloadConcurrency)
	var wg sync.WaitGroup
	for i := 0; i < DefaultDownloadConcurrency; i++ {
		wg.Add(1)
		go d.asyncDownloadPart(taskPartChan, &wg)
	}

	partOffset := stat.Size()
	leftBytes := contentLength - stat.Size()
	go func() {
		for {
			alioss.Log.Printf("Resume download: Left bytes %d\n", leftBytes)
			if leftBytes <= DefaultDownloadPartSize {
				partRange := fmt.Sprintf("bytes=%d-%d", partOffset, partOffset+leftBytes-1)
				alioss.Log.Printf("Resume download: File range %s\n", partRange)
				taskPartChan <- filePart{
					Key:    fileName,
					Range:  partRange,
					Offset: partOffset,
					Length: leftBytes,
					Body:   make([]byte, leftBytes),
				}
				close(taskPartChan)
				alioss.Log.Println("Resume download: All parts send to download. Close channel.")
				return
			}
			fileRange := fmt.Sprintf("bytes=%d-%d", partOffset, partOffset+DefaultDownloadPartSize-1)
			alioss.Log.Printf("Resume download: Part range %s\n", fileRange)
			alioss.Log.Printf("Resume download: Part offset %d\n", partOffset)

			taskPartChan <- filePart{
				Key:    fileName,
				Range:  fileRange,
				Offset: partOffset,
				Length: DefaultDownloadPartSize,
			}
			partOffset = partOffset + DefaultDownloadPartSize
			leftBytes = leftBytes - DefaultDownloadPartSize
		}
	}()

	wg.Wait()
    if d.Err != nil {
        return fmt.Errorf("Failed to download remote %s to %s: %s", fileName, destinationPath, d.Err)
    }

	return nil
}

func (alioss *downloader) asyncDownloadPart(taskPartChan <-chan filePart, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		if part, ok := <-taskPartChan; ok {
            if alioss.Err != nil {
                alioss.Log.Printf("Failed to start download %s: %s\n", part.Range, alioss.Err)
                return
            }
			alioss.Log.Printf("Start to download part for key %s: Range: %s, Offset: %d, Length: %d\n", part.Key, part.Range, part.Offset, part.Length)

			body, err := alioss.GetFilePart(part.Key, part.Offset, part.Offset+part.Length-1)
			alioss.Log.Printf("Request sent for %s range %s\n", part.Key, part.Range)
			if err != nil {
				alioss.Log.Printf("Failed to download file %s range %s: %s\n", part.Key, part.Range, err)
				return
			}
			alioss.Log.Printf("Recieved response for %s range %s\n", part.Key, part.Range)
			alioss.Log.Printf("File offset: %d\n", alioss.FileOffset)
			alioss.Log.Printf("Part offset: %d\n", part.Offset)

			for {
                if alioss.Err != nil {
				    alioss.Log.Printf("Failed to write download %s: %s\n", part.Range, alioss.Err)
                    //alioss.IoClose(body)
				    return
			    }
				if alioss.FileOffset == part.Offset {
					n, err := io.Copy(alioss.File, &body)
					if err != nil {
						alioss.Err = err
						alioss.Log.Printf("Failed to write file %s range %s: %s\n", part.Key, part.Range, err)
                        //alioss.IoClose(body)
						return
					}

					alioss.Log.Printf("Finish write %d bytes part range %s for key %s \n", n, part.Range, part.Key)

					alioss.FileOffset = part.Offset + part.Length
					alioss.Log.Printf("New file offset: %d\n", alioss.FileOffset)
                    //alioss.IoClose(body)
					break
				}
				time.Sleep(10 * time.Millisecond)
			}
		} else {
			alioss.Log.Println("Download channel closed. Return.")
			return
		}
	}
}
<commit_msg>Drop unnecessary code<commit_after>package alioss

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	DefaultDownloadConcurrency int   = 5
	DefaultDownloadPartSize    int64 = 5 * 1024 * 1024 // 5Mb

)

// Download remote "fileName" to local file in "destinationPath"
func (alioss AliOss) Download(fileName, destinationPath string) error {
	bucket, err := alioss.Svc.Bucket(alioss.Bucket)
	if err != nil {
		return fmt.Errorf("Failed to download file %s: %s\n", fileName, err)
	}

	fileName = strings.TrimPrefix(fileName, "/")
	err = bucket.GetObjectToFile(fileName, destinationPath)
	if err != nil {
		return fmt.Errorf("Failed to download file %s to %s: %s\n", fileName, destinationPath, err)
	}

	return nil
}

// Resume download of remote "fileName" to existed local file in "destinationPath"
func (alioss AliOss) ResumeDownload(fileName, destinationPath string) error {
	remoteFileInfo, err := alioss.GetFileInfo(fileName)
	if err != nil {
		alioss.Log.Printf("Failed to get file %s: %s\n", fileName, err)
		return err
	}

	file, err := os.OpenFile(destinationPath, os.O_WRONLY, 666)
	if err != nil {
		return fmt.Errorf("Failed to create destination file %s: %s\n", destinationPath, err)
	}
	defer alioss.IoClose(file)

	stat, err := file.Stat()
	if err != nil {
		return fmt.Errorf("Failed to stat destination file %s: %s\n", destinationPath, err)
	}

	tmpContentLength, err := strconv.Atoi(remoteFileInfo.Get("Content-Length"))
	if err != nil {
		return fmt.Errorf("Failed to get header Content-Length of remote file %s: %s\n", fileName, err)
	}

	var contentLength int64
	contentLength = int64(tmpContentLength)
	if contentLength < stat.Size() {
		return fmt.Errorf("Failed to compare size of remote %s and destination file %s: %d <= %d\n", fileName, destinationPath, contentLength, stat.Size())
	}

	if contentLength == stat.Size() {
		alioss.Log.Printf("Size of remote %s and destination %s file match: %d == %d. Nothing to do.\n", fileName, destinationPath, contentLength, stat.Size())
		return nil
	}

	d := downloader{
		AliOss:     alioss,
		File:       file,
		FileOffset: stat.Size(),
	}

	taskPartChan := make(chan filePart, DefaultDownloadConcurrency)
	var wg sync.WaitGroup
	for i := 0; i < DefaultDownloadConcurrency; i++ {
		wg.Add(1)
		go d.asyncDownloadPart(taskPartChan, &wg)
	}

	partOffset := stat.Size()
	leftBytes := contentLength - stat.Size()
	go func() {
		for {
			alioss.Log.Printf("Resume download: Left bytes %d\n", leftBytes)
			if leftBytes <= DefaultDownloadPartSize {
				partRange := fmt.Sprintf("bytes=%d-%d", partOffset, partOffset+leftBytes-1)
				alioss.Log.Printf("Resume download: File range %s\n", partRange)
				taskPartChan <- filePart{
					Key:    fileName,
					Range:  partRange,
					Offset: partOffset,
					Length: leftBytes,
					Body:   make([]byte, leftBytes),
				}
				close(taskPartChan)
				alioss.Log.Println("Resume download: All parts send to download. Close channel.")
				return
			}
			fileRange := fmt.Sprintf("bytes=%d-%d", partOffset, partOffset+DefaultDownloadPartSize-1)
			alioss.Log.Printf("Resume download: Part range %s\n", fileRange)
			alioss.Log.Printf("Resume download: Part offset %d\n", partOffset)

			taskPartChan <- filePart{
				Key:    fileName,
				Range:  fileRange,
				Offset: partOffset,
				Length: DefaultDownloadPartSize,
			}
			partOffset = partOffset + DefaultDownloadPartSize
			leftBytes = leftBytes - DefaultDownloadPartSize
		}
	}()

	wg.Wait()
    if d.Err != nil {
        return fmt.Errorf("Failed to download remote %s to %s: %s", fileName, destinationPath, d.Err)
    }

	return nil
}

func (alioss *downloader) asyncDownloadPart(taskPartChan <-chan filePart, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		if part, ok := <-taskPartChan; ok {
            if alioss.Err != nil {
                alioss.Log.Printf("Failed to start download %s: %s\n", part.Range, alioss.Err)
                return
            }
			alioss.Log.Printf("Start to download part for key %s: Range: %s, Offset: %d, Length: %d\n", part.Key, part.Range, part.Offset, part.Length)

			body, err := alioss.GetFilePart(part.Key, part.Offset, part.Offset+part.Length-1)
			alioss.Log.Printf("Request sent for %s range %s\n", part.Key, part.Range)
			if err != nil {
				alioss.Log.Printf("Failed to download file %s range %s: %s\n", part.Key, part.Range, err)
				return
			}
			alioss.Log.Printf("Recieved response for %s range %s\n", part.Key, part.Range)
			alioss.Log.Printf("File offset: %d\n", alioss.FileOffset)
			alioss.Log.Printf("Part offset: %d\n", part.Offset)

			for {
                if alioss.Err != nil {
				    alioss.Log.Printf("Failed to write download %s: %s\n", part.Range, alioss.Err)

				    return
			    }
				if alioss.FileOffset == part.Offset {
					n, err := io.Copy(alioss.File, &body)
					if err != nil {
						alioss.Err = err
						alioss.Log.Printf("Failed to write file %s range %s: %s\n", part.Key, part.Range, err)

						return
					}

					alioss.Log.Printf("Finish write %d bytes part range %s for key %s \n", n, part.Range, part.Key)

					alioss.FileOffset = part.Offset + part.Length
					alioss.Log.Printf("New file offset: %d\n", alioss.FileOffset)

					break
				}
				time.Sleep(10 * time.Millisecond)
			}
		} else {
			alioss.Log.Println("Download channel closed. Return.")
			return
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 David R. Jenni. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ds

// --- SList -------

// snode represents a node
// in a singly-linked list.
type snode struct {
	n *snode // next pointer
	v V      // value
}

// SList is a singly-linked list with
// a head and tail pointer.
// It can be used as stack or queue.
type SList struct {
	h, t *snode // head and tail pointer
	n    int    // number of elements
}

// Push pushes a value onto the head of the list.
//
// This operation has a time complexity of O(1).
func (l *SList) Push(v V) {
	l.h = &snode{v: v, n: l.h}
	if l.n == 0 {
		l.t = l.h
	}
	l.n++
}

// Pop removes and returns a value from the
// head of the list.
//
// This operation has a time complexity of O(1).
func (l *SList) Pop() (V, bool) {
	if l.n == 0 {
		return nil, false
	}
	v := l.h.v
	l.h = l.h.n
	l.n--
	if l.n == 0 {
		l.t = nil
	}
	return v, true
}

// Enqueue adds an element to the tail of the list.
//
// This operation has a time complexity of O(1).
func (l *SList) Enqueue(v V) {
	n := &snode{v: v}
	if l.n == 0 {
		l.h = n
	} else {
		l.t.n = n
	}
	l.t = n
	l.n++
}

// Dequeue removes the element from the head of
// the list and is equivalent to Pop.
//
// This operation has a time complexity of O(1).
func (l *SList) Dequeue() (V, bool) { return l.Pop() }

// Len returns the number of elements in the list.
func (l *SList) Len() int { return l.n }

// --- DList -------

// dnode represents a node
// in a doubly-linked list.
type dnode struct {
	n *dnode // next pointer
	p *dnode // previous pointer
	v V      // value
}

// DList represents a doubly-linked list.
type DList struct {
	r *dnode // sentinel node, the root
	n int    // number of elements
}

// get returns the node at the
// given index or nil if not found.
func (l *DList) get(i int) *dnode {
	var n *dnode
	if i < l.n/2 {
		n = l.r.n
		for j := 0; j < i; j++ {
			n = n.n
		}
	} else {
		n = l.r
		for j := l.n; j > i; j-- {
			n = n.p
		}
	}
	return n
}

// Len returns the number of elements in the list.
func (l *DList) Len() int { return l.n }

// Add adds an element to the list at the
// given index and reports whether it was
// successful or not.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Add(i int, v V) bool {
	if i < 0 || i > l.n {
		return false
	}
	// lazy initialization
	if l.r == nil {
		l.r = new(dnode)
		l.r.n = l.r
		l.r.p = l.r
	}
	p := l.get(i)
	n := &dnode{
		v: v,
		p: p.p,
		n: p,
	}
	n.n.p = n
	n.p.n = n
	l.n++
	return true
}

// Remove removes the element of the list at the
// given index and reports whether the operation was
// successful or not.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Remove(i int) (V, bool) {
	if i < 0 || i > l.n-1 {
		return nil, false
	}
	n := l.get(i)
	n.p.n = n.n
	n.n.p = n.p
	n.n = nil
	n.p = nil
	l.n--
	return n.v, true
}

// Get returns the element at the given index.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Get(i int) (V, bool) {
	if i < 0 || i > l.n-1 {
		return nil, false
	}
	return l.get(i).v, true
}

// Set sets the element at the given index
// and returns the old one.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Set(i int, v V) (V, bool) {
	if i < 0 || i > l.n-1 {
		return nil, false
	}
	n := l.get(i)
	t := n.v
	n.v = v
	return t, true
}
<commit_msg>ds: refactor DList.get.<commit_after>// Copyright (c) 2016 David R. Jenni. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ds

// --- SList -------

// snode represents a node
// in a singly-linked list.
type snode struct {
	n *snode // next pointer
	v V      // value
}

// SList is a singly-linked list with
// a head and tail pointer.
// It can be used as stack or queue.
type SList struct {
	h, t *snode // head and tail pointer
	n    int    // number of elements
}

// Push pushes a value onto the head of the list.
//
// This operation has a time complexity of O(1).
func (l *SList) Push(v V) {
	l.h = &snode{v: v, n: l.h}
	if l.n == 0 {
		l.t = l.h
	}
	l.n++
}

// Pop removes and returns a value from the
// head of the list.
//
// This operation has a time complexity of O(1).
func (l *SList) Pop() (V, bool) {
	if l.n == 0 {
		return nil, false
	}
	v := l.h.v
	l.h = l.h.n
	l.n--
	if l.n == 0 {
		l.t = nil
	}
	return v, true
}

// Enqueue adds an element to the tail of the list.
//
// This operation has a time complexity of O(1).
func (l *SList) Enqueue(v V) {
	n := &snode{v: v}
	if l.n == 0 {
		l.h = n
	} else {
		l.t.n = n
	}
	l.t = n
	l.n++
}

// Dequeue removes the element from the head of
// the list and is equivalent to Pop.
//
// This operation has a time complexity of O(1).
func (l *SList) Dequeue() (V, bool) { return l.Pop() }

// Len returns the number of elements in the list.
func (l *SList) Len() int { return l.n }

// --- DList -------

// dnode represents a node
// in a doubly-linked list.
type dnode struct {
	n *dnode // next pointer
	p *dnode // previous pointer
	v V      // value
}

// DList represents a doubly-linked list.
type DList struct {
	r *dnode // sentinel node, the root
	n int    // number of elements
}

// get returns the node at the
// given index or nil if not found.
func (l *DList) get(i int) *dnode {
	if i < l.n/2 {
		n := l.r.n
		for j := 0; j < i; j++ {
			n = n.n
		}
		return n
	}
	n := l.r
	for j := l.n; j > i; j-- {
		n = n.p
	}
	return n
}

// Len returns the number of elements in the list.
func (l *DList) Len() int { return l.n }

// Add adds an element to the list at the
// given index and reports whether it was
// successful or not.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Add(i int, v V) bool {
	if i < 0 || i > l.n {
		return false
	}
	// lazy initialization
	if l.r == nil {
		l.r = new(dnode)
		l.r.n = l.r
		l.r.p = l.r
	}
	p := l.get(i)
	n := &dnode{
		v: v,
		p: p.p,
		n: p,
	}
	n.n.p = n
	n.p.n = n
	l.n++
	return true
}

// Remove removes the element of the list at the
// given index and reports whether the operation was
// successful or not.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Remove(i int) (V, bool) {
	if i < 0 || i > l.n-1 {
		return nil, false
	}
	n := l.get(i)
	n.p.n = n.n
	n.n.p = n.p
	n.n = nil
	n.p = nil
	l.n--
	return n.v, true
}

// Get returns the element at the given index.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Get(i int) (V, bool) {
	if i < 0 || i > l.n-1 {
		return nil, false
	}
	return l.get(i).v, true
}

// Set sets the element at the given index
// and returns the old one.
//
// This operation has a time complexity
// of O(min{i, n-i}).
func (l *DList) Set(i int, v V) (V, bool) {
	if i < 0 || i > l.n-1 {
		return nil, false
	}
	n := l.get(i)
	t := n.v
	n.v = v
	return t, true
}
<|endoftext|>


<commit_before>package flv

import (
	"bytes"
	"fmt"
	"github.com/metachord/amf.go/amf0"
	"io"
	"os"
)

type Header struct {
	Version uint16
	Body    []byte
}

type Frame interface {
	WriteFrame(io.Writer) error
	GetStream() uint32
	GetDts() uint32
	String() string
}

type CFrame struct {
	Stream      uint32
	Dts         uint32
	Type        TagType
	Flavor      Flavor
	Position    int64
	Body        []byte
	PrevTagSize uint32
}

type VideoFrame struct {
	CFrame
	CodecId VideoCodec
	Width   uint16
	Height  uint16
}

type AudioFrame struct {
	CFrame
	CodecId  AudioCodec
	Rate     uint32
	BitSize  AudioSize
	Channels AudioType
}

type MetaFrame struct {
	CFrame
}

func (f CFrame) WriteFrame(w io.Writer) error {
	bl := uint32(len(f.Body))
	var err error
	err = writeType(w, f.Type)
	if err != nil {
		return err
	}
	err = writeBodyLength(w, bl)
	err = writeDts(w, f.Dts)
	err = writeStream(w, f.Stream)
	err = writeBody(w, f.Body)
	prevTagSize := bl + uint32(TAG_HEADER_LENGTH)
	err = writePrevTagSize(w, prevTagSize)
	return nil
}

func (f CFrame) GetStream() uint32 {
	return f.Stream
}
func (f CFrame) GetDts() uint32 {
	return f.Dts
}

func writeType(w io.Writer, t TagType) error {
	_, err := w.Write([]byte{byte(t)})
	return err
}

func writeBodyLength(w io.Writer, bl uint32) error {
	_, err := w.Write([]byte{byte(bl >> 16), byte((bl >> 8) & 0xFF), byte(bl & 0xFF)})
	return err
}

func writeDts(w io.Writer, dts uint32) error {
	_, err := w.Write([]byte{byte((dts >> 16) & 0xFF), byte((dts >> 8) & 0xFF), byte(dts & 0xFF)})
	if err != nil {
		return err
	}
	_, err = w.Write([]byte{byte((dts >> 24) & 0xFF)})
	return err
}

func writeStream(w io.Writer, stream uint32) error {
	_, err := w.Write([]byte{byte(stream >> 16), byte((stream >> 8) & 0xFF), byte(stream & 0xFF)})
	return err
}

func writeBody(w io.Writer, body []byte) error {
	_, err := w.Write(body)
	return err
}

func writePrevTagSize(w io.Writer, prevTagSize uint32) error {
	_, err := w.Write([]byte{byte((prevTagSize >> 24) & 0xFF), byte((prevTagSize >> 16) & 0xFF), byte((prevTagSize >> 8) & 0xFF), byte(prevTagSize & 0xFF)})
	return err
}

func (f VideoFrame) String() string {
	return fmt.Sprintf("%10d\t%d\t%d\t%s\t%s\t{%dx%d,%d bytes}", f.CFrame.Stream, f.CFrame.Dts, f.CFrame.Position, f.CFrame.Type, f.CodecId, f.Width, f.Height, len(f.CFrame.Body))
}

func (f AudioFrame) String() string {
	return fmt.Sprintf("%10d\t%d\t%d\t%s\t%s\t{%d,%s,%s}", f.CFrame.Stream, f.CFrame.Dts, f.CFrame.Position, f.CFrame.Type, f.CodecId, f.Rate, f.BitSize, f.Channels)
}

func (f MetaFrame) String() string {
	buf := bytes.NewReader(f.CFrame.Body)
	dec := amf0.NewDecoder(buf)
	evName, err := dec.Decode()
	mds := ""
	if err == nil {
		switch evName {
		case amf0.StringType("onMetaData"):
			md, err := dec.Decode()
			if err == nil {

				var ea map[amf0.StringType]interface{}
				switch md := md.(type) {
				case *amf0.EcmaArrayType:
					ea = *md
				case *amf0.ObjectType:
					ea = *md
				}
				for k, v := range ea {
					mds += fmt.Sprintf("%v=%+v;", k, v)
				}
			}
		}
	}

	return fmt.Sprintf("%10d\t%d\t%d\t%s\t%s", f.CFrame.Stream, f.CFrame.Dts, f.CFrame.Position, f.CFrame.Type, mds)
}

type FlvReader struct {
	InFile *os.File
	width  uint16
	height uint16
}

func NewReader(inFile *os.File) *FlvReader {
	return &FlvReader{
		InFile: inFile,
		width:  0,
		height: 0,
	}
}

type FlvWriter struct {
	OutFile *os.File
}

func NewWriter(outFile *os.File) *FlvWriter {
	return &FlvWriter{
		OutFile: outFile,
	}
}

func (frReader *FlvReader) ReadHeader() (*Header, error) {
	header := make([]byte, HEADER_LENGTH+4)
	_, err := frReader.InFile.Read(header)
	if err != nil {
		return nil, err
	}

	sig := header[0:3]
	if bytes.Compare(sig, []byte(SIG)) != 0 {
		return nil, fmt.Errorf("bad file format")
	}
	version := (uint16(header[3]) << 8) | (uint16(header[4]) << 0)
	//skip := header[4:5]
	//offset := header[5:9]
	//next_id := header[9:13]

	return &Header{Version: version, Body: header}, nil
}

func (frWriter *FlvWriter) WriteHeader(header *Header) error {
	_, err := frWriter.OutFile.Write(header.Body)
	if err != nil {
		return err
	}
	return nil
}

func (frReader *FlvReader) ReadFrame() (fr Frame, e error) {

	var n int
	var err error

	curPos, _ := frReader.InFile.Seek(0, os.SEEK_CUR)

	tagHeaderB := make([]byte, TAG_HEADER_LENGTH)
	n, err = frReader.InFile.Read(tagHeaderB)
	if n == 0 {
		return nil, nil
	}
	if TagSize(n) != TAG_HEADER_LENGTH {
		return nil, fmt.Errorf("bad tag length: %d", n)
	}
	if err != nil {
		return nil, err
	}

	tagType := TagType(tagHeaderB[0])
	bodyLen := (uint32(tagHeaderB[1]) << 16) | (uint32(tagHeaderB[2]) << 8) | (uint32(tagHeaderB[3]) << 0)
	ts := (uint32(tagHeaderB[4]) << 16) | (uint32(tagHeaderB[5]) << 8) | (uint32(tagHeaderB[6]) << 0)
	tsExt := uint32(tagHeaderB[7])
	stream := (uint32(tagHeaderB[8]) << 16) | (uint32(tagHeaderB[9]) << 8) | (uint32(tagHeaderB[10]) << 0)

	var dts uint32
	dts = (tsExt << 24) | ts

	bodyBuf := make([]byte, bodyLen)
	n, err = frReader.InFile.Read(bodyBuf)
	if err != nil {
		return nil, err
	}

	prevTagSizeB := make([]byte, PREV_TAG_SIZE_LENGTH)
	n, err = frReader.InFile.Read(prevTagSizeB)
	if err != nil {
		return nil, err
	}
	prevTagSize := (uint32(prevTagSizeB[0]) << 24) | (uint32(prevTagSizeB[1]) << 16) | (uint32(prevTagSizeB[2]) << 8) | (uint32(prevTagSizeB[3]) << 0)

	pFrame := CFrame{
		Stream:      stream,
		Dts:         dts,
		Type:        tagType,
		Position:    curPos,
		Body:        bodyBuf,
		PrevTagSize: prevTagSize,
	}

	var resFrame Frame

	switch tagType {
	case TAG_TYPE_META:
		pFrame.Flavor = METADATA
		resFrame = MetaFrame{pFrame}
	case TAG_TYPE_VIDEO:
		vft := VideoFrameType(uint8(bodyBuf[0]) >> 4)
		codecId := VideoCodec(uint8(bodyBuf[0]) & 0x0F)
		switch vft {
		case VIDEO_FRAME_TYPE_KEYFRAME:
			pFrame.Flavor = KEYFRAME
			switch codecId {
			case VIDEO_CODEC_ON2VP6:
				hHelper := (uint16(bodyBuf[1]) >> 4) & 0x0F
				wHelper := uint16(bodyBuf[1]) & 0x0F
				w := uint16(bodyBuf[5])
				h := uint16(bodyBuf[6])

				frReader.width = w*16 - wHelper
				frReader.height = h*16 - hHelper
			}
		default:
			pFrame.Flavor = FRAME
		}
		resFrame = VideoFrame{CFrame: pFrame, CodecId: codecId, Width: frReader.width, Height: frReader.height}
	case TAG_TYPE_AUDIO:
		pFrame.Flavor = FRAME
		codecId := AudioCodec(uint8(bodyBuf[0]) >> 4)
		rate := audioRate(AudioRate((uint8(bodyBuf[0]) >> 2) & 0x03))
		bitSize := AudioSize((uint8(bodyBuf[0]) >> 1) & 0x01)
		channels := AudioType(uint8(bodyBuf[0]) & 0x01)
		resFrame = AudioFrame{CFrame: pFrame, CodecId: codecId, Rate: rate, BitSize: bitSize, Channels: channels}
	}

	return resFrame, nil
}

func audioRate(ar AudioRate) uint32 {
	var ret uint32
	switch ar {
	case AUDIO_RATE_5_5:
		ret = 5500
	case AUDIO_RATE_11:
		ret = 11000
	case AUDIO_RATE_22:
		ret = 22000
	case AUDIO_RATE_44:
		ret = 44000
	}
	return ret
}

func (frWriter *FlvWriter) WriteFrame(fr Frame) (e error) {
	return fr.WriteFrame(frWriter.OutFile)
}
<commit_msg>Handle frames with empty body<commit_after>package flv

import (
	"bytes"
	"fmt"
	"github.com/metachord/amf.go/amf0"
	"io"
	"os"
)

type Header struct {
	Version uint16
	Body    []byte
}

type Frame interface {
	WriteFrame(io.Writer) error
	GetStream() uint32
	GetDts() uint32
	String() string
}

type CFrame struct {
	Stream      uint32
	Dts         uint32
	Type        TagType
	Flavor      Flavor
	Position    int64
	Body        []byte
	PrevTagSize uint32
}

type VideoFrame struct {
	CFrame
	CodecId VideoCodec
	Width   uint16
	Height  uint16
}

type AudioFrame struct {
	CFrame
	CodecId  AudioCodec
	Rate     uint32
	BitSize  AudioSize
	Channels AudioType
}

type MetaFrame struct {
	CFrame
}

func (f CFrame) WriteFrame(w io.Writer) error {
	bl := uint32(len(f.Body))
	var err error
	err = writeType(w, f.Type)
	if err != nil {
		return err
	}
	err = writeBodyLength(w, bl)
	err = writeDts(w, f.Dts)
	err = writeStream(w, f.Stream)
	err = writeBody(w, f.Body)
	prevTagSize := bl + uint32(TAG_HEADER_LENGTH)
	err = writePrevTagSize(w, prevTagSize)
	return nil
}

func (f CFrame) GetStream() uint32 {
	return f.Stream
}
func (f CFrame) GetDts() uint32 {
	return f.Dts
}

func writeType(w io.Writer, t TagType) error {
	_, err := w.Write([]byte{byte(t)})
	return err
}

func writeBodyLength(w io.Writer, bl uint32) error {
	_, err := w.Write([]byte{byte(bl >> 16), byte((bl >> 8) & 0xFF), byte(bl & 0xFF)})
	return err
}

func writeDts(w io.Writer, dts uint32) error {
	_, err := w.Write([]byte{byte((dts >> 16) & 0xFF), byte((dts >> 8) & 0xFF), byte(dts & 0xFF)})
	if err != nil {
		return err
	}
	_, err = w.Write([]byte{byte((dts >> 24) & 0xFF)})
	return err
}

func writeStream(w io.Writer, stream uint32) error {
	_, err := w.Write([]byte{byte(stream >> 16), byte((stream >> 8) & 0xFF), byte(stream & 0xFF)})
	return err
}

func writeBody(w io.Writer, body []byte) error {
	_, err := w.Write(body)
	return err
}

func writePrevTagSize(w io.Writer, prevTagSize uint32) error {
	_, err := w.Write([]byte{byte((prevTagSize >> 24) & 0xFF), byte((prevTagSize >> 16) & 0xFF), byte((prevTagSize >> 8) & 0xFF), byte(prevTagSize & 0xFF)})
	return err
}

func (f VideoFrame) String() string {
	return fmt.Sprintf("%10d\t%d\t%d\t%s\t%s\t{%dx%d,%d bytes}", f.CFrame.Stream, f.CFrame.Dts, f.CFrame.Position, f.CFrame.Type, f.CodecId, f.Width, f.Height, len(f.CFrame.Body))
}

func (f AudioFrame) String() string {
	return fmt.Sprintf("%10d\t%d\t%d\t%s\t%s\t{%d,%s,%s}", f.CFrame.Stream, f.CFrame.Dts, f.CFrame.Position, f.CFrame.Type, f.CodecId, f.Rate, f.BitSize, f.Channels)
}

func (f MetaFrame) String() string {
	buf := bytes.NewReader(f.CFrame.Body)
	dec := amf0.NewDecoder(buf)
	evName, err := dec.Decode()
	mds := ""
	if err == nil {
		switch evName {
		case amf0.StringType("onMetaData"):
			md, err := dec.Decode()
			if err == nil {

				var ea map[amf0.StringType]interface{}
				switch md := md.(type) {
				case *amf0.EcmaArrayType:
					ea = *md
				case *amf0.ObjectType:
					ea = *md
				}
				for k, v := range ea {
					mds += fmt.Sprintf("%v=%+v;", k, v)
				}
			}
		}
	}

	return fmt.Sprintf("%10d\t%d\t%d\t%s\t%s", f.CFrame.Stream, f.CFrame.Dts, f.CFrame.Position, f.CFrame.Type, mds)
}

type FlvReader struct {
	InFile *os.File
	width  uint16
	height uint16
}

func NewReader(inFile *os.File) *FlvReader {
	return &FlvReader{
		InFile: inFile,
		width:  0,
		height: 0,
	}
}

type FlvWriter struct {
	OutFile *os.File
}

func NewWriter(outFile *os.File) *FlvWriter {
	return &FlvWriter{
		OutFile: outFile,
	}
}

func (frReader *FlvReader) ReadHeader() (*Header, error) {
	header := make([]byte, HEADER_LENGTH+4)
	_, err := frReader.InFile.Read(header)
	if err != nil {
		return nil, err
	}

	sig := header[0:3]
	if bytes.Compare(sig, []byte(SIG)) != 0 {
		return nil, fmt.Errorf("bad file format")
	}
	version := (uint16(header[3]) << 8) | (uint16(header[4]) << 0)
	//skip := header[4:5]
	//offset := header[5:9]
	//next_id := header[9:13]

	return &Header{Version: version, Body: header}, nil
}

func (frWriter *FlvWriter) WriteHeader(header *Header) error {
	_, err := frWriter.OutFile.Write(header.Body)
	if err != nil {
		return err
	}
	return nil
}

func (frReader *FlvReader) ReadFrame() (fr Frame, e error) {

	var n int
	var err error

	curPos, _ := frReader.InFile.Seek(0, os.SEEK_CUR)

	tagHeaderB := make([]byte, TAG_HEADER_LENGTH)
	n, err = frReader.InFile.Read(tagHeaderB)
	if n == 0 {
		return nil, nil
	}
	if TagSize(n) != TAG_HEADER_LENGTH {
		return nil, fmt.Errorf("bad tag length: %d", n)
	}
	if err != nil {
		return nil, err
	}

	tagType := TagType(tagHeaderB[0])
	bodyLen := (uint32(tagHeaderB[1]) << 16) | (uint32(tagHeaderB[2]) << 8) | (uint32(tagHeaderB[3]) << 0)
	ts := (uint32(tagHeaderB[4]) << 16) | (uint32(tagHeaderB[5]) << 8) | (uint32(tagHeaderB[6]) << 0)
	tsExt := uint32(tagHeaderB[7])
	stream := (uint32(tagHeaderB[8]) << 16) | (uint32(tagHeaderB[9]) << 8) | (uint32(tagHeaderB[10]) << 0)

	var dts uint32
	dts = (tsExt << 24) | ts

	bodyBuf := make([]byte, bodyLen)
	n, err = frReader.InFile.Read(bodyBuf)
	if err != nil {
		return nil, err
	}

	prevTagSizeB := make([]byte, PREV_TAG_SIZE_LENGTH)
	n, err = frReader.InFile.Read(prevTagSizeB)
	if err != nil {
		return nil, err
	}
	prevTagSize := (uint32(prevTagSizeB[0]) << 24) | (uint32(prevTagSizeB[1]) << 16) | (uint32(prevTagSizeB[2]) << 8) | (uint32(prevTagSizeB[3]) << 0)

	pFrame := CFrame{
		Stream:      stream,
		Dts:         dts,
		Type:        tagType,
		Position:    curPos,
		Body:        bodyBuf,
		PrevTagSize: prevTagSize,
	}

	switch tagType {
	case TAG_TYPE_META:
		pFrame.Flavor = METADATA
		return MetaFrame{CFrame: pFrame}, nil
	case TAG_TYPE_VIDEO:
		resFrame := VideoFrame{CFrame: pFrame}
		if len(bodyBuf) == 0 {
			return resFrame, nil
		}
		vft := VideoFrameType(uint8(bodyBuf[0]) >> 4)
		codecId := VideoCodec(uint8(bodyBuf[0]) & 0x0F)
		switch vft {
		case VIDEO_FRAME_TYPE_KEYFRAME:
			pFrame.Flavor = KEYFRAME
			switch codecId {
			case VIDEO_CODEC_ON2VP6:
				hHelper := (uint16(bodyBuf[1]) >> 4) & 0x0F
				wHelper := uint16(bodyBuf[1]) & 0x0F
				w := uint16(bodyBuf[5])
				h := uint16(bodyBuf[6])

				frReader.width = w*16 - wHelper
				frReader.height = h*16 - hHelper
			}
		default:
			pFrame.Flavor = FRAME
		}
		resFrame.CodecId = codecId
		resFrame.Width = frReader.width
		resFrame.Height = frReader.height
		return resFrame, nil
	case TAG_TYPE_AUDIO:
		pFrame.Flavor = FRAME
		resFrame := AudioFrame{CFrame: pFrame}
		if len(bodyBuf) == 0 {
			return resFrame, nil
		}
		resFrame.CodecId = AudioCodec(uint8(bodyBuf[0]) >> 4)
		resFrame.Rate = audioRate(AudioRate((uint8(bodyBuf[0]) >> 2) & 0x03))
		resFrame.BitSize = AudioSize((uint8(bodyBuf[0]) >> 1) & 0x01)
		resFrame.Channels = AudioType(uint8(bodyBuf[0]) & 0x01)
		return resFrame, nil
	}
	return nil, nil
}

func audioRate(ar AudioRate) uint32 {
	var ret uint32
	switch ar {
	case AUDIO_RATE_5_5:
		ret = 5500
	case AUDIO_RATE_11:
		ret = 11000
	case AUDIO_RATE_22:
		ret = 22000
	case AUDIO_RATE_44:
		ret = 44000
	}
	return ret
}

func (frWriter *FlvWriter) WriteFrame(fr Frame) (e error) {
	return fr.WriteFrame(frWriter.OutFile)
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| rpc/core/service_context.go                              |
|                                                          |
| LastModified: Jan 24, 2021                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package core

import (
	"net"
)

// ServiceContext for RPC.
type ServiceContext interface {
	Context
	Service() Service
	Method() Method
	LocalAddr() net.Addr
	RemoteAddr() net.Addr
	SetMethod(method Method)
	SetLocalAddr(addr net.Addr)
	SetRemoteAddr(addr net.Addr)
}

type serviceContext struct {
	Context
	service    Service
	method     Method
	localAddr  net.Addr
	remoteAddr net.Addr
}

// NewServiceContext returns a core.ServiceContext.
func NewServiceContext(service Service) ServiceContext {
	return &serviceContext{
		Context: NewContext(),
		service: service,
	}
}

func (c *serviceContext) Service() Service {
	return c.service
}

func (c *serviceContext) Method() Method {
	return c.method
}

func (c *serviceContext) LocalAddr() net.Addr {
	return c.localAddr
}

func (c *serviceContext) RemoteAddr() net.Addr {
	return c.remoteAddr
}

func (c *serviceContext) SetMethod(method Method) {
	c.method = method
}

func (c *serviceContext) SetLocalAddr(addr net.Addr) {
	c.localAddr = addr
}

func (c *serviceContext) SetRemoteAddr(addr net.Addr) {
	c.remoteAddr = addr
}

func (c *serviceContext) Clone() Context {
	return &serviceContext{
		c.Context.Clone(),
		c.service,
		c.method,
		c.localAddr,
		c.remoteAddr,
	}
}
<commit_msg>Update service_context.go<commit_after>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| rpc/core/service_context.go                              |
|                                                          |
| LastModified: Jan 24, 2021                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package core

import (
	"net"
)

// ServiceContext for RPC.
type ServiceContext interface {
	Context
	Service() *Service
	Method() Method
	LocalAddr() net.Addr
	RemoteAddr() net.Addr
	SetMethod(method Method)
	SetLocalAddr(addr net.Addr)
	SetRemoteAddr(addr net.Addr)
}

type serviceContext struct {
	Context
	service    *Service
	method     Method
	localAddr  net.Addr
	remoteAddr net.Addr
}

// NewServiceContext returns a core.ServiceContext.
func NewServiceContext(service *Service) ServiceContext {
	return &serviceContext{
		Context: NewContext(),
		service: service,
	}
}

func (c *serviceContext) Service() *Service {
	return c.service
}

func (c *serviceContext) Method() Method {
	return c.method
}

func (c *serviceContext) LocalAddr() net.Addr {
	return c.localAddr
}

func (c *serviceContext) RemoteAddr() net.Addr {
	return c.remoteAddr
}

func (c *serviceContext) SetMethod(method Method) {
	c.method = method
}

func (c *serviceContext) SetLocalAddr(addr net.Addr) {
	c.localAddr = addr
}

func (c *serviceContext) SetRemoteAddr(addr net.Addr) {
	c.remoteAddr = addr
}

func (c *serviceContext) Clone() Context {
	return &serviceContext{
		c.Context.Clone(),
		c.service,
		c.method,
		c.localAddr,
		c.remoteAddr,
	}
}
<|endoftext|>


<commit_before>package htmlquery

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/antchfx/gxpath"
	"github.com/antchfx/gxpath/xpath"
	"golang.org/x/net/html"
)

// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node.
func CreateXPathNavigator(top *html.Node) xpath.NodeNavigator {
	return &htmlNodeNavigator{curr: top, root: top, attr: -1}
}

// Find searches the html.Node that matches by the specified XPath expr.
func Find(top *html.Node, expr string) []*html.Node {
	var elems []*html.Node
	t := gxpath.Select(CreateXPathNavigator(top), expr)
	for t.MoveNext() {
		elems = append(elems, (t.Current().(*htmlNodeNavigator)).curr)
	}
	return elems
}

// FindOne searches the html.Node that matches by the specified XPath expr,
// and returns first element of matched html.Node.
func FindOne(top *html.Node, expr string) *html.Node {
	var elem *html.Node
	t := gxpath.Select(CreateXPathNavigator(top), expr)
	if t.MoveNext() {
		elem = (t.Current().(*htmlNodeNavigator)).curr
	}
	return elem
}

// FindEach searches the html.Node and calls functions cb.
func FindEach(top *html.Node, expr string, cb func(int, *html.Node)) {
	t := gxpath.Select(CreateXPathNavigator(top), expr)
	i := 0
	if t.MoveNext() {
		cb(i, (t.Current().(*htmlNodeNavigator)).curr)
		i++
	}
}

// InnerText returns the text between the start and end tags of the object.
func InnerText(n *html.Node) string {
	if n.Type == html.TextNode || n.Type == html.CommentNode {
		return n.Data
	}
	var buf bytes.Buffer
	for child := n.FirstChild; child != nil; child = child.NextSibling {
		buf.WriteString(InnerText(child))
	}
	return buf.String()
}

func isSelfClosingTag(t string) bool {
	switch t {
	case "area", "hr", "img", "meta", "source", "br", "input":
		return true
	default:
		return false
	}
}

func outputXML(buf *bytes.Buffer, n *html.Node) {
	if n.Type == html.TextNode || n.Type == html.CommentNode {
		buf.WriteString(strings.TrimSpace(n.Data))
		return
	}

	buf.WriteString("<" + n.Data)
	for _, attr := range n.Attr {
		buf.WriteString(fmt.Sprintf(` %s="%s"`, attr.Key, attr.Val))
	}
	selfClosing := isSelfClosingTag(n.Data)
	if selfClosing {
		buf.WriteString("/>")
	} else {
		buf.WriteString(">")
	}
	for child := n.FirstChild; child != nil; child = child.NextSibling {
		outputXML(buf, child)
	}
	if !selfClosing {
		buf.WriteString(fmt.Sprintf("</%s>", n.Data))
	}
}

// OutputHTML returns the text including tags name.
func OutputHTML(n *html.Node) string {
	var buf bytes.Buffer
	outputXML(&buf, n)
	return buf.String()
}

type htmlNodeNavigator struct {
	root, curr *html.Node
	attr       int
}

func (h *htmlNodeNavigator) NodeType() xpath.NodeType {
	switch h.curr.Type {
	case html.CommentNode:
		return xpath.CommentNode
	case html.TextNode:
		return xpath.TextNode
	case html.DocumentNode:
		return xpath.RootNode
	case html.ElementNode:
		if h.attr != -1 {
			return xpath.AttributeNode
		}
		return xpath.ElementNode
	case html.DoctypeNode:
		// ignored <!DOCTYPE HTML> declare and as Root-Node type.
		return xpath.RootNode
	}
	panic(fmt.Sprintf("unknown HTML node type: %v", h.curr.Type))
}

func (h *htmlNodeNavigator) LocalName() string {
	if h.attr != -1 {
		return h.curr.Attr[h.attr].Key
	}
	return h.curr.Data
}

func (*htmlNodeNavigator) Prefix() string {
	return ""
}

func (h *htmlNodeNavigator) Value() string {
	switch h.curr.Type {
	case html.CommentNode:
		return h.curr.Data
	case html.ElementNode:
		if h.attr != -1 {
			return h.curr.Attr[h.attr].Val
		}
		return InnerText(h.curr)
	case html.TextNode:
		return h.curr.Data
	}
	return ""
}

func (h *htmlNodeNavigator) Copy() xpath.NodeNavigator {
	n := *h
	return &n
}

func (h *htmlNodeNavigator) MoveToRoot() {
	h.curr = h.root
}

func (h *htmlNodeNavigator) MoveToParent() bool {
	if node := h.curr.Parent; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveToNextAttribute() bool {
	if h.attr >= len(h.curr.Attr)-1 {
		return false
	}
	h.attr++
	return true
}

func (h *htmlNodeNavigator) MoveToChild() bool {
	if node := h.curr.FirstChild; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveToFirst() bool {
	if h.curr.PrevSibling == nil {
		return false
	}
	for {
		node := h.curr.PrevSibling
		if node == nil {
			break
		}
		h.curr = node
	}
	return true
}

func (h *htmlNodeNavigator) String() string {
	return h.Value()
}

func (h *htmlNodeNavigator) MoveToNext() bool {
	if node := h.curr.NextSibling; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveToPrevious() bool {
	if node := h.curr.PrevSibling; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveTo(other xpath.NodeNavigator) bool {
	node, ok := other.(*htmlNodeNavigator)
	if !ok || node.root != h.root {
		return false
	}

	h.curr = node.curr
	h.attr = node.attr
	return true
}
<commit_msg>fix: ForEach<commit_after>package htmlquery

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/antchfx/gxpath"
	"github.com/antchfx/gxpath/xpath"
	"golang.org/x/net/html"
)

// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node.
func CreateXPathNavigator(top *html.Node) xpath.NodeNavigator {
	return &htmlNodeNavigator{curr: top, root: top, attr: -1}
}

// Find searches the html.Node that matches by the specified XPath expr.
func Find(top *html.Node, expr string) []*html.Node {
	var elems []*html.Node
	t := gxpath.Select(CreateXPathNavigator(top), expr)
	for t.MoveNext() {
		elems = append(elems, (t.Current().(*htmlNodeNavigator)).curr)
	}
	return elems
}

// FindOne searches the html.Node that matches by the specified XPath expr,
// and returns first element of matched html.Node.
func FindOne(top *html.Node, expr string) *html.Node {
	var elem *html.Node
	t := gxpath.Select(CreateXPathNavigator(top), expr)
	if t.MoveNext() {
		elem = (t.Current().(*htmlNodeNavigator)).curr
	}
	return elem
}

// FindEach searches the html.Node and calls functions cb.
func FindEach(top *html.Node, expr string, cb func(int, *html.Node)) {
	t := gxpath.Select(CreateXPathNavigator(top), expr)
	i := 0
	for t.MoveNext() {
		cb(i, (t.Current().(*htmlNodeNavigator)).curr)
		i++
	}
}

// InnerText returns the text between the start and end tags of the object.
func InnerText(n *html.Node) string {
	if n.Type == html.TextNode || n.Type == html.CommentNode {
		return n.Data
	}
	var buf bytes.Buffer
	for child := n.FirstChild; child != nil; child = child.NextSibling {
		buf.WriteString(InnerText(child))
	}
	return buf.String()
}

func isSelfClosingTag(t string) bool {
	switch t {
	case "area", "hr", "img", "meta", "source", "br", "input":
		return true
	default:
		return false
	}
}

func outputXML(buf *bytes.Buffer, n *html.Node) {
	if n.Type == html.TextNode || n.Type == html.CommentNode {
		buf.WriteString(strings.TrimSpace(n.Data))
		return
	}

	buf.WriteString("<" + n.Data)
	for _, attr := range n.Attr {
		buf.WriteString(fmt.Sprintf(` %s="%s"`, attr.Key, attr.Val))
	}
	selfClosing := isSelfClosingTag(n.Data)
	if selfClosing {
		buf.WriteString("/>")
	} else {
		buf.WriteString(">")
	}
	for child := n.FirstChild; child != nil; child = child.NextSibling {
		outputXML(buf, child)
	}
	if !selfClosing {
		buf.WriteString(fmt.Sprintf("</%s>", n.Data))
	}
}

// OutputHTML returns the text including tags name.
func OutputHTML(n *html.Node) string {
	var buf bytes.Buffer
	outputXML(&buf, n)
	return buf.String()
}

type htmlNodeNavigator struct {
	root, curr *html.Node
	attr       int
}

func (h *htmlNodeNavigator) NodeType() xpath.NodeType {
	switch h.curr.Type {
	case html.CommentNode:
		return xpath.CommentNode
	case html.TextNode:
		return xpath.TextNode
	case html.DocumentNode:
		return xpath.RootNode
	case html.ElementNode:
		if h.attr != -1 {
			return xpath.AttributeNode
		}
		return xpath.ElementNode
	case html.DoctypeNode:
		// ignored <!DOCTYPE HTML> declare and as Root-Node type.
		return xpath.RootNode
	}
	panic(fmt.Sprintf("unknown HTML node type: %v", h.curr.Type))
}

func (h *htmlNodeNavigator) LocalName() string {
	if h.attr != -1 {
		return h.curr.Attr[h.attr].Key
	}
	return h.curr.Data
}

func (*htmlNodeNavigator) Prefix() string {
	return ""
}

func (h *htmlNodeNavigator) Value() string {
	switch h.curr.Type {
	case html.CommentNode:
		return h.curr.Data
	case html.ElementNode:
		if h.attr != -1 {
			return h.curr.Attr[h.attr].Val
		}
		return InnerText(h.curr)
	case html.TextNode:
		return h.curr.Data
	}
	return ""
}

func (h *htmlNodeNavigator) Copy() xpath.NodeNavigator {
	n := *h
	return &n
}

func (h *htmlNodeNavigator) MoveToRoot() {
	h.curr = h.root
}

func (h *htmlNodeNavigator) MoveToParent() bool {
	if node := h.curr.Parent; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveToNextAttribute() bool {
	if h.attr >= len(h.curr.Attr)-1 {
		return false
	}
	h.attr++
	return true
}

func (h *htmlNodeNavigator) MoveToChild() bool {
	if node := h.curr.FirstChild; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveToFirst() bool {
	if h.curr.PrevSibling == nil {
		return false
	}
	for {
		node := h.curr.PrevSibling
		if node == nil {
			break
		}
		h.curr = node
	}
	return true
}

func (h *htmlNodeNavigator) String() string {
	return h.Value()
}

func (h *htmlNodeNavigator) MoveToNext() bool {
	if node := h.curr.NextSibling; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveToPrevious() bool {
	if node := h.curr.PrevSibling; node != nil {
		h.curr = node
		return true
	}
	return false
}

func (h *htmlNodeNavigator) MoveTo(other xpath.NodeNavigator) bool {
	node, ok := other.(*htmlNodeNavigator)
	if !ok || node.root != h.root {
		return false
	}

	h.curr = node.curr
	h.attr = node.attr
	return true
}
<|endoftext|>


<commit_before>package jira

import (
	"io"
	"net/http"
)

type HttpClient interface {
	Delete(url string) (*http.Response, error)
	GetJSON(url string) (*http.Response, error)
	Post(url, bodyType string, body io.Reader) (*http.Response, error)
	Put(url, bodyType string, body io.Reader) (*http.Response, error)
}
<commit_msg>adding Do required for request language<commit_after>package jira

import (
	"io"
	"net/http"
)

type HttpClient interface {
	Delete(url string) (*http.Response, error)
	Do(*http.Request) (*http.Response, error)
	GetJSON(url string) (*http.Response, error)
	Post(url, bodyType string, body io.Reader) (*http.Response, error)
	Put(url, bodyType string, body io.Reader) (*http.Response, error)
}
<|endoftext|>


<commit_before>package ohauth

import (
	"crypto/subtle"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"time"
)

type grantRequest struct {
	client *Client
	form   url.Values
}

type tokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int64  `json:"expires_in"`
	RefreshToken string `json:"refresh_token,omitempty"`
}

var grantHandlers = map[string]func(*context, *grantRequest) error{
	AuthorizationCode: grantWithCode,
	Password:          grantWithPassword,
	ClientCredentials: grantWithClient,
	RefreshToken:      grantWithRefreshToken,
}

func grantWithCode(ctx *context, gr *grantRequest) error {
	c := gr.client
	p := ctx.provider
	ru, err := ParseURL(gr.form.Get("redirect_uri"))
	if err != nil {
		ctx.json(http.StatusBadRequest, ErrBadRedirect)
		return nil
	}

	if c.RedirectURI.String() != ru.String() {
		ctx.json(http.StatusBadRequest, ErrBadRedirect)
		return nil
	}

	tc, err := p.Tokenizer.Parse(gr.form.Get("code"), c.Keys.Verify)
	if err != nil {
		return err
	}

	authz, err := p.Store.FetchAuthorization(c.ID, tc.Subject)
	if err != nil {
		return err
	}
	if authz == nil {
		ctx.json(http.StatusForbidden, ErrUnauthorized)
		return nil
	}

	bl, err := p.Store.TokenBlacklisted(tc.ID)
	if err != nil {
		return err
	}
	if bl {
		ctx.json(http.StatusForbidden, ErrCodeUsed)
		return nil
	}

	scope := c.Scope.Contains(tc.Scope) && p.Issuer.ScopePermitted(tc.Scope, c.GrantType)
	if !scope {
		ctx.json(http.StatusForbidden, ErrScopeNotAllowed)
		return nil
	}

	role := tc.Role == RoleCode
	aud := tc.Audience == c.ID
	iss := tc.Issuer == p.URL.String()
	exp := tc.Expires > ctx.timestamp.Unix()
	grant := tc.Grant == AuthorizationCode
	fmt.Println(role, aud, iss, exp, grant)
	if !role || !aud || !iss || !exp || !grant || !scope {
		ctx.json(http.StatusForbidden, ErrAccessDenied)
		return nil
	}

	at := NewTokenClaims(RoleAccessToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(c.GrantType)))
	at.ID = randID()
	at.Audience = c.ID
	at.Subject = tc.Subject
	at.Issuer = p.URL.String()
	at.Scope = tc.Scope
	at.Grant = AuthorizationCode

	rt := NewTokenClaims(RoleRefreshToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(RefreshToken)))
	rt.ID = randID()
	rt.Subject = at.ID
	at.Issuer = p.URL.String()

	sat, err := p.Tokenizer.Tokenize(at, c.Keys.Sign)
	if err != nil {
		return err
	}
	srt, err := p.Tokenizer.Tokenize(rt, c.Keys.Sign)
	if err != nil {
		return err
	}

	if err := p.Store.BlacklistToken(tc.ID); err != nil {
		return err
	}

	ctx.json(http.StatusOK, &tokenResponse{
		sat,
		"bearer",
		at.Expires - time.Now().Unix(),
		srt,
	})

	return nil
}
func grantWithPassword(ctx *context, gr *grantRequest) error {
	p := ctx.provider
	c := gr.client
	f := gr.form
	scope := ParseScope(f.Get("scope"))
	username := f.Get("username")
	password := f.Get("password")

	s, err := p.Authenticator.Authenticate(username, password, c)
	if err != nil {
		return err
	}
	if s == nil {
		ctx.json(http.StatusForbidden, ErrAccessDenied)
		return nil
	}

	validscope := c.Scope.Contains(scope) && p.Issuer.ScopePermitted(scope, c.GrantType)
	if !validscope {
		ctx.json(http.StatusForbidden, ErrScopeNotAllowed)
		return nil
	}

	at := NewTokenClaims(RoleAccessToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(c.GrantType)))
	at.ID = randID()
	at.Audience = c.ID
	at.Subject = s.Subject
	at.Issuer = p.URL.String()
	at.Scope = scope
	at.Grant = Password

	rt := NewTokenClaims(RoleRefreshToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(RefreshToken)))
	rt.ID = randID()
	rt.Subject = at.ID
	at.Issuer = p.URL.String()

	sat, err := p.Tokenizer.Tokenize(at, c.Keys.Sign)
	if err != nil {
		return err
	}
	srt, err := p.Tokenizer.Tokenize(rt, c.Keys.Sign)
	if err != nil {
		return err
	}

	ctx.json(http.StatusOK, &tokenResponse{
		sat,
		"bearer",
		at.Expires - time.Now().Unix(),
		srt,
	})

	return nil
}
func grantWithClient(ctx *context, gr *grantRequest) error {
	p := ctx.provider
	c := gr.client
	f := gr.form
	scope := ParseScope(f.Get("scope"))

	validscope := c.Scope.Contains(scope) && p.Issuer.ScopePermitted(scope, c.GrantType)
	if !validscope {
		ctx.json(http.StatusForbidden, ErrScopeNotAllowed)
		return nil
	}

	at := NewTokenClaims(RoleAccessToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(c.GrantType)))
	at.ID = randID()
	at.Audience = c.ID
	at.Subject = c.ID
	at.Issuer = p.URL.String()
	at.Scope = scope
	at.Grant = Password

	sat, err := p.Tokenizer.Tokenize(at, c.Keys.Sign)
	if err != nil {
		return err
	}

	ctx.json(http.StatusOK, &tokenResponse{
		sat,
		"bearer",
		at.Expires - time.Now().Unix(),
		"",
	})

	return nil
}
func grantWithRefreshToken(ctx *context, gr *grantRequest) error {
	return errors.New("not implemented")
}

func handleGrant(ctx *context) error {
	p := ctx.provider
	if ctx.request.Method != "POST" {
		ctx.abort(http.StatusMethodNotAllowed, "Method not allowed")
		return nil
	}
	if err := ctx.request.ParseForm(); err != nil {
		return err
	}

	f := ctx.request.PostForm
	gt := f.Get("grant_type")
	handler, found := grantHandlers[gt]
	if !found {
		ctx.json(http.StatusBadRequest, ErrInvalidGrant)
		return nil
	}

	client, err := p.Store.FetchClient(f.Get("client_id"))
	if err != nil {
		return err
	}
	if client == nil || client.Status != ClientActive {
		ctx.json(http.StatusBadRequest, ErrClientNotFound)
		return nil
	}

	if gt != client.GrantType && gt != RefreshToken {
		ctx.json(http.StatusBadRequest, ErrInvalidGrant)
		return nil
	}

	if subtle.ConstantTimeCompare([]byte(f.Get("client_secret")), []byte(client.Secret)) != 1 {
		ctx.json(http.StatusForbidden, ErrAccessDenied)
		return nil
	}

	return handler(ctx, &grantRequest{client, f})
}
<commit_msg>fixed invalid token grant<commit_after>package ohauth

import (
	"crypto/subtle"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"time"
)

type grantRequest struct {
	client *Client
	form   url.Values
}

type tokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int64  `json:"expires_in"`
	RefreshToken string `json:"refresh_token,omitempty"`
}

var grantHandlers = map[string]func(*context, *grantRequest) error{
	AuthorizationCode: grantWithCode,
	Password:          grantWithPassword,
	ClientCredentials: grantWithClient,
	RefreshToken:      grantWithRefreshToken,
}

func grantWithCode(ctx *context, gr *grantRequest) error {
	c := gr.client
	p := ctx.provider
	ru, err := ParseURL(gr.form.Get("redirect_uri"))
	if err != nil {
		ctx.json(http.StatusBadRequest, ErrBadRedirect)
		return nil
	}

	if c.RedirectURI.String() != ru.String() {
		ctx.json(http.StatusBadRequest, ErrBadRedirect)
		return nil
	}

	tc, err := p.Tokenizer.Parse(gr.form.Get("code"), c.Keys.Verify)
	if err != nil {
		return err
	}

	authz, err := p.Store.FetchAuthorization(c.ID, tc.Subject)
	if err != nil {
		return err
	}
	if authz == nil {
		ctx.json(http.StatusForbidden, ErrUnauthorized)
		return nil
	}

	bl, err := p.Store.TokenBlacklisted(tc.ID)
	if err != nil {
		return err
	}
	if bl {
		ctx.json(http.StatusForbidden, ErrCodeUsed)
		return nil
	}

	scope := c.Scope.Contains(tc.Scope) && p.Issuer.ScopePermitted(tc.Scope, c.GrantType)
	if !scope {
		ctx.json(http.StatusForbidden, ErrScopeNotAllowed)
		return nil
	}

	role := tc.Role == RoleCode
	aud := tc.Audience == c.ID
	iss := tc.Issuer == p.URL.String()
	exp := tc.Expires > ctx.timestamp.Unix()
	grant := tc.Grant == AuthorizationCode
	fmt.Println(role, aud, iss, exp, grant)
	if !role || !aud || !iss || !exp || !grant || !scope {
		ctx.json(http.StatusForbidden, ErrAccessDenied)
		return nil
	}

	at := NewTokenClaims(RoleAccessToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(c.GrantType)))
	at.ID = randID()
	at.Audience = c.ID
	at.Subject = tc.Subject
	at.Issuer = p.URL.String()
	at.Scope = tc.Scope
	at.Grant = AuthorizationCode

	rt := NewTokenClaims(RoleRefreshToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(RefreshToken)))
	rt.ID = randID()
	rt.Subject = at.ID
	at.Issuer = p.URL.String()

	sat, err := p.Tokenizer.Tokenize(at, c.Keys.Sign)
	if err != nil {
		return err
	}
	srt, err := p.Tokenizer.Tokenize(rt, c.Keys.Sign)
	if err != nil {
		return err
	}

	if err := p.Store.BlacklistToken(tc.ID); err != nil {
		return err
	}

	ctx.json(http.StatusOK, &tokenResponse{
		sat,
		"bearer",
		at.Expires - time.Now().Unix(),
		srt,
	})

	return nil
}
func grantWithPassword(ctx *context, gr *grantRequest) error {
	p := ctx.provider
	c := gr.client
	f := gr.form
	scope := ParseScope(f.Get("scope"))
	username := f.Get("username")
	password := f.Get("password")

	s, err := p.Authenticator.Authenticate(username, password, c)
	if err != nil {
		return err
	}
	if s == nil {
		ctx.json(http.StatusForbidden, ErrAccessDenied)
		return nil
	}

	validscope := c.Scope.Contains(scope) && p.Issuer.ScopePermitted(scope, c.GrantType)
	if !validscope {
		ctx.json(http.StatusForbidden, ErrScopeNotAllowed)
		return nil
	}

	at := NewTokenClaims(RoleAccessToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(c.GrantType)))
	at.ID = randID()
	at.Audience = c.ID
	at.Subject = s.Subject
	at.Issuer = p.URL.String()
	at.Scope = scope
	at.Grant = Password

	rt := NewTokenClaims(RoleRefreshToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(RefreshToken)))
	rt.ID = randID()
	rt.Subject = at.ID
	at.Issuer = p.URL.String()

	sat, err := p.Tokenizer.Tokenize(at, c.Keys.Sign)
	if err != nil {
		return err
	}
	srt, err := p.Tokenizer.Tokenize(rt, c.Keys.Sign)
	if err != nil {
		return err
	}

	ctx.json(http.StatusOK, &tokenResponse{
		sat,
		"bearer",
		at.Expires - time.Now().Unix(),
		srt,
	})

	return nil
}
func grantWithClient(ctx *context, gr *grantRequest) error {
	p := ctx.provider
	c := gr.client
	f := gr.form
	scope := ParseScope(f.Get("scope"))

	validscope := c.Scope.Contains(scope) && p.Issuer.ScopePermitted(scope, c.GrantType)
	if !validscope {
		ctx.json(http.StatusForbidden, ErrScopeNotAllowed)
		return nil
	}

	at := NewTokenClaims(RoleAccessToken, ctx.timestamp, ctx.timestamp.Add(p.Issuer.ExpiryForToken(c.GrantType)))
	at.ID = randID()
	at.Audience = c.ID
	at.Subject = c.ID
	at.Issuer = p.URL.String()
	at.Scope = scope
	at.Grant = ClientCredentials

	sat, err := p.Tokenizer.Tokenize(at, c.Keys.Sign)
	if err != nil {
		return err
	}

	ctx.json(http.StatusOK, &tokenResponse{
		sat,
		"bearer",
		at.Expires - time.Now().Unix(),
		"",
	})

	return nil
}
func grantWithRefreshToken(ctx *context, gr *grantRequest) error {
	return errors.New("not implemented")
}

func handleGrant(ctx *context) error {
	p := ctx.provider
	if ctx.request.Method != "POST" {
		ctx.abort(http.StatusMethodNotAllowed, "Method not allowed")
		return nil
	}
	if err := ctx.request.ParseForm(); err != nil {
		return err
	}

	f := ctx.request.PostForm
	gt := f.Get("grant_type")
	handler, found := grantHandlers[gt]
	if !found {
		ctx.json(http.StatusBadRequest, ErrInvalidGrant)
		return nil
	}

	client, err := p.Store.FetchClient(f.Get("client_id"))
	if err != nil {
		return err
	}
	if client == nil || client.Status != ClientActive {
		ctx.json(http.StatusBadRequest, ErrClientNotFound)
		return nil
	}

	if gt != client.GrantType && gt != RefreshToken {
		ctx.json(http.StatusBadRequest, ErrInvalidGrant)
		return nil
	}

	if subtle.ConstantTimeCompare([]byte(f.Get("client_secret")), []byte(client.Secret)) != 1 {
		ctx.json(http.StatusForbidden, ErrAccessDenied)
		return nil
	}

	return handler(ctx, &grantRequest{client, f})
}
<|endoftext|>


<commit_before>/**
 * (C) Copyright 2013, Deft Labs
 *
 * 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 dlshared

import (
	"fmt"
	"net/http"
	"io/ioutil"
	"time"
	"bytes"
	"strings"
	"errors"
	"labix.org/v2/mgo/bson"
	"encoding/json"
	"github.com/mreiferson/go-httpclient"
)

const (
	SocketTimeout = 40
	HttpPostMethod = "POST"
	ContentTypeHeader = "Content-Type"
	ContentTypeTextPlain = "text/plain; charset=utf-8"
)

func HttpPostStr(url string, value string) ([]byte, error) {

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, err := http.NewRequest("POST", url, bytes.NewReader([]byte(value)))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	if data, err := ioutil.ReadAll(response.Body); err != nil {
		return nil, err
	} else {
		return data, nil
	}
}

func HttpPostJson(url string, value interface{}) ([]byte, error) {

	rawJson, err := json.Marshal(value)
	if err != nil {
		return nil, err
	}

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, err := http.NewRequest("POST", url, bytes.NewReader(rawJson))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/json")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	if data, err := ioutil.ReadAll(response.Body); err != nil {
		return nil, err
	} else {
		return data, nil
	}
}

func HttpPostBson(url string, bsonDoc interface{}) ([]byte, error) {

	rawBson, err := bson.Marshal(bsonDoc)
	if err != nil {
		return nil, err
	}

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, err := http.NewRequest("POST", url, bytes.NewReader(rawBson))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	// We do not return the response so don't report if there is an error.
	if data, err := ioutil.ReadAll(response.Body); err != nil {
		return nil, err
	} else {
		return data, nil
	}
}

func getDefaultHttpClient() (*http.Client, *httpclient.Transport) {
	transport := getDefaultHttpTransport()
	return &http.Client{ Transport: transport }, transport
}

func getDefaultHttpTransport() *httpclient.Transport {
	return &httpclient.Transport {
		ConnectTimeout:        SocketTimeout * time.Second,
		RequestTimeout:        SocketTimeout * time.Second,
		ResponseHeaderTimeout: SocketTimeout * time.Second,
	}
}

func HttpGetBson(url string) (bson.M, error) {

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, requestErr := http.NewRequest("GET", url, nil)
	if requestErr != nil {
		return nil, requestErr
	}

	response, err := httpClient.Do(request)

	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	rawBson, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	var bsonDoc bson.M
	if err := bson.Unmarshal(rawBson, &bsonDoc); err != nil {
		return nil, err
	}

	return bsonDoc, nil
}

// This method returns true if the http request method is a HTTP post. If the
// field missing or incorrect, false is returned. This method will panic if the request
// is nil.
func IsHttpMethodPost(request *http.Request) bool {
	if request == nil {
		panic("request param is nil")
	}
	return len(request.Method) > 0 && strings.ToUpper(request.Method) == HttpPostMethod
}

// Write an http ok response string. The content type is text/plain.
func WriteOkResponseString(response http.ResponseWriter, msg string) error {
	if response == nil {
		panic("response param is nil")
	}

	msgLength := len(msg)

	if msgLength == 0 {
		panic("do not write an empty string to the response")
	}

	response.Header().Set(ContentTypeHeader, ContentTypeTextPlain)

	written, err := response.Write([]byte(msg))

	if err != nil {
		return err
	}

	if written != msgLength {
		return errors.New(fmt.Sprintf("Did not write full message - bytes written %d - expected %d", written, msgLength))
	}

	return nil
}

<commit_msg>hacking<commit_after>/**
 * (C) Copyright 2013, Deft Labs
 *
 * 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 dlshared

import (
	"fmt"
	"net/http"
	"io/ioutil"
	"time"
	"bytes"
	"strings"
	"errors"
	"labix.org/v2/mgo/bson"
	"encoding/json"
	"github.com/mreiferson/go-httpclient"
)

const (
	SocketTimeout = 40
	HttpPostMethod = "POST"
	ContentTypeHeader = "Content-Type"
	ContentTypeTextPlain = "text/plain; charset=utf-8"
)

func HttpPostStr(url string, value string) ([]byte, error) {

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, err := http.NewRequest("POST", url, bytes.NewReader([]byte(value)))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	if data, err := ioutil.ReadAll(response.Body); err != nil {
		return nil, err
	} else {
		return data, nil
	}
}

func HttpPostJson(url string, value interface{}) ([]byte, error) {

	rawJson, err := json.Marshal(value)
	if err != nil {
		return nil, err
	}

	fmt.Println("rawJson:", string(jawJson))

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, err := http.NewRequest("POST", url, bytes.NewReader(rawJson))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/json")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	if data, err := ioutil.ReadAll(response.Body); err != nil {
		return nil, err
	} else {
		return data, nil
	}
}

func HttpPostBson(url string, bsonDoc interface{}) ([]byte, error) {

	rawBson, err := bson.Marshal(bsonDoc)
	if err != nil {
		return nil, err
	}

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, err := http.NewRequest("POST", url, bytes.NewReader(rawBson))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	response, err := httpClient.Do(request)
	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	// We do not return the response so don't report if there is an error.
	if data, err := ioutil.ReadAll(response.Body); err != nil {
		return nil, err
	} else {
		return data, nil
	}
}

func getDefaultHttpClient() (*http.Client, *httpclient.Transport) {
	transport := getDefaultHttpTransport()
	return &http.Client{ Transport: transport }, transport
}

func getDefaultHttpTransport() *httpclient.Transport {
	return &httpclient.Transport {
		ConnectTimeout:        SocketTimeout * time.Second,
		RequestTimeout:        SocketTimeout * time.Second,
		ResponseHeaderTimeout: SocketTimeout * time.Second,
	}
}

func HttpGetBson(url string) (bson.M, error) {

	httpClient, httpTransport := getDefaultHttpClient()
	defer httpTransport.Close()

	request, requestErr := http.NewRequest("GET", url, nil)
	if requestErr != nil {
		return nil, requestErr
	}

	response, err := httpClient.Do(request)

	if err != nil {
		return nil, err
	}

	defer response.Body.Close()

	rawBson, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	var bsonDoc bson.M
	if err := bson.Unmarshal(rawBson, &bsonDoc); err != nil {
		return nil, err
	}

	return bsonDoc, nil
}

// This method returns true if the http request method is a HTTP post. If the
// field missing or incorrect, false is returned. This method will panic if the request
// is nil.
func IsHttpMethodPost(request *http.Request) bool {
	if request == nil {
		panic("request param is nil")
	}
	return len(request.Method) > 0 && strings.ToUpper(request.Method) == HttpPostMethod
}

// Write an http ok response string. The content type is text/plain.
func WriteOkResponseString(response http.ResponseWriter, msg string) error {
	if response == nil {
		panic("response param is nil")
	}

	msgLength := len(msg)

	if msgLength == 0 {
		panic("do not write an empty string to the response")
	}

	response.Header().Set(ContentTypeHeader, ContentTypeTextPlain)

	written, err := response.Write([]byte(msg))

	if err != nil {
		return err
	}

	if written != msgLength {
		return errors.New(fmt.Sprintf("Did not write full message - bytes written %d - expected %d", written, msgLength))
	}

	return nil
}

<|endoftext|>


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

package rpc

import (
	"errors"
	"fmt"
	"net"
	"strings"
	"testing"
)

type shutdownCodec struct {
	responded chan int
	closed    bool
}

func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
func (c *shutdownCodec) ReadResponseBody(interface{}) error       { return nil }
func (c *shutdownCodec) ReadResponseHeader(*Response) error {
	c.responded <- 1
	return errors.New("shutdownCodec ReadResponseHeader")
}
func (c *shutdownCodec) Close() error {
	c.closed = true
	return nil
}

func TestCloseCodec(t *testing.T) {
	codec := &shutdownCodec{responded: make(chan int)}
	client := NewClientWithCodec(codec)
	<-codec.responded
	client.Close()
	if !codec.closed {
		t.Error("client.Close did not close codec")
	}
}

// Test that errors in gob shut down the connection. Issue 7689.

type R struct {
	msg []byte // Not exported, so R does not work with gob.
}

type S struct{}

func (s *S) Recv(nul *struct{}, reply *R) error {
	*reply = R{[]byte("foo")}
	return nil
}

func TestGobError(t *testing.T) {
	defer func() {
		err := recover()
		if err == nil {
			t.Fatal("no error")
		}
		if !strings.Contains("reading body EOF", err.(error).Error()) {
			t.Fatal("expected `reading body EOF', got", err)
		}
	}()
	Register(new(S))

	listen, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(err)
	}
	go Accept(listen)

	client, err := Dial("tcp", listen.Addr().String())
	if err != nil {
		panic(err)
	}

	var reply Reply
	err = client.Call("S.Recv", &struct{}{}, &reply)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", reply)
	client.Close()

	listen.Close()
}
<commit_msg>net/rpc: skip TestGobError on Plan 9<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpc

import (
	"errors"
	"fmt"
	"net"
	"strings"
	"testing"
)

type shutdownCodec struct {
	responded chan int
	closed    bool
}

func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
func (c *shutdownCodec) ReadResponseBody(interface{}) error       { return nil }
func (c *shutdownCodec) ReadResponseHeader(*Response) error {
	c.responded <- 1
	return errors.New("shutdownCodec ReadResponseHeader")
}
func (c *shutdownCodec) Close() error {
	c.closed = true
	return nil
}

func TestCloseCodec(t *testing.T) {
	codec := &shutdownCodec{responded: make(chan int)}
	client := NewClientWithCodec(codec)
	<-codec.responded
	client.Close()
	if !codec.closed {
		t.Error("client.Close did not close codec")
	}
}

// Test that errors in gob shut down the connection. Issue 7689.

type R struct {
	msg []byte // Not exported, so R does not work with gob.
}

type S struct{}

func (s *S) Recv(nul *struct{}, reply *R) error {
	*reply = R{[]byte("foo")}
	return nil
}

func TestGobError(t *testing.T) {
	if runtime.GOOS == "plan9" {
		t.Skip("skipping test; see http://golang.org/issue/8908")
	}
	defer func() {
		err := recover()
		if err == nil {
			t.Fatal("no error")
		}
		if !strings.Contains("reading body EOF", err.(error).Error()) {
			t.Fatal("expected `reading body EOF', got", err)
		}
	}()
	Register(new(S))

	listen, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(err)
	}
	go Accept(listen)

	client, err := Dial("tcp", listen.Addr().String())
	if err != nil {
		panic(err)
	}

	var reply Reply
	err = client.Call("S.Recv", &struct{}{}, &reply)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", reply)
	client.Close()

	listen.Close()
}
<|endoftext|>


<commit_before>package mount

import (
	"errors"
	"flag"
	"syscall"
	"strings"
)

var (
	flagSet   = flag.NewFlagSet("mount", flag.PanicOnError)
	typeFlag  = flagSet.String("t", "", "Filesystem type of the mount")
	flagsFlag = flagSet.String("o", "defaults", "Comma-separated list of flags for the mount")
	helpFlag  = flagSet.Bool("help", false, "Show this help")
)

func Mount(call []string) error {
	e := flagSet.Parse(call[1:])
	if e != nil {
		return e
	}

	if flagSet.NArg() != 2 || *helpFlag {
		println("`mount` [options] <device> <dir>")
		flagSet.PrintDefaults()
		println("\nAvailable options are:")
		for opt, _ := range flagMap {
			print(opt, ", ")
		}
		println()
		return nil
	}

	flags, e := parseFlags()
	if e != nil {
		return e
	}

	errno := syscall.Mount(flagSet.Arg(0), flagSet.Arg(1), *typeFlag, uintptr(flags), "")
	if errno != 0 {
		return errors.New(syscall.Errstr(errno))
	}
	return nil
}

var (
	flagMap = map[string]uint32{
		"defaults":   0,
		"noatime":    syscall.MS_NOATIME,
		"nodev":      syscall.MS_NODEV,
		"nodiratime": syscall.MS_NODIRATIME,
		"noexec":     syscall.MS_NOEXEC,
		"nosuid":     syscall.MS_NOSUID,
		"remount":    syscall.MS_REMOUNT,
		"ro":         syscall.MS_RDONLY,
		"sync":       syscall.MS_SYNCHRONOUS,
	}
)

func parseFlags() (uint32, error) {
	ret := uint32(0)
	parts := strings.Split(*flagsFlag, ",")
	for _, part := range parts {
		part = strings.TrimSpace(part)
		val, ok := flagMap[strings.ToLower(part)]
		if !ok {
			return 0, errors.New("Invalid flag \"" + part + "\"")
		}
		ret |= val
	}
	return ret, nil
}
<commit_msg>Fixed linux mount for weekly<commit_after>package mount

import (
	"errors"
	"flag"
	"syscall"
	"strings"
)

var (
	flagSet   = flag.NewFlagSet("mount", flag.PanicOnError)
	typeFlag  = flagSet.String("t", "", "Filesystem type of the mount")
	flagsFlag = flagSet.String("o", "defaults", "Comma-separated list of flags for the mount")
	helpFlag  = flagSet.Bool("help", false, "Show this help")
)

func Mount(call []string) error {
	e := flagSet.Parse(call[1:])
	if e != nil {
		return e
	}

	if flagSet.NArg() != 2 || *helpFlag {
		println("`mount` [options] <device> <dir>")
		flagSet.PrintDefaults()
		println("\nAvailable options are:")
		for opt, _ := range flagMap {
			print(opt, ", ")
		}
		println()
		return nil
	}

	flags, e := parseFlags()
	if e != nil {
		return e
	}

	e = syscall.Mount(flagSet.Arg(0), flagSet.Arg(1), *typeFlag, uintptr(flags), "")
	return e
}

var (
	flagMap = map[string]uint32{
		"defaults":   0,
		"noatime":    syscall.MS_NOATIME,
		"nodev":      syscall.MS_NODEV,
		"nodiratime": syscall.MS_NODIRATIME,
		"noexec":     syscall.MS_NOEXEC,
		"nosuid":     syscall.MS_NOSUID,
		"remount":    syscall.MS_REMOUNT,
		"ro":         syscall.MS_RDONLY,
		"sync":       syscall.MS_SYNCHRONOUS,
	}
)

func parseFlags() (uint32, error) {
	ret := uint32(0)
	parts := strings.Split(*flagsFlag, ",")
	for _, part := range parts {
		part = strings.TrimSpace(part)
		val, ok := flagMap[strings.ToLower(part)]
		if !ok {
			return 0, errors.New("Invalid flag \"" + part + "\"")
		}
		ret |= val
	}
	return ret, nil
}
<|endoftext|>


<commit_before>package fs

import (
	"errors"
	"path"
	"strings"
)

/*
	Relative paths and absolute paths are not interchangeable.
	Using these path structures aids in keeping these ideas separate and
	hopefully prevent certain kinds of errors caused by accidentally using the incorrect path type.
	It is recommended to use absolute paths when possible.
*/
type RelPath struct {
	path      string
	lastSplit int
}

/*
	Converts a string to an relative path struct.
	Will panic if the given path is absolute.
*/
func MustRelPath(p string) RelPath {
	p = path.Clean(p)
	if p[0] == '/' {
		panic("fs: not a relative path")
	}
	if p == "." { // We can't stop people from using the zero value, so, use it.
		return RelPath{}
	}
	return RelPath{p, strings.LastIndexByte(p, '/')}
}

/*
	An relative path string with a zero value of "." for current directory
*/
func (p RelPath) String() string {
	if p.path == "" {
		return "."
	} else if p.path[0] == '.' { // a '..' prefix
		return p.path
	} else {
		return "./" + p.path
	}
}

/*
	Returns the relative path of the directory containing this path
*/
func (p RelPath) Dir() RelPath {
	if p.path == "" {
		return p
	} else if p.lastSplit == -1 {
		return RelPath{}
	} else {
		p2 := p.path[0:p.lastSplit]
		return RelPath{p2, strings.LastIndexByte(p2, '/')}
	}
}

/*
	Returns the filename of this path
*/
func (p RelPath) Last() string {
	if p.path == "" {
		return "."
	} else if p.lastSplit == -1 {
		return p.path
	} else {
		return p.path[p.lastSplit+1:]
	}
}

/*
	Creates a new relative path by following the relative path from this path.
*/
func (p RelPath) Join(p2 RelPath) RelPath {
	switch {
	case p2.path == "":
		return p
	case p.path == "":
		return p2
	case p2.path[0] == '.': // '..' prefix requires cleaning again.
		pj := path.Clean(p.path + "/" + p2.path)
		if pj == "." { // We can't stop people from using the zero value, so, use it.
			return RelPath{}
		}
		return RelPath{pj, strings.LastIndexByte(pj, '/')}
	default:
		return RelPath{p.path + "/" + p2.path, len(p.path) + p2.lastSplit + 1}
	}
}

/*
	Returns a slice of relative paths for each segment in the path.

	E.g. for "./a/b/c" it will return [".", "./a", "./a/b", "./a/b/c"].

	For some path where you wish to create all parent paths, it may be useful
	to `range path.Dir().Split()`.
*/
func (p RelPath) Split() []RelPath {
	if p.path == "" {
		return []RelPath{RelPath{}}
	}
	if p.lastSplit == -1 {
		return []RelPath{RelPath{}, p}
	}
	n := strings.Count(p.path, "/") + 1
	slice := make([]RelPath, n+1)
	slice[n] = p
	for i := n - 1; i >= 0; i-- {
		slice[i] = slice[i+1].Dir()
	}
	return slice
}

/*
	Relative paths and absolute paths are not interchangeable.
	Using these path structures aids in keeping these ideas separate and
	hopefully prevent certain kinds of errors caused by accidentally using the incorrect path type.
	It is recommended to use absolute paths when possible.
*/
type AbsolutePath struct {
	path      string
	lastSplit int
}

/*
	Converts a string to an absolute path struct.
	Will panic if the given path is not absolute.
*/
func MustAbsolutePath(p string) AbsolutePath {
	path, err := ParseAbsolutePath(p)
	if err != nil {
		panic(err)
	}
	return path
}

/*
	Converts a string to an absolute path struct,
	returning an error if the given path string is not absolute.
*/
func ParseAbsolutePath(p string) (AbsolutePath, error) {
	p = path.Clean(p)
	if p[0] != '/' {
		return AbsolutePath{}, errors.New("fs: not an absolute path")
	}
	if p == "/" { // We can't stop people from using the zero value, so, use it.
		return AbsolutePath{}, nil
	}
	return AbsolutePath{p, strings.LastIndexByte(p, '/')}, nil

}

/*
	An absolute path string with a zero value of "/" for the root directory
*/
func (p AbsolutePath) String() string {
	if p.path == "" {
		return "/"
	}
	return p.path
}

/*
	Returns the absolute path of the directory containing this path
*/
func (p AbsolutePath) Dir() AbsolutePath {
	if p.path == "" {
		return p
	} else if p.lastSplit == 0 {
		return AbsolutePath{}
	} else {
		p2 := p.path[0:p.lastSplit]
		return AbsolutePath{p2, strings.LastIndexByte(p2, '/')}
	}
}

/*
	Returns the filename of this path
*/
func (p AbsolutePath) Last() string {
	if p.path == "" {
		return "/"
	} else {
		return p.path[p.lastSplit+1:]
	}
}

/*
	Creates a new absolute path by following the relative path from this path.
*/
func (p AbsolutePath) Join(p2 RelPath) AbsolutePath {
	switch {
	case p2.path == "":
		return p
	//case p.path == "": // Comes out the same as the math in the default case.
	//	return AbsolutePath{"/" + p2.path, p2.lastSplit + 1}
	case p2.path[0] == '.': // '..' prefix requires cleaning again.
		pj := path.Clean(p.path + "/" + p2.path)
		if pj == "/" { // We can't stop people from using the zero value, so, use it.
			return AbsolutePath{}
		}
		return AbsolutePath{pj, strings.LastIndexByte(pj, '/')}
	default:
		return AbsolutePath{p.path + "/" + p2.path, len(p.path) + p2.lastSplit + 1}
	}
}

func (p AbsolutePath) CoerceRelative() RelPath {
	return MustRelPath("." + p.path)
}
<commit_msg>fs: be increasingly less rude on path parse error.<commit_after>package fs

import (
	"fmt"
	"path"
	"strings"
)

/*
	Relative paths and absolute paths are not interchangeable.
	Using these path structures aids in keeping these ideas separate and
	hopefully prevent certain kinds of errors caused by accidentally using the incorrect path type.
	It is recommended to use absolute paths when possible.
*/
type RelPath struct {
	path      string
	lastSplit int
}

/*
	Converts a string to an relative path struct.
	Will panic if the given path is absolute.
*/
func MustRelPath(p string) RelPath {
	p = path.Clean(p)
	if p[0] == '/' {
		panic("fs: not a relative path")
	}
	if p == "." { // We can't stop people from using the zero value, so, use it.
		return RelPath{}
	}
	return RelPath{p, strings.LastIndexByte(p, '/')}
}

/*
	An relative path string with a zero value of "." for current directory
*/
func (p RelPath) String() string {
	if p.path == "" {
		return "."
	} else if p.path[0] == '.' { // a '..' prefix
		return p.path
	} else {
		return "./" + p.path
	}
}

/*
	Returns the relative path of the directory containing this path
*/
func (p RelPath) Dir() RelPath {
	if p.path == "" {
		return p
	} else if p.lastSplit == -1 {
		return RelPath{}
	} else {
		p2 := p.path[0:p.lastSplit]
		return RelPath{p2, strings.LastIndexByte(p2, '/')}
	}
}

/*
	Returns the filename of this path
*/
func (p RelPath) Last() string {
	if p.path == "" {
		return "."
	} else if p.lastSplit == -1 {
		return p.path
	} else {
		return p.path[p.lastSplit+1:]
	}
}

/*
	Creates a new relative path by following the relative path from this path.
*/
func (p RelPath) Join(p2 RelPath) RelPath {
	switch {
	case p2.path == "":
		return p
	case p.path == "":
		return p2
	case p2.path[0] == '.': // '..' prefix requires cleaning again.
		pj := path.Clean(p.path + "/" + p2.path)
		if pj == "." { // We can't stop people from using the zero value, so, use it.
			return RelPath{}
		}
		return RelPath{pj, strings.LastIndexByte(pj, '/')}
	default:
		return RelPath{p.path + "/" + p2.path, len(p.path) + p2.lastSplit + 1}
	}
}

/*
	Returns a slice of relative paths for each segment in the path.

	E.g. for "./a/b/c" it will return [".", "./a", "./a/b", "./a/b/c"].

	For some path where you wish to create all parent paths, it may be useful
	to `range path.Dir().Split()`.
*/
func (p RelPath) Split() []RelPath {
	if p.path == "" {
		return []RelPath{RelPath{}}
	}
	if p.lastSplit == -1 {
		return []RelPath{RelPath{}, p}
	}
	n := strings.Count(p.path, "/") + 1
	slice := make([]RelPath, n+1)
	slice[n] = p
	for i := n - 1; i >= 0; i-- {
		slice[i] = slice[i+1].Dir()
	}
	return slice
}

/*
	Relative paths and absolute paths are not interchangeable.
	Using these path structures aids in keeping these ideas separate and
	hopefully prevent certain kinds of errors caused by accidentally using the incorrect path type.
	It is recommended to use absolute paths when possible.
*/
type AbsolutePath struct {
	path      string
	lastSplit int
}

/*
	Converts a string to an absolute path struct.
	Will panic if the given path is not absolute.
*/
func MustAbsolutePath(p string) AbsolutePath {
	path, err := ParseAbsolutePath(p)
	if err != nil {
		panic(err)
	}
	return path
}

/*
	Converts a string to an absolute path struct,
	returning an error if the given path string is not absolute.
*/
func ParseAbsolutePath(p string) (AbsolutePath, error) {
	p = path.Clean(p)
	if p[0] != '/' {
		return AbsolutePath{}, fmt.Errorf("fs: not an absolute path (%q)", p)
	}
	if p == "/" { // We can't stop people from using the zero value, so, use it.
		return AbsolutePath{}, nil
	}
	return AbsolutePath{p, strings.LastIndexByte(p, '/')}, nil

}

/*
	An absolute path string with a zero value of "/" for the root directory
*/
func (p AbsolutePath) String() string {
	if p.path == "" {
		return "/"
	}
	return p.path
}

/*
	Returns the absolute path of the directory containing this path
*/
func (p AbsolutePath) Dir() AbsolutePath {
	if p.path == "" {
		return p
	} else if p.lastSplit == 0 {
		return AbsolutePath{}
	} else {
		p2 := p.path[0:p.lastSplit]
		return AbsolutePath{p2, strings.LastIndexByte(p2, '/')}
	}
}

/*
	Returns the filename of this path
*/
func (p AbsolutePath) Last() string {
	if p.path == "" {
		return "/"
	} else {
		return p.path[p.lastSplit+1:]
	}
}

/*
	Creates a new absolute path by following the relative path from this path.
*/
func (p AbsolutePath) Join(p2 RelPath) AbsolutePath {
	switch {
	case p2.path == "":
		return p
	//case p.path == "": // Comes out the same as the math in the default case.
	//	return AbsolutePath{"/" + p2.path, p2.lastSplit + 1}
	case p2.path[0] == '.': // '..' prefix requires cleaning again.
		pj := path.Clean(p.path + "/" + p2.path)
		if pj == "/" { // We can't stop people from using the zero value, so, use it.
			return AbsolutePath{}
		}
		return AbsolutePath{pj, strings.LastIndexByte(pj, '/')}
	default:
		return AbsolutePath{p.path + "/" + p2.path, len(p.path) + p2.lastSplit + 1}
	}
}

func (p AbsolutePath) CoerceRelative() RelPath {
	return MustRelPath("." + p.path)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gopherjs/gopherjs/js"
)

const (
	callbackPrefix = "_callback"
)

var (
	callbackNum int
)

// JSONP
func JSONP(url string, timeout Duration) (channel chan js.Object, err error) {
	return doJSONP(url+"?callback=", timeout)
}

// DataJSONP
func DataJSONP(url string, data interface{}, timeout Duration) (channel chan js.Object, err error) {
	json, err := StringifyJSON(data)
	if err != nil {
		return
	}

	return doJSONP(url+"?data="+EncodeURIComponent(json)+"&callback=", timeout)
}

func doJSONP(url string, timeout Duration) (channel chan js.Object, err error) {
	defer func() {
		err = jsError(recover())
	}()

	callbackId, _ := StringifyJSON(callbackNum)
	callbackNum = (callbackNum + 1) & 0x7fffffff

	function := callbackPrefix + callbackId
	callback := namespace + "." + function

	channel = make(chan js.Object, 1)

	timeoutId := SetTimeout(func() {
		module.Set(function, func(js.Object) {
			module.Delete(function)
		})

		go func() {
			close(channel)
		}()
	}, timeout)

	module.Set(function, func(object js.Object) {
		ClearTimeout(timeoutId)
		module.Delete(function)

		go func() {
			channel <- object
		}()
	})

	document := js.Global.Get("document")

	script := document.Call("createElement", "script")
	script.Set("type", "text/javascript")
	script.Set("async", true)
	script.Set("src", url+callback)

	head := document.Call("getElementsByTagName", "head").Index(0)
	head.Call("appendChild", script)

	return
}
<commit_msg>don't leave dangling callback functions on network error<commit_after>package main

import (
	"github.com/gopherjs/gopherjs/js"
)

const (
	callbackPrefix = "_callback"
)

var (
	callbackNum int
)

// JSONP
func JSONP(url string, timeout Duration) (channel chan js.Object, err error) {
	return doJSONP(url+"?callback=", timeout)
}

// DataJSONP
func DataJSONP(url string, data interface{}, timeout Duration) (channel chan js.Object, err error) {
	json, err := StringifyJSON(data)
	if err != nil {
		return
	}

	return doJSONP(url+"?data="+EncodeURIComponent(json)+"&callback=", timeout)
}

func doJSONP(url string, timeout Duration) (channel chan js.Object, err error) {
	defer func() {
		err = jsError(recover())
	}()

	callbackId, _ := StringifyJSON(callbackNum)
	callbackNum = (callbackNum + 1) & 0x7fffffff

	function := callbackPrefix + callbackId
	callback := namespace + "." + function

	channel = make(chan js.Object, 1)

	timeoutId := SetTimeout(func() {
		module.Delete(function)

		go func() {
			close(channel)
		}()
	}, timeout)

	module.Set(function, func(object js.Object) {
		ClearTimeout(timeoutId)
		module.Delete(function)

		go func() {
			channel <- object
		}()
	})

	document := js.Global.Get("document")

	script := document.Call("createElement", "script")
	script.Set("type", "text/javascript")
	script.Set("async", true)
	script.Set("src", url+callback)

	head := document.Call("getElementsByTagName", "head").Index(0)
	head.Call("appendChild", script)

	return
}
<|endoftext|>


<commit_before>package geojson

import (
	_"fmt"
	"github.com/dhconnelly/rtreego"
	"github.com/jeffail/gabs"
	"io/ioutil"
)

// See also
// https://github.com/dhconnelly/rtreego#storing-updating-and-deleting-objects

type WOFBounds struct {
     where *rtreego.Rect
     Id int
}

func (b WOFBounds) Bounds() *rtreego.Rect {
     return b.where
}

/*
Something like this using "github.com/paulmach/go.geojson" seems
like it would be a good thing but I don't think I have the stamina
to figure out how to parse the properties separately right now...
(20151005/thisisaaronland)
/*

type WOFProperties struct {
     Raw    []byte
     Parsed *gabs.Container
}

type WOFFeature struct {
     ID          json.Number            `json:"id,omitempty"`
     Type        string                 `json:"type"`
     BoundingBox []float64              `json:"bbox,omitempty"`	// maybe make this a WOFBounds (rtree) like properties?
     Geometry    *gj.Geometry      `json:"geometry"`
     Properties  WOFProperties			`json:"properties"`
     // Properties  map[string]interface{} `json:"properties"`
     CRS         map[string]interface{} `json:"crs,omitempty"` // Coordinate Reference System Objects are not currently supported
}
*/

type WOFFeature struct {
	Raw    []byte
	Parsed *gabs.Container
}

func (wof WOFFeature) Body() *gabs.Container {
	return wof.Parsed
}

func (wof WOFFeature) Dumps() string {
	return wof.Parsed.String()
}

func (wof WOFFeature) Id() int {

	body := wof.Body()

	var flid float64
	flid = body.Path("properties.wof:id").Data().(float64)

	id := int(flid)
	return id
}

// See notes above in WOFFeature.BoundingBox - for now this will do...
// (20151012/thisisaaronland)

func (wof WOFFeature) Bounds() (*WOFBounds, error) {

	id := wof.Id()
	body := wof.Body()

	var swlon float64
	var swlat float64
	var nelon float64
	var nelat float64

	children, _ := body.S("bbox").Children()

	swlon = children[0].Data().(float64)
	swlat = children[1].Data().(float64)
	nelon = children[2].Data().(float64)
	nelat = children[3].Data().(float64)

	llat := nelat - swlat
	llon := nelon - swlon

	// fmt.Printf("%f - %f = %f\n", nelat, swlat, llat)
	// fmt.Printf("%f - %f = %f\n", nelon, swlon, llon)

	pt := rtreego.Point{swlon, swlat}
	rect, err := rtreego.NewRect(pt, []float64{llon, llat})

	if err != nil {
		return nil, err
	}

	return &WOFBounds{rect, id}, nil
}

func UnmarshalFile(path string) (*WOFFeature, error) {

	body, read_err := ioutil.ReadFile(path)

	if read_err != nil {
		return nil, read_err
	}

	return UnmarshalFeature(body)
}

func UnmarshalFeature(raw []byte) (*WOFFeature, error) {

	parsed, parse_err := gabs.ParseJSON(raw)

	if parse_err != nil {
		return nil, parse_err
	}

	rsp := WOFFeature{
		Raw:    raw,
		Parsed: parsed,
	}

	return &rsp, nil
}
<commit_msg>helper method to return placetype<commit_after>package geojson

import (
	_"fmt"
	"github.com/dhconnelly/rtreego"
	"github.com/jeffail/gabs"
	"io/ioutil"
)

// See also
// https://github.com/dhconnelly/rtreego#storing-updating-and-deleting-objects

type WOFBounds struct {
     where *rtreego.Rect
     Id int
     Placetype string
}

func (b WOFBounds) Bounds() *rtreego.Rect {
     return b.where
}

/*
Something like this using "github.com/paulmach/go.geojson" seems
like it would be a good thing but I don't think I have the stamina
to figure out how to parse the properties separately right now...
(20151005/thisisaaronland)
/*

type WOFProperties struct {
     Raw    []byte
     Parsed *gabs.Container
}

type WOFFeature struct {
     ID          json.Number            `json:"id,omitempty"`
     Type        string                 `json:"type"`
     BoundingBox []float64              `json:"bbox,omitempty"`	// maybe make this a WOFBounds (rtree) like properties?
     Geometry    *gj.Geometry      `json:"geometry"`
     Properties  WOFProperties			`json:"properties"`
     // Properties  map[string]interface{} `json:"properties"`
     CRS         map[string]interface{} `json:"crs,omitempty"` // Coordinate Reference System Objects are not currently supported
}
*/

type WOFFeature struct {
	Raw    []byte
	Parsed *gabs.Container
}

func (wof WOFFeature) Body() *gabs.Container {
	return wof.Parsed
}

func (wof WOFFeature) Dumps() string {
	return wof.Parsed.String()
}

func (wof WOFFeature) Id() int {

	body := wof.Body()

	var flid float64
	flid = body.Path("properties.wof:id").Data().(float64)

	id := int(flid)
	return id
}

// Should return a full-on WOFPlacetype object thing-y
// (20151012/thisisaaronland)

func (wof WOFFeature) Placetype() placetype {

	body := wof.Body()

	var placetype string
	placetype = body.Path("properties.wof:placetype").Data().(string)

	return placetype
}

// See notes above in WOFFeature.BoundingBox - for now this will do...
// (20151012/thisisaaronland)

func (wof WOFFeature) Bounds() (*WOFBounds, error) {

	id := wof.Id()
	placetype = wof.Placetype()

	body := wof.Body()

	var swlon float64
	var swlat float64
	var nelon float64
	var nelat float64

	children, _ := body.S("bbox").Children()

	swlon = children[0].Data().(float64)
	swlat = children[1].Data().(float64)
	nelon = children[2].Data().(float64)
	nelat = children[3].Data().(float64)

	llat := nelat - swlat
	llon := nelon - swlon

	// fmt.Printf("%f - %f = %f\n", nelat, swlat, llat)
	// fmt.Printf("%f - %f = %f\n", nelon, swlon, llon)

	pt := rtreego.Point{swlon, swlat}
	rect, err := rtreego.NewRect(pt, []float64{llon, llat})

	if err != nil {
		return nil, err
	}

	return &WOFBounds{rect, id, placetype}, nil
}

func UnmarshalFile(path string) (*WOFFeature, error) {

	body, read_err := ioutil.ReadFile(path)

	if read_err != nil {
		return nil, read_err
	}

	return UnmarshalFeature(body)
}

func UnmarshalFeature(raw []byte) (*WOFFeature, error) {

	parsed, parse_err := gabs.ParseJSON(raw)

	if parse_err != nil {
		return nil, parse_err
	}

	rsp := WOFFeature{
		Raw:    raw,
		Parsed: parsed,
	}

	return &rsp, nil
}
<|endoftext|>


<commit_before>package hitGox

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
)

// Game is a response body.
type Game struct {
	Request    Request  `json:"request"`
	Categories Category `json:"category"`
}

// GetGameByID return information about game category by gameID (eg. 1)
func GetGameByID(gameID int) (Game, error) {
	requestURL := fmt.Sprintf("%s/game/%d", API, gameID)
	_, body, err := fasthttp.Get(nil, requestURL)
	if err != nil {
		return Game{}, err
	}
	var obj Game
	if err = json.NewDecoder(bytes.NewReader(body)).Decode(&obj); err != nil {
		return Game{}, err
	}
	return obj, nil
}

// GetGameByKey return information about game category by `gameKey` (eg. league-of-legends)
func GetGameByKey(gameKey string) (Game, error) {
	var args fasthttp.Args
	args.Add("seo", "true") // If using a game name, this must be true.
	requestURL := fmt.Sprintf("%s/game/%s?%s", API, gameKey, args.String())
	_, body, err := fasthttp.Get(nil, requestURL)
	if err != nil {
		return Game{}, err
	}
	var obj Game
	if err = json.NewDecoder(bytes.NewReader(body)).Decode(&obj); err != nil {
		return Game{}, err
	}
	return obj, nil
}
<commit_msg>✅ Updated getGame<commit_after>package hitGox

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/valyala/fasthttp"
	"strconv"
)

// Game is about category of streams.
type Game struct {
	Request struct {
		This string `json:"this"`
	} `json:"request"`
	Category struct {
		CategoryID         string      `json:"category_id"`
		CategoryName       string      `json:"category_name"`
		CategoryNameShort  interface{} `json:"category_name_short"`
		CategorySeoKey     string      `json:"category_seo_key"`
		CategoryViewers    string      `json:"category_viewers"`
		CategoryMediaCount string      `json:"category_media_count"`
		CategoryChannels   interface{} `json:"category_channels"`
		CategoryLogoSmall  interface{} `json:"category_logo_small"`
		CategoryLogoLarge  string      `json:"category_logo_large"`
		CategoryUpdated    string      `json:"category_updated"`
	} `json:"category"`
}

// GetGame return information about game category.
func GetGame(game interface{}) (*Game, error) {
	var seo bool

	switch game.(type) {
	case string:
		if game == "" {
			return nil, errors.New("game can not be empty")
		}
		seo = true
	case int:
		seo = false
	default:
		return nil, errors.New("game mast be only as string or int")
	}

	var args fasthttp.Args
	args.Add("seo", strconv.FormatBool(seo))

	url := fmt.Sprint(APIEndpoint, "/game/", game)
	resp, err := get(url, &args)
	if err != nil {
		return nil, err
	}

	var obj Game
	if err = json.NewDecoder(bytes.NewReader(resp)).Decode(&obj); err != nil {
		return nil, err
	}

	return &obj, nil
}
<|endoftext|>