<commit_before>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their JavaScript syntax.
//
// Type conversions between Go types and JavaScript types are performed automatically according to the following table:
//
//  | Go types                       | Go interface type              | JavaScript type |
//  | ------------------------------ | ------------------------------ | --------------- |
//  | bool                           | bool                           | Boolean         |
//  | int?, uint?, float?            | float64                        | Number          |
//  | string                         | string                         | String          |
//  | [?]int8                        | []int8                         | Int8Array       |
//  | [?]int16                       | []int16                        | Int16Array      |
//  | [?]int32, [?]int               | []int                          | Int32Array      |
//  | [?]uint8                       | []uint8                        | Uint8Array      |
//  | [?]uint16                      | []uint16                       | Uint16Array     |
//  | [?]uint32, [?]uint, [?]uintptr | []uint                         | Uint32Array     |
//  | [?]float32                     | []float32                      | Float32Array    |
//  | [?]float64                     | []float64                      | Float64Array    |
//  | all other slices and arrays    | []interface{}                  | Array           |
//  | maps, structs                  | map[string]interface{}         | Object          |
//  | functions                      | func(...interface{}) js.Object | Function        |
//  | time.Time                      | time.Time                      | Date            |
//
// The second column denotes the types that are used when converting to `interface{}`. An exception are DOM elements, those are kept with the js.Object type. Additionally, a pointer to a named type is passed to JavaScript as an object which has wrappers for the type's exported methods. This can be used to provide getter and setter methods for Go fields to JavaScript.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. Nil is equal to JavaScript's "null".
// Object can not be used as a map key and it can only be converted to Any, but no other interface type, including interface{}. This means that you can't pass an Object obj to fmt.Println(obj), but using the println(obj) built-in is possible.
type Object interface {

	// Get returns the object's property with the given key.
	Get(key string) Object

	// Set assigns the value to the object's property with the given key.
	Set(key string, value Any)

	// Delete removes the object's property with the given key.
	Delete(key string)

	// Get returns the object's "length" property, converted to int.
	Length() int

	// Index returns the i'th element of an array.
	Index(i int) Object

	// SetIndex sets the i'th element of an array.
	SetIndex(i int, value Any)

	// Call calls the object's method with the given name.
	Call(name string, args ...Any) Object

	// Invoke calls the object itself. This will fail if it is not a function.
	Invoke(args ...Any) Object

	// New creates a new instance of this type object. This will fail if it not a function (constructor).
	New(args ...Any) Object

	// Bool returns the object converted to bool according to JavaScript type conversions.
	Bool() bool

	// String returns the object converted to string according to JavaScript type conversions.
	String() string

	// Int returns the object converted to int according to JavaScript type conversions (parseInt).
	Int() int

	// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
	Int64() int64

	// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
	Uint64() uint64

	// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
	Float() float64

	// Interface returns the object converted to interface{}. See GopherJS' README for details.
	Interface() interface{}

	// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
	Unsafe() uintptr
}

// Any may contain a JavaScript object or some Go value. Any can not be used as a map key and it can not be converted to some other interface type, including interface{}.
type Any interface{}

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be rescued, giving an *Error that holds the JavaScript error object.
type Error struct {
	Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").String()
}

// Stack returns the stack property of the encapsulated JavaScript error object.
func (err *Error) Stack() string {
	return err.Get("stack").String()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js). Set this to a mock for testing with pure Go.
var Global Object

// This gives the value of JavaScript's "this" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var This Object

// Arguments gives the value of JavaScript's "arguments" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var Arguments []Object

// Module gives the value of the "module" variable set by Node.js. Hint: Set a module export with 'js.Module.Get("exports").Set("exportName", ...)'.
var Module Object

// Undefined gives the JavaScript value "undefined".
var Undefined Object

// Debugger gets compiled to JavaScript's "debugger;" statement.
func Debugger() {}

// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) Object {
	return nil
}

// Keys returns the keys of the given JavaScript object.
func Keys(o Object) []string {
	if o == Undefined || o == nil {
		return nil
	}
	a := Global.Get("Object").Call("keys", o)
	s := make([]string, a.Length())
	for i := 0; i < a.Length(); i++ {
		s[i] = a.Index(i).String()
	}
	return s
}

// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
type M map[string]Any

// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
type S []Any

func init() {
	// avoid dead code elimination of Error
	e := Error{}
	_ = e
}
<commit_msg>improved doc of js package<commit_after>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their corresponding JavaScript syntax.
// The types Object and Any are containers for JavaScript objects and are no real citizens of the Go world, e.g. they do not implement interface{} and you cannot type assert them. The type Any may also contain Go values, but it provides no methods for accessing its content. It is only useful for passing it to functions of this package. The relation between interface{} (Go world), Object (JS world) and Any looks like this:
//
//  +------------------------------------+
//  |                                    |
//  |  +-------------+  +-------------+  |
//  |  |             |  |             |  |
//  |  | interface{} |  |  js.Object  |  |
//  |  |             |  |             |  |
//  |  +-------------+  +-------------+  |
//  |                                    |
//  |               js.Any               |
//  |                                    |
//  +------------------------------------+
//
// Type conversions between Go types and JavaScript types are performed automatically according to the following table:
//
//  | Go types                       | Go interface type              | JavaScript type |
//  | ------------------------------ | ------------------------------ | --------------- |
//  | bool                           | bool                           | Boolean         |
//  | int?, uint?, float?            | float64                        | Number          |
//  | string                         | string                         | String          |
//  | [?]int8                        | []int8                         | Int8Array       |
//  | [?]int16                       | []int16                        | Int16Array      |
//  | [?]int32, [?]int               | []int                          | Int32Array      |
//  | [?]uint8                       | []uint8                        | Uint8Array      |
//  | [?]uint16                      | []uint16                       | Uint16Array     |
//  | [?]uint32, [?]uint, [?]uintptr | []uint                         | Uint32Array     |
//  | [?]float32                     | []float32                      | Float32Array    |
//  | [?]float64                     | []float64                      | Float64Array    |
//  | all other slices and arrays    | []interface{}                  | Array           |
//  | maps, structs                  | map[string]interface{}         | Object          |
//  | functions                      | func(...interface{}) js.Object | Function        |
//  | time.Time                      | time.Time                      | Date            |
//
// The second column denotes the types that are used when converting to `interface{}`. An exception are DOM elements, those are kept with the js.Object type. Additionally, a pointer to a named type is passed to JavaScript as an object which has wrappers for the type's exported methods. This can be used to provide getter and setter methods for Go fields to JavaScript.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. Nil is equal to JavaScript's "null".
// Object can not be used as a map key and it can only be converted to Any, but no other interface type, including interface{}. This means that you can't pass an Object obj to fmt.Println(obj), but using the println(obj) built-in is possible.
type Object interface {

	// Get returns the object's property with the given key.
	Get(key string) Object

	// Set assigns the value to the object's property with the given key.
	Set(key string, value Any)

	// Delete removes the object's property with the given key.
	Delete(key string)

	// Get returns the object's "length" property, converted to int.
	Length() int

	// Index returns the i'th element of an array.
	Index(i int) Object

	// SetIndex sets the i'th element of an array.
	SetIndex(i int, value Any)

	// Call calls the object's method with the given name.
	Call(name string, args ...Any) Object

	// Invoke calls the object itself. This will fail if it is not a function.
	Invoke(args ...Any) Object

	// New creates a new instance of this type object. This will fail if it not a function (constructor).
	New(args ...Any) Object

	// Bool returns the object converted to bool according to JavaScript type conversions.
	Bool() bool

	// String returns the object converted to string according to JavaScript type conversions.
	String() string

	// Int returns the object converted to int according to JavaScript type conversions (parseInt).
	Int() int

	// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
	Int64() int64

	// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
	Uint64() uint64

	// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
	Float() float64

	// Interface returns the object converted to interface{}. See GopherJS' README for details.
	Interface() interface{}

	// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
	Unsafe() uintptr
}

// Any may contain a JavaScript object or some Go value. Any can not be used as a map key and it can not be converted to some other interface type, including interface{}.
type Any interface{}

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be rescued, giving an *Error that holds the JavaScript error object.
type Error struct {
	Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").String()
}

// Stack returns the stack property of the encapsulated JavaScript error object.
func (err *Error) Stack() string {
	return err.Get("stack").String()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js). Set this to a mock for testing with pure Go.
var Global Object

// This gives the value of JavaScript's "this" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var This Object

// Arguments gives the value of JavaScript's "arguments" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var Arguments []Object

// Module gives the value of the "module" variable set by Node.js. Hint: Set a module export with 'js.Module.Get("exports").Set("exportName", ...)'.
var Module Object

// Undefined gives the JavaScript value "undefined".
var Undefined Object

// Debugger gets compiled to JavaScript's "debugger;" statement.
func Debugger() {}

// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) Object {
	return nil
}

// Keys returns the keys of the given JavaScript object.
func Keys(o Object) []string {
	if o == Undefined || o == nil {
		return nil
	}
	a := Global.Get("Object").Call("keys", o)
	s := make([]string, a.Length())
	for i := 0; i < a.Length(); i++ {
		s[i] = a.Index(i).String()
	}
	return s
}

// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
type M map[string]Any

// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
type S []Any

func init() {
	// avoid dead code elimination of Error
	e := Error{}
	_ = e
}
<|endoftext|>


<commit_before>// Copyright 2009 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 net

import (
	"context"
	"syscall"
)

// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgUDP and
// WriteMsgUDP methods of UDPConn are not implemented.

// BUG(mikio): On Windows, the File method of UDPConn is not
// implemented.

// BUG(mikio): On NaCl the ListenMulticastUDP function is
// not implemented.

// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
	IP   IP
	Port int
	Zone string // IPv6 scoped addressing zone
}

// Network returns the address's network name, "udp".
func (a *UDPAddr) Network() string { return "udp" }

func (a *UDPAddr) String() string {
	if a == nil {
		return "<nil>"
	}
	ip := ipEmptyString(a.IP)
	if a.Zone != "" {
		return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port))
	}
	return JoinHostPort(ip, itoa(a.Port))
}

func (a *UDPAddr) isWildcard() bool {
	if a == nil || a.IP == nil {
		return true
	}
	return a.IP.IsUnspecified()
}

func (a *UDPAddr) opAddr() Addr {
	if a == nil {
		return nil
	}
	return a
}

// ResolveUDPAddr parses addr as a UDP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "udp", "udp4" or
// "udp6".  A literal address or host name for IPv6 must be enclosed
// in square brackets, as in "[::1]:80", "[ipv6-host]:http" or
// "[ipv6-host%zone]:80".
//
// Resolving a hostname is not recommended because this returns at most
// one of its IP addresses.
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
	switch net {
	case "udp", "udp4", "udp6":
	case "": // a hint wildcard for Go 1.0 undocumented behavior
		net = "udp"
	default:
		return nil, UnknownNetworkError(net)
	}
	addrs, err := DefaultResolver.internetAddrList(context.Background(), net, addr)
	if err != nil {
		return nil, err
	}
	return addrs.first(isIPv4).(*UDPAddr), nil
}

// UDPConn is the implementation of the Conn and PacketConn interfaces
// for UDP network connections.
type UDPConn struct {
	conn
}

// ReadFromUDP reads a UDP packet from c, copying the payload into b.
// It returns the number of bytes copied into b and the return address
// that was on the packet.
//
// ReadFromUDP can be made to time out and return an error with
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
	if !c.ok() {
		return 0, nil, syscall.EINVAL
	}
	n, addr, err := c.readFrom(b)
	if err != nil {
		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return n, addr, err
}

// ReadFrom implements the PacketConn ReadFrom method.
func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
	if !c.ok() {
		return 0, nil, syscall.EINVAL
	}
	n, addr, err := c.readFrom(b)
	if err != nil {
		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	if addr == nil {
		return n, nil, err
	}
	return n, addr, err
}

// ReadMsgUDP reads a packet from c, copying the payload into b and
// the associated out-of-band data into oob. It returns the number
// of bytes copied into b, the number of bytes copied into oob, the
// flags that were set on the packet and the source address of the
// packet.
func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
	if !c.ok() {
		return 0, 0, 0, nil, syscall.EINVAL
	}
	n, oobn, flags, addr, err = c.readMsg(b, oob)
	if err != nil {
		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return
}

// WriteToUDP writes a UDP packet to addr via c, copying the payload
// from b.
//
// WriteToUDP can be made to time out and return an error with
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetWriteDeadline. On packet-oriented connections, write timeouts
// are rare.
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	n, err := c.writeTo(b, addr)
	if err != nil {
		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
	}
	return n, err
}

// WriteTo implements the PacketConn WriteTo method.
func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	a, ok := addr.(*UDPAddr)
	if !ok {
		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
	}
	n, err := c.writeTo(b, a)
	if err != nil {
		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
	}
	return n, err
}

// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
// to c's remote destination address if c is connected (in which case
// addr must be nil).  The payload is copied from b and the associated
// out-of-band data is copied from oob. It returns the number of
// payload and out-of-band bytes written.
func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
	if !c.ok() {
		return 0, 0, syscall.EINVAL
	}
	n, oobn, err = c.writeMsg(b, oob, addr)
	if err != nil {
		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
	}
	return
}

func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }

// DialUDP connects to the remote address raddr on the network net,
// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is
// used as the local address for the connection.
func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
	switch net {
	case "udp", "udp4", "udp6":
	default:
		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
	}
	if raddr == nil {
		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
	}
	c, err := dialUDP(context.Background(), net, laddr, raddr)
	if err != nil {
		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
	}
	return c, nil
}

// ListenUDP listens for incoming UDP packets addressed to the local
// address laddr. Net must be "udp", "udp4", or "udp6".  If laddr has
// a port of 0, ListenUDP will choose an available port.
// The LocalAddr method of the returned UDPConn can be used to
// discover the port. The returned connection's ReadFrom and WriteTo
// methods can be used to receive and send UDP packets with per-packet
// addressing.
func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
	switch net {
	case "udp", "udp4", "udp6":
	default:
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
	}
	if laddr == nil {
		laddr = &UDPAddr{}
	}
	c, err := listenUDP(context.Background(), net, laddr)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
	}
	return c, nil
}

// ListenMulticastUDP listens for incoming multicast UDP packets
// addressed to the group address gaddr on the interface ifi.
// Network must be "udp", "udp4" or "udp6".
// ListenMulticastUDP uses the system-assigned multicast interface
// when ifi is nil, although this is not recommended because the
// assignment depends on platforms and sometimes it might require
// routing configuration.
//
// ListenMulticastUDP is just for convenience of simple, small
// applications. There are golang.org/x/net/ipv4 and
// golang.org/x/net/ipv6 packages for general purpose uses.
func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
	switch network {
	case "udp", "udp4", "udp6":
	default:
		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
	}
	if gaddr == nil || gaddr.IP == nil {
		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
	}
	c, err := listenMulticastUDP(context.Background(), network, ifi, gaddr)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: err}
	}
	return c, nil
}
<commit_msg>net: add missing comma on BUGS section for consistency<commit_after>// Copyright 2009 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 net

import (
	"context"
	"syscall"
)

// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgUDP and
// WriteMsgUDP methods of UDPConn are not implemented.

// BUG(mikio): On Windows, the File method of UDPConn is not
// implemented.

// BUG(mikio): On NaCl, the ListenMulticastUDP function is not
// implemented.

// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
	IP   IP
	Port int
	Zone string // IPv6 scoped addressing zone
}

// Network returns the address's network name, "udp".
func (a *UDPAddr) Network() string { return "udp" }

func (a *UDPAddr) String() string {
	if a == nil {
		return "<nil>"
	}
	ip := ipEmptyString(a.IP)
	if a.Zone != "" {
		return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port))
	}
	return JoinHostPort(ip, itoa(a.Port))
}

func (a *UDPAddr) isWildcard() bool {
	if a == nil || a.IP == nil {
		return true
	}
	return a.IP.IsUnspecified()
}

func (a *UDPAddr) opAddr() Addr {
	if a == nil {
		return nil
	}
	return a
}

// ResolveUDPAddr parses addr as a UDP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "udp", "udp4" or
// "udp6".  A literal address or host name for IPv6 must be enclosed
// in square brackets, as in "[::1]:80", "[ipv6-host]:http" or
// "[ipv6-host%zone]:80".
//
// Resolving a hostname is not recommended because this returns at most
// one of its IP addresses.
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
	switch net {
	case "udp", "udp4", "udp6":
	case "": // a hint wildcard for Go 1.0 undocumented behavior
		net = "udp"
	default:
		return nil, UnknownNetworkError(net)
	}
	addrs, err := DefaultResolver.internetAddrList(context.Background(), net, addr)
	if err != nil {
		return nil, err
	}
	return addrs.first(isIPv4).(*UDPAddr), nil
}

// UDPConn is the implementation of the Conn and PacketConn interfaces
// for UDP network connections.
type UDPConn struct {
	conn
}

// ReadFromUDP reads a UDP packet from c, copying the payload into b.
// It returns the number of bytes copied into b and the return address
// that was on the packet.
//
// ReadFromUDP can be made to time out and return an error with
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
	if !c.ok() {
		return 0, nil, syscall.EINVAL
	}
	n, addr, err := c.readFrom(b)
	if err != nil {
		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return n, addr, err
}

// ReadFrom implements the PacketConn ReadFrom method.
func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
	if !c.ok() {
		return 0, nil, syscall.EINVAL
	}
	n, addr, err := c.readFrom(b)
	if err != nil {
		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	if addr == nil {
		return n, nil, err
	}
	return n, addr, err
}

// ReadMsgUDP reads a packet from c, copying the payload into b and
// the associated out-of-band data into oob. It returns the number
// of bytes copied into b, the number of bytes copied into oob, the
// flags that were set on the packet and the source address of the
// packet.
func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
	if !c.ok() {
		return 0, 0, 0, nil, syscall.EINVAL
	}
	n, oobn, flags, addr, err = c.readMsg(b, oob)
	if err != nil {
		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return
}

