<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fieldpath

import (
	"bytes"
	"io"
	"unsafe"

	jsoniter "github.com/json-iterator/go"
)

func (s *Set) ToJSON() ([]byte, error) {
	buf := bytes.Buffer{}
	err := s.ToJSONStream(&buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (s *Set) ToJSONStream(w io.Writer) error {
	stream := writePool.BorrowStream(w)
	defer writePool.ReturnStream(stream)

	var r reusableBuilder

	stream.WriteObjectStart()
	err := s.emitContents_v1(false, stream, &r)
	if err != nil {
		return err
	}
	stream.WriteObjectEnd()
	return stream.Flush()
}

func manageMemory(stream *jsoniter.Stream) error {
	// Help jsoniter manage its buffers--without this, it does a bunch of
	// alloctaions that are not necessary. They were probably optimizing
	// for folks using the buffer directly.
	b := stream.Buffer()
	if len(b) > 4096 || cap(b)-len(b) < 2048 {
		if err := stream.Flush(); err != nil {
			return err
		}
		stream.SetBuffer(b[:0])
	}
	return nil
}

type reusableBuilder struct {
	bytes.Buffer
}

func (r *reusableBuilder) unsafeString() string {
	b := r.Bytes()
	return *(*string)(unsafe.Pointer(&b))
}

func (r *reusableBuilder) reset() *bytes.Buffer {
	r.Reset()
	return &r.Buffer
}

func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream, r *reusableBuilder) error {
	mi, ci := 0, 0
	first := true
	preWrite := func() {
		if first {
			first = false
			return
		}
		stream.WriteMore()
	}

	for mi < len(s.Members.members) && ci < len(s.Children.members) {
		mpe := s.Members.members[mi]
		cpe := s.Children.members[ci].pathElement

		if mpe.Less(cpe) {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteEmptyObject()
			mi++
		} else if cpe.Less(mpe) {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContents_v1(false, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			ci++
		} else {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContents_v1(true, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			mi++
			ci++
		}
	}

	for mi < len(s.Members.members) {
		mpe := s.Members.members[mi]

		preWrite()
		if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteEmptyObject()
		mi++
	}

	for ci < len(s.Children.members) {
		cpe := s.Children.members[ci].pathElement

		preWrite()
		if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteObjectStart()
		if err := s.Children.members[ci].set.emitContents_v1(false, stream, r); err != nil {
			return err
		}
		stream.WriteObjectEnd()
		ci++
	}

	if includeSelf && !first {
		preWrite()
		stream.WriteObjectField(".")
		stream.WriteEmptyObject()
	}
	return manageMemory(stream)
}

// FromJSON clears s and reads a JSON formatted set structure.
func (s *Set) FromJSON(r io.Reader) error {
	// The iterator pool is completely useless for memory management, grrr.
	iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, r, 4096)

	found, _ := readIter_v1(iter)
	if found == nil {
		*s = Set{}
	} else {
		*s = *found
	}
	return iter.Error
}

// returns true if this subtree is also (or only) a member of parent; s is nil
// if there are no further children.
func readIter_v1(iter *jsoniter.Iterator) (children *Set, isMember bool) {
	iter.ReadMapCB(func(iter *jsoniter.Iterator, key string) bool {
		if key == "." {
			isMember = true
			iter.Skip()
			return true
		}
		pe, err := DeserializePathElement(key)
		if err == ErrUnknownPathElementType {
			// Ignore these-- a future version maybe knows what
			// they are. We drop these completely rather than try
			// to preserve things we don't understand.
			iter.Skip()
			return true
		} else if err != nil {
			iter.ReportError("parsing key as path element", err.Error())
			iter.Skip()
			return true
		}
		grandchildren, childIsMember := readIter_v1(iter)
		if childIsMember {
			if children == nil {
				children = &Set{}
			}
			m := &children.Members.members
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].Less(pe)
			if appendOK {
				*m = append(*m, pe)
			} else {
				children.Members.Insert(pe)
			}
		}
		if grandchildren != nil {
			if children == nil {
				children = &Set{}
			}
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			m := &children.Children.members
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].pathElement.Less(pe)
			if appendOK {
				*m = append(*m, setNode{pe, grandchildren})
			} else {
				*children.Children.Descend(pe) = *grandchildren
			}
		}
		return true
	})
	if children == nil {
		isMember = true
	}

	return children, isMember
}
<commit_msg>fix golint errors<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fieldpath

import (
	"bytes"
	"io"
	"unsafe"

	jsoniter "github.com/json-iterator/go"
)