// WriteToUDP writes a UDP packet to addr via c, copying the payload
// from b.
//
// WriteToUDP can be made to time out and return an error with
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetWriteDeadline. On packet-oriented connections, write timeouts
// are rare.
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	n, err := c.writeTo(b, addr)
	if err != nil {
		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
	}
	return n, err
}

// WriteTo implements the PacketConn WriteTo method.
func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	a, ok := addr.(*UDPAddr)
	if !ok {
		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
	}
	n, err := c.writeTo(b, a)
	if err != nil {
		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
	}
	return n, err
}

// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
// to c's remote destination address if c is connected (in which case
// addr must be nil).  The payload is copied from b and the associated
// out-of-band data is copied from oob. It returns the number of
// payload and out-of-band bytes written.
func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
	if !c.ok() {
		return 0, 0, syscall.EINVAL
	}
	n, oobn, err = c.writeMsg(b, oob, addr)
	if err != nil {
		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
	}
	return
}

func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }

// DialUDP connects to the remote address raddr on the network net,
// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is
// used as the local address for the connection.
func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
	switch net {
	case "udp", "udp4", "udp6":
	default:
		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
	}
	if raddr == nil {
		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
	}
	c, err := dialUDP(context.Background(), net, laddr, raddr)
	if err != nil {
		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
	}
	return c, nil
}

// ListenUDP listens for incoming UDP packets addressed to the local
// address laddr. Net must be "udp", "udp4", or "udp6".  If laddr has
// a port of 0, ListenUDP will choose an available port.
// The LocalAddr method of the returned UDPConn can be used to
// discover the port. The returned connection's ReadFrom and WriteTo
// methods can be used to receive and send UDP packets with per-packet
// addressing.
func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
	switch net {
	case "udp", "udp4", "udp6":
	default:
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
	}
	if laddr == nil {
		laddr = &UDPAddr{}
	}
	c, err := listenUDP(context.Background(), net, laddr)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
	}
	return c, nil
}

// ListenMulticastUDP listens for incoming multicast UDP packets
// addressed to the group address gaddr on the interface ifi.
// Network must be "udp", "udp4" or "udp6".
// ListenMulticastUDP uses the system-assigned multicast interface
// when ifi is nil, although this is not recommended because the
// assignment depends on platforms and sometimes it might require
// routing configuration.
//
// ListenMulticastUDP is just for convenience of simple, small
// applications. There are golang.org/x/net/ipv4 and
// golang.org/x/net/ipv6 packages for general purpose uses.
func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
	switch network {
	case "udp", "udp4", "udp6":
	default:
		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
	}
	if gaddr == nil || gaddr.IP == nil {
		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
	}
	c, err := listenMulticastUDP(context.Background(), network, ifi, gaddr)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: err}
	}
	return c, nil
}
<|endoftext|>


<commit_before>// 封装了tcp网关的操作
// 其实是实现了接口imodule
package gateway

import (
	"fmt"
	"lib/network"
	"lib/network/protobuff"
	"lib/util"
	"net"
	"time"
)

// 定义网关结构体
type Gate struct {
	MaxConnNum       int              // 允许的最大的连接数
	PendingNum       int              // 最大发送队列长度（server -> client）
	MaxMsgLen        int              // 允许的最大的消息长度
	MessageProcessor network.Imessage // 用于消息体的处理

	ServerAddress string // tcp服务地址
	LenMsgLen     int    // tcp消息长度

	WsServerAddress string        // websocket服务地址
	HTTPTimeout     time.Duration // http超时时间
	CertFile        string        // wws
	KeyFile         string        // wws
}

type Agent struct {
	Conn     network.Iconn // 套接字套作接口
	Gate     *Gate         // 网关配置数据
	UserData interface{}   // 用户数据
}

// tcp服务器
var tcpServer *network.TcpServer

// ws服务器
var wsServer *network.WsServer

/***************************实现imodule接口*******************************/

// 启动网关
func (gate *Gate) Run(chClose chan bool) {
	switch {
	case tcpServer != nil:
		tcpServer.Start()
		<-chClose
		tcpServer.Close()
	case wsServer != nil:
		wsServer.Start()
		<-chClose
		wsServer.Close()
	}
}

// 初始化
func (gate *Gate) OnInit() {
	if gate == nil {
		fmt.Println("tcp_gateway run failed, because gate is nil")
		return
	}
	switch {
	case gate.ServerAddress != "":
		tcpServer = new(network.TcpServer)
		tcpServer.ServerAddress = gate.ServerAddress
		tcpServer.MaxConnNum = gate.MaxConnNum
		tcpServer.PendingNum = gate.PendingNum
		tcpServer.Agent = func(conn *network.Conn) network.Iagent {
			fmt.Println("NewAgent:", util.GetPid())
			arg := &Agent{Conn: conn, Gate: gate}
			return arg
		}
	case gate.WsServerAddress != "":
		wsServer = new(network.WsServer)
		wsServer.ServerAddress = gate.WsServerAddress
		wsServer.MaxConnNum = gate.MaxConnNum
		wsServer.MaxMsgLen = gate.MaxMsgLen
		wsServer.PendingNum = gate.PendingNum
		wsServer.HTTPTimeout = gate.HTTPTimeout
		wsServer.CertFile = gate.CertFile
		wsServer.KeyFile = gate.KeyFile
		wsServer.Agent = func(conn *network.WsConn) network.Iagent {
			arg := &Agent{Conn: conn, Gate: gate}
			return arg
		}
	}
}

// 资源回收
func (gate *Gate) OnDestroy() {
	fmt.Println("网关销毁中")
}

/****************************实现了Iagent接口**********************************/

func (agent *Agent) Run() {
	fmt.Println("客户端代理执行的run函数:", util.GetPid())
	if agent.Gate == nil {
		fmt.Println("Run params is nil")
		return
	}
	for {
		// 读取消息
		msg, err := agent.Conn.ReadMsg()
		if err != nil {
			fmt.Println(err)
			break
		}
		if agent.Gate.MessageProcessor != nil {
			// 反序列化
			realMsg, errs := agent.Gate.MessageProcessor.Deserialize(msg)
			if errs != nil {
				fmt.Println(errs)
				break
			}
			// 消息路由
			if err := agent.Gate.MessageProcessor.Router(realMsg, agent); err != nil {
				fmt.Println("msg route err:", err)
				break
			}
		}
	}
}

func (agent *Agent) OnClose() {
	fmt.Println("代理被销毁")
}

/****************************实现了Igateway接口**********************************/

func (agent *Agent) WriteMsg(msg protobuff.RawMessage) {
	if agent.Gate.MessageProcessor != nil {
		data, err := agent.Gate.MessageProcessor.Serialize(msg)
		if err != nil {
			fmt.Println(err)
			return
		}
		err = agent.Conn.WriteMsg(data...)
		if err != nil {
			fmt.Printf("write message %v error: %v \n", msg.MsgId, err)
		}
	}
}

func (agent *Agent) LocalAddr() net.Addr {
	if agent.Conn != nil {
		return agent.Conn.LocalAddr()
	}
	return nil
}
func (agent *Agent) RemoteAddr() net.Addr {
	if agent.Conn != nil {
		return agent.Conn.RemoteAddr()
	}
	return nil
}
func (agent *Agent) Close() {
	if agent.Conn != nil {
		agent.Conn.Close()
	}
}
func (agent *Agent) Destroy() {
	if agent.Conn != nil {
		agent.Conn.Destroy()
	}
}
func (agent *Agent) GetUserData() interface{} {
	return agent.UserData
}
func (agent *Agent) SetUserData(data interface{}) {

}
<commit_msg>update gateway.go<commit_after>// 封装了网关的操作
package gateway

import (
	"fmt"
	"lib/network"
	"lib/network/protobuff"
	"lib/util"
	"net"
	"time"
)

// 定义网关结构体
type Gate struct {
	MaxConnNum       int              // 允许的最大的连接数
	PendingNum       int              // 最大发送队列长度（server -> client）
	MaxMsgLen        int              // 允许的最大的消息长度
	MessageProcessor network.Imessage // 用于消息体的处理

	ServerAddress string // tcp服务地址
	LenMsgLen     int    // tcp消息长度

	WsServerAddress string        // websocket服务地址
	HTTPTimeout     time.Duration // http超时时间
	CertFile        string        // wws
	KeyFile         string        // wws
}

type Agent struct {
	Conn     network.Iconn // 套接字套作接口
	Gate     *Gate         // 网关配置数据
	UserData interface{}   // 用户数据
}

// tcp服务器
var tcpServer *network.TcpServer

// ws服务器
var wsServer *network.WsServer

/***************************实现imodule接口*******************************/

// 启动网关
func (gate *Gate) Run(chClose chan bool) {
	switch {
	case tcpServer != nil:
		tcpServer.Start()
		<-chClose
		tcpServer.Close()
	case wsServer != nil:
		wsServer.Start()
		<-chClose
		wsServer.Close()
	}
}

// 初始化
func (gate *Gate) OnInit() {
	if gate == nil {
		fmt.Println("tcp_gateway run failed, because gate is nil")
		return
	}
	switch {
	case gate.ServerAddress != "":
		tcpServer = new(network.TcpServer)
		tcpServer.ServerAddress = gate.ServerAddress
		tcpServer.MaxConnNum = gate.MaxConnNum
		tcpServer.PendingNum = gate.PendingNum
		tcpServer.Agent = func(conn *network.Conn) network.Iagent {
			fmt.Println("NewAgent:", util.GetPid())
			arg := &Agent{Conn: conn, Gate: gate}
			return arg
		}
	case gate.WsServerAddress != "":
		wsServer = new(network.WsServer)
		wsServer.ServerAddress = gate.WsServerAddress
		wsServer.MaxConnNum = gate.MaxConnNum
		wsServer.MaxMsgLen = gate.MaxMsgLen
		wsServer.PendingNum = gate.PendingNum
		wsServer.HTTPTimeout = gate.HTTPTimeout
		wsServer.CertFile = gate.CertFile
		wsServer.KeyFile = gate.KeyFile
		wsServer.Agent = func(conn *network.WsConn) network.Iagent {
			arg := &Agent{Conn: conn, Gate: gate}
			return arg
		}
	}
}

// 资源回收
func (gate *Gate) OnDestroy() {
	fmt.Println("网关销毁中")
}

/****************************实现了Iagent接口**********************************/

func (agent *Agent) Run() {
	fmt.Println("客户端代理执行的run函数:", util.GetPid())
	if agent.Gate == nil {
		fmt.Println("Run params is nil")
		return
	}
	for {
		// 读取消息
		msg, err := agent.Conn.ReadMsg()
		if err != nil {
			fmt.Println(err)
			break
		}
		if agent.Gate.MessageProcessor != nil {
			// 反序列化
			realMsg, errs := agent.Gate.MessageProcessor.Deserialize(msg)
			if errs != nil {
				fmt.Println(errs)
				break
			}
			// 消息路由
			if err := agent.Gate.MessageProcessor.Router(realMsg, agent); err != nil {
				fmt.Println("msg route err:", err)
				break
			}
		}
	}
}

func (agent *Agent) OnClose() {
	fmt.Println("代理被销毁")
}

/****************************实现了Igateway接口**********************************/

func (agent *Agent) WriteMsg(msg protobuff.RawMessage) {
	if agent.Gate.MessageProcessor != nil {
		data, err := agent.Gate.MessageProcessor.Serialize(msg)
		if err != nil {
			fmt.Println(err)
			return
		}
		err = agent.Conn.WriteMsg(data...)
		if err != nil {
			fmt.Printf("write message %v error: %v \n", msg.MsgId, err)
		}
	}
}

func (agent *Agent) LocalAddr() net.Addr {
	if agent.Conn != nil {
		return agent.Conn.LocalAddr()
	}
	return nil
}
func (agent *Agent) RemoteAddr() net.Addr {
	if agent.Conn != nil {
		return agent.Conn.RemoteAddr()
	}
	return nil
}
func (agent *Agent) Close() {
	if agent.Conn != nil {
		agent.Conn.Close()
	}
}
func (agent *Agent) Destroy() {
	if agent.Conn != nil {
		agent.Conn.Destroy()
	}
}
func (agent *Agent) GetUserData() interface{} {
	return agent.UserData
}
func (agent *Agent) SetUserData(data interface{}) {

}
<|endoftext|>


<commit_before>package main

/*
TODO
create new keys
add user for key
add admin for key
front end with appache
appache user auth
dockerize
api doc
figure out way to load secrets
encrypt keys in DB
DB backup

*/

import (
        "database/sql"
	_ "github.com/lib/pq"
        "log"
	"os"
	 "html/template"
	"net/http"
	"io"
	"strings"
	"strconv"
)

var db *sql.DB

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

func setupDatabase( hostName string, pgPassword string ) { // todo pass in hostname, port, username
        var err error

        // set up DB
        db, err = sql.Open("postgres", "password='"+pgPassword+"' user=postgres dbname=postgres host="+hostName+" port=5432 sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}

	// a postgess bigint is signed 64 bit int
	sqlSetup := `
        CREATE TABLE IF NOT EXISTS keys ( kID BIGINT NOT NULL, kVal bytea NOT NULL ,  oID BIGINT NOT NULL, PRIMARY KEY( kID ) );
        CREATE TABLE IF NOT EXISTS keyUsers ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        CREATE TABLE IF NOT EXISTS keyAdmins ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        `
        _, err = db.Exec(sqlSetup)
        if err != nil {
                log.Println("sql fatal error in setupDatabase")
                log.Printf("%q\n", err)
        }

	log.Printf("Setup Database\n")
}

func getKey( keyID int64, userID int64 ) (string) {
	// note if using mySQL use ? but Postgres is $1 in prepare statements
	stmt, err := db.Prepare(
		"SELECT keys.kVal  FROM keyUsers JOIN keys ON  keys.kID = keyUsers.kID WHERE keyUsers.uID = $2 AND keyUsers.kID = $1")
	if err != nil {
		log.Println("sql fatal error in getKey prep")
		log.Fatal(err)
	}
	var keyVal string
	err = stmt.QueryRow(keyID,userID).Scan( &keyVal )
	switch {
	case err == sql.ErrNoRows:
            log.Printf("no key found")
	case err != nil:
		log.Println("sql fatal error in getKey querry")
		log.Fatal(err)
	default:
		log.Println("got key " + keyVal)
		return keyVal;
	}
	return "";
}

func createKey(  userID int64, keyVal string ) (int64) {
	var keyID int64 = 104;

	return keyID;
}

func mainHandler(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }

        type PageData struct {
                Junk string
        }
        data := PageData{Junk: "nothing"}
        err := templates.ExecuteTemplate(w, "index.html", data)
        if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
        }
}

func searchKeyHandler(w http.ResponseWriter, r *http.Request) {
	var err error

        w.Header().Set("Access-Control-Allow-Origin", "*")

	log.Println("got URL path " + r.URL.Path )

	elements := strings.Split( r.URL.Path  , "/" );
	// note since the URL starts with a /, we get an empty element as first thing in array

	if len(elements) != 4  {
		http.NotFound(w, r)
                return
	}

	var keyID int64 = 0;
	var userID int64 = 1;

	keyID,err = strconv.ParseInt( elements[3] , 0, 64 );
	if err != nil {
		http.NotFound(w, r)
		return
	}

	log.Println("GET keyID=", keyID, " userID=",userID )

	io.WriteString(w, getKey(keyID,userID) )
}

func createKeyHandler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")

        if r.Method != "POST" {
                http.Error(w, "method must be POST", http.StatusMethodNotAllowed)
                return
        }

	err := r.ParseForm()
        if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
        }

	var keyVal string = r.FormValue("keyVal");
	var userID int64 = 1;

	var keyID int64 = createKey( userID, keyVal );

	log.Println("POST keyID=", keyID, "userID=",userID, "keyVal=",keyVal )

	io.WriteString(w, "{ keyID: " )
	io.WriteString(w, strconv.FormatInt(keyID,10) )
	io.WriteString(w, " }" )
}

func main() {
	var err error

	var pgPassword string = os.Getenv("SECM_DB_SECRET")
	var hostName string = os.Args[1]

	setupDatabase(hostName,pgPassword)
        defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", mainHandler)
	http.HandleFunc("/v1/key/", searchKeyHandler)
	http.HandleFunc("/v1/key", createKeyHandler)

        http.ListenAndServe(":8080", nil)
}
<commit_msg>write key to DB<commit_after>package main

/*
TODO
create new keys
add user for key
add admin for key
front end with appache
appache user auth
dockerize
api doc
figure out way to load secrets
encrypt keys in DB
DB backup

*/

import (
        "database/sql"
	_ "github.com/lib/pq"
        "log"
	"os"
	 "html/template"
	"net/http"
	"io"
	"strings"
	"strconv"
)

var db *sql.DB

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