func (s *Set) ToJSON() ([]byte, error) {
	buf := bytes.Buffer{}
	err := s.ToJSONStream(&buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (s *Set) ToJSONStream(w io.Writer) error {
	stream := writePool.BorrowStream(w)
	defer writePool.ReturnStream(stream)

	var r reusableBuilder

	stream.WriteObjectStart()
	err := s.emitContentsV1(false, stream, &r)
	if err != nil {
		return err
	}
	stream.WriteObjectEnd()
	return stream.Flush()
}

func manageMemory(stream *jsoniter.Stream) error {
	// Help jsoniter manage its buffers--without this, it does a bunch of
	// alloctaions that are not necessary. They were probably optimizing
	// for folks using the buffer directly.
	b := stream.Buffer()
	if len(b) > 4096 || cap(b)-len(b) < 2048 {
		if err := stream.Flush(); err != nil {
			return err
		}
		stream.SetBuffer(b[:0])
	}
	return nil
}

type reusableBuilder struct {
	bytes.Buffer
}

func (r *reusableBuilder) unsafeString() string {
	b := r.Bytes()
	return *(*string)(unsafe.Pointer(&b))
}

func (r *reusableBuilder) reset() *bytes.Buffer {
	r.Reset()
	return &r.Buffer
}

func (s *Set) emitContentsV1(includeSelf bool, stream *jsoniter.Stream, r *reusableBuilder) error {
	mi, ci := 0, 0
	first := true
	preWrite := func() {
		if first {
			first = false
			return
		}
		stream.WriteMore()
	}

	for mi < len(s.Members.members) && ci < len(s.Children.members) {
		mpe := s.Members.members[mi]
		cpe := s.Children.members[ci].pathElement

		if mpe.Less(cpe) {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteEmptyObject()
			mi++
		} else if cpe.Less(mpe) {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContentsV1(false, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			ci++
		} else {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContentsV1(true, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			mi++
			ci++
		}
	}

	for mi < len(s.Members.members) {
		mpe := s.Members.members[mi]

		preWrite()
		if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteEmptyObject()
		mi++
	}

	for ci < len(s.Children.members) {
		cpe := s.Children.members[ci].pathElement

		preWrite()
		if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteObjectStart()
		if err := s.Children.members[ci].set.emitContentsV1(false, stream, r); err != nil {
			return err
		}
		stream.WriteObjectEnd()
		ci++
	}

	if includeSelf && !first {
		preWrite()
		stream.WriteObjectField(".")
		stream.WriteEmptyObject()
	}
	return manageMemory(stream)
}

// FromJSON clears s and reads a JSON formatted set structure.
func (s *Set) FromJSON(r io.Reader) error {
	// The iterator pool is completely useless for memory management, grrr.
	iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, r, 4096)

	found, _ := readIterV1(iter)
	if found == nil {
		*s = Set{}
	} else {
		*s = *found
	}
	return iter.Error
}

// returns true if this subtree is also (or only) a member of parent; s is nil
// if there are no further children.
func readIterV1(iter *jsoniter.Iterator) (children *Set, isMember bool) {
	iter.ReadMapCB(func(iter *jsoniter.Iterator, key string) bool {
		if key == "." {
			isMember = true
			iter.Skip()
			return true
		}
		pe, err := DeserializePathElement(key)
		if err == ErrUnknownPathElementType {
			// Ignore these-- a future version maybe knows what
			// they are. We drop these completely rather than try
			// to preserve things we don't understand.
			iter.Skip()
			return true
		} else if err != nil {
			iter.ReportError("parsing key as path element", err.Error())
			iter.Skip()
			return true
		}
		grandchildren, childIsMember := readIterV1(iter)
		if childIsMember {
			if children == nil {
				children = &Set{}
			}
			m := &children.Members.members
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].Less(pe)
			if appendOK {
				*m = append(*m, pe)
			} else {
				children.Members.Insert(pe)
			}
		}
		if grandchildren != nil {
			if children == nil {
				children = &Set{}
			}
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			m := &children.Children.members
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].pathElement.Less(pe)
			if appendOK {
				*m = append(*m, setNode{pe, grandchildren})
			} else {
				*children.Children.Descend(pe) = *grandchildren
			}
		}
		return true
	})
	if children == nil {
		isMember = true
	}

	return children, isMember
}
<|endoftext|>


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

// Package auth provides a set of user authentication handlers for the ozzo routing package.
package jwt

import (
	"github.com/dgrijalva/jwt-go"
	"github.com/go-ozzo/ozzo-routing"
	"log"
	"net/http"
	"strings"
	"time"
)

// User is the key used to store and retrieve the user identity information in routing.Context
const User = "User"

type JWTConfig struct {
	SecretKey string
}

// Identity represents an authenticated user. If a user is successfully authenticated by
// an auth handler (Basic, Bearer, or Query), an Identity object will be made available for injection.
type Identity interface{}
type Payload interface{}

// DefaultRealm is the default realm name for HTTP authentication. It is used by HTTP authentication based on
// Basic and Bearer.
var DefaultRealm = "API"

// TokenAuthFunc is the function for authenticating a user based on a secret token.
type TokenAuthFunc func(c *routing.Context, payload map[string]interface{}) (Payload, error)

// TokenName is the query parameter name for auth token.
var TokenName = "access-token"

// JWT returns a routing.Handler that performs HTTP authentication based on bearer token.
// It can be used like the following:
//
//   import (
//     "errors"
//     "fmt"
//     "net/http"
//     "github.com/go-ozzo/ozzo-routing"
//     "github.com/go-ozzo/ozzo-routing/auth/jwt"
//   )
//   func main() {
//     r := routing.New()
//     r.Use(auth.JWT(func(c *routing.Context, token string) (auth.Identity, error) {
//!       if token == "secret" {
//!         return auth.Identity("demo"), nil
//!       }
//!       return nil, errors.New("invalid credential")
//!     }))
//     r.Get("/demo", func(c *routing.Context) error {
//       fmt.Fprintf(res, "Hello, %v", c.Get(auth.User))
//       return nil
//     })
//   }
//
// By default, the auth realm is named as "API". You may customize it by specifying the realm parameter.
//
// When authentication fails, a "WWW-Authenticate" header will be sent, and an http.StatusUnauthorized
// error will be reported via routing.Context.Error().

func JWT(fn TokenAuthFunc, jwtConfig JWTConfig, realm ...string) routing.Handler {
	name := DefaultRealm
	if len(realm) > 0 {
		name = realm[0]
	}
	return func(c *routing.Context) error {

		header := c.Request.Header.Get("Authorization")
		if !strings.HasPrefix(header, "Bearer ") {
			c.Response.Header().Set("WWW-Authenticate", `Bearer realm="`+name+`"`)
			return routing.NewHTTPError(http.StatusUnauthorized, "ivalid credential")
		}

		token, err := jwt.Parse(header[7:], func(t *jwt.Token) (interface{}, error) { return []byte(jwtConfig.SecretKey), nil })
		if err != nil {
			c.Response.Header().Set("WWW-Authenticate", `Bearer realm="`+name+`"`)
			return routing.NewHTTPError(http.StatusUnauthorized, "ivalid credential")
		}

		payload := token.Claims

		identity, e := fn(c, payload)
		if e == nil {
			c.Set(User, identity)
			return nil
		}

		c.Response.Header().Set("WWW-Authenticate", `Bearer realm="`+name+`"`)
		return routing.NewHTTPError(http.StatusUnauthorized, e.Error())

	}
}

func CreateToken(jwtConfig JWTConfig) string {
	// Create JWT token
	token := jwt.New(jwt.SigningMethodHS256)

	token.Claims["id"] = "userId"

	// Expire in 120 minutes
	token.Claims["exp"] = time.Now().Add(time.Minute * 120).Unix()
	tokenString, err := token.SignedString([]byte(jwtConfig.SecretKey))
	if err != nil {
	}
	log.Println(tokenString)
	return tokenString

}
<commit_msg>Payload for token<commit_after>// Copyright 2016  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package auth provides a set of user authentication handlers for the ozzo routing package.
package jwt

import (
	"github.com/dgrijalva/jwt-go"
	"github.com/go-ozzo/ozzo-routing"
	"log"
	"net/http"
	"strings"
	"time"
)

// User is the key used to store and retrieve the user identity information in routing.Context
const User = "User"

type JWTConfig struct {
	SecretKey string
}

// Identity represents an authenticated user. If a user is successfully authenticated by
// an auth handler (Basic, Bearer, or Query), an Identity object will be made available for injection.
type Identity interface{}

type Payload interface{}
type JWTPayload map[string]interface{}

// DefaultRealm is the default realm name for HTTP authentication. It is used by HTTP authentication based on
// Basic and Bearer.
var DefaultRealm = "API"

// TokenAuthFunc is the function for authenticating a user based on a secret token.
type TokenAuthFunc func(c *routing.Context, payload map[string]interface{}) (Payload, error)

// TokenName is the query parameter name for auth token.
var TokenName = "access-token"

// JWT returns a routing.Handler that performs HTTP authentication based on bearer token.
// It can be used like the following:
//
// Example
//
// By default, the auth realm is named as "API". You may customize it by specifying the realm parameter.
//
// When authentication fails, a "WWW-Authenticate" header will be sent, and an http.StatusUnauthorized
// error will be reported via routing.Context.Error().

func JWT(fn TokenAuthFunc, jwtConfig JWTConfig, realm ...string) routing.Handler {
	name := DefaultRealm
	if len(realm) > 0 {
		name = realm[0]
	}
	return func(c *routing.Context) error {

		header := c.Request.Header.Get("Authorization")
		if !strings.HasPrefix(header, "Bearer ") {
			c.Response.Header().Set("WWW-Authenticate", `Bearer realm="`+name+`"`)
			return routing.NewHTTPError(http.StatusUnauthorized, "ivalid credential")
		}

		token, err := jwt.Parse(header[7:], func(t *jwt.Token) (interface{}, error) { return []byte(jwtConfig.SecretKey), nil })
		if err != nil {
			c.Response.Header().Set("WWW-Authenticate", `Bearer realm="`+name+`"`)
			return routing.NewHTTPError(http.StatusUnauthorized, "ivalid credential")
		}

		payload := token.Claims

		identity, e := fn(c, payload)
		if e == nil {
			c.Set(User, identity)
			return nil
		}

		c.Response.Header().Set("WWW-Authenticate", `Bearer realm="`+name+`"`)
		return routing.NewHTTPError(http.StatusUnauthorized, e.Error())

	}
}

func CreateToken(jwtConfig JWTConfig, payload JWTPayload ) string {
	// Create JWT token
	token := jwt.New(jwt.SigningMethodHS256)
	token.Claims = payload

	// Expire in 120 minutes
	token.Claims["exp"] = time.Now().Add(time.Minute * 120).Unix()
	tokenString, err := token.SignedString([]byte(jwtConfig.SecretKey))

	if err != nil {
	}

	return tokenString

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

func PostShow(w http.ResponseWriter, r *http.Request) {
	body, err := ioutil.ReadFile("public/posts.html")
	fmt.Fprint(w, string(body))
}

// PostIndex queries the database for all of the posts,
// appends each row to an array of post, and then
// renders all of them as JSON
func APIPostIndex(w http.ResponseWriter, r *http.Request) {
	var (
		posts   Posts
		id      int
		title   string
		content string
		posted  string
	)

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p := Post{id, title, content, posted}
		posts = append(posts, p)
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(posts); err != nil {
		log.Fatal(err)
	}
}

// PostShow queries the database for a specific post by
// it's ID. It will then create a Post from the values
// that were grabbed and render the Post as JSON
func APIPostShow(w http.ResponseWriter, r *http.Request) {
	var (
		p       Post
		id      int
		title   string
		content string
		posted  string
	)

	vars := mux.Vars(r)
	postId := vars["postId"]

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts WHERE ID = ?", postId)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p = Post{id, title, content, posted}
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(p); err != nil {
		log.Fatal(err)
	}
}

// PostCreate accepts a JSON object that includes the
// attributes `title` and `content`. It will then insert
// a new row to the database containing that data. After
// adding the new row, PostCreate responds with a JSON
// object of the created Post
func APIPostCreate(w http.ResponseWriter, r *http.Request) {
	var (
		post    Post
		id      int
		title   string
		content string
		posted  string
	)

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Fatal(err)
	}
	if err := r.Body.Close(); err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(body, &post); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422)
	}

	db := dbConnection()
	_, err = db.Query("INSERT INTO posts (title, content) values (?, ?)", post.Title, post.Content)
	if err != nil {
		log.Fatal(err)
	}

	rows, err := db.Query("SELECT * FROM posts ORDER BY id DESC LIMIT 1")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		post = Post{id, title, content, posted}
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(post); err != nil {
		log.Fatal(err)
	}
}

// PostUpdate receives data from the client that will replace
// a post with the specified ID that is sent over as well.
func APIPostUpdate(w http.ResponseWriter, r *http.Request) {
	var post Post

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Fatal(err)
	}
	if err := r.Body.Close(); err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(body, &post); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422)
	}

	vars := mux.Vars(r)
	postId := vars["postId"]

	db := dbConnection()
	_, err = db.Query("UPDATE posts SET title=?, content=? WHERE ID = ?", post.Title, post.Content, postId)
	if err != nil {
		log.Fatal(err)
		ErrorStatus(w, r)
	}
	defer db.Close()
	SuccessStatus(w, r)
}

// PostDelete queries the database for the ID specified
// by the client and deletes it.
// TODO: return `x` umong delete
func APIPostDelete(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	postId := vars["postId"]

	db := dbConnection()
	_, err := db.Query("DELETE FROM posts WHERE ID = ?", postId)
	if err != nil {
		log.Fatal(err)
		ErrorStatus(w, r)
	}
	defer db.Close()
	SuccessStatus(w, r)

}
<commit_msg>Add handler to render show page<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

// PostShow renders html file
func PostShow(w http.ResponseWriter, r *http.Request) {
	body, _ := ioutil.ReadFile("./public/post.html")
	fmt.Fprintf(w, string(body))
}

// APIPostIndex queries the database for all of the posts,
// appends each row to an array of post, and then
// renders all of them as JSON
func APIPostIndex(w http.ResponseWriter, r *http.Request) {
	var (
		posts   Posts
		id      int
		title   string
		content string
		posted  string
	)

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p := Post{id, title, content, posted}
		posts = append(posts, p)
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(posts); err != nil {
		log.Fatal(err)
	}
}

// APIPostShow queries the database for a specific post by
// it's ID. It will then create a Post from the values
// that were grabbed and render the Post as JSON
func APIPostShow(w http.ResponseWriter, r *http.Request) {
	var (
		p       Post
		id      int
		title   string
		content string
		posted  string
	)

	vars := mux.Vars(r)
	postID := vars["postID"]

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts WHERE ID = ?", postID)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p = Post{id, title, content, posted}
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(p); err != nil {
		log.Fatal(err)
	}
}

// APIPostCreate accepts a JSON object that includes the
// attributes `title` and `content`. It will then insert
// a new row to the database containing that data. After
// adding the new row, PostCreate responds with a JSON
// object of the created Post
func APIPostCreate(w http.ResponseWriter, r *http.Request) {
	var (
		post    Post
		id      int
		title   string
		content string
		posted  string
	)

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Fatal(err)
	}
	if err := r.Body.Close(); err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(body, &post); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422)
	}

	db := dbConnection()
	_, err = db.Query("INSERT INTO posts (title, content) values (?, ?)", post.Title, post.Content)
	if err != nil {
		log.Fatal(err)
	}

	rows, err := db.Query("SELECT * FROM posts ORDER BY id DESC LIMIT 1")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		post = Post{id, title, content, posted}
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(post); err != nil {
		log.Fatal(err)
	}
}

// APIPostUpdate receives data from the client that will replace
// a post with the specified ID that is sent over as well.
func APIPostUpdate(w http.ResponseWriter, r *http.Request) {
	var post Post

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Fatal(err)
	}
	if err := r.Body.Close(); err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(body, &post); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422)
	}

	vars := mux.Vars(r)
	postID := vars["postID"]

	db := dbConnection()
	_, err = db.Query("UPDATE posts SET title=?, content=? WHERE ID = ?", post.Title, post.Content, postID)
	if err != nil {
		log.Fatal(err)
		ErrorStatus(w, r)
	}
	defer db.Close()
	SuccessStatus(w, r)
}