func setupDatabase( hostName string, pgPassword string ) { // todo pass in hostname, port, username
        var err error

        // set up DB
        db, err = sql.Open("postgres", "password='"+pgPassword+"' user=postgres dbname=postgres host="+hostName+" port=5432 sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}

	// a postgess bigint is signed 64 bit int
	sqlSetup := `
        CREATE TABLE IF NOT EXISTS keys ( kID BIGINT NOT NULL, kVal bytea NOT NULL ,  oID BIGINT NOT NULL, PRIMARY KEY( kID ) );
        CREATE TABLE IF NOT EXISTS keyUsers ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        CREATE TABLE IF NOT EXISTS keyAdmins ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        `
        _, err = db.Exec(sqlSetup)
        if err != nil {
                log.Println("sql fatal error in setupDatabase")
                log.Printf("%q\n", err)
        }

	log.Printf("Setup Database\n")
}

func getKey( keyID int64, userID int64 ) (string) {
	// note if using mySQL use ? but Postgres is $1 in prepare statements
	stmt, err := db.Prepare(
		"SELECT keys.kVal  FROM keyUsers JOIN keys ON  keys.kID = keyUsers.kID WHERE keyUsers.uID = $2 AND keyUsers.kID = $1")
	if err != nil {
		log.Println("sql fatal error in getKey prep")
		log.Fatal(err)
	}
	var keyVal string
	err = stmt.QueryRow(keyID,userID).Scan( &keyVal )
	switch {
	case err == sql.ErrNoRows:
            log.Printf("no key found")
	case err != nil:
		log.Println("sql fatal error in getKey querry")
		log.Fatal(err)
	default:
		log.Println("got key " + keyVal)
		return keyVal;
	}
	return "";
}

func createKey(  userID int64, keyVal string ) (int64) {
	var keyID int64 = 108; // TODO - random

	// note if using mySQL use ? but Postgres is $1 in prepare statements
	//var stmt [3]*sql.Stmt;
	var err error;

	var stmt [3]*sql.Stmt;
	var cmd  [3]string = [3]string{"INSERT INTO keys (kID, kVal, oID) VALUES ($1, $2::bytea,$3)",
		"INSERT INTO keyUsers (kID,uID) VALUES ($1,$2)",
		"INSERT INTO keyAdmins (kID,uID) VALUES ($1,$2);" }

	for i := range cmd {
		stmt[i], err = db.Prepare( cmd[i] )
		if err != nil {
			log.Println("sql fatal error in createKey prep for", cmd[i])
			log.Fatal(err)
		}
	}

	for i := range cmd {
		if i == 0 {
			_,err = stmt[i].Exec(keyID,keyVal,userID)
		} else {
			_,err = stmt[i].Exec(keyID,userID)
		}

		if err != nil {
			log.Println("sql error in createKey",err)
			return 0;
		}
	}

	return keyID;
}

func mainHandler(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }

        type PageData struct {
                Junk string
        }
        data := PageData{Junk: "nothing"}
        err := templates.ExecuteTemplate(w, "index.html", data)
        if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
        }
}

func searchKeyHandler(w http.ResponseWriter, r *http.Request) {
	var err error

        w.Header().Set("Access-Control-Allow-Origin", "*")

	log.Println("got URL path " + r.URL.Path )

	elements := strings.Split( r.URL.Path  , "/" );
	// note since the URL starts with a /, we get an empty element as first thing in array

	if len(elements) != 4  {
		http.NotFound(w, r)
                return
	}

	var keyID int64 = 0;
	var userID int64 = 1;

	keyID,err = strconv.ParseInt( elements[3] , 0, 64 );
	if err != nil {
		http.NotFound(w, r)
		return
	}

	log.Println("GET keyID=", keyID, " userID=",userID )

	io.WriteString(w, getKey(keyID,userID) )
}

func createKeyHandler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")

        if r.Method != "POST" {
                http.Error(w, "method must be POST", http.StatusMethodNotAllowed)
                return
        }

	err := r.ParseForm()
        if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
        }

	var keyVal string = r.FormValue("keyVal");
	var userID int64 = 1;

	var keyID int64 = createKey( userID, keyVal );

	log.Println("POST keyID=", keyID, "userID=",userID, "keyVal=",keyVal )

	io.WriteString(w, "{ keyID: " )
	io.WriteString(w, strconv.FormatInt(keyID,10) )
	io.WriteString(w, " }" )
}

func main() {
	var err error

	var pgPassword string = os.Getenv("SECM_DB_SECRET")
	var hostName string = os.Args[1]

	setupDatabase(hostName,pgPassword)
        defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", mainHandler)
	http.HandleFunc("/v1/key/", searchKeyHandler)
	http.HandleFunc("/v1/key", createKeyHandler)

        http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package gateways

import (
	"fmt"
	"io"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"

	"github.com/ghmeier/bloodlines/config"
)

/*S3 defines an interface that will upload an image and return the image's url*/
type S3 interface {
	Upload(bucket, name string, body io.Reader) (string, error)
}

type s3Client struct {
	config config.S3
	client *s3.S3
}

/*NewS3 creates and returns an S3 gateway. If config is not empty, it attempts to set
  the environment variables, otherwise it relies on AWS_* env variables to be set*/
func NewS3(config config.S3) S3 {

	// Create S3 service client
	s := &s3Client{config: config}
	if config.Region != "" {
		os.Setenv("AWS_REGION", config.Region)
	}
	if config.AccessKey != "" {
		os.Setenv("AWS_ACCESS_KEY_ID", config.AccessKey)
	}
	if config.Secret != "" {
		os.Setenv("AWS_SECRET_ACCESS_KEY", config.Secret)
	}

	s.connect()
	return s
}

func (s *s3Client) connect() {
	if s.client != nil {
		return
	}

	sess := session.Must(session.NewSession(aws.NewConfig()))
	s.client = s3.New(sess)
}

func (s *s3Client) Upload(location, name string, body io.Reader) (string, error) {
	s.connect()

	err := s.client.WaitUntilBucketExists(&s3.HeadBucketInput{
		Bucket: aws.String(s.bucket(location)),
	})
	if err != nil {
		return "", err
	}

	uploader := s3manager.NewUploaderWithClient(s.client)
	res, err := uploader.Upload(&s3manager.UploadInput{
		Bucket: aws.String(s.bucket(location)),
		Key:    aws.String(name),
		Body:   body,
	})
	if err != nil {
		return "", err
	}

	fmt.Println(res.Location)
	return res.Location, nil
}

func (s *s3Client) bucket(name string) string {
	return fmt.Sprintf("%s-%s", s.config.Bucket, name)
}
<commit_msg>Update s3 default permissions<commit_after>package gateways

import (
	"fmt"
	"io"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"

	"github.com/ghmeier/bloodlines/config"
)

/*S3 defines an interface that will upload an image and return the image's url*/
type S3 interface {
	Upload(bucket, name string, body io.Reader) (string, error)
}

type s3Client struct {
	config config.S3
	client *s3.S3
}

/*NewS3 creates and returns an S3 gateway. If config is not empty, it attempts to set
  the environment variables, otherwise it relies on AWS_* env variables to be set*/
func NewS3(config config.S3) S3 {

	// Create S3 service client
	s := &s3Client{config: config}
	if config.Region != "" {
		os.Setenv("AWS_REGION", config.Region)
	}
	if config.AccessKey != "" {
		os.Setenv("AWS_ACCESS_KEY_ID", config.AccessKey)
	}
	if config.Secret != "" {
		os.Setenv("AWS_SECRET_ACCESS_KEY", config.Secret)
	}

	s.connect()
	return s
}

func (s *s3Client) connect() {
	if s.client != nil {
		return
	}

	sess := session.Must(session.NewSession(aws.NewConfig()))
	s.client = s3.New(sess)
}

func (s *s3Client) Upload(location, name string, body io.Reader) (string, error) {
	s.connect()

	err := s.client.WaitUntilBucketExists(&s3.HeadBucketInput{
		Bucket: aws.String(s.bucket(location)),
	})
	if err != nil {
		return "", err
	}

	uploader := s3manager.NewUploaderWithClient(s.client)
	res, err := uploader.Upload(&s3manager.UploadInput{
		Bucket: aws.String(s.bucket(location)),
		Key:    aws.String(name),
		Body:   body,
		ACL:    aws.String("public-read"),
	})
	if err != nil {
		return "", err
	}

	return res.Location, nil
}

func (s *s3Client) bucket(name string) string {
	return fmt.Sprintf("%s-%s", s.config.Bucket, name)
}
<|endoftext|>


<commit_before>package git

/*
#include <git2.h>
#include <git2/sys/repository.h>
*/
import "C"
import (
	"runtime"
	"unsafe"
)

// Repository
type Repository struct {
	ptr *C.git_repository
	// Remotes represents the collection of remotes and can be
	// used to add, remove and configure remotes for this
	// repository.
	Remotes RemoteCollection
	// Submodules represents the collection of submodules and can
	// be used to add, remove and configure submodules in this
	// repostiory.
	Submodules SubmoduleCollection
	// References represents the collection of references and can
	// be used to create, remove or update refernces for this repository.
	References ReferenceCollection
	// Notes represents the collection of notes and can be used to
	// read, write and delete notes from this repository.
	Notes NoteCollection
	// Tags represents the collection of tags and can be used to create,
	// list and iterate tags in this repository.
	Tags TagsCollection
	// Stashes represents the collection of stashes and can be used to
	// save, apply and iterate over stash states in this repository.
	Stashes StashCollection
}

func newRepositoryFromC(ptr *C.git_repository) *Repository {
	repo := &Repository{ptr: ptr}

	repo.Remotes.repo = repo
	repo.Submodules.repo = repo
	repo.References.repo = repo
	repo.Notes.repo = repo
	repo.Tags.repo = repo
	repo.Stashes.repo = repo

	runtime.SetFinalizer(repo, (*Repository).Free)

	return repo
}

func OpenRepository(path string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open(&ptr, cpath)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

type RepositoryOpenFlag int

const (
	RepositoryOpenNoSearch RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_NO_SEARCH
	RepositoryOpenCrossFs  RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_CROSS_FS
	RepositoryOpenBare     RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_BARE
)

func OpenRepositoryExtended(path string, flags RepositoryOpenFlag, ceiling string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	var cceiling *C.char = nil
	if len(ceiling) > 0 {
		cceiling = C.CString(ceiling)
		defer C.free(unsafe.Pointer(cceiling))
	}

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open_ext(&ptr, cpath, C.uint(flags), cceiling)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func InitRepository(path string, isbare bool) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_init(&ptr, cpath, ucbool(isbare))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func NewRepositoryWrapOdb(odb *Odb) (repo *Repository, err error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_wrap_odb(&ptr, odb.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func (v *Repository) SetRefdb(refdb *Refdb) {
	C.git_repository_set_refdb(v.ptr, refdb.ptr)
}

func (v *Repository) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_repository_free(v.ptr)
}

func (v *Repository) Config() (*Config, error) {
	config := new(Config)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_config(&config.ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(config, (*Config).Free)
	return config, nil
}

func (v *Repository) Index() (*Index, error) {
	var ptr *C.git_index

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_index(&ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newIndexFromC(ptr), nil
}

func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
	var ptr *C.git_object

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return allocObject(ptr, v), nil
}

func (v *Repository) Lookup(id *Oid) (*Object, error) {
	return v.lookupType(id, ObjectAny)
}

func (v *Repository) LookupTree(id *Oid) (*Tree, error) {
	obj, err := v.lookupType(id, ObjectTree)
	if err != nil {
		return nil, err
	}

	return obj.AsTree()
}

func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
	obj, err := v.lookupType(id, ObjectCommit)
	if err != nil {
		return nil, err
	}

	return obj.AsCommit()
}

func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
	obj, err := v.lookupType(id, ObjectBlob)
	if err != nil {
		return nil, err
	}

	return obj.AsBlob()
}

func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
	obj, err := v.lookupType(id, ObjectTag)
	if err != nil {
		return nil, err
	}

	return obj.AsTag()
}

func (v *Repository) Head() (*Reference, error) {
	var ptr *C.git_reference

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_head(&ptr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return newReferenceFromC(ptr, v), nil
}

func (v *Repository) SetHead(refname string) error {
	cname := C.CString(refname)
	defer C.free(unsafe.Pointer(cname))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head(v.ptr, cname)
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) SetHeadDetached(id *Oid) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head_detached(v.ptr, id.toC())
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) IsHeadDetached() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_head_detached(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}

	return ret != 0, nil
}

func (v *Repository) Walk() (*RevWalk, error) {

	var walkPtr *C.git_revwalk

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_revwalk_new(&walkPtr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return revWalkFromC(v, walkPtr), nil
}

func (v *Repository) CreateCommit(
	refname string, author, committer *Signature,
	message string, tree *Tree, parents ...*Commit) (*Oid, error) {

	oid := new(Oid)

	var cref *C.char
	if refname == "" {
		cref = nil
	} else {
		cref = C.CString(refname)
		defer C.free(unsafe.Pointer(cref))
	}

	cmsg := C.CString(message)
	defer C.free(unsafe.Pointer(cmsg))

	var cparents []*C.git_commit = nil
	var parentsarg **C.git_commit = nil

	nparents := len(parents)
	if nparents > 0 {
		cparents = make([]*C.git_commit, nparents)
		for i, v := range parents {
			cparents[i] = v.cast_ptr
		}
		parentsarg = &cparents[0]
	}

	authorSig, err := author.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(authorSig)

	committerSig, err := committer.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(committerSig)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_commit_create(
		oid.toC(), v.ptr, cref,
		authorSig, committerSig,
		nil, cmsg, tree.cast_ptr, C.size_t(nparents), parentsarg)

	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return oid, nil
}

func (v *Odb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_odb_free(v.ptr)
}

func (v *Refdb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_refdb_free(v.ptr)
}

func (v *Repository) Odb() (odb *Odb, err error) {
	odb = new(Odb)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_odb(&odb.ptr, v.ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(odb, (*Odb).Free)
	return odb, nil
}

func (repo *Repository) Path() string {
	return C.GoString(C.git_repository_path(repo.ptr))
}

func (repo *Repository) IsBare() bool {
	return C.git_repository_is_bare(repo.ptr) != 0
}

func (repo *Repository) Workdir() string {
	return C.GoString(C.git_repository_workdir(repo.ptr))
}

func (repo *Repository) SetWorkdir(workdir string, updateGitlink bool) error {
	cstr := C.CString(workdir)
	defer C.free(unsafe.Pointer(cstr))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_set_workdir(repo.ptr, cstr, cbool(updateGitlink)); ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

func (v *Repository) TreeBuilder() (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, nil); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, tree.cast_ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

type RepositoryState int

const (
	RepositoryStateNone                 RepositoryState = C.GIT_REPOSITORY_STATE_NONE
	RepositoryStateMerge                RepositoryState = C.GIT_REPOSITORY_STATE_MERGE
	RepositoryStateRevert               RepositoryState = C.GIT_REPOSITORY_STATE_REVERT
	RepositoryStateCherrypick           RepositoryState = C.GIT_REPOSITORY_STATE_CHERRYPICK
	RepositoryStateBisect               RepositoryState = C.GIT_REPOSITORY_STATE_BISECT
	RepositoryStateRebase               RepositoryState = C.GIT_REPOSITORY_STATE_REBASE
	RepositoryStateRebaseInteractive    RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE
	RepositoryStateRebaseMerge          RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_MERGE
	RepositoryStateApplyMailbox         RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX
	RepositoryStateApplyMailboxOrRebase RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE
)

func (r *Repository) State() RepositoryState {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	return RepositoryState(C.git_repository_state(r.ptr))
}

func (r *Repository) StateCleanup() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	cErr := C.git_repository_state_cleanup(r.ptr)
	if cErr < 0 {
		return MakeGitError(cErr)
	}
	return nil
}
func (r *Repository) AddGitIgnoreRules(rules string) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	crules := C.CString(rules)
	defer C.free(unsafe.Pointer(crules))
	if ret := C.git_ignore_add_rule(r.ptr, crules); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}

func (r *Repository) ClearGitIgnoreRules() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_ignore_clear_internal_rules(r.ptr); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}
<commit_msg>Add Repository.IsHeadUnborn<commit_after>package git

/*
#include <git2.h>
#include <git2/sys/repository.h>
*/
import "C"
import (
	"runtime"
	"unsafe"
)

// Repository
type Repository struct {
	ptr *C.git_repository
	// Remotes represents the collection of remotes and can be
	// used to add, remove and configure remotes for this
	// repository.
	Remotes RemoteCollection
	// Submodules represents the collection of submodules and can
	// be used to add, remove and configure submodules in this
	// repostiory.
	Submodules SubmoduleCollection
	// References represents the collection of references and can
	// be used to create, remove or update refernces for this repository.
	References ReferenceCollection
	// Notes represents the collection of notes and can be used to
	// read, write and delete notes from this repository.
	Notes NoteCollection
	// Tags represents the collection of tags and can be used to create,
	// list and iterate tags in this repository.
	Tags TagsCollection
	// Stashes represents the collection of stashes and can be used to
	// save, apply and iterate over stash states in this repository.
	Stashes StashCollection
}

func newRepositoryFromC(ptr *C.git_repository) *Repository {
	repo := &Repository{ptr: ptr}

	repo.Remotes.repo = repo
	repo.Submodules.repo = repo
	repo.References.repo = repo
	repo.Notes.repo = repo
	repo.Tags.repo = repo
	repo.Stashes.repo = repo

	runtime.SetFinalizer(repo, (*Repository).Free)

	return repo
}

func OpenRepository(path string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open(&ptr, cpath)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

type RepositoryOpenFlag int

const (
	RepositoryOpenNoSearch RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_NO_SEARCH
	RepositoryOpenCrossFs  RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_CROSS_FS
	RepositoryOpenBare     RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_BARE
)

func OpenRepositoryExtended(path string, flags RepositoryOpenFlag, ceiling string) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	var cceiling *C.char = nil
	if len(ceiling) > 0 {
		cceiling = C.CString(ceiling)
		defer C.free(unsafe.Pointer(cceiling))
	}

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_open_ext(&ptr, cpath, C.uint(flags), cceiling)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func InitRepository(path string, isbare bool) (*Repository, error) {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_init(&ptr, cpath, ucbool(isbare))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func NewRepositoryWrapOdb(odb *Odb) (repo *Repository, err error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	var ptr *C.git_repository
	ret := C.git_repository_wrap_odb(&ptr, odb.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newRepositoryFromC(ptr), nil
}

func (v *Repository) SetRefdb(refdb *Refdb) {
	C.git_repository_set_refdb(v.ptr, refdb.ptr)
}

func (v *Repository) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_repository_free(v.ptr)
}

func (v *Repository) Config() (*Config, error) {
	config := new(Config)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_config(&config.ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(config, (*Config).Free)
	return config, nil
}

func (v *Repository) Index() (*Index, error) {
	var ptr *C.git_index

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_index(&ptr, v.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return newIndexFromC(ptr), nil
}

func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
	var ptr *C.git_object

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return allocObject(ptr, v), nil
}

func (v *Repository) Lookup(id *Oid) (*Object, error) {
	return v.lookupType(id, ObjectAny)
}

func (v *Repository) LookupTree(id *Oid) (*Tree, error) {
	obj, err := v.lookupType(id, ObjectTree)
	if err != nil {
		return nil, err
	}

	return obj.AsTree()
}

func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
	obj, err := v.lookupType(id, ObjectCommit)
	if err != nil {
		return nil, err
	}

	return obj.AsCommit()
}

func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
	obj, err := v.lookupType(id, ObjectBlob)
	if err != nil {
		return nil, err
	}

	return obj.AsBlob()
}

func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
	obj, err := v.lookupType(id, ObjectTag)
	if err != nil {
		return nil, err
	}

	return obj.AsTag()
}

func (v *Repository) Head() (*Reference, error) {
	var ptr *C.git_reference

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_head(&ptr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return newReferenceFromC(ptr, v), nil
}

func (v *Repository) SetHead(refname string) error {
	cname := C.CString(refname)
	defer C.free(unsafe.Pointer(cname))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head(v.ptr, cname)
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) SetHeadDetached(id *Oid) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_repository_set_head_detached(v.ptr, id.toC())
	if ecode != 0 {
		return MakeGitError(ecode)
	}
	return nil
}

func (v *Repository) IsHeadDetached() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_head_detached(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}

	return ret != 0, nil
}