// APIPostDelete queries the database for the ID specified
// by the client and deletes it.
// TODO: return `x` umong delete
func APIPostDelete(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	postID := vars["postID"]

	db := dbConnection()
	_, err := db.Query("DELETE FROM posts WHERE ID = ?", postID)
	if err != nil {
		log.Fatal(err)
		ErrorStatus(w, r)
	}
	defer db.Close()
	SuccessStatus(w, r)

}
<|endoftext|>


<commit_before>package gnosis

// package file will contain MarkdownHandler and RawHandler to handle incoming requests
// Whole thing needs to be written

import (
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"

	"github.com/JackKnifed/blackfriday"
)

var fileFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)?(\\.)?([a-zA-Z0-9_ ]+)?")

func oldRawHandler(responsePipe http.ResponseWriter, request *http.Request) {
	var err error

	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)
	config := GetConfig()

	if filteredRequest == nil {
		log.Printf("null request improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	}

	if filteredRequest[1] != config.Mainserver.Prefix {
		log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, err.Error(), 500)
	}

	contents, err := ioutil.ReadFile(config.Mainserver.Prefix + filteredRequest[2] + ".md")
	if err != nil {
		log.Printf("request %s points to an bad file target sent to server %s", request.URL.Path, config.Mainserver.Prefix)
		http.Error(responsePipe, err.Error(), 403)
	}

	_, err = responsePipe.Write([]byte(contents))
	if err != nil {
		http.Error(responsePipe, err.Error(), 500)
	}
}

const (
	bodyHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_USE_SMARTYPANTS |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

	bodyExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK

	tocHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES |
		blackfriday.HTML_TOC |
		blackfriday.HTML_OMIT_CONTENTS

	tocExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK
)

type WikiPage struct {
	Title string
	ToC   template.HTML
	Body  template.HTML
}

var templates = template.Must(template.ParseFiles("wiki.html"))

var wikiFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)$")

func bodyParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(bodyHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, bodyExtensions)
}

func tocParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(tocHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, tocExtensions)
}

// Of note - this markdown handler is not a direct handler
func MarkdownHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {

	var err error

	// break up the request parameters - for reference, regex is listed below
	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

	// if there are no matches, the regex ovbiously didn't match up
	if filteredRequest == nil {
		log.Printf("null request [ %s ] improperly routed to wiki handler [ %s ]", request.URL.Path, serverConfig.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	} else {
		if filteredRequest[1] != serverConfig.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(serverConfig.Path + filteredRequest[3] + ".md")
		if err != nil {
			log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 404)
		}
		// parse any markdown in the input
		body := template.HTML(bodyParseMarkdown(contents))

		toc := template.HTML(tocParseMarkdown(contents))

		response := WikiPage{Title: filteredRequest[3], ToC: toc, Body: body}
		err = templates.ExecuteTemplate(responsePipe, serverConfig.Template, response)
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}

func RawHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {

	var err error

	// break up the request parameters - for reference, regex is listed below
	filteredRequest := fileFilter.FindStringSubmatch(request.URL.Path)

	// if there are no matches, the regex ovbiously didn't match up
	if filteredRequest == nil {
		log.Printf("null request [ %s ] improperly routed to file handler [ %s ]", request.URL.Path, serverConfig.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	} else {
		if filteredRequest[1] != serverConfig.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(serverConfig.Path + filteredRequest[3] + ".md")
		if err != nil {
			log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 404)
		}

		_, err = responsePipe.Write([]byte(contents))
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}

func MakeHandler(handlerConfig ServerSection) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		switch handlerConfig.ServerType {
		case "markdown":
			MarkdownHandler(w, r, handlerConfig)
		case "raw":
			RawHandler(w, r, handlerConfig)
		default:
			log.Printf("Bad server type [%s]", handlerConfig.ServerType)
		}
	}
}

/*
func GenerateRawHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {
	return func(responsePipe http.responseWriter, request *http.Request) {
		var err error

		filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

		if filteredRequest == nil {
			log.Printf("null request improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, "Request not allowed", 403)
		}

		if filteredRequest[1] != config.Mainserver.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(config.Mainserver.Prefix + filteredRequest[2] + ".md")
		if err != nil {
			log.Printf("request %s points to an bad file target sent to server %s", request.URL.Path, config.Mainserver.Prefix)
			http.Error(responsePipe, err.Error(), 403)
		}

		_, err = responsePipe.Write([]byte(contents))
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}
*/
<commit_msg>removed some old functions from handlers.go - old versions of rawHandler<commit_after>package gnosis

// package file will contain MarkdownHandler and RawHandler to handle incoming requests
// Whole thing needs to be written

import (
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"

	"github.com/JackKnifed/blackfriday"
)

const (
	bodyHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_USE_SMARTYPANTS |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

	bodyExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK

	tocHtmlFlags = 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES |
		blackfriday.HTML_TOC |
		blackfriday.HTML_OMIT_CONTENTS

	tocExtensions = 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_AUTO_HEADER_IDS |
		blackfriday.EXTENSION_TITLEBLOCK
)

type WikiPage struct {
	Title string
	ToC   template.HTML
	Body  template.HTML
}

var templates = template.Must(template.ParseFiles("wiki.html"))

var wikiFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)$")

func bodyParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(bodyHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, bodyExtensions)
}

func tocParseMarkdown(input []byte) []byte {
	// set up the HTML renderer
	renderer := blackfriday.HtmlRenderer(tocHtmlFlags, "", "")
	return blackfriday.Markdown(input, renderer, tocExtensions)
}

// Of note - this markdown handler is not a direct handler
func MarkdownHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {

	var err error

	// break up the request parameters - for reference, regex is listed below
	filteredRequest := wikiFilter.FindStringSubmatch(request.URL.Path)

	// if there are no matches, the regex ovbiously didn't match up
	if filteredRequest == nil {
		log.Printf("null request [ %s ] improperly routed to wiki handler [ %s ]", request.URL.Path, serverConfig.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	} else {
		if filteredRequest[1] != serverConfig.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(serverConfig.Path + filteredRequest[3] + ".md")
		if err != nil {
			log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 404)
		}
		// parse any markdown in the input
		body := template.HTML(bodyParseMarkdown(contents))

		toc := template.HTML(tocParseMarkdown(contents))

		response := WikiPage{Title: filteredRequest[3], ToC: toc, Body: body}
		err = templates.ExecuteTemplate(responsePipe, serverConfig.Template, response)
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}

var fileFilter = regexp.MustCompile("^(/([a-zA-Z0-9_ /]+/)?)([a-zA-Z0-9_ ]+)?(\\.)?([a-zA-Z0-9_ ]+)?")

func RawHandler(responsePipe http.ResponseWriter, request *http.Request, serverConfig ServerSection) {

	var err error

	// break up the request parameters - for reference, regex is listed below
	filteredRequest := fileFilter.FindStringSubmatch(request.URL.Path)

	// if there are no matches, the regex ovbiously didn't match up
	if filteredRequest == nil {
		log.Printf("null request [ %s ] improperly routed to file handler [ %s ]", request.URL.Path, serverConfig.Prefix)
		http.Error(responsePipe, "Request not allowed", 403)
	} else {
		if filteredRequest[1] != serverConfig.Prefix {
			log.Printf("request %s was improperly routed to wiki handler %s", request.URL.Path, serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 500)
		}

		contents, err := ioutil.ReadFile(serverConfig.Path + filteredRequest[3] + ".md")
		if err != nil {
			log.Printf("request [ %s ] points to an bad file target [ %s ]sent to server %s", request.URL.Path, filteredRequest[3], serverConfig.Prefix)
			http.Error(responsePipe, err.Error(), 404)
		}

		_, err = responsePipe.Write([]byte(contents))
		if err != nil {
			http.Error(responsePipe, err.Error(), 500)
		}
	}
}

func MakeHandler(handlerConfig ServerSection) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		switch handlerConfig.ServerType {
		case "markdown":
			MarkdownHandler(w, r, handlerConfig)
		case "raw":
			RawHandler(w, r, handlerConfig)
		default:
			log.Printf("Bad server type [%s]", handlerConfig.ServerType)
		}
	}
}
<|endoftext|>


<commit_before>package req

import (
	"crypto/tls"
	"net"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"time"
)

var defaultCookieJar http.CookieJar

func init() {
	defaultCookieJar, _ = cookiejar.New(nil)
}

type setting struct {
	Timeout             time.Duration // total timeout
	DialTimeout         time.Duration
	ReadTimeout         time.Duration
	WriteTimeout        time.Duration
	TLSHandshakeTimeout time.Duration
	InsecureTLS         bool
	Jar                 http.CookieJar
	Proxy               func(*http.Request) (*url.URL, error)
	TlsClientConfig     *tls.Config
	Transport           *http.Transport
	Client              *http.Client
}

func (r *Request) prepareSetting() bool {
	if r == nil {
		return false
	}
	if r.setting == nil {
		r.setting = &setting{}
	}
	return true
}

// GetClient returns the *http.Client according to the setting.
func (r *Request) GetClient() *http.Client {
	if !r.prepareSetting() {
		return http.DefaultClient
	}
	s := r.setting
	if s.Client == nil {
		c := &http.Client{
			Transport: r.GetTransport(),
		}
		if s.Jar != nil {
			c.Jar = s.Jar
		}
		if s.Timeout > 0 {
			c.Timeout = s.Timeout
		}
		s.Client = c
	}
	return s.Client
}

func (r *Request) createTransport() *http.Transport {
	s := r.setting
	trans := &http.Transport{}
	trans.Dial = func(network, address string) (conn net.Conn, err error) {
		if s.DialTimeout > 0 {
			conn, err = net.DialTimeout(network, address, s.DialTimeout)
			if err != nil {
				return
			}
		} else {
			conn, err = net.Dial(network, address)
			if err != nil {
				return
			}
		}
		if s.ReadTimeout > 0 {
			conn.SetReadDeadline(time.Now().Add(s.ReadTimeout))
		}
		if s.WriteTimeout > 0 {
			conn.SetWriteDeadline(time.Now().Add(s.WriteTimeout))
		}
		return
	}
	if s.TlsClientConfig != nil {
		trans.TLSClientConfig = s.TlsClientConfig
	}
	if s.TLSHandshakeTimeout > 0 {
		trans.TLSHandshakeTimeout = s.TLSHandshakeTimeout
	}
	if s.InsecureTLS {
		if trans.TLSClientConfig != nil {
			trans.TLSClientConfig.InsecureSkipVerify = true
		} else {
			trans.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
		}
	}
	if s.Proxy != nil {
		trans.Proxy = s.Proxy
	} else {
		trans.Proxy = http.ProxyFromEnvironment
	}
	return trans
}