func (v *Repository) IsHeadUnborn() (bool, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_repository_head_unborn(v.ptr)
	if ret < 0 {
		return false, MakeGitError(ret)
	}
	return ret != 0, nil
}

func (v *Repository) Walk() (*RevWalk, error) {

	var walkPtr *C.git_revwalk

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ecode := C.git_revwalk_new(&walkPtr, v.ptr)
	if ecode < 0 {
		return nil, MakeGitError(ecode)
	}

	return revWalkFromC(v, walkPtr), nil
}

func (v *Repository) CreateCommit(
	refname string, author, committer *Signature,
	message string, tree *Tree, parents ...*Commit) (*Oid, error) {

	oid := new(Oid)

	var cref *C.char
	if refname == "" {
		cref = nil
	} else {
		cref = C.CString(refname)
		defer C.free(unsafe.Pointer(cref))
	}

	cmsg := C.CString(message)
	defer C.free(unsafe.Pointer(cmsg))

	var cparents []*C.git_commit = nil
	var parentsarg **C.git_commit = nil

	nparents := len(parents)
	if nparents > 0 {
		cparents = make([]*C.git_commit, nparents)
		for i, v := range parents {
			cparents[i] = v.cast_ptr
		}
		parentsarg = &cparents[0]
	}

	authorSig, err := author.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(authorSig)

	committerSig, err := committer.toC()
	if err != nil {
		return nil, err
	}
	defer C.git_signature_free(committerSig)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_commit_create(
		oid.toC(), v.ptr, cref,
		authorSig, committerSig,
		nil, cmsg, tree.cast_ptr, C.size_t(nparents), parentsarg)

	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return oid, nil
}

func (v *Odb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_odb_free(v.ptr)
}

func (v *Refdb) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_refdb_free(v.ptr)
}

func (v *Repository) Odb() (odb *Odb, err error) {
	odb = new(Odb)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_odb(&odb.ptr, v.ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(odb, (*Odb).Free)
	return odb, nil
}

func (repo *Repository) Path() string {
	return C.GoString(C.git_repository_path(repo.ptr))
}

func (repo *Repository) IsBare() bool {
	return C.git_repository_is_bare(repo.ptr) != 0
}

func (repo *Repository) Workdir() string {
	return C.GoString(C.git_repository_workdir(repo.ptr))
}

func (repo *Repository) SetWorkdir(workdir string, updateGitlink bool) error {
	cstr := C.CString(workdir)
	defer C.free(unsafe.Pointer(cstr))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_repository_set_workdir(repo.ptr, cstr, cbool(updateGitlink)); ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

func (v *Repository) TreeBuilder() (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, nil); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) {
	bld := new(TreeBuilder)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, tree.cast_ptr); ret < 0 {
		return nil, MakeGitError(ret)
	}
	runtime.SetFinalizer(bld, (*TreeBuilder).Free)

	bld.repo = v
	return bld, nil
}

type RepositoryState int

const (
	RepositoryStateNone                 RepositoryState = C.GIT_REPOSITORY_STATE_NONE
	RepositoryStateMerge                RepositoryState = C.GIT_REPOSITORY_STATE_MERGE
	RepositoryStateRevert               RepositoryState = C.GIT_REPOSITORY_STATE_REVERT
	RepositoryStateCherrypick           RepositoryState = C.GIT_REPOSITORY_STATE_CHERRYPICK
	RepositoryStateBisect               RepositoryState = C.GIT_REPOSITORY_STATE_BISECT
	RepositoryStateRebase               RepositoryState = C.GIT_REPOSITORY_STATE_REBASE
	RepositoryStateRebaseInteractive    RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE
	RepositoryStateRebaseMerge          RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_MERGE
	RepositoryStateApplyMailbox         RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX
	RepositoryStateApplyMailboxOrRebase RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE
)

func (r *Repository) State() RepositoryState {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	return RepositoryState(C.git_repository_state(r.ptr))
}

func (r *Repository) StateCleanup() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	cErr := C.git_repository_state_cleanup(r.ptr)
	if cErr < 0 {
		return MakeGitError(cErr)
	}
	return nil
}
func (r *Repository) AddGitIgnoreRules(rules string) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	crules := C.CString(rules)
	defer C.free(unsafe.Pointer(crules))
	if ret := C.git_ignore_add_rule(r.ptr, crules); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}

func (r *Repository) ClearGitIgnoreRules() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if ret := C.git_ignore_clear_internal_rules(r.ptr); ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2011 The Perkeep 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 localdisk registers the "filesystem" blobserver storage type,
storing blobs in a forest of sharded directories at the specified root.

Example low-level config:

     "/storage/": {
         "handler": "storage-filesystem",
         "handlerArgs": {
            "path": "/var/camlistore/blobs"
          }
     },

*/
package localdisk // import "perkeep.org/pkg/blobserver/localdisk"

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"perkeep.org/internal/osutil"
	"perkeep.org/pkg/blob"
	"perkeep.org/pkg/blobserver"
	"perkeep.org/pkg/blobserver/files"
	"perkeep.org/pkg/blobserver/local"

	"go4.org/jsonconfig"
	"go4.org/syncutil"
)

// DiskStorage implements the blobserver.Storage interface using the
// local filesystem.
type DiskStorage struct {
	blobserver.Storage

	root string

	// gen will be nil if partition != ""
	gen *local.Generationer
}

func (ds *DiskStorage) String() string {
	return fmt.Sprintf("\"filesystem\" file-per-blob at %s", ds.root)
}

// IsDir reports whether root is a localdisk (file-per-blob) storage directory.
func IsDir(root string) (bool, error) {
	if osutil.DirExists(filepath.Join(root, "sha1")) {
		return true, nil
	}
	if osutil.DirExists(filepath.Join(root, blob.RefFromString("").HashName())) {
		return true, nil
	}
	return false, nil
}

const (
	// We refuse to create a DiskStorage when the user's ulimit is lower than
	// minFDLimit. 100 is ridiculously low, but the default value on OSX is 256, and we
	// don't want to fail by default, so our min value has to be lower than 256.
	minFDLimit         = 100
	recommendedFDLimit = 1024
)

// New returns a new local disk storage implementation at the provided
// root directory, which must already exist.
func New(root string) (*DiskStorage, error) {
	// Local disk.
	fi, err := os.Stat(root)
	if os.IsNotExist(err) {
		// As a special case, we auto-created the "packed" directory for subpacked.
		if filepath.Base(root) == "packed" {
			if err := os.Mkdir(root, 0700); err != nil {
				return nil, fmt.Errorf("failed to mkdir packed directory: %v", err)
			}
			fi, err = os.Stat(root)
		} else {
			return nil, fmt.Errorf("Storage root %q doesn't exist", root)
		}
	}
	if err != nil {
		return nil, fmt.Errorf("Failed to stat directory %q: %v", root, err)
	}
	if !fi.IsDir() {
		return nil, fmt.Errorf("storage root %q exists but is not a directory", root)
	}
	fileSto := files.NewStorage(files.OSFS(), root)
	ds := &DiskStorage{
		Storage: fileSto,
		root:    root,
		gen:     local.NewGenerationer(root),
	}
	if _, _, err := ds.StorageGeneration(); err != nil {
		return nil, fmt.Errorf("Error initialization generation for %q: %v", root, err)
	}
	ul, err := osutil.MaxFD()
	if err != nil {
		if err == osutil.ErrNotSupported {
			// Do not set the gate on Windows, since we don't know the ulimit.
			return ds, nil
		}
		return nil, err
	}
	if ul < minFDLimit {
		return nil, fmt.Errorf("the max number of open file descriptors on your system (ulimit -n) is too low. Please fix it with 'ulimit -S -n X' with X being at least %d", recommendedFDLimit)
	}
	// Setting the gate to 80% of the ulimit, to leave a bit of room for other file ops happening in Perkeep.
	// TODO(mpl): make this used and enforced Perkeep-wide. Issue #837.
	fileSto.SetNewFileGate(syncutil.NewGate(int(ul * 80 / 100)))

	err = ds.checkFS()
	if err != nil {
		return nil, err
	}
	return ds, nil
}

func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (storage blobserver.Storage, err error) {
	path := config.RequiredString("path")
	if err := config.Validate(); err != nil {
		return nil, err
	}
	return New(path)
}

func init() {
	blobserver.RegisterStorageConstructor("filesystem", blobserver.StorageConstructor(newFromConfig))
}

// checkFS verifies the DiskStorage root storage path
// operations include: stat, read/write file, mkdir, delete (files and directories)
//
// TODO: move this into the files package too?
func (ds *DiskStorage) checkFS() (ret error) {
	tempdir, err := ioutil.TempDir(ds.root, "")
	if err != nil {
		return fmt.Errorf("localdisk check: unable to create tempdir in %s, err=%v", ds.root, err)
	}
	defer func() {
		err := os.RemoveAll(tempdir)
		if err != nil {
			cleanErr := fmt.Errorf("localdisk check: unable to clean temp dir: %v", err)
			if ret == nil {
				ret = cleanErr
			} else {
				log.Printf("WARNING: %v", cleanErr)
			}
		}
	}()

	tempfile := filepath.Join(tempdir, "FILE.tmp")
	filename := filepath.Join(tempdir, "FILE")
	data := []byte("perkeep rocks")
	err = ioutil.WriteFile(tempfile, data, 0644)
	if err != nil {
		return fmt.Errorf("localdisk check: unable to write into %s, err=%v", ds.root, err)
	}

	out, err := ioutil.ReadFile(tempfile)
	if err != nil {
		return fmt.Errorf("localdisk check: unable to read from %s, err=%v", tempfile, err)
	}
	if bytes.Compare(out, data) != 0 {
		return fmt.Errorf("localdisk check: tempfile contents didn't match, got=%q", out)
	}
	if _, err := os.Lstat(filename); !os.IsNotExist(err) {
		return fmt.Errorf("localdisk check: didn't expect file to exist, Lstat had other error, err=%v", err)
	}
	if err := os.Rename(tempfile, filename); err != nil {
		return fmt.Errorf("localdisk check: rename failed, err=%v", err)
	}
	if _, err := os.Lstat(filename); err != nil {
		return fmt.Errorf("localdisk check: after rename passed Lstat had error, err=%v", err)
	}
	return nil
}
<commit_msg>blobserver/localdisk: be sure to implement SubFetcher for blobpacked<commit_after>/*
Copyright 2011 The Perkeep 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 localdisk registers the "filesystem" blobserver storage type,
storing blobs in a forest of sharded directories at the specified root.

Example low-level config:

     "/storage/": {
         "handler": "storage-filesystem",
         "handlerArgs": {
            "path": "/var/camlistore/blobs"
          }
     },

*/
package localdisk // import "perkeep.org/pkg/blobserver/localdisk"

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"perkeep.org/internal/osutil"
	"perkeep.org/pkg/blob"
	"perkeep.org/pkg/blobserver"
	"perkeep.org/pkg/blobserver/files"
	"perkeep.org/pkg/blobserver/local"

	"go4.org/jsonconfig"
	"go4.org/syncutil"
)

// TODO: rename DiskStorage to Storage.

// DiskStorage implements the blobserver.Storage interface using the
// local filesystem.
type DiskStorage struct {
	blobserver.Storage
	blob.SubFetcher

	root string

	// gen will be nil if partition != ""
	gen *local.Generationer
}

// Validate we implement expected interfaces.
var (
	_ blobserver.Storage = (*DiskStorage)(nil)
	_ blob.SubFetcher    = (*DiskStorage)(nil) // for blobpacked; Issue 1136
)

func (ds *DiskStorage) String() string {
	return fmt.Sprintf("\"filesystem\" file-per-blob at %s", ds.root)
}

// IsDir reports whether root is a localdisk (file-per-blob) storage directory.
func IsDir(root string) (bool, error) {
	if osutil.DirExists(filepath.Join(root, "sha1")) {
		return true, nil
	}
	if osutil.DirExists(filepath.Join(root, blob.RefFromString("").HashName())) {
		return true, nil
	}
	return false, nil
}

const (
	// We refuse to create a DiskStorage when the user's ulimit is lower than
	// minFDLimit. 100 is ridiculously low, but the default value on OSX is 256, and we
	// don't want to fail by default, so our min value has to be lower than 256.
	minFDLimit         = 100
	recommendedFDLimit = 1024
)

// New returns a new local disk storage implementation at the provided
// root directory, which must already exist.
func New(root string) (*DiskStorage, error) {
	// Local disk.
	fi, err := os.Stat(root)
	if os.IsNotExist(err) {
		// As a special case, we auto-created the "packed" directory for subpacked.
		if filepath.Base(root) == "packed" {
			if err := os.Mkdir(root, 0700); err != nil {
				return nil, fmt.Errorf("failed to mkdir packed directory: %v", err)
			}
			fi, err = os.Stat(root)
		} else {
			return nil, fmt.Errorf("Storage root %q doesn't exist", root)
		}
	}
	if err != nil {
		return nil, fmt.Errorf("Failed to stat directory %q: %v", root, err)
	}
	if !fi.IsDir() {
		return nil, fmt.Errorf("storage root %q exists but is not a directory", root)
	}
	fileSto := files.NewStorage(files.OSFS(), root)
	ds := &DiskStorage{
		Storage:    fileSto,
		SubFetcher: fileSto,
		root:       root,
		gen:        local.NewGenerationer(root),
	}
	if _, _, err := ds.StorageGeneration(); err != nil {
		return nil, fmt.Errorf("Error initialization generation for %q: %v", root, err)
	}
	ul, err := osutil.MaxFD()
	if err != nil {
		if err == osutil.ErrNotSupported {
			// Do not set the gate on Windows, since we don't know the ulimit.
			return ds, nil
		}
		return nil, err
	}
	if ul < minFDLimit {
		return nil, fmt.Errorf("the max number of open file descriptors on your system (ulimit -n) is too low. Please fix it with 'ulimit -S -n X' with X being at least %d", recommendedFDLimit)
	}
	// Setting the gate to 80% of the ulimit, to leave a bit of room for other file ops happening in Perkeep.
	// TODO(mpl): make this used and enforced Perkeep-wide. Issue #837.
	fileSto.SetNewFileGate(syncutil.NewGate(int(ul * 80 / 100)))

	err = ds.checkFS()
	if err != nil {
		return nil, err
	}
	return ds, nil
}

func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (storage blobserver.Storage, err error) {
	path := config.RequiredString("path")
	if err := config.Validate(); err != nil {
		return nil, err
	}
	return New(path)
}

func init() {
	blobserver.RegisterStorageConstructor("filesystem", blobserver.StorageConstructor(newFromConfig))
}

// checkFS verifies the DiskStorage root storage path
// operations include: stat, read/write file, mkdir, delete (files and directories)
//
// TODO: move this into the files package too?
func (ds *DiskStorage) checkFS() (ret error) {
	tempdir, err := ioutil.TempDir(ds.root, "")
	if err != nil {
		return fmt.Errorf("localdisk check: unable to create tempdir in %s, err=%v", ds.root, err)
	}
	defer func() {
		err := os.RemoveAll(tempdir)
		if err != nil {
			cleanErr := fmt.Errorf("localdisk check: unable to clean temp dir: %v", err)
			if ret == nil {
				ret = cleanErr
			} else {
				log.Printf("WARNING: %v", cleanErr)
			}
		}
	}()

	tempfile := filepath.Join(tempdir, "FILE.tmp")
	filename := filepath.Join(tempdir, "FILE")
	data := []byte("perkeep rocks")
	err = ioutil.WriteFile(tempfile, data, 0644)
	if err != nil {
		return fmt.Errorf("localdisk check: unable to write into %s, err=%v", ds.root, err)
	}

	out, err := ioutil.ReadFile(tempfile)
	if err != nil {
		return fmt.Errorf("localdisk check: unable to read from %s, err=%v", tempfile, err)
	}
	if bytes.Compare(out, data) != 0 {
		return fmt.Errorf("localdisk check: tempfile contents didn't match, got=%q", out)
	}
	if _, err := os.Lstat(filename); !os.IsNotExist(err) {
		return fmt.Errorf("localdisk check: didn't expect file to exist, Lstat had other error, err=%v", err)
	}
	if err := os.Rename(tempfile, filename); err != nil {
		return fmt.Errorf("localdisk check: rename failed, err=%v", err)
	}
	if _, err := os.Lstat(filename); err != nil {
		return fmt.Errorf("localdisk check: after rename passed Lstat had error, err=%v", err)
	}
	return nil
}
<|endoftext|>