// GetTransport return the http.Transport according to the setting.
func (r *Request) GetTransport() *http.Transport {
	if !r.prepareSetting() {
		trans, _ := http.DefaultTransport.(*http.Transport)
		return trans
	}
	s := r.setting
	if s.Transport == nil {
		s.Transport = r.createTransport()
	}
	return s.Transport
}

// Client set the http.Client for the request
func (r *Request) Client(client *http.Client) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Client = client
	return r
}

// Transport set the http.Transport for request
func (r *Request) Transport(trans *http.Transport) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Transport = trans
	r.setting.Client = nil
	return r
}

// Proxy set the proxy for request
func (r *Request) Proxy(proxy func(*http.Request) (*url.URL, error)) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Proxy = proxy
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// Timeout set the total timeout for request,
// once timeout reached, request will be canceled.
func (r *Request) Timeout(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Timeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutDial sets the timeout for dial connection.
func (r *Request) TimeoutDial(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.DialTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutRead sets the timeout for read operation.
func (r *Request) TimeoutRead(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.ReadTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutWrite sets the timeout for write operation.
func (r *Request) TimeoutWrite(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.WriteTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutTLSHandshake specifies the maximum amount of time waiting to
// wait for a TLS handshake. Zero means no timeout.
func (r *Request) TimeoutTLSHandshake(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.TLSHandshakeTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// InsecureTLS allows to access the insecure https server.
func (r *Request) InsecureTLS(ins bool) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.InsecureTLS = ins
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// EnableCookie set the default CookieJar to the request if enable==true, otherwise set to nil.
func (r *Request) EnableCookie(enable bool) *Request {
	if !r.prepareSetting() {
		return nil
	}
	if enable {
		r.setting.Jar = defaultCookieJar
	} else {
		r.setting.Jar = nil
	}
	r.setting.Client = nil
	return r
}

// EnableCookieWithJar set the specified *http.CookieJar to the request.
func (r *Request) EnableCookieWithJar(jar http.CookieJar) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Jar = jar
	r.setting.Client = nil
	return r
}

// Merge clone some properties of another Request into this.
func (r *Request) Merge(rr *Request) *Request {
	if r == nil || rr == nil {
		return nil
	}
	if len(rr.params) > 0 { // merge params
		for name, value := range rr.params {
			if _, ok := r.params[name]; !ok {
				r.params[name] = value
			}
		}
	}
	if rr.req != nil { // merge internal http.Request
		if r.req == nil {
			r.req = basicRequest()
		}
		if r.req.Method == "" && rr.req.Method != "" {
			r.req.Method = rr.req.Method
		}
		if r.req.Host == "" && rr.req.Host != "" {
			r.req.Host = rr.req.Host
		}
		if r.req.Proto != rr.req.Proto {
			r.req.Proto = rr.req.Proto
			r.req.ProtoMajor = rr.req.ProtoMajor
			r.req.ProtoMinor = rr.req.ProtoMinor
		}
		for name, value := range rr.req.Header {
			if _, ok := r.req.Header[name]; !ok {
				r.req.Header[name] = value
			}
		}
	}
	if rr.setting != nil { // merge setting
		rr.GetClient() // ensure client has been created. prevent creating client every request.
		s := *rr.setting
		r.setting = &s
	}

	return r
}
<commit_msg>add TLSClientConfig method for req.Request<commit_after>package req

import (
	"crypto/tls"
	"net"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"time"
)

var defaultCookieJar http.CookieJar

func init() {
	defaultCookieJar, _ = cookiejar.New(nil)
}

type setting struct {
	Timeout             time.Duration // total timeout
	DialTimeout         time.Duration
	ReadTimeout         time.Duration
	WriteTimeout        time.Duration
	TLSHandshakeTimeout time.Duration
	InsecureTLS         bool
	Jar                 http.CookieJar
	Proxy               func(*http.Request) (*url.URL, error)
	TLSClientConfig     *tls.Config
	Transport           *http.Transport
	Client              *http.Client
}

func (r *Request) prepareSetting() bool {
	if r == nil {
		return false
	}
	if r.setting == nil {
		r.setting = &setting{}
	}
	return true
}

// GetClient returns the *http.Client according to the setting.
func (r *Request) GetClient() *http.Client {
	if !r.prepareSetting() {
		return http.DefaultClient
	}
	s := r.setting
	if s.Client == nil {
		c := &http.Client{
			Transport: r.GetTransport(),
		}
		if s.Jar != nil {
			c.Jar = s.Jar
		}
		if s.Timeout > 0 {
			c.Timeout = s.Timeout
		}
		s.Client = c
	}
	return s.Client
}

func (r *Request) createTransport() *http.Transport {
	s := r.setting
	trans := &http.Transport{}
	trans.Dial = func(network, address string) (conn net.Conn, err error) {
		if s.DialTimeout > 0 {
			conn, err = net.DialTimeout(network, address, s.DialTimeout)
			if err != nil {
				return
			}
		} else {
			conn, err = net.Dial(network, address)
			if err != nil {
				return
			}
		}
		if s.ReadTimeout > 0 {
			conn.SetReadDeadline(time.Now().Add(s.ReadTimeout))
		}
		if s.WriteTimeout > 0 {
			conn.SetWriteDeadline(time.Now().Add(s.WriteTimeout))
		}
		return
	}
	if s.TLSClientConfig != nil {
		trans.TLSClientConfig = s.TLSClientConfig
	}
	if s.TLSHandshakeTimeout > 0 {
		trans.TLSHandshakeTimeout = s.TLSHandshakeTimeout
	}
	if s.InsecureTLS {
		if trans.TLSClientConfig != nil {
			trans.TLSClientConfig.InsecureSkipVerify = true
		} else {
			trans.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
		}
	}
	if s.Proxy != nil {
		trans.Proxy = s.Proxy
	} else {
		trans.Proxy = http.ProxyFromEnvironment
	}
	return trans
}

// GetTransport return the http.Transport according to the setting.
func (r *Request) GetTransport() *http.Transport {
	if !r.prepareSetting() {
		trans, _ := http.DefaultTransport.(*http.Transport)
		return trans
	}
	s := r.setting
	if s.Transport == nil {
		s.Transport = r.createTransport()
	}
	return s.Transport
}

// Client set the http.Client for the request
func (r *Request) Client(client *http.Client) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Client = client
	return r
}

// Transport set the http.Transport for request
func (r *Request) Transport(trans *http.Transport) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Transport = trans
	r.setting.Client = nil
	return r
}

// TLSClientConfig set the tls config to the request
func (r *Request) TLSClientConfig(config *tls.Config) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.TLSClientConfig = config
	r.setting.Transport = nil
	r.setting.Client = nil
	return r
}

// Proxy set the proxy for request
func (r *Request) Proxy(proxy func(*http.Request) (*url.URL, error)) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Proxy = proxy
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// Timeout set the total timeout for request,
// once timeout reached, request will be canceled.
func (r *Request) Timeout(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Timeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutDial sets the timeout for dial connection.
func (r *Request) TimeoutDial(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.DialTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutRead sets the timeout for read operation.
func (r *Request) TimeoutRead(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.ReadTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutWrite sets the timeout for write operation.
func (r *Request) TimeoutWrite(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.WriteTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// TimeoutTLSHandshake specifies the maximum amount of time waiting to
// wait for a TLS handshake. Zero means no timeout.
func (r *Request) TimeoutTLSHandshake(d time.Duration) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.TLSHandshakeTimeout = d
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// InsecureTLS allows to access the insecure https server.
func (r *Request) InsecureTLS(ins bool) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.InsecureTLS = ins
	r.setting.Client = nil
	r.setting.Transport = nil
	return r
}

// EnableCookie set the default CookieJar to the request if enable==true, otherwise set to nil.
func (r *Request) EnableCookie(enable bool) *Request {
	if !r.prepareSetting() {
		return nil
	}
	if enable {
		r.setting.Jar = defaultCookieJar
	} else {
		r.setting.Jar = nil
	}
	r.setting.Client = nil
	return r
}

// EnableCookieWithJar set the specified *http.CookieJar to the request.
func (r *Request) EnableCookieWithJar(jar http.CookieJar) *Request {
	if !r.prepareSetting() {
		return nil
	}
	r.setting.Jar = jar
	r.setting.Client = nil
	return r
}

// Merge clone some properties of another Request into this.
func (r *Request) Merge(rr *Request) *Request {
	if r == nil || rr == nil {
		return nil
	}
	if len(rr.params) > 0 { // merge params
		for name, value := range rr.params {
			if _, ok := r.params[name]; !ok {
				r.params[name] = value
			}
		}
	}
	if rr.req != nil { // merge internal http.Request
		if r.req == nil {
			r.req = basicRequest()
		}
		if r.req.Method == "" && rr.req.Method != "" {
			r.req.Method = rr.req.Method
		}
		if r.req.Host == "" && rr.req.Host != "" {
			r.req.Host = rr.req.Host
		}
		if r.req.Proto != rr.req.Proto {
			r.req.Proto = rr.req.Proto
			r.req.ProtoMajor = rr.req.ProtoMajor
			r.req.ProtoMinor = rr.req.ProtoMinor
		}
		for name, value := range rr.req.Header {
			if _, ok := r.req.Header[name]; !ok {
				r.req.Header[name] = value
			}
		}
	}
	if rr.setting != nil { // merge setting
		rr.GetClient() // ensure client has been created. prevent creating client every request.
		s := *rr.setting
		r.setting = &s
	}

	return r
}
<|endoftext|>


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

// +build windows

package win

import (
	"syscall"
	"unsafe"
)

type CSIDL uint32
type HDROP HANDLE

const (
	CSIDL_DESKTOP                 = 0x00
	CSIDL_INTERNET                = 0x01
	CSIDL_PROGRAMS                = 0x02
	CSIDL_CONTROLS                = 0x03
	CSIDL_PRINTERS                = 0x04
	CSIDL_PERSONAL                = 0x05
	CSIDL_FAVORITES               = 0x06
	CSIDL_STARTUP                 = 0x07
	CSIDL_RECENT                  = 0x08
	CSIDL_SENDTO                  = 0x09
	CSIDL_BITBUCKET               = 0x0A
	CSIDL_STARTMENU               = 0x0B
	CSIDL_MYDOCUMENTS             = 0x0C
	CSIDL_MYMUSIC                 = 0x0D
	CSIDL_MYVIDEO                 = 0x0E
	CSIDL_DESKTOPDIRECTORY        = 0x10
	CSIDL_DRIVES                  = 0x11
	CSIDL_NETWORK                 = 0x12
	CSIDL_NETHOOD                 = 0x13
	CSIDL_FONTS                   = 0x14
	CSIDL_TEMPLATES               = 0x15
	CSIDL_COMMON_STARTMENU        = 0x16
	CSIDL_COMMON_PROGRAMS         = 0x17
	CSIDL_COMMON_STARTUP          = 0x18
	CSIDL_COMMON_DESKTOPDIRECTORY = 0x19
	CSIDL_APPDATA                 = 0x1A
	CSIDL_PRINTHOOD               = 0x1B
	CSIDL_LOCAL_APPDATA           = 0x1C
	CSIDL_ALTSTARTUP              = 0x1D
	CSIDL_COMMON_ALTSTARTUP       = 0x1E
	CSIDL_COMMON_FAVORITES        = 0x1F
	CSIDL_INTERNET_CACHE          = 0x20
	CSIDL_COOKIES                 = 0x21
	CSIDL_HISTORY                 = 0x22
	CSIDL_COMMON_APPDATA          = 0x23
	CSIDL_WINDOWS                 = 0x24
	CSIDL_SYSTEM                  = 0x25
	CSIDL_PROGRAM_FILES           = 0x26
	CSIDL_MYPICTURES              = 0x27
	CSIDL_PROFILE                 = 0x28
	CSIDL_SYSTEMX86               = 0x29
	CSIDL_PROGRAM_FILESX86        = 0x2A
	CSIDL_PROGRAM_FILES_COMMON    = 0x2B
	CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C
	CSIDL_COMMON_TEMPLATES        = 0x2D
	CSIDL_COMMON_DOCUMENTS        = 0x2E
	CSIDL_COMMON_ADMINTOOLS       = 0x2F
	CSIDL_ADMINTOOLS              = 0x30
	CSIDL_CONNECTIONS             = 0x31
	CSIDL_COMMON_MUSIC            = 0x35
	CSIDL_COMMON_PICTURES         = 0x36
	CSIDL_COMMON_VIDEO            = 0x37
	CSIDL_RESOURCES               = 0x38
	CSIDL_RESOURCES_LOCALIZED     = 0x39
	CSIDL_COMMON_OEM_LINKS        = 0x3A
	CSIDL_CDBURN_AREA             = 0x3B
	CSIDL_COMPUTERSNEARME         = 0x3D
	CSIDL_FLAG_CREATE             = 0x8000
	CSIDL_FLAG_DONT_VERIFY        = 0x4000
	CSIDL_FLAG_NO_ALIAS           = 0x1000
	CSIDL_FLAG_PER_USER_INIT      = 0x8000
	CSIDL_FLAG_MASK               = 0xFF00
)

// NotifyIcon flags
const (
	NIF_MESSAGE = 0x00000001
	NIF_ICON    = 0x00000002
	NIF_TIP     = 0x00000004
	NIF_STATE   = 0x00000008
	NIF_INFO    = 0x00000010
)

// NotifyIcon messages
const (
	NIM_ADD        = 0x00000000
	NIM_MODIFY     = 0x00000001
	NIM_DELETE     = 0x00000002
	NIM_SETFOCUS   = 0x00000003
	NIM_SETVERSION = 0x00000004
)

// NotifyIcon states
const (
	NIS_HIDDEN     = 0x00000001
	NIS_SHAREDICON = 0x00000002
)

// NotifyIcon info flags
const (
	NIIF_NONE    = 0x00000000
	NIIF_INFO    = 0x00000001
	NIIF_WARNING = 0x00000002
	NIIF_ERROR   = 0x00000003
	NIIF_USER    = 0x00000004
	NIIF_NOSOUND = 0x00000010
)

const NOTIFYICON_VERSION = 3

// SHGetFileInfo flags
const (
	SHGFI_LARGEICON         = 0x000000000
	SHGFI_SMALLICON         = 0x000000001
	SHGFI_OPENICON          = 0x000000002
	SHGFI_SHELLICONSIZE     = 0x000000004
	SHGFI_PIDL              = 0x000000008
	SHGFI_USEFILEATTRIBUTES = 0x000000010
	SHGFI_ADDOVERLAYS       = 0x000000020
	SHGFI_OVERLAYINDEX      = 0x000000040
	SHGFI_ICON              = 0x000000100
	SHGFI_DISPLAYNAME       = 0x000000200
	SHGFI_TYPENAME          = 0x000000400
	SHGFI_ATTRIBUTES        = 0x000000800
	SHGFI_ICONLOCATION      = 0x000001000
	SHGFI_EXETYPE           = 0x000002000
	SHGFI_SYSICONINDEX      = 0x000004000
	SHGFI_LINKOVERLAY       = 0x000008000
	SHGFI_SELECTED          = 0x000010000
	SHGFI_ATTR_SPECIFIED    = 0x000020000
)

type NOTIFYICONDATA struct {
	CbSize           uint32
	HWnd             HWND
	UID              uint32
	UFlags           uint32
	UCallbackMessage uint32
	HIcon            HICON
	SzTip            [128]uint16
	DwState          uint32
	DwStateMask      uint32
	SzInfo           [256]uint16
	UVersion         uint32
	SzInfoTitle      [64]uint16
	DwInfoFlags      uint32
	GuidItem         syscall.GUID
}

type SHFILEINFO struct {
	HIcon         HICON
	IIcon         int32
	DwAttributes  uint32
	SzDisplayName [MAX_PATH]uint16
	SzTypeName    [80]uint16
}

type BROWSEINFO struct {
	HwndOwner      HWND
	PidlRoot       uintptr
	PszDisplayName *uint16
	LpszTitle      *uint16
	UlFlags        uint32
	Lpfn           uintptr
	LParam         uintptr
	IImage         int32
}

var (
	// Library
	libshell32 uintptr

	// Functions
	dragAcceptFiles        uintptr
	dragFinish             uintptr
	dragQueryFile          uintptr
	shBrowseForFolder      uintptr
	shGetFileInfo          uintptr
	shGetPathFromIDList    uintptr
	shGetSpecialFolderPath uintptr
	shell_NotifyIcon       uintptr
)

func init() {
	// Library
	libshell32 = MustLoadLibrary("shell32.dll")

	// Functions
	dragAcceptFiles = MustGetProcAddress(libshell32, "DragAcceptFiles")
	dragFinish = MustGetProcAddress(libshell32, "DragFinish")
	dragQueryFile = MustGetProcAddress(libshell32, "DragQueryFileW")
	shBrowseForFolder = MustGetProcAddress(libshell32, "SHBrowseForFolderW")
	shGetFileInfo = MustGetProcAddress(libshell32, "SHGetFileInfoW")
	shGetPathFromIDList = MustGetProcAddress(libshell32, "SHGetPathFromIDListW")
	shGetSpecialFolderPath = MustGetProcAddress(libshell32, "SHGetSpecialFolderPathW")
	shell_NotifyIcon = MustGetProcAddress(libshell32, "Shell_NotifyIconW")
}

func DragAcceptFiles(hWnd HWND, fAccept bool) bool {
	ret, _, _ := syscall.Syscall(dragAcceptFiles, 2,
		uintptr(hWnd),
		uintptr(BoolToBOOL(fAccept)),
		0)

	return ret != 0
}

func DragQueryFile(hDrop HDROP, iFile uint, lpszFile *uint16, cch uint) uint {
	ret, _, _ := syscall.Syscall6(dragQueryFile, 4,
		uintptr(hDrop),
		uintptr(iFile),
		uintptr(unsafe.Pointer(lpszFile)),
		uintptr(cch),
		0,
		0)

	return uint(ret)
}

func DragFinish(hDrop HDROP) {
	syscall.Syscall(dragAcceptFiles, 1,
		uintptr(hDrop),
		0,
		0)
}

func SHBrowseForFolder(lpbi *BROWSEINFO) uintptr {
	ret, _, _ := syscall.Syscall(shBrowseForFolder, 1,
		uintptr(unsafe.Pointer(lpbi)),
		0,
		0)

	return ret
}

func SHGetFileInfo(pszPath *uint16, dwFileAttributes uint32, psfi *SHFILEINFO, cbFileInfo, uFlags uint32) uintptr {
	ret, _, _ := syscall.Syscall6(shGetFileInfo, 5,
		uintptr(unsafe.Pointer(pszPath)),
		uintptr(dwFileAttributes),
		uintptr(unsafe.Pointer(psfi)),
		uintptr(cbFileInfo),
		uintptr(uFlags),
		0)

	return ret
}

func SHGetPathFromIDList(pidl uintptr, pszPath *uint16) bool {
	ret, _, _ := syscall.Syscall(shGetPathFromIDList, 2,
		pidl,
		uintptr(unsafe.Pointer(pszPath)),
		0)

	return ret != 0
}

func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool {
	ret, _, _ := syscall.Syscall6(shGetSpecialFolderPath, 4,
		uintptr(hwndOwner),
		uintptr(unsafe.Pointer(lpszPath)),
		uintptr(csidl),
		uintptr(BoolToBOOL(fCreate)),
		0,
		0)

	return ret != 0
}

func Shell_NotifyIcon(dwMessage uint32, lpdata *NOTIFYICONDATA) bool {
	ret, _, _ := syscall.Syscall(shell_NotifyIcon, 2,
		uintptr(dwMessage),
		uintptr(unsafe.Pointer(lpdata)),
		0)

	return ret != 0
}
<commit_msg>Add SHParseDisplayName<commit_after>// Copyright 2010 The win Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package win

import (
	"syscall"
	"unsafe"
)

type CSIDL uint32
type HDROP HANDLE

const (
	CSIDL_DESKTOP                 = 0x00
	CSIDL_INTERNET                = 0x01
	CSIDL_PROGRAMS                = 0x02
	CSIDL_CONTROLS                = 0x03
	CSIDL_PRINTERS                = 0x04
	CSIDL_PERSONAL                = 0x05
	CSIDL_FAVORITES               = 0x06
	CSIDL_STARTUP                 = 0x07
	CSIDL_RECENT                  = 0x08
	CSIDL_SENDTO                  = 0x09
	CSIDL_BITBUCKET               = 0x0A
	CSIDL_STARTMENU               = 0x0B
	CSIDL_MYDOCUMENTS             = 0x0C
	CSIDL_MYMUSIC                 = 0x0D
	CSIDL_MYVIDEO                 = 0x0E
	CSIDL_DESKTOPDIRECTORY        = 0x10
	CSIDL_DRIVES                  = 0x11
	CSIDL_NETWORK                 = 0x12
	CSIDL_NETHOOD                 = 0x13
	CSIDL_FONTS                   = 0x14
	CSIDL_TEMPLATES               = 0x15
	CSIDL_COMMON_STARTMENU        = 0x16
	CSIDL_COMMON_PROGRAMS         = 0x17
	CSIDL_COMMON_STARTUP          = 0x18
	CSIDL_COMMON_DESKTOPDIRECTORY = 0x19
	CSIDL_APPDATA                 = 0x1A
	CSIDL_PRINTHOOD               = 0x1B
	CSIDL_LOCAL_APPDATA           = 0x1C
	CSIDL_ALTSTARTUP              = 0x1D
	CSIDL_COMMON_ALTSTARTUP       = 0x1E
	CSIDL_COMMON_FAVORITES        = 0x1F
	CSIDL_INTERNET_CACHE          = 0x20
	CSIDL_COOKIES                 = 0x21
	CSIDL_HISTORY                 = 0x22
	CSIDL_COMMON_APPDATA          = 0x23
	CSIDL_WINDOWS                 = 0x24
	CSIDL_SYSTEM                  = 0x25
	CSIDL_PROGRAM_FILES           = 0x26
	CSIDL_MYPICTURES              = 0x27
	CSIDL_PROFILE                 = 0x28
	CSIDL_SYSTEMX86               = 0x29
	CSIDL_PROGRAM_FILESX86        = 0x2A
	CSIDL_PROGRAM_FILES_COMMON    = 0x2B
	CSIDL_PROGRAM_FILES_COMMONX86 = 0x2C
	CSIDL_COMMON_TEMPLATES        = 0x2D
	CSIDL_COMMON_DOCUMENTS        = 0x2E
	CSIDL_COMMON_ADMINTOOLS       = 0x2F
	CSIDL_ADMINTOOLS              = 0x30
	CSIDL_CONNECTIONS             = 0x31
	CSIDL_COMMON_MUSIC            = 0x35
	CSIDL_COMMON_PICTURES         = 0x36
	CSIDL_COMMON_VIDEO            = 0x37
	CSIDL_RESOURCES               = 0x38
	CSIDL_RESOURCES_LOCALIZED     = 0x39
	CSIDL_COMMON_OEM_LINKS        = 0x3A
	CSIDL_CDBURN_AREA             = 0x3B
	CSIDL_COMPUTERSNEARME         = 0x3D
	CSIDL_FLAG_CREATE             = 0x8000
	CSIDL_FLAG_DONT_VERIFY        = 0x4000
	CSIDL_FLAG_NO_ALIAS           = 0x1000
	CSIDL_FLAG_PER_USER_INIT      = 0x8000
	CSIDL_FLAG_MASK               = 0xFF00
)

// NotifyIcon flags
const (
	NIF_MESSAGE = 0x00000001
	NIF_ICON    = 0x00000002
	NIF_TIP     = 0x00000004
	NIF_STATE   = 0x00000008
	NIF_INFO    = 0x00000010
)

// NotifyIcon messages
const (
	NIM_ADD        = 0x00000000
	NIM_MODIFY     = 0x00000001
	NIM_DELETE     = 0x00000002
	NIM_SETFOCUS   = 0x00000003
	NIM_SETVERSION = 0x00000004
)

// NotifyIcon states
const (
	NIS_HIDDEN     = 0x00000001
	NIS_SHAREDICON = 0x00000002
)

// NotifyIcon info flags
const (
	NIIF_NONE    = 0x00000000
	NIIF_INFO    = 0x00000001
	NIIF_WARNING = 0x00000002
	NIIF_ERROR   = 0x00000003
	NIIF_USER    = 0x00000004
	NIIF_NOSOUND = 0x00000010
)

const NOTIFYICON_VERSION = 3

// SHGetFileInfo flags
const (
	SHGFI_LARGEICON         = 0x000000000
	SHGFI_SMALLICON         = 0x000000001
	SHGFI_OPENICON          = 0x000000002
	SHGFI_SHELLICONSIZE     = 0x000000004
	SHGFI_PIDL              = 0x000000008
	SHGFI_USEFILEATTRIBUTES = 0x000000010
	SHGFI_ADDOVERLAYS       = 0x000000020
	SHGFI_OVERLAYINDEX      = 0x000000040
	SHGFI_ICON              = 0x000000100
	SHGFI_DISPLAYNAME       = 0x000000200
	SHGFI_TYPENAME          = 0x000000400
	SHGFI_ATTRIBUTES        = 0x000000800
	SHGFI_ICONLOCATION      = 0x000001000
	SHGFI_EXETYPE           = 0x000002000
	SHGFI_SYSICONINDEX      = 0x000004000
	SHGFI_LINKOVERLAY       = 0x000008000
	SHGFI_SELECTED          = 0x000010000
	SHGFI_ATTR_SPECIFIED    = 0x000020000
)

type NOTIFYICONDATA struct {
	CbSize           uint32
	HWnd             HWND
	UID              uint32
	UFlags           uint32
	UCallbackMessage uint32
	HIcon            HICON
	SzTip            [128]uint16
	DwState          uint32
	DwStateMask      uint32
	SzInfo           [256]uint16
	UVersion         uint32
	SzInfoTitle      [64]uint16
	DwInfoFlags      uint32
	GuidItem         syscall.GUID
}

type SHFILEINFO struct {
	HIcon         HICON
	IIcon         int32
	DwAttributes  uint32
	SzDisplayName [MAX_PATH]uint16
	SzTypeName    [80]uint16
}

type BROWSEINFO struct {
	HwndOwner      HWND
	PidlRoot       uintptr
	PszDisplayName *uint16
	LpszTitle      *uint16
	UlFlags        uint32
	Lpfn           uintptr
	LParam         uintptr
	IImage         int32
}

var (
	// Library
	libshell32 uintptr

	// Functions
	dragAcceptFiles        uintptr
	dragFinish             uintptr
	dragQueryFile          uintptr
	shBrowseForFolder      uintptr
	shGetFileInfo          uintptr
	shGetPathFromIDList    uintptr
	shGetSpecialFolderPath uintptr
	shParseDisplayName     uintptr
	shell_NotifyIcon       uintptr
)

func init() {
	// Library
	libshell32 = MustLoadLibrary("shell32.dll")

	// Functions
	dragAcceptFiles = MustGetProcAddress(libshell32, "DragAcceptFiles")
	dragFinish = MustGetProcAddress(libshell32, "DragFinish")
	dragQueryFile = MustGetProcAddress(libshell32, "DragQueryFileW")
	shBrowseForFolder = MustGetProcAddress(libshell32, "SHBrowseForFolderW")
	shGetFileInfo = MustGetProcAddress(libshell32, "SHGetFileInfoW")
	shGetPathFromIDList = MustGetProcAddress(libshell32, "SHGetPathFromIDListW")
	shGetSpecialFolderPath = MustGetProcAddress(libshell32, "SHGetSpecialFolderPathW")
	shParseDisplayName = MustGetProcAddress(libshell32, "SHParseDisplayName")
	shell_NotifyIcon = MustGetProcAddress(libshell32, "Shell_NotifyIconW")
}

func DragAcceptFiles(hWnd HWND, fAccept bool) bool {
	ret, _, _ := syscall.Syscall(dragAcceptFiles, 2,
		uintptr(hWnd),
		uintptr(BoolToBOOL(fAccept)),
		0)

	return ret != 0
}

func DragQueryFile(hDrop HDROP, iFile uint, lpszFile *uint16, cch uint) uint {
	ret, _, _ := syscall.Syscall6(dragQueryFile, 4,
		uintptr(hDrop),
		uintptr(iFile),
		uintptr(unsafe.Pointer(lpszFile)),
		uintptr(cch),
		0,
		0)

	return uint(ret)
}

func DragFinish(hDrop HDROP) {
	syscall.Syscall(dragAcceptFiles, 1,
		uintptr(hDrop),
		0,
		0)
}

func SHBrowseForFolder(lpbi *BROWSEINFO) uintptr {
	ret, _, _ := syscall.Syscall(shBrowseForFolder, 1,
		uintptr(unsafe.Pointer(lpbi)),
		0,
		0)

	return ret
}

func SHGetFileInfo(pszPath *uint16, dwFileAttributes uint32, psfi *SHFILEINFO, cbFileInfo, uFlags uint32) uintptr {
	ret, _, _ := syscall.Syscall6(shGetFileInfo, 5,
		uintptr(unsafe.Pointer(pszPath)),
		uintptr(dwFileAttributes),
		uintptr(unsafe.Pointer(psfi)),
		uintptr(cbFileInfo),
		uintptr(uFlags),
		0)

	return ret
}

func SHGetPathFromIDList(pidl uintptr, pszPath *uint16) bool {
	ret, _, _ := syscall.Syscall(shGetPathFromIDList, 2,
		pidl,
		uintptr(unsafe.Pointer(pszPath)),
		0)

	return ret != 0
}

func SHGetSpecialFolderPath(hwndOwner HWND, lpszPath *uint16, csidl CSIDL, fCreate bool) bool {
	ret, _, _ := syscall.Syscall6(shGetSpecialFolderPath, 4,
		uintptr(hwndOwner),
		uintptr(unsafe.Pointer(lpszPath)),
		uintptr(csidl),
		uintptr(BoolToBOOL(fCreate)),
		0,
		0)

	return ret != 0
}

func SHParseDisplayName(pszName *uint16, pbc uintptr, ppidl *uintptr, sfgaoIn uint32, psfgaoOut *uint32) HRESULT {
	ret, _, _ := syscall.Syscall6(shParseDisplayName, 5,
		uintptr(unsafe.Pointer(pszName)),
		pbc,
		uintptr(unsafe.Pointer(ppidl)),
		0,
		uintptr(unsafe.Pointer(psfgaoOut)),
		0)

	return HRESULT(ret)
}

func Shell_NotifyIcon(dwMessage uint32, lpdata *NOTIFYICONDATA) bool {
	ret, _, _ := syscall.Syscall(shell_NotifyIcon, 2,
		uintptr(dwMessage),
		uintptr(unsafe.Pointer(lpdata)),
		0)

	return ret != 0
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/masci/flickr.go/flickr"
	"github.com/masci/flickr.go/flickr/photos"
)

func main() {
	var pause = func() {
		var foo string
		fmt.Println("Press a key to continue")
		fmt.Scanln(&foo)
	}

	// retrieve Flickr credentials from env vars
	apik := os.Getenv("FLICKRGO_API_KEY")
	apisec := os.Getenv("FLICKRGO_API_SECRET")
	token := os.Getenv("FLICKRGO_OAUTH_TOKEN")
	tokenSecret := os.Getenv("FLICKRGO_OAUTH_TOKEN_SECRET")

	// do not proceed if credentials were not provided
	if apik == "" || apisec == "" || token == "" || tokenSecret == "" {
		fmt.Fprintln(os.Stderr, "Please set FLICKRGO_API_KEY, FLICKRGO_API_SECRET "+
			"and FLICKRGO_OAUTH_TOKEN env vars")
		os.Exit(1)
	}

	// create an API client with credentials
	client := flickr.NewFlickrClient(apik, apisec)
	client.OAuthToken = token
	client.OAuthTokenSecret = tokenSecret

	// upload a photo
	path, _ := filepath.Abs("examples/upload/gopher.jpg")
	params := flickr.NewUploadParams()
	params.Title = "A Gopher"
	resp, err := flickr.UploadPhoto(client, path, params)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	} else {
		fmt.Println("Photo uploaded, id:", resp.Id)
		pause()
	}

	// delete the photo
	respD, err := photos.Delete(client, resp.Id)
	if err != nil {
		fmt.Println(err)
		fmt.Println(respD.ErrorMsg())
		os.Exit(1)
	} else {
		fmt.Println("Successfully removed photo")
		pause()
	}
}
<commit_msg>create a demo set<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/masci/flickr.go/flickr"
	"github.com/masci/flickr.go/flickr/photos"
	"github.com/masci/flickr.go/flickr/photosets"
)

func main() {
	var pause = func() {
		var foo string
		fmt.Println("Press a key to continue")
		fmt.Scanln(&foo)
	}

	// retrieve Flickr credentials from env vars
	apik := os.Getenv("FLICKRGO_API_KEY")
	apisec := os.Getenv("FLICKRGO_API_SECRET")
	token := os.Getenv("FLICKRGO_OAUTH_TOKEN")
	tokenSecret := os.Getenv("FLICKRGO_OAUTH_TOKEN_SECRET")

	// do not proceed if credentials were not provided
	if apik == "" || apisec == "" || token == "" || tokenSecret == "" {
		fmt.Fprintln(os.Stderr, "Please set FLICKRGO_API_KEY, FLICKRGO_API_SECRET "+
			"and FLICKRGO_OAUTH_TOKEN env vars")
		os.Exit(1)
	}

	// create an API client with credentials
	client := flickr.NewFlickrClient(apik, apisec)
	client.OAuthToken = token
	client.OAuthTokenSecret = tokenSecret

	// upload a photo
	path, _ := filepath.Abs("examples/upload/gopher.jpg")
	params := flickr.NewUploadParams()
	params.Title = "A Gopher"
	resp, err := flickr.UploadPhoto(client, path, params)
	if err != nil {
		fmt.Println("Failed uploading:", err, resp.ErrorMsg())
		os.Exit(1)
	} else {
		fmt.Println("Photo uploaded, id:", resp.Id)
		pause()
	}

	// create a photoset
	respS, err := photosets.Create(client, "A Set", "", resp.Id)
	if err != nil {
		fmt.Println("Failed creating set:", respS.ErrorMsg())
		os.Exit(1)
	} else {
		fmt.Println("Set created, id:", respS.Set.Id, "url:", respS.Set.Url)
		pause()
	}

	// TODO assign photo to the photoset
	// TODO remove the photo from the photoset

	// delete the photo
	respD, err := photos.Delete(client, resp.Id)
	if err != nil {
		fmt.Println("Failed deleting photo:", err)
		fmt.Println(respD.ErrorMsg())
		os.Exit(1)
	} else {
		fmt.Println("Successfully removed photo")
		pause()
	}
}
<|endoftext|>


<commit_before>// Package multiconfig provides a way to load and read configurations from
// multiple sources
package multiconfig

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/fatih/structs"
)

var (
	errPathNotSet = errors.New("config path is not set")
)

// Config is used to handle multiple configuration sources
type Config struct {
	// Path contains the JSON or TOML file
	Path string
}

// NewWithPath returns a new instance of Config to read from the given
// configuration file.
func NewWithPath(path string) *Config {
	return &Config{
		Path: path,
	}
}

// New returns a new instance of Config.
func New() *Config {
	return &Config{}
}

// MustLoad is like Load but panics if the config cannot be parsed.
func (c *Config) MustLoad(conf interface{}) {
	if err := c.Load(conf); err != nil {
		panic(err)
	}
}

// Load initializes the given pointer of struct s with configuration from
// multiple sources.
func (c *Config) Load(conf interface{}) error {
	if !structs.IsStruct(conf) {
		return fmt.Errorf("passed configuration is not a struct: %T", conf)
	}

	// Initialize struct from the config path.
	if err := c.LoadFile(conf); err != nil {
		// Means it its initialzed with New()
		if err != errPathNotSet {
			return err
		}
	}

	// If any environment variable is available override it.
	if err := c.LoadEnv(conf); err != nil {
		return err
	}

	// Finally check if any flag is defined, which overrides the field again
	if err := c.LoadFlag(conf); err != nil {
		return err
	}

	return nil
}

// LoadFile sets the fields of the given s struct by reading from the given path.
func (c *Config) LoadFile(s interface{}) error {
	// Initialize struct from the config path.
	if c.Path == "" {
		return errPathNotSet
	}

	if strings.HasSuffix(c.Path, "toml") {
		if _, err := toml.DecodeFile(c.Path, s); err != nil {
			return err
		}

		return nil
	}

	if strings.HasSuffix(c.Path, "json") {
		file, err := ioutil.ReadFile(c.Path)
		if err != nil {
			return err
		}

		if err := json.Unmarshal(file, s); err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("file format is not supported: %s. Want TOML or JSON.", c.Path)
}

// LoadEnv sets the fields of the given s struct by looking for environment
// variables in the form of STRUCTNAME_FIELDNAME.
func (c *Config) LoadEnv(s interface{}) error {
	strct := structs.New(s)
	strctName := strct.Name()

	for _, field := range strct.Fields() {
		envName := strings.ToUpper(strctName) + "_" + strings.ToUpper(field.Name())

		v := os.Getenv(envName)
		if v == "" {
			continue
		}

		if err := fieldSet(field, v); err != nil {
			return err
		}
	}

	return nil
}

func (c *Config) printEnvs(s interface{}) {
	strct := structs.New(s)
	strctName := strct.Name()

	for _, field := range strct.Fields() {
		envName := strings.ToUpper(strctName) + "_" + strings.ToUpper(field.Name())
		fmt.Println("  ", envName)
	}
}

// LoadFlag creates on the fly flags based on the field names and parses them to
// load into the given pointer of struct s.
func (c *Config) LoadFlag(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	f := flag.NewFlagSet(structName, flag.ExitOnError)
	// f.SetOutput(ioutil.Discard)

	for _, field := range strct.Fields() {
		name := field.Name()

		f.Var(newFieldValue(field), flagName(name), flagUsage(name))
	}

	f.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		f.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		c.printEnvs(s)
		fmt.Println("")
	}

	return f.Parse(os.Args[1:])
}

// fieldSet sets field value from the given string value. It converts the
// string value in a sane way and is usefulf or environment variables or flags
// which are by nature in string types.
func fieldSet(field *structs.Field, v string) error {
	// TODO: add support for other types
	switch field.Kind() {
	case reflect.Bool:
		val, err := strconv.ParseBool(v)
		if err != nil {
			return err
		}

		if err := field.Set(val); err != nil {
			return err
		}
	case reflect.Int:
		i, err := strconv.Atoi(v)
		if err != nil {
			return err
		}

		if err := field.Set(i); err != nil {
			return err
		}
	case reflect.String:
		field.Set(v)
	case reflect.Slice:
		if _, ok := field.Value().([]string); !ok {
			errors.New("can't set on non string slices")
		}

		if err := field.Set(strings.Split(v, ",")); err != nil {
			return err
		}
	case reflect.Float64:
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return err
		}

		if err := field.Set(f); err != nil {
			return err
		}
	default:
		return fmt.Errorf("multiconfig: not supported type: %s", field.Kind())
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<commit_msg>multiconfig: improve doc<commit_after>// Package multiconfig provides a way to load and read configurations from
// multiple sources
package multiconfig

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/fatih/structs"
)

var (
	errPathNotSet = errors.New("config path is not set")
)

// Config is used to handle multiple configuration sources
type Config struct {
	// Path contains the JSON or TOML file
	Path string
}

// NewWithPath returns a new instance of Config to read from the given
// configuration file.
func NewWithPath(path string) *Config {
	return &Config{
		Path: path,
	}
}

// New returns a new instance of Config.
func New() *Config {
	return &Config{}
}

// MustLoad is like Load but panics if the config cannot be parsed.
func (c *Config) MustLoad(conf interface{}) {
	if err := c.Load(conf); err != nil {
		panic(err)
	}
}

// Load initializes the given pointer of struct s with configuration from the
// default sources. The order of load is LoadFile, LoadEnv and lastly LoadFlag.
// An error in any step stops the loading process. Each step overrides the
// previous step's config (i.e: defining a flag will override previous
// environment or file config). To customize the order use the individual load
// functions.
func (c *Config) Load(conf interface{}) error {
	if !structs.IsStruct(conf) {
		return fmt.Errorf("passed configuration is not a struct: %T", conf)
	}

	// Initialize struct from the config path.
	if err := c.LoadFile(conf); err != nil {
		// Means it its initialzed with New()
		if err != errPathNotSet {
			return err
		}
	}

	// If any environment variable is available override it.
	if err := c.LoadEnv(conf); err != nil {
		return err
	}

	// Finally check if any flag is defined, which overrides the field again
	if err := c.LoadFlag(conf); err != nil {
		return err
	}

	return nil
}

// LoadFile sets the fields of the given s struct by reading from the given path.
func (c *Config) LoadFile(s interface{}) error {
	// Initialize struct from the config path.
	if c.Path == "" {
		return errPathNotSet
	}

	if strings.HasSuffix(c.Path, "toml") {
		if _, err := toml.DecodeFile(c.Path, s); err != nil {
			return err
		}

		return nil
	}

	if strings.HasSuffix(c.Path, "json") {
		file, err := ioutil.ReadFile(c.Path)
		if err != nil {
			return err
		}

		if err := json.Unmarshal(file, s); err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("file format is not supported: %s. Want TOML or JSON.", c.Path)
}

// LoadEnv sets the fields of the given s struct by looking for environment
// variables in the form of STRUCTNAME_FIELDNAME.
func (c *Config) LoadEnv(s interface{}) error {
	strct := structs.New(s)
	strctName := strct.Name()

	for _, field := range strct.Fields() {
		envName := strings.ToUpper(strctName) + "_" + strings.ToUpper(field.Name())

		v := os.Getenv(envName)
		if v == "" {
			continue
		}

		if err := fieldSet(field, v); err != nil {
			return err
		}
	}

	return nil
}

func (c *Config) printEnvs(s interface{}) {
	strct := structs.New(s)
	strctName := strct.Name()

	for _, field := range strct.Fields() {
		envName := strings.ToUpper(strctName) + "_" + strings.ToUpper(field.Name())
		fmt.Println("  ", envName)
	}
}

// LoadFlag creates on the fly flags based on the field names and parses them to
// load into the given pointer of struct s.
func (c *Config) LoadFlag(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	f := flag.NewFlagSet(structName, flag.ExitOnError)
	// f.SetOutput(ioutil.Discard)

	for _, field := range strct.Fields() {
		name := field.Name()

		f.Var(newFieldValue(field), flagName(name), flagUsage(name))
	}

	f.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		f.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		c.printEnvs(s)
		fmt.Println("")
	}

	return f.Parse(os.Args[1:])
}

// fieldSet sets field value from the given string value. It converts the
// string value in a sane way and is usefulf or environment variables or flags
// which are by nature in string types.
func fieldSet(field *structs.Field, v string) error {
	// TODO: add support for other types
	switch field.Kind() {
	case reflect.Bool:
		val, err := strconv.ParseBool(v)
		if err != nil {
			return err
		}

		if err := field.Set(val); err != nil {
			return err
		}
	case reflect.Int:
		i, err := strconv.Atoi(v)
		if err != nil {
			return err
		}

		if err := field.Set(i); err != nil {
			return err
		}
	case reflect.String:
		field.Set(v)
	case reflect.Slice:
		if _, ok := field.Value().([]string); !ok {
			errors.New("can't set on non string slices")
		}

		if err := field.Set(strings.Split(v, ",")); err != nil {
			return err
		}
	case reflect.Float64:
		f, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return err
		}

		if err := field.Set(f); err != nil {
			return err
		}
	default:
		return fmt.Errorf("multiconfig: not supported type: %s", field.Kind())
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<|endoftext|>


<commit_before>package filestore

import (
	"context"

	"github.com/ipfs/go-ipfs/blocks"
	"github.com/ipfs/go-ipfs/blocks/blockstore"
	posinfo "github.com/ipfs/go-ipfs/thirdparty/posinfo"

	logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
	cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
)

var log = logging.Logger("filestore")

type Filestore struct {
	fm *FileManager
	bs blockstore.Blockstore
}

func NewFilestore(bs blockstore.Blockstore, fm *FileManager) *Filestore {
	return &Filestore{fm, bs}
}

func (f *Filestore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
	ctx, cancel := context.WithCancel(ctx)

	a, err := f.bs.AllKeysChan(ctx)
	if err != nil {
		return nil, err
	}

	out := make(chan *cid.Cid)
	go func() {
		defer cancel()
		defer close(out)

		var done bool
		for !done {
			select {
			case c, ok := <-a:
				if !ok {
					done = true
					continue
				}
				select {
				case out <- c:
				case <-ctx.Done():
					return
				}
			case <-ctx.Done():
				return
			}
		}

		// Can't do these at the same time because the abstractions around
		// leveldb make us query leveldb for both operations. We apparently
		// cant query leveldb concurrently
		b, err := f.fm.AllKeysChan(ctx)
		if err != nil {
			log.Error("error querying filestore: ", err)
			return
		}

		done = false
		for !done {
			select {
			case c, ok := <-b:
				if !ok {
					done = true
					continue
				}
				select {
				case out <- c:
				case <-ctx.Done():
					return
				}
			case <-ctx.Done():
				return
			}
		}
	}()
	return out, nil
}

func (f *Filestore) DeleteBlock(c *cid.Cid) error {
	err1 := f.bs.DeleteBlock(c)
	if err1 != nil && err1 != blockstore.ErrNotFound {
		return err1
	}

	if err2 := f.fm.DeleteBlock(c); err2 != nil {
		// if we successfully removed something from the blockstore, but the
		// filestore didnt have it, return success
		if err1 == nil && err2 != blockstore.ErrNotFound {
			return nil
		}
		return err2
	}

	return nil
}

func (f *Filestore) Get(c *cid.Cid) (blocks.Block, error) {
	blk, err := f.bs.Get(c)
	switch err {
	default:
		return nil, err
	case nil:
		return blk, nil
	case blockstore.ErrNotFound:
		// try filestore
	}

	return f.fm.Get(c)
}

func (f *Filestore) Has(c *cid.Cid) (bool, error) {
	has, err := f.bs.Has(c)
	if err != nil {
		return false, err
	}

	if has {
		return true, nil
	}

	return f.fm.Has(c)
}

func (f *Filestore) Put(b blocks.Block) error {
	switch b := b.(type) {
	case *posinfo.FilestoreNode:
		return f.fm.Put(b)
	default:
		return f.bs.Put(b)
	}
}

func (f *Filestore) PutMany(bs []blocks.Block) error {
	var normals []blocks.Block
	var fstores []*posinfo.FilestoreNode

	for _, b := range bs {
		switch b := b.(type) {
		case *posinfo.FilestoreNode:
			fstores = append(fstores, b)
		default:
			normals = append(normals, b)
		}
	}

	if len(normals) > 0 {
		err := f.bs.PutMany(normals)
		if err != nil {
			return err
		}
	}

	if len(fstores) > 0 {
		err := f.fm.PutMany(fstores)
		if err != nil {
			return err
		}
	}
	return nil
}

var _ blockstore.Blockstore = (*Filestore)(nil)
<commit_msg>skip putting blocks we already have<commit_after>package filestore

import (
	"context"

	"github.com/ipfs/go-ipfs/blocks"
	"github.com/ipfs/go-ipfs/blocks/blockstore"
	posinfo "github.com/ipfs/go-ipfs/thirdparty/posinfo"

	logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
	cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
)

var log = logging.Logger("filestore")

type Filestore struct {
	fm *FileManager
	bs blockstore.Blockstore
}

func NewFilestore(bs blockstore.Blockstore, fm *FileManager) *Filestore {
	return &Filestore{fm, bs}
}

func (f *Filestore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
	ctx, cancel := context.WithCancel(ctx)

	a, err := f.bs.AllKeysChan(ctx)
	if err != nil {
		return nil, err
	}

	out := make(chan *cid.Cid)
	go func() {
		defer cancel()
		defer close(out)

		var done bool
		for !done {
			select {
			case c, ok := <-a:
				if !ok {
					done = true
					continue
				}
				select {
				case out <- c:
				case <-ctx.Done():
					return
				}
			case <-ctx.Done():
				return
			}
		}

		// Can't do these at the same time because the abstractions around
		// leveldb make us query leveldb for both operations. We apparently
		// cant query leveldb concurrently
		b, err := f.fm.AllKeysChan(ctx)
		if err != nil {
			log.Error("error querying filestore: ", err)
			return
		}

		done = false
		for !done {
			select {
			case c, ok := <-b:
				if !ok {
					done = true
					continue
				}
				select {
				case out <- c:
				case <-ctx.Done():
					return
				}
			case <-ctx.Done():
				return
			}
		}
	}()
	return out, nil
}

func (f *Filestore) DeleteBlock(c *cid.Cid) error {
	err1 := f.bs.DeleteBlock(c)
	if err1 != nil && err1 != blockstore.ErrNotFound {
		return err1
	}

	if err2 := f.fm.DeleteBlock(c); err2 != nil {
		// if we successfully removed something from the blockstore, but the
		// filestore didnt have it, return success
		if err1 == nil && err2 != blockstore.ErrNotFound {
			return nil
		}
		return err2
	}

	return nil
}

func (f *Filestore) Get(c *cid.Cid) (blocks.Block, error) {
	blk, err := f.bs.Get(c)
	switch err {
	default:
		return nil, err
	case nil:
		return blk, nil
	case blockstore.ErrNotFound:
		// try filestore
	}

	return f.fm.Get(c)
}

func (f *Filestore) Has(c *cid.Cid) (bool, error) {
	has, err := f.bs.Has(c)
	if err != nil {
		return false, err
	}

	if has {
		return true, nil
	}

	return f.fm.Has(c)
}

func (f *Filestore) Put(b blocks.Block) error {
	has, err := f.Has(b.Cid())
	if err != nil {
		return err
	}

	if has {
		return nil
	}

	switch b := b.(type) {
	case *posinfo.FilestoreNode:
		return f.fm.Put(b)
	default:
		return f.bs.Put(b)
	}
}

func (f *Filestore) PutMany(bs []blocks.Block) error {
	var normals []blocks.Block
	var fstores []*posinfo.FilestoreNode

	for _, b := range bs {
		has, err := f.Has(b.Cid())
		if err != nil {
			return err
		}

		if has {
			continue
		}

		switch b := b.(type) {
		case *posinfo.FilestoreNode:
			fstores = append(fstores, b)
		default:
			normals = append(normals, b)
		}
	}

	if len(normals) > 0 {
		err := f.bs.PutMany(normals)
		if err != nil {
			return err
		}
	}

	if len(fstores) > 0 {
		err := f.fm.PutMany(fstores)
		if err != nil {
			return err
		}
	}
	return nil
}

var _ blockstore.Blockstore = (*Filestore)(nil)
<|endoftext|>